--- /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://www.denx.de/en/Software/GIT
+
+Then you need to compile it with the same cross compiler as you would use
+for the Linux kernel. Then you need to flash it to the board either via the
+serial port, or by using a JTAG.
+
+Once you have the bootloader running, you can compile the kernel.
+
+You can get the OMAP sources either from the OMAP GIT tree, or by
+applying patches. The OMAP GIT tree has the most up to date sources
+and is the recommended one.
+
+- Using GIT and cloning OMAP GIT tree please follow the README at:
+
+http://www.muru.com/linux/omap/README_OMAP_GIT
+
+Hint: If you are sitting behind a firewall and have to use a proxy for
+internet access, you can access GIT by http by setting the
+http_proxy envirionment variable:
+
+http_proxy=http://proxy_username:proxy_password@proxy_name:proxy_port/
+
+If you use bash shell, then this might look like:
+
+export http_proxy=http://foo:123@abc.host.com:8080/
+
+with:
+
+foo: Your user name for the proxy
+123: Your password for the proxy
+abc.host.com: The name of your proxy you use for internet access
+8080: The port used on to access the proxy
+
+
+- Using Patches:
+
+If you don't want to use GIT, then you can do the same thing with patch.
+
+Download the latest OMAP Linux patch from:
+
+http://www.muru.com/linux/omap/
+
+Get a matching Linux kernel from:
+
+ftp://ftp.kernel.org/pub/linux/kernel/v2.6/
+
+For example, if you download Linux-2.6.4-omap1 from muru.com, then you need
+linux-2.6.4 kernel from kernel.org:
+
+$ wget ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.4.tar.bz2
+$ tar xjf linux-2.6.4.tar.bz2
+$ cd linux-2.6.4
+$ cat ../Linux-2.6.4-omap1 | patch -p1
+
+Note: If OMAP patch from muru.com is against a kernel release candidate,
+marked by -rcX, then kernel can be found on kernel.org under v2.6/testing/
+
+Now, if you have a local kernel tree, either by GIT or by patch, you
+should look into arch/arm/configs/ to see which of the various omap_xxx
+configurations there you want to use. For example, if you have a OMAP1510
+based Innovator board, you select omap_innovator_1510_defconfig by
+
+$ make omap_innovator_1510_defconfig
+
+at top level directory (linux-2.6.4 in the example above).
+
+Then you can compile the kernel with
+
+$ make vmlinux
+
+Or make Image or make zImage or make uImage.
+
+Once you have the kernel compiled, you can upload it to the board via serial
+port or JTAG (see below).
+
+Then you need a root file system either as initrd or on the flash.
+
+Once you have the system booting to Linux, you can use pretty much any Linux
+applications cross compiled for ARM.
+
+
+2. JTAG usage
+--------------------------------------------------------------
+
+If the flash of your board is really 'empty' and no bootloader is on the board
+(e.g. u-boot) then you need a JTAG connection. With JTAG you can write
+a bootloader to board's flash or download OMAP Linux kernel. For OMAP
+commercial JTAG tools are available, so you have to pay for it.
+
+Examples are TI's Code Composer Studio (CCS) or Lauterbach's TRACE32 JTAG.
+
+- Linux kernel download with CCS
+
+You can use CCS to directly load an ELF file to your board. For example, use
+arch/arm/boot/compressed/vmlinux. zImage isn't suited because it is not an ELF
+file. CCS looks for .out files, so copy arch/arm/boot/compressed/vmlinux
+to vmlinux.out and load it using CCS. Or use the filter *.* to select
+vmlinux directly. Remember to run arm-linux-strip on ELF file first as CCS
+get stroppy about unstripped ELF files.
+
+If you want vmlinux to be linked to run at a specific address, you can use
+the CONFIG_ZBOOT options in the kernel build. But first try without
+CONFIG_ZBOOT as the compressed image should be able to run from address
+zero (if your CCS .gel files map address zero.)
+
+Otherwise, use something like this:
+
+CONFIG_ZBOOT_ROM=y
+CONFIG_ZBOOT_ROM_TEXT=10408000
+CONFIG_ZBOOT_ROM_BSS=10800000
+
+Also note that CCS is pretty useless for debugging Linux as it doesn't
+properly handle virtual memory. In other words, once the MMU is
+turned on and Linux is using virtual memory, CCS can no longer
+properly disassemble, set breakpoints or read memory.
+
+
+- Linux kernel download with Lauterbach TRACE32
+
+To be done.
+
+
+3. How to add new processor or board to OMAP Linux kernel tree
+--------------------------------------------------------------
+
+It is assumed that the OMAP processor to be added is based on an already
+supported ARM core (e.g. ARM925 or ARM926). How to add support for new ARM
+processor core that is not supported by ARM Linux is not scope of this document.
+
+1. If a new OMAP processor should be added, identify the ARM core of this
+processor. E.g. at time of writing this document in March 2004 OMAP730 (ARM926
+core), OMAP1510 (ARM925 core) and OMAP1610 (ARM926 core) are supported.
+
+For a new board or device, identify the OMAP processor on the board. E.g. at
+time of writing this document in March 2004 four boards are supported:
+Innovator1510 (OMAP1510 processor), Innovator1610 (OMAP1610 processor),
+Perseus2 (OMAP730 processor) and H2 (OMAP1610 processor).
+
+Please refer http://www.muru.com/linux/omap/ to get latest information on the
+list of boards supported.
+
+/* Discussion needed: How to handle the tons of compatible processors?
+E.g. what to do if OMAP16xx is mainly identical with OMAP16yy? */
+
+2. Start with arch/arm/mach-omap[1/2]/Kconfig and add a new processor or board
+option.
+
+To add a new processor add a new config option to the "OMAP Core Type" choice.
+See examples for the syntax. The config option has to be called "ARCH_OMAPxxxx"
+where xxxx is the number of OMAP processor. Don't forget to select a existing
+clock frequency or to add a new one in "OMAP Feature Selections" section for
+your new processor.
+
+To add a new board or device, add a new config option to the "OMAP Board Type"
+choice. See examples for the syntax. The config option for boards has to be
+called "MACH_OMAP_yyyy" where yyyy is the board name. Don't forget to add a
+short help.
+
+Note: Kernel 2.6 Kconfig system will automatically expand the configuration
+names with a leading "CONFIG_". So "ARCH_OMAPxxxx" will be expanded to
+"CONFIG_ARCH_OMAPxxxx" and "MACH_OMAP_yyy" will expand to
+"CONFIG_MACH_OMAP_yyyy". In code this can then be used by macros like
+"#ifdef CONFIG_ARCH_OMAPxxxx" and "#ifdef CONFIG_MACH_OMAP_yyyy".
+
+Note: How to handle boards which are compatible or extensions of other boards?
+See MACH_OMAP_H2 for example. The H2 depends on MACH_OMAP_INNOVATOR and expands
+it. This is done by an additional select MACH_OMAP_INNOVATOR in MACH_OMAP_H2
+configuration option. With this the whole MACH_OMAP_INNOVATOR configuration is
+selected and an additional symbol CONFIG_MACH_OMAP_H2 is available to
+distinguish between INNOVATOR and H2 where necessary.
+
+3a. Only for new processors: Add the ARCH_OMAPxxxx to the correct ARM core in
+arch/arm/mm/Kconfig. E.g. ARCH_OMAP730 in CPU_ARM926T configuration.
+
+3b. Only for new boards: Register the board within ARM Linux machine
+registration system from RMK. For the CONFIG_ section use the same name like
+in arch/arm/mach-omap[1/2]/Kconfig. E.g. MACH_OMAP_yyyy. For MACH_TYPE_ section use
+OMAP_yyyy where yyyy is the board name like above.
+
+Note: The elements of RMKs machine registration are used in
+arch/arm/tools/mach-types. While kernel compilation
+include/asm-arm/mach-types.h is generated automagically from this file. The
+content of mach-types.h then is used for machine identification by kernel
+bootcode and can be used for board identification.
+
+Note: The ARM Linux machine registration system from RMK can be found under:
+
+www.arm.linux.org.uk/developer/machines/
+
+Note: Only OMAP based boards should be registered to RMKs registration
+system. Not processors.
+
+4. Add a processor or board specific header file in include/asm-arm/arch-omap/.
+Use board-yyyy.h with yyyy board name or omapxxxx.h with xxxx processor number.
+
+5. Add a processor or board specific section into include/asm-arm/arch-omap/
+hardware.h. Use examples for syntax and use CONFIG_ names as defined in
+arch/arm/mach-omap[1/2]/Kconfig.
+
+6. Add processor or board specific macros to board-yyyy.h or omapxxxx.h. The
+macros to these specific files have to be named OMAPxxxx_ with xxxx processor
+number to make them unique.
+
+7a. Only for new boards: Add a file board-yyyy.c with yyyy board name to
+arch/arm/mach-omap[1/2]/. Put board specific initialization code and resource
+description into this file. The first element of MACHINE_START must be equal to
+MACH_TYPE_ section of machine registration (see arch/arm/tools/mach-types after
+machine registration at RMKs registration system).
+
+Put only code into this file that is board specific and not common. See other
+board files for examples.
+
+7b. Only for new processors: Add processor specific IO description and
+iotable_init() to arch/arm/mach-omap[1/2]/io.c. See examples for the syntax.
+
+If you have introduced new clock definition in 2., add support for this new
+clock in include/asm-arm/arch-omap/clocks.h and arch/arm/mach-omap[1/2]/clocks.c.
+
+8. Only for new boards: Add "obj-$(CONFIG_MACH_OMAP_yyyy) += board-yyyy.o" with
+yyyy board name to arch/arm/mach-omap[1/2]/Makefile. This is used to compile your new
+board specific initialization code from 7a.
+
+9. Check if other of the existing files have to be adjusted for the new
+processor or board. Things to check:
+
+- Pin multiplexing
+- GPIO configuration
+- Power Management
+- Clocking
+- Interrupt controller and interrupt configuration
+- Additional board specific things (e.g. FPGAs)
+
+If other existing files or device drivers have to be changed, use the following
+mechanism for processor specific things:
+
+#ifdef CONFIG_ARCH_OMAPxxxx
+ if (cpu_is_omapxxxx()) {
+ /* Do the OMAPxxxx processor specific magic */
+ }
+#endif
+
+Note: cpu_is_omapxxxx() macro is defined in include/asm-arm/arch-omap/hardware.h
+and uses OMAP_ID_REG for runtime processor identifcation.
+
+For board differentiation use board macro from include/asm-arm/mach-types.h:
+
+#ifdef CONFIG_MACH_OMAP_yyyy
+ if (machine_is_omap_yyyy()) {
+ /* Do the board specific magic */
+ }
+#endif
+
+Note: If technically possible and already implemented the OMAP Linux kernel
+has support for a "one binary fits all" machanism. That is, the goal is to be
+able to enable support for multiple OMAP processors and/or boards in Kconfig
+system. Then it is decided by bootparameters and at runtime on which processor
+and/or board the kernel is actually running on. With this machanism it is
+possible to use the same kernel binary on different OMAP processors or boards
+without recompiling. This is achived by the cpu_is_omapxxxx() and
+machine_is_omap_yyyy() macros.
+
+On the other hand, for memory limited embedded systems it should be possible
+to compile the kernel with support for only one processor/board combination.
+For this a kernel binary is necessary which isn't bloated with code for all
+other (unused) processors and boards. This is achived by using the preprocessor
+CONFIG_ARCH_OMAPxxxx and CONFIG_MACH_OMAP_yyyy macros around the runtime
+cpu_is_omapxxxx() and machine_is_omap_yyyy() selection.
+
+At the moment, the price for this flexibility is a increased number of #ifdef's
+throughout the code.
+
+10. Configure the kernel by make menuconfig or make xconfig and select the new
+processor or board.
+
+11. Compile the kernel by an appropriate cross compilation toolchain. Make this
+until the code compiles error and warning free. The kernel should also be
+compiled with the various debug checking thingies enabled (e.g.
+CONFIG_DEBUG_SPINLOCK, CONFIG_DEBUG_PAGEALLOC etc.).
+
+/* ToDo: Anything to say about toolchain? */
+
+12. Download the kernel image to the board and test it until it works ;-)
+
+It's not in the scope of this document how to do this (use a appropriate
+bootloader or JTAG download).
+
+Note: The kernel initialization code expects some special values in the
+registers R0, R1 and R2 of the ARM processor. These registers have to be
+written by bootloader or debugger before starting the kernel. R0 has to be
+zero, R1 has to contain the machine number from machine registration in
+arch/arm/tools/mach-types. R2 points to the physical address of tagged list
+in system RAM. For more information see Documentation/arm/Booting.
+
+While testing a new processor or board configuration, it is recommended to
+enable low level debugging. This uses low level output functions to print kernel
+messages on serial line before console is working. Enable it by
+
+Kernel hacking -> Kernel debugging -> Kernel low-level debugging functions
+
+in kernel configuration system.
+
+13. Check that no other processors or boards are broken by the new code. A first
+test is to successful compile the other omap_xxx configurations from
+arch/arm/configs/. Do this by e.g.
+
+cd linux
+make omap_innovator_1510_defconfig
+Compile the kernel
+
+Even better: Enable support for several processors and boards in Kconfig
+system and compile kernel successfully.
+
+14. Only for new boards: Add a new default board configuration to
+arch/arm/configs. Use omap_yyyy_xxxx_defconfig with yyyy boardname and xxxx
+processornumber as filename.
+
+15. If the new code works, compiles without warnings and seems to break no other
+configurations, post a patch to linux-omap-open-source@list.ti.com.
+
+With sending a patch to the community, it is reviewed, can be used and tested by
+other users. It then can be included into the public OMAP kernel tree.
+
+16. Then adapt device drivers or write additional drivers for non-existing
+processor peripherals or board devices. Improve and maintain the code for your
+new processor or board.
+
+
+4. General guidelines to write clean and OMAP Linux compatible code
+-------------------------------------------------------------------
+
+- For register access use the __REG8/16/32() macros. At the moment, see first
+example in include/asm-arm/arch-omap/hardware.h.
+
+Allegedly __REG() makes at least some versions of GCC emit tighter code
+than the more direct wrappers. Presumably by making it easier to use certain
+addressing modes.
+
+Make sure that the registers names are clearly marked as being registers
+(and not addresses of registers). This has to be done by adding a '_REG'
+suffix. E.g.
+
+#define OMAP_ID_REG (__REG32(0xfffed400))
+#define DPLL_CTL_REG (__REG16(0xfffecf00))
+
+__raw_read[bwl] and __raw_write[bwl] are deprecated. They will converted to
+__REG8/16/32() syntax, soon. Don't use anything else like own pointer
+definitions or in[bwl]/out[bwl] etc., too.
+
+- Make read-modify-write register access preemption save. Use spin_lock() and
+spin_unlock() where necessary. If an IRQ handler can access the registers,
+use spin_lock_irqsave(), too.
+
+- Functions declared as __init shouldn't have any references after the kernel
+initialization phase is complete. Usually they should be static as well.
+
+- Don't use return statements at end of void functions.
+
+- Use consistent indentation style. Don't use space indentations. Use tab
+indentations.
+
+- In general use Linux formatting style. See Documentation/CodingStyle for more
+information. If you use GNU emacs, see also chapter 8 of that document how to
+add a linux-c-mode to emacs.
+
+
+------------------------------------------------------------------
+Last modified 15. March 2006
+The OMAP Linux Kernel Team
+Dirk Behme <dirk.behme@de.bosch.com>
--- /dev/null
+
+ OMAP GPIO API's HowTo
+ =====================
+
+This document is a short summary how to use OMAP Linux GPIO API. It is
+mainly focussed on OMAP5912 OSK, but should fit with extensions (more
+or less GPIOs) to other OMAP processors as well.
+
+If anything is missing, is wrong, needs extension or update, please send
+update to Linux-omap-open-source@linux.omap.com.
+
+I. GPIO Modules/Banks
+---------------------
+
+OMAP5912 OSK has 64 GPIOs (general purpose IO pins). These are organized
+in four modules (banks) with 16 pins each. OMAP GPIO API doesn't distinguish
+between modules and numbers the pins from 0 - 63:
+
+A) GPIO MODULE/BANK 0 - PIN 0-15
+B) GPIO MODULE/BANK 1 - PIN 16-31
+C) GPIO MODULE/BANK 2 - PIN 32-47
+D) GPIO MODULE/BANK 3 - PIN 48-63
+
+See
+
+http://www-s.ti.com/sc/psheets/spru767a/spru767a.pdf
+
+for more details.
+
+II. GPIO API's
+--------------
+
+A) Include
+
+#include <asm/arch/gpio.h>
+
+B) omap_cfg_reg(xxxx);
+
+Description: Configure pin mux.
+
+Parameter: Pin to be configured for GPIO.
+
+Note: This function may only be necessary for some GPIO pins. Because OMAP
+ chip itself has less real hardware pins than necessary to use all
+ its functionality at the same time, some pins share different
+ functions (called pin multiplexing, short pin mux). E.g. one pin may
+ be used for serial interface *or* GPIO. Check if this is the case for
+ the GPIO you want to use and if you have to configure the pin mux.
+
+C) omap_request_gpio(int gpio)
+
+Description: Request GPIO to be used.
+
+Parameter: int gpio - GPIO PIN (Pin 0-63)
+
+Note: Using this function, you dont have to worry about banks/modules where
+ the gpio pin is.
+
+D) omap_set_gpio_direction(int gpio, int is_input)
+
+Description: This function is responsible for setting the gpio pin direction
+ (input or output).
+
+Parameter: int gpio - GPIO PIN (Pin 0-63)
+ int is_input - pin direction (0 = output, 1 = input)
+
+E) omap_set_gpio_dataout(int gpio, int enable)
+
+Description: This function is responsible for writing to a pin.
+
+Parameter: int gpio - GPIO PIN (Pin 0-63)
+ int enable - pin value (0 or 1)
+
+F) omap_get_gpio_datain(int gpio)
+
+Description: This function is responsible for reading pin values.
+
+Parameter: int gpio - GPIO PIN (Pin 0-63)
+
+G) omap_free_gpio(int gpio)
+
+Description: This function is responsible for freeing the pin used.
+
+Parameter: int gpio - GPIO PIN (Pin 0-63)
+
+H) OMAP_GPIO_IRQ(int gpio)
+
+Description: Returns the Interrupt number for the specified gpio pin.
+
+Parameter: int gpio - GPIO PIN (Pin 0-63)
+
+I) set_irq_type(unsigned int irq, unsigned int type)
+
+Description: This function is responsible for setting the type of interrupt
+ (RISING or FALLING).
+
+Parameter: unsigned int irq - The interrupt number for the gpio pin.
+ unsigned int type - (IRQT_RISING = rising, IRQT_FALLING= falling)
+
+
+III. Example
+------------
+
+1) Writing to gpio pin#3 a value 1 and reading the value of gpio pin#3.
+
+#include <asm/arch/gpio.h>
+
+int ret; /* Return value */
+
+omap_request_gpio(3); /* Request for gpio pin */
+omap_set_gpio_direction(3,0);
+omap_set_set_dataout(3,1); /* Writing a 1 to gpio pin # 3: */
+ret = omap_get_datain(3); /* Reading the value of pin # 3 */
+printk("value of pin # 3 = %d\n",ret);
+omap_free_gpio(3); /* Freeing gpio pin # 3 */
+
+2) Interrupt input by gpio pin#3
+
+#include <asm/arch/gpio.h>
+
+omap_request_gpio(3); /* Request for gpio pin */
+omap_set_gpio_direction(3,0);
+set_irq_type(OMAP_GPIO_IRQ(3),IRQT_RISING); /* Setting up pin for interrupt */
+request_irq(OMAP_GPIO_IRQ(3), (void *)&my_int_handler, SA_SHIRQ,....);
+
+... /* Do stuff, handle interrupts in my_int_handler */
+
+free_irq(OMAP_GPIO_IRQ(3),&id); /* Freeing interrupt and gpio pin */
+omap_free_gpio(3);
+
+------------------------------------------------------------------
+Last modified 14. August 2006
+The OMAP Linux Kernel Team
+Arnold <abo_gwapo@yahoo.com>
+Dirk Behme <dirk.behme@gmail.com>
+
+ OMAP GPIO API's HowTo
+ =====================
+
+This document is a short summary how to use OMAP Linux GPIO API. It is
+mainly focussed on OMAP5912 OSK, but should fit with extensions (more
+or less GPIOs) to other OMAP processors as well.
+
+If anything is missing, is wrong, needs extension or update, please send
+update to Linux-omap-open-source@linux.omap.com.
+
+I. GPIO Modules/Banks
+---------------------
+
+OMAP5912 OSK has 64 GPIOs (general purpose IO pins). These are organized
+in four modules (banks) with 16 pins each. OMAP GPIO API doesn't distinguish
+between modules and numbers the pins from 0 - 63:
+
+A) GPIO MODULE/BANK 0 - PIN 0-15
+B) GPIO MODULE/BANK 1 - PIN 16-31
+C) GPIO MODULE/BANK 2 - PIN 32-47
+D) GPIO MODULE/BANK 3 - PIN 48-63
+
+See
+
+http://www-s.ti.com/sc/psheets/spru767a/spru767a.pdf
+
+for more details.
+
+II. GPIO API's
+--------------
+
+A) Include
+
+#include <asm/arch/gpio.h>
+
+B) omap_cfg_reg(xxxx);
+
+Description: Configure pin mux.
+
+Parameter: Pin to be configured for GPIO.
+
+Note: This function may only be necessary for some GPIO pins. Because OMAP
+ chip itself has less real hardware pins than necessary to use all
+ its functionality at the same time, some pins share different
+ functions (called pin multiplexing, short pin mux). E.g. one pin may
+ be used for serial interface *or* GPIO. Check if this is the case for
+ the GPIO you want to use and if you have to configure the pin mux.
+
+C) omap_request_gpio(int gpio)
+
+Description: Request GPIO to be used.
+
+Parameter: int gpio - GPIO PIN (Pin 0-63)
+
+Note: Using this function, you dont have to worry about banks/modules where
+ the gpio pin is.
+
+D) omap_set_gpio_direction(int gpio, int is_input)
+
+Description: This function is responsible for setting the gpio pin direction
+ (input or output).
+
+Parameter: int gpio - GPIO PIN (Pin 0-63)
+ int is_input - pin direction (0 = output, 1 = input)
+
+E) omap_set_gpio_dataout(int gpio, int enable)
+
+Description: This function is responsible for writing to a pin.
+
+Parameter: int gpio - GPIO PIN (Pin 0-63)
+ int enable - pin value (0 or 1)
+
+F) omap_get_gpio_datain(int gpio)
+
+Description: This function is responsible for reading pin values.
+
+Parameter: int gpio - GPIO PIN (Pin 0-63)
+
+G) omap_free_gpio(int gpio)
+
+Description: This function is responsible for freeing the pin used.
+
+Parameter: int gpio - GPIO PIN (Pin 0-63)
+
+H) OMAP_GPIO_IRQ(int gpio)
+
+Description: Returns the Interrupt number for the specified gpio pin.
+
+Parameter: int gpio - GPIO PIN (Pin 0-63)
+
+I) set_irq_type(unsigned int irq, unsigned int type)
+
+Description: This function is responsible for setting the type of interrupt
+ (RISING or FALLING).
+
+Parameter: unsigned int irq - The interrupt number for the gpio pin.
+ unsigned int type - (IRQT_RISING = rising, IRQT_FALLING= falling)
+
+
+III. Example
+------------
+
+1) Writing to gpio pin#3 a value 1 and reading the value of gpio pin#3.
+
+#include <asm/arch/gpio.h>
+
+int ret; /* Return value */
+
+omap_request_gpio(3); /* Request for gpio pin */
+omap_set_gpio_direction(3,0);
+omap_set_set_dataout(3,1); /* Writing a 1 to gpio pin # 3: */
+ret = omap_get_datain(3); /* Reading the value of pin # 3 */
+printk("value of pin # 3 = %d\n",ret);
+omap_free_gpio(3); /* Freeing gpio pin # 3 */
+
+2) Interrupt input by gpio pin#3
+
+#include <asm/arch/gpio.h>
+
+omap_request_gpio(3); /* Request for gpio pin */
+omap_set_gpio_direction(3,0);
+set_irq_type(OMAP_GPIO_IRQ(3),IRQT_RISING); /* Setting up pin for interrupt */
+request_irq(OMAP_GPIO_IRQ(3), (void *)&my_int_handler, SA_SHIRQ,....);
+
+... /* Do stuff, handle interrupts in my_int_handler */
+
+free_irq(OMAP_GPIO_IRQ(3),&id); /* Freeing interrupt and gpio pin */
+omap_free_gpio(3);
+
+------------------------------------------------------------------
+Last modified 14. August 2006
+The OMAP Linux Kernel Team
+Arnold <abo_gwapo@yahoo.com>
+Dirk Behme <dirk.behme@gmail.com>
TI OMAP MMC INTERFACE DRIVER
P: Carlos Aguiar, Anderson Briglia and Syed Khasim
-M: linux-omap-open-source@linux.omap.com (subscribers only)
+M: linux-omap@vger.kernel.org
W: http://linux.omap.com
W: http://www.muru.com/linux/omap/
S: Maintained
# o print "Entering directory ...";
MAKEFLAGS += -rR --no-print-directory
+# Add custom flags here to avoid conflict with updates
+EXTRAVERSION := $(EXTRAVERSION)-omap1
+
# We are using a recursive build, so we need to do a little thinking
# to get the ordering right.
#
-e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
-e s/sh.*/sh/ )
+SUBARCH := arm
+
# Cross compiling and selecting different set of gcc/bin-utils
# ---------------------------------------------------------------------------
#
# Note: Some architectures assign CROSS_COMPILE in their arch/*/Makefile
export KBUILD_BUILDHOST := $(SUBARCH)
ARCH ?= $(SUBARCH)
-CROSS_COMPILE ?=
+CROSS_COMPILE ?= arm-linux-
# Architecture as present in compile.h
UTS_MACHINE := $(ARCH)
source "drivers/uio/Kconfig"
+if ARCH_OMAP
+source "drivers/cbus/Kconfig"
+source "drivers/dsp/dspgateway/Kconfig"
+endif
+
endmenu
source "fs/Kconfig"
machine-$(CONFIG_ARCH_IXP23XX) := ixp23xx
machine-$(CONFIG_ARCH_OMAP1) := omap1
machine-$(CONFIG_ARCH_OMAP2) := omap2
+ machine-$(CONFIG_ARCH_OMAP3) := omap2
incdir-$(CONFIG_ARCH_OMAP) := omap
machine-$(CONFIG_ARCH_S3C2410) := s3c2410
machine-$(CONFIG_ARCH_LH7A40X) := lh7a40x
Image
zImage
+uImage
xipImage
bootpImage
-uImage
OBJS += head-sharpsl.o
endif
+ifeq ($(CONFIG_MACH_OMAP_PERSEUS2),y)
+OBJS += head-omap.o
+endif
+
ifeq ($(CONFIG_CPU_BIG_ENDIAN),y)
ifeq ($(CONFIG_CPU_CP15),y)
OBJS += big-endian.o
--- /dev/null
+/*
+ * linux/arch/arm/boot/compressed/head-omap.S
+ *
+ * OMAP specific tweaks. This is merged into head.S by the linker.
+ *
+ */
+
+#include <linux/linkage.h>
+#include <asm/mach-types.h>
+
+ .section ".start", "ax"
+
+__OMAP_start:
+#ifdef CONFIG_MACH_OMAP_PERSEUS2
+ /* support for booting without u-boot */
+ mov r7, #(MACH_TYPE_OMAP_PERSEUS2 & ~0xf)
+ orr r7, r7, #(MACH_TYPE_OMAP_PERSEUS2 & 0xf)
+#endif
#elif defined(CONFIG_ARCH_S3C2410)
.macro loadsp, rb
mov \rb, #0x50000000
- add \rb, \rb, #0x4000 * CONFIG_S3C_LOWLEVEL_UART_PORT
+ add \rb, \rb, #0x4000 * CONFIG_S3C2410_LOWLEVEL_UART_PORT
.endm
#else
.macro loadsp, rb
mcr p15, 0, r10, c7, c14, 0 @ clean+invalidate D
b iflush
hierarchical:
+ adr sp, no_cache_id @ non-v7 code is temp stack
stmfd sp!, {r0-r5, r7, r9-r11}
mrc p15, 1, r0, c0, c0, 1 @ read clidr
ands r3, r0, #0x7000000 @ extract loc from clidr
--- /dev/null
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.22-rc1-omap1
+# Thu Jun 7 04:28:32 2007
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ZONE_DMA=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP1=y
+# CONFIG_ARCH_OMAP2 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+# CONFIG_OMAP_BOOT_TAG is not set
+# CONFIG_OMAP_GPIO_SWITCH is not set
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_WARNINGS=y
+CONFIG_OMAP_MCBSP=y
+CONFIG_OMAP_MMU_FWK=y
+CONFIG_OMAP_MBOX_FWK=m
+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_LL_DEBUG_LCD is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+CONFIG_OMAP_DSP=m
+# CONFIG_OMAP_DSP_MBCMD_VERBOSE is not set
+# CONFIG_OMAP_DSP_TASK_MULTIOPEN is not set
+# CONFIG_OMAP_DSP_FBEXPORT is not set
+
+#
+# OMAP Core Type
+#
+# CONFIG_ARCH_OMAP730 is not set
+CONFIG_ARCH_OMAP15XX=y
+# CONFIG_ARCH_OMAP16XX is not set
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_INNOVATOR is not set
+# CONFIG_MACH_VOICEBLUE is not set
+# CONFIG_MACH_OMAP_PALMTE is not set
+# CONFIG_MACH_OMAP_PALMZ71 is not set
+# CONFIG_MACH_OMAP_PALMTT is not set
+# CONFIG_MACH_SX1 is not set
+CONFIG_MACH_AMS_DELTA=y
+# CONFIG_MACH_OMAP_GENERIC is not set
+
+#
+# OMAP CPU Speed
+#
+# CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER is not set
+# CONFIG_OMAP_ARM_168MHZ is not set
+CONFIG_OMAP_ARM_150MHZ=y
+# CONFIG_OMAP_ARM_120MHZ is not set
+# CONFIG_OMAP_ARM_60MHZ is not set
+# CONFIG_OMAP_ARM_30MHZ is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM925T=y
+CONFIG_CPU_32v4T=y
+CONFIG_CPU_ABRT_EV4T=y
+CONFIG_CPU_CACHE_V4WT=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+CONFIG_CPU_DCACHE_WRITETHROUGH=y
+# CONFIG_OUTER_CACHE is not set
+
+#
+# Bus support
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_PREEMPT=y
+CONFIG_HZ=100
+# CONFIG_AEABI is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="mem=32M console=ttyS0,115200n8 root=/dev/ram0 initrd=0x11c00000,4M"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+
+#
+# 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=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+CONFIG_INET_TUNNEL=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+CONFIG_IPV6=y
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_IPV6_MIP6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+CONFIG_INET6_XFRM_MODE_TRANSPORT=y
+CONFIG_INET6_XFRM_MODE_TUNNEL=y
+CONFIG_INET6_XFRM_MODE_BEET=y
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=y
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_AMS_DELTA=y
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNPACPI is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_ESP_CORE is not set
+# CONFIG_ATA is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# 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
+# 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
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+
+#
+# USB Network Adapters
+#
+CONFIG_USB_CATC=y
+CONFIG_USB_KAWETH=y
+CONFIG_USB_PEGASUS=y
+CONFIG_USB_RTL8150=y
+CONFIG_USB_USBNET_MII=y
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_AX8817X=y
+CONFIG_USB_NET_CDCETHER=y
+# CONFIG_USB_NET_DM9601 is not set
+# CONFIG_USB_NET_GL620A is not set
+CONFIG_USB_NET_NET1080=y
+# CONFIG_USB_NET_PLUSB is not set
+# CONFIG_USB_NET_MCS7830 is not set
+# CONFIG_USB_NET_RNDIS_HOST is not set
+CONFIG_USB_NET_CDC_SUBSET=y
+# CONFIG_USB_ALI_M5632 is not set
+# CONFIG_USB_AN2720 is not set
+CONFIG_USB_BELKIN=y
+CONFIG_USB_ARMLINUX=y
+# CONFIG_USB_EPSON2888 is not set
+# CONFIG_USB_KC2190 is not set
+CONFIG_USB_NET_ZAURUS=y
+# CONFIG_WAN is not set
+CONFIG_PPP=y
+CONFIG_PPP_MULTILINK=y
+# CONFIG_PPP_FILTER is not set
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_PPP_DEFLATE is not set
+# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPP_MPPE is not set
+# CONFIG_PPPOE is not set
+# CONFIG_SLIP is not set
+CONFIG_SLHC=y
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+CONFIG_KEYBOARD_OMAP=y
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=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_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_SENSORS_TLV320AIC23 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+# CONFIG_HWMON is not set
+
+#
+# Misc devices
+#
+# CONFIG_BLINK is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# LED devices
+#
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+CONFIG_LEDS_AMS_DELTA=y
+# CONFIG_LEDS_OMAP_DEBUG is not set
+# CONFIG_LEDS_OMAP is not set
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+CONFIG_FB=y
+CONFIG_FIRMWARE_EDID=y
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_OMAP=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_LCD_MIPID is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=2
+# CONFIG_FB_OMAP_DMA_TUNE is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FONTS=y
+# CONFIG_FONT_8x8 is not set
+# CONFIG_FONT_8x16 is not set
+CONFIG_FONT_6x11=y
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_CLEAN_4x6 is not set
+# CONFIG_FONT_CLEAN_5x8 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# HID Devices
+#
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_MUSB_HDRC is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+# CONFIG_MMC is not set
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_OMAP=y
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4DEV_FS 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_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+CONFIG_AUTOFS_FS=y
+CONFIG_AUTOFS4_FS=y
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+CONFIG_JFFS2_SUMMARY=y
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_BIND34 is not set
+# 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
+# CONFIG_SYSV68_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+CONFIG_NLS_CODEPAGE_850=y
+CONFIG_NLS_CODEPAGE_852=y
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_2=y
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_PREEMPT=y
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
--- /dev/null
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.24-rc8-omap1
+# Fri Jan 18 10:21:06 2008
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ZONE_DMA=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_FAIR_USER_SCHED=y
+# CONFIG_FAIR_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# 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_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+CONFIG_ARCH_OMAP1=y
+# CONFIG_ARCH_OMAP2 is not set
+# CONFIG_ARCH_OMAP3 is not set
+
+#
+# OMAP Feature Selections
+#
+CONFIG_OMAP_DEBUG_SRAM_PATCH=y
+CONFIG_OMAP_RESET_CLOCKS=y
+CONFIG_OMAP_BOOT_TAG=y
+CONFIG_OMAP_BOOT_REASON=y
+CONFIG_OMAP_COMPONENT_VERSION=y
+CONFIG_OMAP_GPIO_SWITCH=y
+# CONFIG_OMAP_MUX is not set
+CONFIG_OMAP_STI=y
+CONFIG_OMAP_STI_CONSOLE=y
+CONFIG_OMAP_MCBSP=y
+CONFIG_OMAP_MMU_FWK=y
+CONFIG_OMAP_MBOX_FWK=y
+# CONFIG_OMAP_MPU_TIMER is not set
+CONFIG_OMAP_32K_TIMER=y
+CONFIG_OMAP_32K_TIMER_HZ=128
+CONFIG_OMAP_DM_TIMER=y
+CONFIG_OMAP_LL_DEBUG_UART1=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
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_PABRT_NOIFAR=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+# CONFIG_OUTER_CACHE is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=128
+# CONFIG_AEABI is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+# 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
+# CONFIG_KEXEC is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_PM_LEGACY is not set
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND_UP_POSSIBLE=y
+CONFIG_SUSPEND=y
+# CONFIG_APM_EMULATION is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IP_VS is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETLABEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_NETLINK=y
+# CONFIG_NETFILTER_NETLINK_QUEUE is not set
+# CONFIG_NETFILTER_NETLINK_LOG is not set
+# CONFIG_NF_CONNTRACK_ENABLED is not set
+# CONFIG_NF_CONNTRACK is not set
+# CONFIG_NETFILTER_XTABLES is not set
+
+#
+# IP: Netfilter Configuration
+#
+# CONFIG_IP_NF_QUEUE is not set
+# CONFIG_IP_NF_IPTABLES is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# 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_HCIBTUSB is not set
+# CONFIG_BT_HCIBTSDIO 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_HCIH4P is not set
+# CONFIG_BT_HCIVHCI is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+CONFIG_CONNECTOR=y
+# CONFIG_PROC_EVENTS is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS 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
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_OMAP_HW=y
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# 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_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_SCSI_PROC_FS is not set
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=y
+# CONFIG_VETH is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_B44 is not set
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 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=y
+# CONFIG_USB_NET_AX8817X is not set
+CONFIG_USB_NET_CDCETHER=y
+# CONFIG_USB_NET_DM9601 is not set
+# CONFIG_USB_NET_GL620A is not set
+CONFIG_USB_NET_NET1080=y
+# CONFIG_USB_NET_PLUSB is not set
+# CONFIG_USB_NET_MCS7830 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_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_PPPOL2TP is not set
+# CONFIG_SLIP is not set
+CONFIG_SLHC=y
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+CONFIG_KEYBOARD_OMAP=y
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ADS7846=y
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_UCB1400 is not set
+# CONFIG_TOUCHSCREEN_TSC2102 is not set
+# CONFIG_TOUCHSCREEN_TSC210X is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=m
+CONFIG_HW_RANDOM_OMAP=m
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=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_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_ISP1301_OMAP is not set
+# CONFIG_TPS65010 is not set
+CONFIG_SENSORS_TLV320AIC23=y
+# CONFIG_GPIOEXPANDER_OMAP is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_BITBANG=y
+CONFIG_SPI_OMAP_UWIRE=y
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_AT25 is not set
+# CONFIG_SPI_TSC2101 is not set
+# CONFIG_SPI_TSC2102 is not set
+# CONFIG_SPI_TSC210X is not set
+# CONFIG_SPI_TSC2301 is not set
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_OMAP_WATCHDOG=y
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_UVESA is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FB_OMAP=y
+CONFIG_FB_OMAP_LCDC_EXTERNAL=y
+CONFIG_FB_OMAP_LCDC_HWA742=y
+# CONFIG_FB_OMAP_LCDC_BLIZZARD is not set
+CONFIG_FB_OMAP_MANUAL_UPDATE=y
+# CONFIG_FB_OMAP_LCD_MIPID is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=2
+# CONFIG_FB_OMAP_DMA_TUNE is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE is not set
+# CONFIG_LOGO 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_PROCFS=y
+# 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
+# CONFIG_SND_OMAP_TSC2101 is not set
+# CONFIG_SND_SX1 is not set
+# CONFIG_SND_OMAP_TSC2102 is not set
+# CONFIG_SND_OMAP24XX_EAC is not set
+
+#
+# SPI devices
+#
+
+#
+# USB devices
+#
+CONFIG_SND_USB_AUDIO=y
+# CONFIG_SND_USB_CAIAQ is not set
+
+#
+# System on Chip audio support
+#
+# CONFIG_SND_SOC is not set
+
+#
+# SoC Audio support for SuperH
+#
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+CONFIG_HID_DEBUG=y
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_SUSPEND=y
+# CONFIG_USB_PERSIST is not set
+CONFIG_USB_OTG=y
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_MUSB_HDRC is not set
+# CONFIG_USB_GADGET_MUSB_HDRC is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_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_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK 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_AIRCABLE is not set
+# CONFIG_USB_SERIAL_AIRPRIME is not set
+# CONFIG_USB_SERIAL_ARK3116 is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_CH341 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_FUNSOFT 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_MOS7720 is not set
+# CONFIG_USB_SERIAL_MOS7840 is not set
+# CONFIG_USB_SERIAL_NAVMAN is not set
+CONFIG_USB_SERIAL_PL2303=y
+# CONFIG_USB_SERIAL_OTI6858 is not set
+# CONFIG_USB_SERIAL_HP4X is not set
+# CONFIG_USB_SERIAL_SAFE is not set
+# CONFIG_USB_SERIAL_SIERRAWIRELESS 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_OPTION is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+# CONFIG_USB_SERIAL_DEBUG is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG is not set
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_ATMEL_USBA is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_M66592 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_S3C2410 is not set
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+# CONFIG_USB_GADGET_DUALSPEED is not set
+# CONFIG_USB_ZERO is not set
+CONFIG_USB_ETH=m
+CONFIG_USB_ETH_RNDIS=y
+# CONFIG_USB_GADGETFS is not set
+CONFIG_USB_FILE_STORAGE=m
+CONFIG_USB_FILE_STORAGE_TEST=y
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+
+#
+# MMC/SD Host Controller Drivers
+#
+CONFIG_MMC_OMAP=y
+# CONFIG_MMC_SPI is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+
+#
+# CBUS support
+#
+CONFIG_CBUS=y
+CONFIG_CBUS_TAHVO=y
+CONFIG_CBUS_TAHVO_USER=y
+CONFIG_CBUS_TAHVO_USB=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
+# CONFIG_CBUS_RETU_HEADSET is not set
+CONFIG_OMAP_DSP=y
+# CONFIG_OMAP_DSP_MBCMD_VERBOSE is not set
+CONFIG_OMAP_DSP_FBEXPORT=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_EXT4DEV_FS is not set
+CONFIG_JBD=y
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS 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_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE 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_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+CONFIG_JFFS2_SUMMARY=y
+# CONFIG_JFFS2_FS_XATTR is not set
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+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_JFFS2_CMODE_FAVOURLZO 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
+CONFIG_NETWORK_FILESYSTEMS=y
+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_SUNRPC_BIND34 is not set
+# 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_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+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
+# CONFIG_DLM is not set
+CONFIG_INSTRUMENTATION=y
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_FORCED_INLINING=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_SAMPLES is not set
+# CONFIG_DEBUG_USER 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_LOWMEM is not set
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
--- /dev/null
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.25-omap1
+# Mon Apr 28 10:58:14 2008
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ARCH_SUPPORTS_AOUT=y
+CONFIG_ZONE_DMA=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_COMPAT_BRK=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+CONFIG_CLASSIC_RCU=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_MSM7X00A is not set
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+# CONFIG_ARCH_OMAP1 is not set
+CONFIG_ARCH_OMAP2=y
+# CONFIG_ARCH_OMAP3 is not set
+
+#
+# OMAP Feature Selections
+#
+CONFIG_OMAP_DEBUG_SRAM_PATCH=y
+# CONFIG_OMAP_DEBUG_POWERDOMAIN is not set
+# CONFIG_OMAP_DEBUG_CLOCKDOMAIN is not set
+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_MCBSP is not set
+CONFIG_OMAP_MMU_FWK=y
+CONFIG_OMAP_MBOX_FWK=y
+# CONFIG_OMAP_MPU_TIMER is not set
+CONFIG_OMAP_32K_TIMER=y
+CONFIG_OMAP_32K_TIMER_HZ=128
+CONFIG_OMAP_DM_TIMER=y
+# CONFIG_OMAP_LL_DEBUG_UART1 is not set
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+CONFIG_OMAP_LL_DEBUG_UART3=y
+# CONFIG_MACH_OMAP_GENERIC is not set
+
+#
+# OMAP Core Type
+#
+CONFIG_ARCH_OMAP24XX=y
+CONFIG_ARCH_OMAP2420=y
+# CONFIG_ARCH_OMAP2430 is not set
+
+#
+# OMAP Board Type
+#
+CONFIG_MACH_NOKIA_N800=y
+CONFIG_MACH_NOKIA_N810=y
+CONFIG_MACH_OMAP2_TUSB6010=y
+# CONFIG_MACH_OMAP_H4 is not set
+# CONFIG_MACH_OMAP_APOLLON is not set
+# CONFIG_MACH_OMAP_2430OSK is not set
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# 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_PABRT_NOIFAR=y
+CONFIG_CPU_CACHE_V6=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V6=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+# CONFIG_OUTER_CACHE is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=128
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+CONFIG_LEDS=y
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x10C08000
+CONFIG_ZBOOT_ROM_BSS=0x10200000
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_CMDLINE="root=1f03 rootfstype=jffs2"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_VFP=y
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_PM_LEGACY is not set
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+# CONFIG_APM_EMULATION is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IP_VS is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETLABEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_NETFILTER_ADVANCED=y
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK_QUEUE is not set
+# CONFIG_NETFILTER_NETLINK_LOG is not set
+# CONFIG_NF_CONNTRACK is not set
+CONFIG_NETFILTER_XTABLES=y
+# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set
+# CONFIG_NETFILTER_XT_TARGET_MARK is not set
+# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set
+# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set
+# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set
+# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set
+# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
+# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
+# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
+# CONFIG_NETFILTER_XT_MATCH_ESP is not set
+# CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set
+# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set
+# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_MAC is not set
+# CONFIG_NETFILTER_XT_MATCH_MARK is not set
+# CONFIG_NETFILTER_XT_MATCH_OWNER is not set
+# CONFIG_NETFILTER_XT_MATCH_POLICY is not set
+# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set
+# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set
+# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set
+# CONFIG_NETFILTER_XT_MATCH_REALM is not set
+# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
+# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set
+# CONFIG_NETFILTER_XT_MATCH_STRING is not set
+# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set
+# CONFIG_NETFILTER_XT_MATCH_TIME is not set
+# CONFIG_NETFILTER_XT_MATCH_U32 is not set
+# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set
+
+#
+# IP: Netfilter Configuration
+#
+# CONFIG_IP_NF_QUEUE is not set
+CONFIG_IP_NF_IPTABLES=y
+# CONFIG_IP_NF_MATCH_RECENT is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_AH is not set
+# CONFIG_IP_NF_MATCH_TTL is not set
+# CONFIG_IP_NF_MATCH_ADDRTYPE is not set
+CONFIG_IP_NF_FILTER=y
+# CONFIG_IP_NF_TARGET_REJECT is not set
+# CONFIG_IP_NF_TARGET_LOG is not set
+# CONFIG_IP_NF_TARGET_ULOG is not set
+CONFIG_IP_NF_TARGET_IDLETIMER=y
+# CONFIG_IP_NF_MANGLE is not set
+# CONFIG_IP_NF_RAW is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN 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_HCIBTUSB is not set
+# CONFIG_BT_HCIBTSDIO is not set
+# CONFIG_BT_HCIUART is not set
+# CONFIG_BT_HCIBCM203X is not set
+# CONFIG_BT_HCIBPA10X is not set
+# CONFIG_BT_HCIBFUSB is not set
+# CONFIG_BT_HCIBRF6150 is not set
+# CONFIG_BT_HCIH4P is not set
+# CONFIG_BT_HCIVHCI is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+CONFIG_WIRELESS_EXT=y
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS 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
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+CONFIG_MTD_ONENAND=y
+# CONFIG_MTD_ONENAND_VERIFY_WRITE is not set
+# CONFIG_MTD_ONENAND_GENERIC is not set
+CONFIG_MTD_ONENAND_OMAP2=y
+CONFIG_MTD_ONENAND_OTP=y
+# CONFIG_MTD_ONENAND_2X_PROGRAM is not set
+# CONFIG_MTD_ONENAND_SIM is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+CONFIG_OMAP_STI=y
+CONFIG_OMAP_STI_CONSOLE=y
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_HAVE_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_SCSI_PROC_FS is not set
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=y
+# CONFIG_VETH is not set
+# CONFIG_NET_ETHERNET is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_E1000E_ENABLED is not set
+CONFIG_NETDEV_10000=y
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS 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_WAN is not set
+CONFIG_PPP=y
+# CONFIG_PPP_MULTILINK is not set
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_BSDCOMP=y
+# CONFIG_PPP_MPPE is not set
+# CONFIG_PPPOE is not set
+# CONFIG_PPPOL2TP is not set
+# CONFIG_SLIP is not set
+CONFIG_SLHC=y
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_OMAP is not set
+CONFIG_KEYBOARD_TSC2301=y
+CONFIG_KEYBOARD_LM8323=y
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_ADS7846 is not set
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_UCB1400 is not set
+CONFIG_TOUCHSCREEN_TSC2005=y
+# CONFIG_TOUCHSCREEN_TSC2102 is not set
+# CONFIG_TOUCHSCREEN_TSC210X is not set
+CONFIG_TOUCHSCREEN_TSC2301=y
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_SERIAL_NONSTANDARD=y
+# CONFIG_N_HDLC is not set
+# CONFIG_RISCOM8 is not set
+# CONFIG_SPECIALIX is not set
+# CONFIG_RIO is not set
+# CONFIG_STALDRV 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
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+# CONFIG_I2C_CHARDEV is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_TINY_USB is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_ISP1301_OMAP is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_SENSORS_TLV320AIC23 is not set
+# CONFIG_GPIOEXPANDER_OMAP is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+CONFIG_SENSORS_TSL2563=y
+CONFIG_LP5521=y
+CONFIG_MENELAUS=y
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+CONFIG_SPI_OMAP24XX=y
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_AT25 is not set
+# CONFIG_SPI_TSC2101 is not set
+# CONFIG_SPI_TSC2102 is not set
+# CONFIG_SPI_TSC210X is not set
+CONFIG_SPI_TSC2301=y
+CONFIG_SPI_TSC2301_AUDIO=y
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+CONFIG_HAVE_GPIO_LIB=y
+
+#
+# GPIO Support
+#
+# CONFIG_DEBUG_GPIO is not set
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ADT7470 is not set
+# CONFIG_SENSORS_ADT7473 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM70 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_DME1737 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_ADS7828 is not set
+# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83L786NG is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_SENSORS_TSC210X is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_OMAP_WATCHDOG=y
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_COMMON=y
+CONFIG_VIDEO_ALLOW_V4L1=y
+CONFIG_VIDEO_V4L1_COMPAT=y
+CONFIG_VIDEO_V4L2=y
+CONFIG_VIDEO_V4L1=y
+CONFIG_VIDEO_CAPTURE_DRIVERS=y
+# CONFIG_VIDEO_ADV_DEBUG is not set
+CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
+CONFIG_VIDEO_TCM825X=y
+# CONFIG_VIDEO_VIVI is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_CPIA2 is not set
+# CONFIG_VIDEO_SAA5246A is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_AU0828 is not set
+# CONFIG_VIDEO_OMAP_CAMERA is not set
+CONFIG_VIDEO_OMAP2=y
+CONFIG_V4L_USB_DRIVERS=y
+# CONFIG_VIDEO_PVRUSB2 is not set
+# CONFIG_VIDEO_EM28XX is not set
+# CONFIG_VIDEO_USBVISION is not set
+# CONFIG_USB_VICAM is not set
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_KONICAWC is not set
+# CONFIG_USB_QUICKCAM_MESSENGER is not set
+# CONFIG_USB_ET61X251 is not set
+# CONFIG_VIDEO_OVCAMCHIP is not set
+# CONFIG_USB_W9968CF is not set
+# CONFIG_USB_OV511 is not set
+# CONFIG_USB_SE401 is not set
+# CONFIG_USB_SN9C102 is not set
+# CONFIG_USB_STV680 is not set
+# CONFIG_USB_ZC0301 is not set
+# CONFIG_USB_PWC is not set
+# CONFIG_USB_ZR364XX is not set
+# CONFIG_USB_STKWEBCAM is not set
+# CONFIG_SOC_CAMERA is not set
+CONFIG_RADIO_ADAPTERS=y
+CONFIG_RADIO_TEA5761=y
+# CONFIG_USB_DSBR is not set
+# CONFIG_USB_SI470X is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_VIDEOBUF_GEN=y
+CONFIG_VIDEOBUF_DMA_SG=y
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FB_OMAP=y
+CONFIG_FB_OMAP_LCDC_EXTERNAL=y
+# CONFIG_FB_OMAP_LCDC_HWA742 is not set
+CONFIG_FB_OMAP_LCDC_BLIZZARD=y
+CONFIG_FB_OMAP_MANUAL_UPDATE=y
+CONFIG_FB_OMAP_LCD_MIPID=y
+CONFIG_FB_OMAP_BOOTLOADER_INIT=y
+CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=4
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE is not set
+# CONFIG_LOGO is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=y
+# CONFIG_SND_SEQUENCER is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=y
+# CONFIG_SND_PCM_OSS is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+# CONFIG_SND_VERBOSE_PROCFS is not set
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# ALSA ARM devices
+#
+# CONFIG_SND_OMAP_AIC23 is not set
+# CONFIG_SND_OMAP_TSC2101 is not set
+# CONFIG_SND_SX1 is not set
+# CONFIG_SND_OMAP_TSC2102 is not set
+CONFIG_SND_OMAP24XX_EAC=y
+
+#
+# SPI devices
+#
+
+#
+# USB devices
+#
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_CAIAQ is not set
+
+#
+# System on Chip audio support
+#
+# CONFIG_SND_SOC is not set
+
+#
+# ALSA SoC audio for Freescale SOCs
+#
+
+#
+# SoC Audio for the Texas Instruments OMAP
+#
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_SUSPEND=y
+# CONFIG_USB_PERSIST is not set
+CONFIG_USB_OTG=y
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+CONFIG_USB_MUSB_HDRC=y
+CONFIG_USB_TUSB6010=y
+# CONFIG_USB_MUSB_HOST is not set
+# CONFIG_USB_MUSB_PERIPHERAL is not set
+CONFIG_USB_MUSB_OTG=y
+CONFIG_USB_GADGET_MUSB_HDRC=y
+CONFIG_USB_MUSB_HDRC_HCD=y
+# CONFIG_MUSB_PIO_ONLY is not set
+# CONFIG_USB_INVENTRA_DMA is not set
+# CONFIG_USB_TI_CPPI_DMA is not set
+CONFIG_USB_TUSB_OMAP_DMA=y
+CONFIG_USB_MUSB_LOGLEVEL=1
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+CONFIG_USB_LIBUSUAL=y
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+CONFIG_USB_TEST=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_ATMEL_USBA is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_M66592 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_S3C2410 is not set
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+# CONFIG_USB_ZERO is not set
+CONFIG_USB_ETH=y
+CONFIG_USB_ETH_RNDIS=y
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_USB_G_PRINTER is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+# CONFIG_MMC_BLOCK_BOUNCE is not set
+# CONFIG_SDIO_UART is not set
+
+#
+# MMC/SD Host Controller Drivers
+#
+CONFIG_MMC_OMAP=y
+# CONFIG_MMC_SPI is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+# CONFIG_LEDS_OMAP_DEBUG is not set
+# CONFIG_LEDS_OMAP is not set
+CONFIG_LEDS_OMAP_PWM=y
+# CONFIG_LEDS_GPIO is not set
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_UIO is not set
+
+#
+# CBUS support
+#
+CONFIG_CBUS=y
+CONFIG_CBUS_TAHVO=y
+CONFIG_CBUS_TAHVO_USER=y
+# CONFIG_CBUS_TAHVO_USB is not set
+CONFIG_CBUS_RETU=y
+CONFIG_CBUS_RETU_USER=y
+CONFIG_CBUS_RETU_POWERBUTTON=y
+CONFIG_CBUS_RETU_RTC=y
+CONFIG_CBUS_RETU_WDT=y
+CONFIG_CBUS_RETU_HEADSET=y
+CONFIG_OMAP_DSP=y
+# CONFIG_OMAP_DSP_MBCMD_VERBOSE is not set
+CONFIG_OMAP_DSP_FBEXPORT=y
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=m
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT2_FS_POSIX_ACL is not set
+# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=m
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=m
+CONFIG_FS_MBCACHE=m
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+CONFIG_JFFS2_SUMMARY=y
+# CONFIG_JFFS2_FS_XATTR is not set
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_LZO=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_JFFS2_CMODE_FAVOURLZO is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+CONFIG_NLS_ISO8859_15=y
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=y
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+CONFIG_PRINTK_TIME=y
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_SAMPLES is not set
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+CONFIG_SECURITY=y
+# CONFIG_SECURITY_NETWORK is not set
+# CONFIG_SECURITY_CAPABILITIES is not set
+# CONFIG_SECURITY_ROOTPLUG is not set
+# CONFIG_SECURITY_LOWMEM is not set
+CONFIG_SECURITY_DEFAULT_MMAP_MIN_ADDR=0
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_MANAGER is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_LZO is not set
+CONFIG_CRYPTO_HW=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
--- /dev/null
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.25-rc9-omap1
+# Wed Apr 16 16:27:20 2008
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ARCH_SUPPORTS_AOUT=y
+CONFIG_ZONE_DMA=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_COMPAT_BRK=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_KMOD=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+CONFIG_CLASSIC_RCU=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_ORION is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_MSM7X00A is not set
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+# CONFIG_ARCH_OMAP1 is not set
+# CONFIG_ARCH_OMAP2 is not set
+CONFIG_ARCH_OMAP3=y
+
+#
+# OMAP Feature Selections
+#
+CONFIG_OMAP_DEBUG_SRAM_PATCH=y
+# CONFIG_OMAP_RESET_CLOCKS is not set
+CONFIG_OMAP_BOOT_TAG=y
+CONFIG_OMAP_BOOT_REASON=y
+# CONFIG_OMAP_COMPONENT_VERSION is not set
+# CONFIG_OMAP_GPIO_SWITCH is not set
+# CONFIG_OMAP_MUX is not set
+# CONFIG_OMAP_MCBSP is not set
+# CONFIG_OMAP_MMU_FWK is not set
+# CONFIG_OMAP_MBOX_FWK is not set
+# CONFIG_OMAP_MPU_TIMER is not set
+CONFIG_OMAP_32K_TIMER=y
+CONFIG_OMAP_32K_TIMER_HZ=128
+CONFIG_OMAP_DM_TIMER=y
+# CONFIG_OMAP_LL_DEBUG_UART1 is not set
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+CONFIG_OMAP_LL_DEBUG_UART3=y
+CONFIG_ARCH_OMAP34XX=y
+CONFIG_ARCH_OMAP3430=y
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_3430SDP is not set
+# CONFIG_MACH_OMAP3EVM is not set
+CONFIG_MACH_OMAP3_BEAGLE=y
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_V7=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+CONFIG_CPU_PABRT_IFAR=y
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_ARM_XENON is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_HAS_TLS_REG=y
+# CONFIG_OUTER_CACHE is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=128
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+# 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/nfs nfsroot=192.168.0.1:/home/user/buildroot ip=192.168.0.2:192.168.0.1:192.168.0.1:255.255.255.0:tgt:eth0:off rw console=ttyS2,115200n8"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_VFP=y
+CONFIG_VFPv3=y
+# CONFIG_NEON is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_MISC=y
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_PM_LEGACY is not set
+# CONFIG_PM_DEBUG is not set
+# CONFIG_SUSPEND is not set
+# CONFIG_APM_EMULATION is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+CONFIG_NET_KEY=y
+# CONFIG_NET_KEY_MIGRATE is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# 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_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_MISC_DEVICES is not set
+# CONFIG_HAVE_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_NET_ETHERNET is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV 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_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=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_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_ISP1301_OMAP is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_SENSORS_TLV320AIC23 is not set
+CONFIG_TWL4030_CORE=y
+CONFIG_TWL4030_GPIO=y
+# CONFIG_TWL4030_MADC is not set
+CONFIG_TWL4030_USB=y
+# CONFIG_TWL4030_PWRBUTTON is not set
+CONFIG_TWL4030_USB_HS_ULPI=y
+# CONFIG_TWL4030_POWEROFF is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+CONFIG_HAVE_GPIO_LIB=y
+
+#
+# GPIO Support
+#
+# CONFIG_DEBUG_GPIO is not set
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_WATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_MMC is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_QUOTA=y
+# CONFIG_QUOTA_NETLINK_INTERFACE is not set
+CONFIG_PRINT_QUOTA_WARNING=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+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_SUNRPC_BIND34 is not set
+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_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_SAMPLES is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_STACK_USAGE 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
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+# CONFIG_CRYPTO_SEQIV is not set
+CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_XTS is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_TEST is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_LZO is not set
+CONFIG_CRYPTO_HW=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+CONFIG_LIBCRC32C=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
--- /dev/null
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.25-omap1
+# Tue Apr 29 08:06:20 2008
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ARCH_SUPPORTS_AOUT=y
+CONFIG_ZONE_DMA=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_COMPAT_BRK=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_KMOD=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+CONFIG_CLASSIC_RCU=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_MSM7X00A is not set
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+# CONFIG_ARCH_OMAP1 is not set
+# CONFIG_ARCH_OMAP2 is not set
+CONFIG_ARCH_OMAP3=y
+
+#
+# OMAP Feature Selections
+#
+CONFIG_OMAP_DEBUG_SRAM_PATCH=y
+# CONFIG_OMAP_DEBUG_POWERDOMAIN is not set
+# CONFIG_OMAP_DEBUG_CLOCKDOMAIN is not set
+# CONFIG_OMAP_RESET_CLOCKS is not set
+CONFIG_OMAP_BOOT_TAG=y
+CONFIG_OMAP_BOOT_REASON=y
+# CONFIG_OMAP_COMPONENT_VERSION is not set
+# CONFIG_OMAP_GPIO_SWITCH is not set
+# CONFIG_OMAP_MUX is not set
+# CONFIG_OMAP_MCBSP is not set
+# CONFIG_OMAP_MMU_FWK is not set
+# CONFIG_OMAP_MBOX_FWK is not set
+# CONFIG_OMAP_MPU_TIMER is not set
+CONFIG_OMAP_32K_TIMER=y
+CONFIG_OMAP_32K_TIMER_HZ=128
+CONFIG_OMAP_DM_TIMER=y
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_ARCH_OMAP34XX=y
+CONFIG_ARCH_OMAP3430=y
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_3430SDP is not set
+CONFIG_MACH_OMAP3EVM=y
+# CONFIG_MACH_OMAP3_BEAGLE is not set
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_V7=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+CONFIG_CPU_PABRT_IFAR=y
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_ARM_THUMBEE is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_HAS_TLS_REG=y
+# CONFIG_OUTER_CACHE is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=128
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+# 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/nfs nfsroot=192.168.0.1:/home/user/buildroot ip=192.168.0.2:192.168.0.1:192.168.0.1:255.255.255.0:tgt:eth0:off rw console=ttyS2,115200n8"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_VFP=y
+CONFIG_VFPv3=y
+# CONFIG_NEON is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_MISC=y
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_PM_LEGACY is not set
+# CONFIG_PM_DEBUG is not set
+# CONFIG_SUSPEND is not set
+# CONFIG_APM_EMULATION is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+CONFIG_NET_KEY=y
+# CONFIG_NET_KEY_MIGRATE is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_PARTITIONS is not set
+
+#
+# User Modules And Translation Layers
+#
+# CONFIG_MTD_CHAR is not set
+# CONFIG_MTD_BLKDEVS is not set
+# CONFIG_MTD_BLOCK is not set
+# CONFIG_MTD_BLOCK_RO is not set
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS 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
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+CONFIG_MTD_ONENAND=y
+CONFIG_MTD_ONENAND_VERIFY_WRITE=y
+# CONFIG_MTD_ONENAND_GENERIC is not set
+CONFIG_MTD_ONENAND_OMAP2=y
+# CONFIG_MTD_ONENAND_OTP is not set
+# CONFIG_MTD_ONENAND_2X_PROGRAM is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# 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_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_MISC_DEVICES is not set
+# CONFIG_HAVE_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_NET_ETHERNET is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV 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_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ADS7846=y
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_UCB1400 is not set
+# CONFIG_TOUCHSCREEN_TSC2005 is not set
+# CONFIG_TOUCHSCREEN_TSC2102 is not set
+# CONFIG_TOUCHSCREEN_TSC210X is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_ISP1301_OMAP is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_SENSORS_TLV320AIC23 is not set
+CONFIG_TWL4030_CORE=y
+CONFIG_TWL4030_GPIO=y
+# CONFIG_TWL4030_MADC is not set
+CONFIG_TWL4030_USB=y
+CONFIG_TWL4030_USB_HS_ULPI=y
+# CONFIG_TWL4030_PWRBUTTON is not set
+# CONFIG_TWL4030_POWEROFF is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_LP5521 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+CONFIG_SPI_OMAP24XX=m
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_AT25 is not set
+# CONFIG_SPI_TSC2101 is not set
+# CONFIG_SPI_TSC2102 is not set
+# CONFIG_SPI_TSC210X is not set
+# CONFIG_SPI_TSC2301 is not set
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+CONFIG_HAVE_GPIO_LIB=y
+
+#
+# GPIO Support
+#
+# CONFIG_DEBUG_GPIO is not set
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_WATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FB_OMAP=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=2
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE is not set
+# CONFIG_LOGO is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_MMC is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_UIO is not set
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=y
+# CONFIG_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_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_QUOTA=y
+# CONFIG_QUOTA_NETLINK_INTERFACE is not set
+CONFIG_PRINT_QUOTA_WARNING=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+# 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_SUNRPC_BIND34 is not set
+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_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_SAMPLES is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_STACK_USAGE 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
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_LZO is not set
+CONFIG_CRYPTO_HW=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+CONFIG_LIBCRC32C=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
--- /dev/null
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.23-omap1
+# Wed Oct 10 12:21:32 2007
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ZONE_DMA=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_USER_NS is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_KMOD=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+
+#
+# TI OMAP Implementations
+#
+# CONFIG_ARCH_OMAP1 is not set
+CONFIG_ARCH_OMAP2=y
+# CONFIG_ARCH_OMAP3 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+CONFIG_OMAP_BOOT_TAG=y
+# CONFIG_OMAP_BOOT_REASON is not set
+# CONFIG_OMAP_COMPONENT_VERSION is not set
+# CONFIG_OMAP_GPIO_SWITCH is not set
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+# CONFIG_OMAP_MUX_WARNINGS is not set
+# CONFIG_OMAP_STI is not set
+# CONFIG_OMAP_MCBSP is not set
+# CONFIG_OMAP_MMU_FWK is not set
+# CONFIG_OMAP_MBOX_FWK is not set
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
+CONFIG_OMAP_DM_TIMER=y
+# CONFIG_OMAP_LL_DEBUG_UART1 is not set
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+CONFIG_OMAP_LL_DEBUG_UART3=y
+CONFIG_OMAP_SERIAL_WAKE=y
+# CONFIG_OMAP_DSP is not set
+# CONFIG_MACH_OMAP_GENERIC is not set
+
+#
+# OMAP Core Type
+#
+CONFIG_ARCH_OMAP24XX=y
+# CONFIG_ARCH_OMAP2420 is not set
+CONFIG_ARCH_OMAP2430=y
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_NOKIA_N800 is not set
+# CONFIG_MACH_OMAP_H4 is not set
+# CONFIG_MACH_OMAP_APOLLON is not set
+# CONFIG_MACH_OMAP_APOLLON_PLUS is not set
+# CONFIG_MACH_OMAP_2430SDP is not set
+CONFIG_MACH_OMAP_2430OSK=y
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# 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_PABRT_NOIFAR=y
+CONFIG_CPU_CACHE_V6=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V6=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+# CONFIG_OUTER_CACHE is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_PREEMPT=y
+CONFIG_HZ=100
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/ram0 rw console=ttyS0,115200n8 initrd=0x80600000,8M ramdisk_size=8192"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_MISC=y
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_PM_LEGACY is not set
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND_UP_POSSIBLE=y
+CONFIG_SUSPEND=y
+# CONFIG_APM_EMULATION 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 is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=16384
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=m
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+CONFIG_CHR_DEV_SG=m
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_OMAP is not set
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ADS7846=y
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_UCB1400 is not set
+# CONFIG_TOUCHSCREEN_TSC2102 is not set
+# CONFIG_TOUCHSCREEN_TSC210X is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_OMAP_WATCHDOG=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_OMAP=y
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=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_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_SENSORS_TLV320AIC23 is not set
+# CONFIG_GPIOEXPANDER_OMAP is not set
+CONFIG_TWL4030_CORE=y
+CONFIG_TWL4030_GPIO=y
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_MENELAUS is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_OMAP24XX is not set
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_AT25 is not set
+# CONFIG_SPI_TSC2101 is not set
+# CONFIG_SPI_TSC2102 is not set
+# CONFIG_SPI_TSC210X is not set
+# CONFIG_SPI_TSC2301 is not set
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+# CONFIG_W1 is not set
+# CONFIG_HWMON is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+# CONFIG_NEW_LEDS is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+CONFIG_DAB=y
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+CONFIG_FB=y
+CONFIG_FIRMWARE_EDID=y
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_OMAP=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=2
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_MMC is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_QUOTA=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_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=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
+# CONFIG_SYSV68_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_PREEMPT=y
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_ERRORS is not set
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_TEST is not set
+CONFIG_CRYPTO_HW=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+CONFIG_LIBCRC32C=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
--- /dev/null
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.23-rc6-omap1
+# Tue Sep 18 11:47:37 2007
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ZONE_DMA=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_KMOD=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+
+#
+# TI OMAP Implementations
+#
+# CONFIG_ARCH_OMAP1 is not set
+CONFIG_ARCH_OMAP2=y
+# CONFIG_ARCH_OMAP3 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+CONFIG_OMAP_BOOT_TAG=y
+# CONFIG_OMAP_BOOT_REASON is not set
+# CONFIG_OMAP_COMPONENT_VERSION is not set
+# CONFIG_OMAP_GPIO_SWITCH is not set
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+# CONFIG_OMAP_MUX_WARNINGS is not set
+# CONFIG_OMAP_STI is not set
+CONFIG_OMAP_MCBSP=y
+# CONFIG_OMAP_MMU_FWK is not set
+# CONFIG_OMAP_MBOX_FWK is not set
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
+CONFIG_OMAP_DM_TIMER=y
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+# CONFIG_OMAP_DSP is not set
+# CONFIG_MACH_OMAP_GENERIC is not set
+
+#
+# OMAP Core Type
+#
+CONFIG_ARCH_OMAP24XX=y
+# CONFIG_ARCH_OMAP2420 is not set
+CONFIG_ARCH_OMAP2430=y
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_NOKIA_N800 is not set
+# CONFIG_MACH_OMAP_H4 is not set
+# CONFIG_MACH_OMAP_APOLLON is not set
+# CONFIG_MACH_OMAP_APOLLON_PLUS is not set
+CONFIG_MACH_OMAP_2430SDP=y
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# 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_PABRT_NOIFAR=y
+CONFIG_CPU_CACHE_V6=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V6=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+# CONFIG_OUTER_CACHE is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_PREEMPT=y
+CONFIG_HZ=100
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/ram0 rw console=ttyS0,115200n8 initrd=0x80600000,8M ramdisk_size=8192"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_MISC=y
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_PM_LEGACY is not set
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND_UP_POSSIBLE=y
+CONFIG_SUSPEND=y
+# CONFIG_APM_EMULATION is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+CONFIG_NET_KEY=y
+# CONFIG_NET_KEY_MIGRATE is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# 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_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+CONFIG_MTD_ONENAND=y
+CONFIG_MTD_ONENAND_VERIFY_WRITE=y
+# CONFIG_MTD_ONENAND_GENERIC is not set
+CONFIG_MTD_ONENAND_OMAP2=y
+# CONFIG_MTD_ONENAND_OTP is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=16384
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=m
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+CONFIG_CHR_DEV_SG=m
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+CONFIG_SMC91X=y
+# CONFIG_DM9000 is not set
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET_MII is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_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
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_OMAP is not set
+CONFIG_KEYBOARD_TWL4030=y
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ADS7846=y
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_UCB1400 is not set
+# CONFIG_TOUCHSCREEN_TSC2102 is not set
+# CONFIG_TOUCHSCREEN_TSC210X is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_OMAP_WATCHDOG=y
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_OMAP=y
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=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_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_SENSORS_TLV320AIC23 is not set
+# CONFIG_GPIOEXPANDER_OMAP is not set
+CONFIG_TWL4030_CORE=y
+CONFIG_TWL4030_GPIO=y
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_MENELAUS is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_OMAP24XX is not set
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_AT25 is not set
+# CONFIG_SPI_TSC2101 is not set
+# CONFIG_SPI_TSC2102 is not set
+# CONFIG_SPI_TSC210X is not set
+# CONFIG_SPI_TSC2301 is not set
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+# CONFIG_W1 is not set
+# CONFIG_HWMON is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+# CONFIG_NEW_LEDS is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+CONFIG_FB=y
+CONFIG_FIRMWARE_EDID=y
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_OMAP=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=2
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=m
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# USB HID Boot Protocol drivers
+#
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=m
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+# CONFIG_USB_DEVICE_CLASS is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_SUSPEND=y
+# CONFIG_USB_PERSIST is not set
+CONFIG_USB_OTG=y
+CONFIG_USB_OTG_WHITELIST=y
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+CONFIG_USB_MUSB_HDRC=m
+CONFIG_USB_MUSB_SOC=y
+
+#
+# OMAP 243x high speed USB support
+#
+# CONFIG_USB_MUSB_HOST is not set
+# CONFIG_USB_MUSB_PERIPHERAL is not set
+CONFIG_USB_MUSB_OTG=y
+CONFIG_USB_GADGET_MUSB_HDRC=y
+CONFIG_USB_MUSB_HDRC_HCD=y
+# CONFIG_MUSB_PIO_ONLY is not set
+CONFIG_USB_INVENTRA_DMA=y
+# CONFIG_USB_TI_CPPI_DMA is not set
+CONFIG_USB_MUSB_LOGLEVEL=0
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+CONFIG_USB_GADGET=m
+# CONFIG_USB_GADGET_DEBUG is not set
+CONFIG_USB_GADGET_DEBUG_FILES=y
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_M66592 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_S3C2410 is not set
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+CONFIG_USB_ZERO=m
+# CONFIG_USB_ZERO_HNPTEST is not set
+CONFIG_USB_ETH=m
+CONFIG_USB_ETH_RNDIS=y
+CONFIG_USB_GADGETFS=m
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+CONFIG_USB_G_SERIAL=m
+# CONFIG_USB_MIDI_GADGET is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+
+#
+# MMC/SD Host Controller Drivers
+#
+CONFIG_MMC_OMAP_HS=y
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_QUOTA=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_JFFS2_CMODE_NONE is not set
+CONFIG_JFFS2_CMODE_PRIORITY=y
+# CONFIG_JFFS2_CMODE_SIZE is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_BIND34 is not set
+# 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_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_PREEMPT=y
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_TEST is not set
+CONFIG_CRYPTO_HW=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+CONFIG_LIBCRC32C=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
--- /dev/null
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.25-rc2-omap1
+# Fri Feb 22 13:58:16 2008
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ARCH_SUPPORTS_AOUT=y
+CONFIG_ZONE_DMA=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_COMPAT_BRK=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_KMOD=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+CONFIG_CLASSIC_RCU=y
+# CONFIG_PREEMPT_RCU is not set
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_ORION is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_MSM7X00A is not set
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+# CONFIG_ARCH_OMAP1 is not set
+# CONFIG_ARCH_OMAP2 is not set
+CONFIG_ARCH_OMAP3=y
+
+#
+# OMAP Feature Selections
+#
+CONFIG_OMAP_DEBUG_SRAM_PATCH=y
+# CONFIG_OMAP_RESET_CLOCKS is not set
+CONFIG_OMAP_BOOT_TAG=y
+CONFIG_OMAP_BOOT_REASON=y
+# 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_MCBSP is not set
+# CONFIG_OMAP_MMU_FWK is not set
+# CONFIG_OMAP_MBOX_FWK is not set
+# CONFIG_OMAP_MPU_TIMER is not set
+CONFIG_OMAP_32K_TIMER=y
+CONFIG_OMAP_32K_TIMER_HZ=128
+CONFIG_OMAP_DM_TIMER=y
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+CONFIG_ARCH_OMAP34XX=y
+CONFIG_ARCH_OMAP3430=y
+
+#
+# OMAP Board Type
+#
+CONFIG_MACH_OMAP_3430SDP=y
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_V7=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+CONFIG_CPU_PABRT_IFAR=y
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_ARM_XENON is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_HAS_TLS_REG=y
+# CONFIG_OUTER_CACHE is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=128
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+# 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/nfs nfsroot=192.168.0.1:/home/user/buildroot ip=192.168.0.2:192.168.0.1:192.168.0.1:255.255.255.0:tgt:eth0:off rw console=ttyS2,115200n8"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+# CONFIG_ATAGS_PROC is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_VFP=y
+CONFIG_VFPv3=y
+# CONFIG_NEON is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_MISC=y
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_PM_LEGACY is not set
+# CONFIG_PM_DEBUG is not set
+# CONFIG_SUSPEND is not set
+# CONFIG_APM_EMULATION is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+CONFIG_NET_KEY=y
+# CONFIG_NET_KEY_MIGRATE is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS 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
+
+#
+# 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_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+CONFIG_MTD_ONENAND=y
+CONFIG_MTD_ONENAND_VERIFY_WRITE=y
+# CONFIG_MTD_ONENAND_GENERIC is not set
+CONFIG_MTD_ONENAND_OMAP2=y
+# CONFIG_MTD_ONENAND_OTP is not set
+# CONFIG_MTD_ONENAND_2X_PROGRAM is not set
+# CONFIG_MTD_ONENAND_SIM is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=16384
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_HAVE_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+CONFIG_SMC91X=y
+# CONFIG_DM9000 is not set
+# CONFIG_ENC28J60 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_B44 is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_E1000E_ENABLED is not set
+CONFIG_NETDEV_10000=y
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 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_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+CONFIG_KEYBOARD_TWL4030=y
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ADS7846=y
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_UCB1400 is not set
+# CONFIG_TOUCHSCREEN_TSC2102 is not set
+# CONFIG_TOUCHSCREEN_TSC210X is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=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_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_ISP1301_OMAP is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_SENSORS_TLV320AIC23 is not set
+CONFIG_TWL4030_CORE=y
+CONFIG_TWL4030_GPIO=y
+CONFIG_TWL4030_USB=y
+CONFIG_TWL4030_USB_HS_ULPI=y
+# CONFIG_TWL4030_POWEROFF is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+CONFIG_SPI_OMAP24XX=y
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_AT25 is not set
+# CONFIG_SPI_TSC2101 is not set
+# CONFIG_SPI_TSC2102 is not set
+# CONFIG_SPI_TSC210X is not set
+# CONFIG_SPI_TSC2301 is not set
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_OMAP_WATCHDOG=y
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_SUSPEND=y
+# CONFIG_USB_PERSIST is not set
+CONFIG_USB_OTG=y
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+
+#
+# USB Host Controller Drivers
+#
+CONFIG_USB_EHCI_HCD=m
+CONFIG_OMAP_EHCI_PHY_MODE=y
+# CONFIG_OMAP_EHCI_TLL_MODE is not set
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+CONFIG_USB_MUSB_HDRC=y
+CONFIG_USB_MUSB_SOC=y
+
+#
+# OMAP 343x high speed USB support
+#
+# CONFIG_USB_MUSB_HOST is not set
+# CONFIG_USB_MUSB_PERIPHERAL is not set
+CONFIG_USB_MUSB_OTG=y
+CONFIG_USB_GADGET_MUSB_HDRC=y
+CONFIG_USB_MUSB_HDRC_HCD=y
+# CONFIG_MUSB_PIO_ONLY is not set
+CONFIG_USB_INVENTRA_DMA=y
+# CONFIG_USB_TI_CPPI_DMA is not set
+CONFIG_USB_MUSB_LOGLEVEL=1
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_DEBUG=y
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+CONFIG_USB_TEST=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_ATMEL_USBA is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_M66592 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_S3C2410 is not set
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+CONFIG_USB_ZERO=y
+# CONFIG_USB_ZERO_HNPTEST is not set
+# 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
+# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_USB_G_PRINTER is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+
+#
+# MMC/SD Host Controller Drivers
+#
+CONFIG_MMC_OMAP_HS=y
+# CONFIG_MMC_SPI is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_QUOTA=y
+# CONFIG_QUOTA_NETLINK_INTERFACE is not set
+CONFIG_PRINT_QUOTA_WARNING=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+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_JFFS2_CMODE_FAVOURLZO is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+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_SUNRPC_BIND34 is not set
+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_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_SAMPLES is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_STACK_USAGE 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
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+# CONFIG_CRYPTO_SEQIV is not set
+CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_XTS is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_TEST is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_LZO is not set
+CONFIG_CRYPTO_HW=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+CONFIG_LIBCRC32C=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
--- /dev/null
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.23-rc6-omap1
+# Tue Sep 18 12:07:29 2007
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ZONE_DMA=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+# CONFIG_ARCH_OMAP1 is not set
+CONFIG_ARCH_OMAP2=y
+# CONFIG_ARCH_OMAP3 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+# CONFIG_OMAP_BOOT_TAG is not set
+# CONFIG_OMAP_GPIO_SWITCH is not set
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_WARNINGS=y
+# CONFIG_OMAP_STI is not set
+# CONFIG_OMAP_MCBSP is not set
+# CONFIG_OMAP_MMU_FWK is not set
+# CONFIG_OMAP_MBOX_FWK is not set
+# CONFIG_OMAP_MPU_TIMER is not set
+CONFIG_OMAP_32K_TIMER=y
+CONFIG_OMAP_32K_TIMER_HZ=128
+CONFIG_OMAP_DM_TIMER=y
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+# CONFIG_OMAP_DSP is not set
+# CONFIG_MACH_OMAP_GENERIC is not set
+
+#
+# OMAP Core Type
+#
+CONFIG_ARCH_OMAP24XX=y
+CONFIG_ARCH_OMAP2420=y
+# CONFIG_ARCH_OMAP2430 is not set
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_NOKIA_N800 is not set
+# CONFIG_MACH_OMAP_H4 is not set
+CONFIG_MACH_OMAP_APOLLON=y
+# CONFIG_MACH_OMAP_APOLLON_PLUS is not set
+# CONFIG_MACH_OMAP_2430SDP is not set
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# 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_PABRT_NOIFAR=y
+CONFIG_CPU_CACHE_V6=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V6=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+# CONFIG_OUTER_CACHE is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_PREEMPT=y
+CONFIG_HZ=128
+# CONFIG_AEABI is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/ram0 rw mem=128M console=ttyS0,115200n8 initrd=0x80600000,8M ramdisk_size=8192"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+# CONFIG_FPE_NWFPE is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_VFP=y
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+CONFIG_SUSPEND_UP_POSSIBLE=y
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI 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
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+CONFIG_MTD_ONENAND=y
+# CONFIG_MTD_ONENAND_VERIFY_WRITE is not set
+CONFIG_MTD_ONENAND_GENERIC=y
+# CONFIG_MTD_ONENAND_OMAP2 is not set
+# CONFIG_MTD_ONENAND_OTP is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+CONFIG_SMC91X=y
+# CONFIG_DM9000 is not set
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# 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
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_OMAP_WATCHDOG=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_OMAP=y
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+CONFIG_SPI_OMAP24XX=y
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_AT25 is not set
+# CONFIG_SPI_TSC2101 is not set
+# CONFIG_SPI_TSC2102 is not set
+# CONFIG_SPI_TSC210X is not set
+# CONFIG_SPI_TSC2301 is not set
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+# CONFIG_W1 is not set
+# CONFIG_HWMON is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+# CONFIG_NEW_LEDS is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+CONFIG_FB=y
+CONFIG_FIRMWARE_EDID=y
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_OMAP=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=2
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+# CONFIG_HID is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
+# CONFIG_USB_MUSB_HDRC is not set
+# CONFIG_USB_GADGET_MUSB_HDRC is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG is not set
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_M66592 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_S3C2410 is not set
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+# CONFIG_USB_GADGET_DUALSPEED is not set
+# CONFIG_USB_ZERO is not set
+CONFIG_USB_ETH=m
+CONFIG_USB_ETH_RNDIS=y
+# CONFIG_USB_GADGETFS is not set
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+
+#
+# MMC/SD Host Controller Drivers
+#
+CONFIG_MMC_OMAP=y
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_INOTIFY is not set
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+CONFIG_AUTOFS4_FS=y
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_CRAMFS=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_BIND34 is not set
+# 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 is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_PREEMPT=y
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+CONFIG_DEBUG_SPINLOCK_SLEEP=y
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+CONFIG_LIBCRC32C=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
--- /dev/null
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.23-rc6-omap1
+# Tue Sep 18 12:20:19 2007
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ZONE_DMA=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP1=y
+# CONFIG_ARCH_OMAP2 is not set
+# CONFIG_ARCH_OMAP3 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+# CONFIG_OMAP_BOOT_TAG is not set
+# CONFIG_OMAP_GPIO_SWITCH is not set
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_WARNINGS=y
+CONFIG_OMAP_MCBSP=y
+# CONFIG_OMAP_MMU_FWK is not set
+# CONFIG_OMAP_MBOX_FWK is not set
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+# CONFIG_OMAP_DSP is not set
+
+#
+# OMAP Core Type
+#
+# CONFIG_ARCH_OMAP730 is not set
+CONFIG_ARCH_OMAP15XX=y
+# CONFIG_ARCH_OMAP16XX is not set
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_INNOVATOR is not set
+# CONFIG_MACH_VOICEBLUE is not set
+# CONFIG_MACH_OMAP_PALMTE is not set
+# CONFIG_MACH_OMAP_PALMZ71 is not set
+# CONFIG_MACH_OMAP_PALMTT is not set
+# CONFIG_MACH_SX1 is not set
+# CONFIG_MACH_AMS_DELTA is not set
+CONFIG_MACH_OMAP_GENERIC=y
+
+#
+# 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_MACH_OMAP_APOLLON_PLUS is not set
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM925T=y
+CONFIG_CPU_32v4T=y
+CONFIG_CPU_ABRT_EV4T=y
+CONFIG_CPU_PABRT_NOIFAR=y
+CONFIG_CPU_CACHE_V4WT=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+CONFIG_CPU_DCACHE_WRITETHROUGH=y
+# CONFIG_OUTER_CACHE is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_PREEMPT=y
+CONFIG_HZ=100
+# CONFIG_AEABI is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="mem=64M console=ttyS2,115200 root=0803 ro init=/bin/sh"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+
+#
+# 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_PM_SLEEP=y
+CONFIG_SUSPEND_UP_POSSIBLE=y
+CONFIG_SUSPEND=y
+# CONFIG_APM_EMULATION is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_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_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=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
+# 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
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+CONFIG_USB_RTL8150=y
+CONFIG_USB_USBNET_MII=y
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_AX8817X=y
+CONFIG_USB_NET_CDCETHER=y
+# CONFIG_USB_NET_DM9601 is not set
+# CONFIG_USB_NET_GL620A is not set
+CONFIG_USB_NET_NET1080=y
+# CONFIG_USB_NET_PLUSB is not set
+# CONFIG_USB_NET_MCS7830 is not set
+# CONFIG_USB_NET_RNDIS_HOST is not set
+CONFIG_USB_NET_CDC_SUBSET=y
+# CONFIG_USB_ALI_M5632 is not set
+CONFIG_USB_AN2720=y
+CONFIG_USB_BELKIN=y
+CONFIG_USB_ARMLINUX=y
+CONFIG_USB_EPSON2888=y
+# CONFIG_USB_KC2190 is not set
+CONFIG_USB_NET_ZAURUS=y
+# CONFIG_WAN is not set
+CONFIG_PPP=y
+CONFIG_PPP_MULTILINK=y
+# CONFIG_PPP_FILTER is not set
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_PPP_DEFLATE is not set
+# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPP_MPPE is not set
+# CONFIG_PPPOE is not set
+# CONFIG_PPPOL2TP is not set
+# CONFIG_SLIP is not set
+CONFIG_SLHC=y
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+CONFIG_KEYBOARD_OMAP=y
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_HW_RANDOM=m
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=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_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_OMAP is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+# CONFIG_W1 is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_ABITUGURU3 is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_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_LM93 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_DME1737 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+# CONFIG_NEW_LEDS is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+# 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
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_PERSIST is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_MUSB_HDRC is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+CONFIG_USB_STORAGE_DATAFAB=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
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+
+#
+# MMC/SD Host Controller Drivers
+#
+CONFIG_MMC_OMAP=y
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_OMAP=y
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4DEV_FS 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_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+CONFIG_AUTOFS_FS=y
+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_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 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_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_BIND34 is not set
+# 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_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_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
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_PREEMPT=y
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_DEBUG_USER 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
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
--- /dev/null
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.23-rc6-omap1
+# Tue Sep 18 13:01:27 2007
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ZONE_DMA=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+CONFIG_ARCH_OMAP1=y
+# CONFIG_ARCH_OMAP2 is not set
+# CONFIG_ARCH_OMAP3 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+# CONFIG_OMAP_BOOT_TAG is not set
+# CONFIG_OMAP_GPIO_SWITCH is not set
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_WARNINGS=y
+# CONFIG_OMAP_STI is not set
+CONFIG_OMAP_MCBSP=y
+# CONFIG_OMAP_MMU_FWK is not set
+# CONFIG_OMAP_MBOX_FWK is not set
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
+# CONFIG_OMAP_DM_TIMER is not set
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+# CONFIG_OMAP_DSP is not set
+
+#
+# OMAP Core Type
+#
+# CONFIG_ARCH_OMAP730 is not set
+# CONFIG_ARCH_OMAP15XX is not set
+CONFIG_ARCH_OMAP16XX=y
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_INNOVATOR is not set
+# CONFIG_MACH_OMAP_H2 is not set
+# CONFIG_MACH_OMAP_H3 is not set
+# CONFIG_MACH_OMAP_OSK is not set
+# CONFIG_MACH_NOKIA770 is not set
+CONFIG_MACH_OMAP_GENERIC=y
+
+#
+# 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_MACH_OMAP_APOLLON_PLUS is not set
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_PABRT_NOIFAR=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB 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
+# CONFIG_OUTER_CACHE is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_PREEMPT=y
+CONFIG_HZ=100
+# CONFIG_AEABI is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="mem=64M console=ttyS2,115200 root=0803 ro init=/bin/sh"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_PM_LEGACY is not set
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND_UP_POSSIBLE=y
+CONFIG_SUSPEND=y
+# CONFIG_APM_EMULATION is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_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_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=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
+# 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
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+CONFIG_USB_RTL8150=y
+CONFIG_USB_USBNET_MII=y
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_AX8817X=y
+CONFIG_USB_NET_CDCETHER=y
+# CONFIG_USB_NET_DM9601 is not set
+# CONFIG_USB_NET_GL620A is not set
+CONFIG_USB_NET_NET1080=y
+# CONFIG_USB_NET_PLUSB is not set
+# CONFIG_USB_NET_MCS7830 is not set
+# CONFIG_USB_NET_RNDIS_HOST is not set
+CONFIG_USB_NET_CDC_SUBSET=y
+CONFIG_USB_ALI_M5632=y
+CONFIG_USB_AN2720=y
+CONFIG_USB_BELKIN=y
+CONFIG_USB_ARMLINUX=y
+CONFIG_USB_EPSON2888=y
+# CONFIG_USB_KC2190 is not set
+CONFIG_USB_NET_ZAURUS=y
+# CONFIG_WAN is not set
+CONFIG_PPP=y
+CONFIG_PPP_MULTILINK=y
+# CONFIG_PPP_FILTER is not set
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_PPP_DEFLATE is not set
+# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPP_MPPE is not set
+# CONFIG_PPPOE is not set
+# CONFIG_PPPOL2TP is not set
+# CONFIG_SLIP is not set
+CONFIG_SLHC=y
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+CONFIG_KEYBOARD_OMAP=y
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_HW_RANDOM=m
+CONFIG_HW_RANDOM_OMAP=m
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=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_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_OMAP is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_ISP1301_OMAP is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_GPIOEXPANDER_OMAP is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+# CONFIG_W1 is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_ABITUGURU3 is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_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_LM93 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_DME1737 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+# CONFIG_NEW_LEDS is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+# 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
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_PERSIST is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_MUSB_HDRC is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+CONFIG_USB_STORAGE_DATAFAB=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
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+
+#
+# MMC/SD Host Controller Drivers
+#
+CONFIG_MMC_OMAP=y
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_OMAP=y
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4DEV_FS 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_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+CONFIG_AUTOFS_FS=y
+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_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 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_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_BIND34 is not set
+# 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_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_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
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_PREEMPT=y
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_DEBUG_USER 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
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
--- /dev/null
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.23-rc6-omap1
+# Tue Sep 18 13:02:08 2007
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ZONE_DMA=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_MODULES is not set
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+CONFIG_ARCH_OMAP1=y
+# CONFIG_ARCH_OMAP2 is not set
+# CONFIG_ARCH_OMAP3 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+CONFIG_OMAP_BOOT_TAG=y
+# CONFIG_OMAP_BOOT_REASON is not set
+# CONFIG_OMAP_COMPONENT_VERSION is not set
+# CONFIG_OMAP_GPIO_SWITCH is not set
+# CONFIG_OMAP_MUX is not set
+# CONFIG_OMAP_STI is not set
+CONFIG_OMAP_MCBSP=y
+# CONFIG_OMAP_MMU_FWK is not set
+# CONFIG_OMAP_MBOX_FWK is not set
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
+# CONFIG_OMAP_DM_TIMER 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_DSP is not set
+
+#
+# OMAP Core Type
+#
+# CONFIG_ARCH_OMAP730 is not set
+# CONFIG_ARCH_OMAP15XX is not set
+CONFIG_ARCH_OMAP16XX=y
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_INNOVATOR is not set
+# CONFIG_MACH_OMAP_H2 is not set
+# CONFIG_MACH_OMAP_H3 is not set
+# CONFIG_MACH_OMAP_OSK is not set
+# CONFIG_MACH_NOKIA770 is not set
+CONFIG_MACH_OMAP_GENERIC=y
+
+#
+# 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_MACH_OMAP_APOLLON_PLUS is not set
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_PABRT_NOIFAR=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB 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
+# CONFIG_OUTER_CACHE is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=100
+# CONFIG_AEABI is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="mem=64M console=tty0 console=ttyS2,115200 root=0801"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+CONFIG_ARTHUR=y
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_PM_LEGACY is not set
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND_UP_POSSIBLE=y
+CONFIG_SUSPEND=y
+# CONFIG_APM_EMULATION is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETLABEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_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_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+CONFIG_USB_USBNET_MII=y
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_AX8817X=y
+CONFIG_USB_NET_CDCETHER=y
+# CONFIG_USB_NET_DM9601 is not set
+# CONFIG_USB_NET_GL620A is not set
+CONFIG_USB_NET_NET1080=y
+# CONFIG_USB_NET_PLUSB is not set
+# CONFIG_USB_NET_MCS7830 is not set
+# CONFIG_USB_NET_RNDIS_HOST is not set
+CONFIG_USB_NET_CDC_SUBSET=y
+CONFIG_USB_ALI_M5632=y
+# CONFIG_USB_AN2720 is not set
+# CONFIG_USB_BELKIN is not set
+# CONFIG_USB_ARMLINUX is not set
+# CONFIG_USB_EPSON2888 is not set
+# CONFIG_USB_KC2190 is not set
+CONFIG_USB_NET_ZAURUS=y
+# CONFIG_WAN is not set
+CONFIG_PPP=y
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_PPP_DEFLATE is not set
+# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPP_MPPE is not set
+# CONFIG_PPPOE is not set
+# CONFIG_PPPOL2TP is not set
+# CONFIG_SLIP is not set
+CONFIG_SLHC=y
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=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_STOWAWAY is not set
+CONFIG_KEYBOARD_OMAP=y
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_OMAP=y
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+# CONFIG_W1 is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_ABITUGURU3 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+# CONFIG_NEW_LEDS is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=y
+# 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
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+CONFIG_HID_DEBUG=y
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_PERSIST is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_MUSB_HDRC is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+
+#
+# MMC/SD Host Controller Drivers
+#
+CONFIG_MMC_OMAP=y
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4DEV_FS 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_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_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 is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+# CONFIG_SUNRPC_BIND34 is not set
+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_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_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
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+CONFIG_DEBUG_SPINLOCK=y
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_FORCED_INLINING=y
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_DEBUG_USER 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=y
+# CONFIG_SECURITY_ROOTPLUG is not set
+# CONFIG_SECURITY_LOWMEM is not set
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+CONFIG_CRYPTO_ECB=y
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_PCBC=y
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+CONFIG_CRYPTO_HW=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
--- /dev/null
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.23-rc6-omap1
+# Tue Sep 18 11:44:48 2007
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ZONE_DMA=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_USER_NS is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+# CONFIG_ARCH_OMAP1 is not set
+CONFIG_ARCH_OMAP2=y
+# CONFIG_ARCH_OMAP3 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+CONFIG_OMAP_BOOT_TAG=y
+# CONFIG_OMAP_BOOT_REASON is not set
+# CONFIG_OMAP_COMPONENT_VERSION is not set
+# CONFIG_OMAP_GPIO_SWITCH is not set
+# CONFIG_OMAP_MUX is not set
+# CONFIG_OMAP_STI is not set
+CONFIG_OMAP_MCBSP=y
+# CONFIG_OMAP_MMU_FWK is not set
+# CONFIG_OMAP_MBOX_FWK is not set
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
+CONFIG_OMAP_DM_TIMER=y
+# CONFIG_OMAP_LL_DEBUG_UART1 is not set
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+CONFIG_OMAP_LL_DEBUG_UART3=y
+# CONFIG_OMAP_DSP is not set
+CONFIG_MACH_OMAP_GENERIC=y
+
+#
+# OMAP Core Type
+#
+CONFIG_ARCH_OMAP24XX=y
+CONFIG_ARCH_OMAP2420=y
+# CONFIG_ARCH_OMAP2430 is not set
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_NOKIA_N800 is not set
+# CONFIG_MACH_OMAP_H4 is not set
+# CONFIG_MACH_OMAP_APOLLON is not set
+# CONFIG_MACH_OMAP_APOLLON_PLUS is not set
+# CONFIG_MACH_OMAP_2430SDP is not set
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# 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_PABRT_NOIFAR=y
+CONFIG_CPU_CACHE_V6=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V6=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+# CONFIG_OUTER_CACHE is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=100
+# CONFIG_AEABI is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+CONFIG_LEDS=y
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x10C08000
+CONFIG_ZBOOT_ROM_BSS=0x10200000
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_CMDLINE=""
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+CONFIG_SUSPEND_UP_POSSIBLE=y
+
+#
+# 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
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# 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_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_OMAP_WATCHDOG is not set
+CONFIG_HW_RANDOM=m
+CONFIG_HW_RANDOM_OMAP=m
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+# CONFIG_W1 is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_ABITUGURU3 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+# CONFIG_NEW_LEDS is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+CONFIG_DAB=y
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+# 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
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+CONFIG_HID_DEBUG=y
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
+
+#
+# Enable Host or Gadget support to see Inventra options
+#
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+# CONFIG_MMC is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT2_FS_POSIX_ACL is not set
+# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+CONFIG_ROMFS_FS=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# 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_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_ERRORS=y
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.25-rc3
-# Mon Mar 3 03:39:48 2008
+# Linux kernel version: 2.6.25-rc2-omap1
+# Wed Feb 20 17:12:36 2008
#
CONFIG_ARM=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
#
CONFIG_EXPERIMENTAL=y
CONFIG_BROKEN_ON_SMP=y
-CONFIG_LOCK_KERNEL=y
CONFIG_INIT_ENV_ARG_LIMIT=32
CONFIG_LOCALVERSION=""
CONFIG_LOCALVERSION_AUTO=y
# CONFIG_RT_GROUP_SCHED is not set
CONFIG_USER_SCHED=y
# CONFIG_CGROUP_SCHED is not set
-# CONFIG_SYSFS_DEPRECATED is not set
+CONFIG_SYSFS_DEPRECATED=y
# CONFIG_RELAY is not set
CONFIG_NAMESPACES=y
# CONFIG_UTS_NS is not set
CONFIG_UID16=y
CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
# CONFIG_KALLSYMS_EXTRA_PASS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_ARCH_OMAP_OTG=y
CONFIG_ARCH_OMAP1=y
# CONFIG_ARCH_OMAP2 is not set
+# CONFIG_ARCH_OMAP3 is not set
#
# OMAP Feature Selections
#
+CONFIG_OMAP_DEBUG_SRAM_PATCH=y
# CONFIG_OMAP_RESET_CLOCKS is not set
+CONFIG_OMAP_BOOT_TAG=y
+# CONFIG_OMAP_BOOT_REASON is not set
+# CONFIG_OMAP_COMPONENT_VERSION is not set
+CONFIG_OMAP_GPIO_SWITCH=y
CONFIG_OMAP_MUX=y
-# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_DEBUG=y
CONFIG_OMAP_MUX_WARNINGS=y
+# CONFIG_OMAP_STI is not set
CONFIG_OMAP_MCBSP=y
# CONFIG_OMAP_MMU_FWK is not set
+# CONFIG_OMAP_MBOX_FWK is not set
# CONFIG_OMAP_MPU_TIMER is not set
CONFIG_OMAP_32K_TIMER=y
CONFIG_OMAP_32K_TIMER_HZ=128
-# CONFIG_OMAP_DM_TIMER is not set
+CONFIG_OMAP_DM_TIMER=y
CONFIG_OMAP_LL_DEBUG_UART1=y
# CONFIG_OMAP_LL_DEBUG_UART2 is not set
# CONFIG_OMAP_LL_DEBUG_UART3 is not set
#
# CONFIG_OMAP_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_CPU_ARM926T=y
CONFIG_CPU_32v5=y
CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_PABRT_NOIFAR=y
CONFIG_CPU_CACHE_VIVT=y
CONFIG_CPU_COPY_V4WB=y
CONFIG_CPU_TLB_V4WBI=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
-CONFIG_PREEMPT=y
+# CONFIG_PREEMPT is not set
CONFIG_HZ=128
-CONFIG_AEABI=y
-CONFIG_OABI_COMPAT=y
+# CONFIG_AEABI is not set
# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_FLATMEM_MANUAL=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-# CONFIG_LEDS is not set
+CONFIG_LEDS=y
+# 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
# CONFIG_KEXEC is not set
# CONFIG_ATAGS_PROC 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_DEFAULT_GOV_ONDEMAND is not set
-# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
-# 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
# Userspace binary formats
#
CONFIG_BINFMT_ELF=y
-CONFIG_BINFMT_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
#
# Power management options
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_FW_LOADER is not set
+CONFIG_DEBUG_DRIVER=y
+# CONFIG_DEBUG_DEVRES is not set
# CONFIG_SYS_HYPERVISOR is not set
# CONFIG_CONNECTOR is not set
-# CONFIG_MTD is not set
+CONFIG_MTD=y
+CONFIG_MTD_DEBUG=y
+CONFIG_MTD_DEBUG_VERBOSE=3
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS 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
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_OMAP_NOR is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# 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_XIP is not set
# CONFIG_CDROM_PKTCDVD is not set
-CONFIG_ATA_OVER_ETH=m
+# CONFIG_ATA_OVER_ETH is not set
CONFIG_MISC_DEVICES=y
# CONFIG_EEPROM_93CX6 is not set
# CONFIG_ENCLOSURE_SERVICES is not set
# SCSI device support
#
# CONFIG_RAID_ATTRS is not set
-CONFIG_SCSI=y
-CONFIG_SCSI_DMA=y
-# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
# CONFIG_SCSI_NETLINK is not set
-CONFIG_SCSI_PROC_FS=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-# CONFIG_BLK_DEV_SD is not set
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_CHR_DEV_OSST is not set
-# CONFIG_BLK_DEV_SR is not set
-# CONFIG_CHR_DEV_SG is not set
-# CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
-# CONFIG_SCSI_MULTI_LUN is not set
-# CONFIG_SCSI_CONSTANTS is not set
-# CONFIG_SCSI_LOGGING is not set
-# CONFIG_SCSI_SCAN_ASYNC is not set
-CONFIG_SCSI_WAIT_SCAN=m
-
-#
-# SCSI Transports
-#
-# CONFIG_SCSI_SPI_ATTRS is not set
-# CONFIG_SCSI_FC_ATTRS is not set
-# CONFIG_SCSI_ISCSI_ATTRS is not set
-# CONFIG_SCSI_SAS_LIBSAS is not set
-# CONFIG_SCSI_SRP_ATTRS is not set
-CONFIG_SCSI_LOWLEVEL=y
-# CONFIG_ISCSI_TCP is not set
-# CONFIG_SCSI_DEBUG is not set
# CONFIG_ATA is not set
# CONFIG_MD is not set
CONFIG_NETDEVICES=y
# CONFIG_AX88796 is not set
CONFIG_SMC91X=y
# CONFIG_DM9000 is not set
+# CONFIG_ENC28J60 is not set
# CONFIG_IBM_NEW_EMAC_ZMII is not set
# CONFIG_IBM_NEW_EMAC_RGMII is not set
# CONFIG_IBM_NEW_EMAC_TAH is not set
#
# CONFIG_WLAN_PRE80211 is not set
# CONFIG_WLAN_80211 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_WAN is not set
CONFIG_PPP=y
# CONFIG_PPP_MULTILINK is not set
CONFIG_UNIX98_PTYS=y
# CONFIG_LEGACY_PTYS is not set
# CONFIG_IPMI_HANDLER is not set
-# CONFIG_HW_RANDOM is not set
+CONFIG_HW_RANDOM=m
+CONFIG_HW_RANDOM_OMAP=m
# CONFIG_NVRAM is not set
# CONFIG_R3964 is not set
# CONFIG_RAW_DRIVER is not set
# CONFIG_I2C_SIMTEC is not set
# CONFIG_I2C_TAOS_EVM is not set
# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_TINY_USB is not set
#
# Miscellaneous I2C Chip support
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_PCF8575 is not set
# CONFIG_SENSORS_PCF8591 is not set
-# CONFIG_ISP1301_OMAP 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_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
#
# SPI support
#
-# CONFIG_SPI is not set
-# CONFIG_SPI_MASTER is not set
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_BITBANG=y
+CONFIG_SPI_OMAP_UWIRE=y
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_AT25 is not set
+CONFIG_SPI_TSC2101=y
+# CONFIG_SPI_TSC2102 is not set
+# CONFIG_SPI_TSC210X is not set
+# CONFIG_SPI_TSC2301 is not set
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
# CONFIG_W1 is not set
# CONFIG_POWER_SUPPLY is not set
CONFIG_HWMON=y
# CONFIG_SENSORS_ADM1031 is not set
# CONFIG_SENSORS_ADM9240 is not set
# CONFIG_SENSORS_ADT7470 is not set
-# CONFIG_SENSORS_ADT7473 is not set
# CONFIG_SENSORS_ATXP1 is not set
# CONFIG_SENSORS_DS1621 is not set
# CONFIG_SENSORS_F71805F is not set
# CONFIG_SENSORS_GL520SM is not set
# CONFIG_SENSORS_IT87 is not set
# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM70 is not set
# CONFIG_SENSORS_LM75 is not set
# CONFIG_SENSORS_LM77 is not set
# CONFIG_SENSORS_LM78 is not set
# CONFIG_SENSORS_W83L786NG is not set
# CONFIG_SENSORS_W83627HF is not set
# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_SENSORS_TSC210X is not set
# CONFIG_HWMON_DEBUG_CHIP is not set
CONFIG_WATCHDOG=y
CONFIG_WATCHDOG_NOWAYOUT=y
# CONFIG_SOFT_WATCHDOG is not set
# CONFIG_OMAP_WATCHDOG is not set
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+
#
# Sonics Silicon Backplane
#
# CONFIG_VIDEO_DEV is not set
# CONFIG_DVB_CORE is not set
CONFIG_DAB=y
+# CONFIG_USB_DABUSB is not set
#
# Graphics support
CONFIG_FB=y
CONFIG_FIRMWARE_EDID=y
# CONFIG_FB_DDC is not set
-# CONFIG_FB_CFB_FILLRECT is not set
-# CONFIG_FB_CFB_COPYAREA is not set
-# CONFIG_FB_CFB_IMAGEBLIT is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
# CONFIG_FB_SYS_FILLRECT is not set
# CONFIG_FB_SYS_COPYAREA is not set
#
# CONFIG_FB_S1D13XXX is not set
# CONFIG_FB_VIRTUAL is not set
-# CONFIG_FB_OMAP is not set
+CONFIG_FB_OMAP=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=2
+# CONFIG_FB_OMAP_DMA_TUNE is not set
# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
CONFIG_FRAMEBUFFER_CONSOLE=y
# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
# 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_LOGO=y
# CONFIG_LOGO_LINUX_MONO is not set
# CONFIG_LOGO_LINUX_VGA16 is not set
#
# Sound
#
-CONFIG_SOUND=y
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
#
-# Advanced Linux Sound Architecture
+# USB Input Devices
#
-# CONFIG_SND is not set
+# CONFIG_USB_HID is not set
#
-# Open Sound System
+# USB HID Boot Protocol drivers
#
-CONFIG_SOUND_PRIME=y
-# CONFIG_SOUND_MSNDCLAS is not set
-# CONFIG_SOUND_MSNDPIN is not set
-CONFIG_HID_SUPPORT=y
-CONFIG_HID=y
-CONFIG_HID_DEBUG=y
-# CONFIG_HIDRAW is not set
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
CONFIG_USB_SUPPORT=y
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
# CONFIG_USB_ARCH_HAS_EHCI is not set
-# CONFIG_USB is not set
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_SUSPEND=y
+# CONFIG_USB_PERSIST is not set
+CONFIG_USB_OTG=y
+CONFIG_USB_OTG_WHITELIST=y
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_MUSB_HDRC is not set
+# CONFIG_USB_GADGET_MUSB_HDRC is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
#
# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
#
-# CONFIG_USB_GADGET is not set
-# CONFIG_MMC is not set
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+CONFIG_USB_TEST=y
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG is not set
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_ATMEL_USBA is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_M66592 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_S3C2410 is not set
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+# CONFIG_USB_GADGET_DUALSPEED is not set
+# CONFIG_USB_ZERO is not set
+CONFIG_USB_ETH=y
+CONFIG_USB_ETH_RNDIS=y
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_USB_G_PRINTER is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+
+#
+# MMC/SD Host Controller Drivers
+#
+CONFIG_MMC_OMAP=y
+# CONFIG_MMC_SPI is not set
# CONFIG_NEW_LEDS is not set
CONFIG_RTC_LIB=y
-# CONFIG_RTC_CLASS is not set
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_OMAP=y
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+# CONFIG_OMAP_DSP is not set
#
# File systems
# CONFIG_BEFS_FS is not set
# CONFIG_BFS_FS is not set
# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
CONFIG_CRAMFS=y
# CONFIG_VXFS_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_UFS_FS is not set
CONFIG_NETWORK_FILESYSTEMS=y
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_SUNRPC_BIND34 is not set
-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
# CONFIG_UNUSED_SYMBOLS is not set
# CONFIG_DEBUG_FS is not set
# CONFIG_HEADERS_CHECK is not set
-# CONFIG_DEBUG_KERNEL is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
CONFIG_FRAME_POINTER=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
# CONFIG_SAMPLES is not set
-# CONFIG_DEBUG_USER is not set
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_LL is not set
#
# Security options
# CONFIG_SECURITY is not set
# CONFIG_SECURITY_FILE_CAPABILITIES is not set
CONFIG_CRYPTO=y
-CONFIG_CRYPTO_ALGAPI=y
-CONFIG_CRYPTO_BLKCIPHER=y
# CONFIG_CRYPTO_SEQIV is not set
-CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_MANAGER is not set
# CONFIG_CRYPTO_HMAC is not set
# CONFIG_CRYPTO_XCBC is not set
# CONFIG_CRYPTO_NULL is not set
# CONFIG_CRYPTO_MD4 is not set
-CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_MD5 is not set
# CONFIG_CRYPTO_SHA1 is not set
# CONFIG_CRYPTO_SHA256 is not set
# CONFIG_CRYPTO_SHA512 is not set
# CONFIG_CRYPTO_WP512 is not set
# CONFIG_CRYPTO_TGR192 is not set
# CONFIG_CRYPTO_GF128MUL is not set
-CONFIG_CRYPTO_ECB=m
-CONFIG_CRYPTO_CBC=y
-CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_PCBC is not set
# CONFIG_CRYPTO_LRW is not set
# CONFIG_CRYPTO_XTS is not set
# CONFIG_CRYPTO_CTR is not set
# CONFIG_CRYPTO_GCM is not set
# CONFIG_CRYPTO_CCM is not set
# CONFIG_CRYPTO_CRYPTD is not set
-CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_DES is not set
# CONFIG_CRYPTO_FCRYPT is not set
# CONFIG_CRYPTO_BLOWFISH is not set
# CONFIG_CRYPTO_TWOFISH is not set
# CONFIG_CRC7 is not set
# CONFIG_LIBCRC32C is not set
CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
CONFIG_PLIST=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
--- /dev/null
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.25-rc2-omap1
+# Wed Feb 20 17:05:42 2008
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ARCH_SUPPORTS_AOUT=y
+CONFIG_ZONE_DMA=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_COMPAT_BRK=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+CONFIG_CLASSIC_RCU=y
+# CONFIG_PREEMPT_RCU is not set
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_ORION is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_MSM7X00A is not set
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+CONFIG_ARCH_OMAP1=y
+# CONFIG_ARCH_OMAP2 is not set
+# CONFIG_ARCH_OMAP3 is not set
+
+#
+# OMAP Feature Selections
+#
+CONFIG_OMAP_DEBUG_SRAM_PATCH=y
+# CONFIG_OMAP_RESET_CLOCKS is not set
+# CONFIG_OMAP_BOOT_TAG is not set
+CONFIG_OMAP_GPIO_SWITCH=y
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_WARNINGS=y
+# CONFIG_OMAP_STI is not set
+CONFIG_OMAP_MCBSP=y
+# CONFIG_OMAP_MMU_FWK is not set
+# CONFIG_OMAP_MBOX_FWK is not set
+# CONFIG_OMAP_MPU_TIMER is not set
+CONFIG_OMAP_32K_TIMER=y
+CONFIG_OMAP_32K_TIMER_HZ=128
+CONFIG_OMAP_DM_TIMER=y
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+
+#
+# OMAP Core Type
+#
+# CONFIG_ARCH_OMAP730 is not set
+# CONFIG_ARCH_OMAP15XX is not set
+CONFIG_ARCH_OMAP16XX=y
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_INNOVATOR is not set
+# CONFIG_MACH_OMAP_H2 is not set
+CONFIG_MACH_OMAP_H3=y
+# CONFIG_MACH_OMAP_OSK is not set
+# CONFIG_MACH_NOKIA770 is not set
+# CONFIG_MACH_OMAP_GENERIC is not set
+
+#
+# OMAP CPU Speed
+#
+# CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER is not set
+# CONFIG_OMAP_ARM_216MHZ is not set
+# CONFIG_OMAP_ARM_192MHZ is not set
+CONFIG_OMAP_ARM_168MHZ=y
+# CONFIG_OMAP_ARM_120MHZ is not set
+# CONFIG_OMAP_ARM_60MHZ is not set
+# CONFIG_OMAP_ARM_30MHZ is not set
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_PABRT_NOIFAR=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+# CONFIG_OUTER_CACHE is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=128
+# CONFIG_AEABI is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+CONFIG_LEDS=y
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x10C08000
+CONFIG_ZBOOT_ROM_BSS=0x10200000
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_CMDLINE="mem=32M console=ttyS0,115200n8 initrd=0x10A00000,8M root=/dev/ram0 rw ip=dhcp devfs=mount"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+# CONFIG_ATAGS_PROC 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_PM_SLEEP=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+# CONFIG_APM_EMULATION is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN 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
+#
+# CONFIG_KINGSUN_DONGLE is not set
+# CONFIG_KSDAZZLE_DONGLE is not set
+# CONFIG_KS959_DONGLE is not set
+
+#
+# FIR device drivers
+#
+# CONFIG_USB_IRDA is not set
+# CONFIG_SIGMATEL_FIR is not set
+# CONFIG_MCS_FIR is not set
+# CONFIG_OMAP_IR is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# 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_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_HAVE_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+CONFIG_SMC91X=y
+# CONFIG_DM9000 is not set
+# CONFIG_ENC28J60 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_B44 is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_E1000E_ENABLED is not set
+CONFIG_NETDEV_10000=y
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 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_WAN is not set
+CONFIG_PPP=y
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_PPP_DEFLATE is not set
+# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPP_MPPE is not set
+# CONFIG_PPPOE is not set
+# CONFIG_PPPOL2TP is not set
+CONFIG_SLIP=y
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLHC=y
+# CONFIG_SLIP_SMART is not set
+# CONFIG_SLIP_MODE_SLIP6 is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+CONFIG_KEYBOARD_OMAP=y
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=m
+CONFIG_HW_RANDOM_OMAP=m
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=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_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+CONFIG_ISP1301_OMAP=m
+CONFIG_TPS65010=y
+# CONFIG_SENSORS_TLV320AIC23 is not set
+CONFIG_GPIOEXPANDER_OMAP=y
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_BITBANG=y
+CONFIG_SPI_OMAP_UWIRE=y
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_AT25 is not set
+# CONFIG_SPI_TSC2101 is not set
+# CONFIG_SPI_TSC2102 is not set
+# CONFIG_SPI_TSC210X is not set
+# CONFIG_SPI_TSC2301 is not set
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ADT7470 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM70 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_DME1737 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_ADS7828 is not set
+# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83L786NG is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_SENSORS_TSC210X is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_OMAP_WATCHDOG is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_COMMON=y
+CONFIG_VIDEO_V4L1=y
+CONFIG_VIDEO_V4L1_COMPAT=y
+CONFIG_VIDEO_V4L2=y
+CONFIG_VIDEO_CAPTURE_DRIVERS=y
+# CONFIG_VIDEO_ADV_DEBUG is not set
+CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
+# CONFIG_VIDEO_VIVI is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_CPIA2 is not set
+# CONFIG_VIDEO_SAA5246A is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_OMAP_CAMERA is not set
+CONFIG_V4L_USB_DRIVERS=y
+# CONFIG_VIDEO_PVRUSB2 is not set
+# CONFIG_VIDEO_EM28XX is not set
+# CONFIG_VIDEO_USBVISION is not set
+# CONFIG_USB_VICAM is not set
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_KONICAWC is not set
+# CONFIG_USB_QUICKCAM_MESSENGER is not set
+# CONFIG_USB_ET61X251 is not set
+# CONFIG_VIDEO_OVCAMCHIP is not set
+# CONFIG_USB_W9968CF is not set
+# CONFIG_USB_OV511 is not set
+# CONFIG_USB_SE401 is not set
+# CONFIG_USB_SN9C102 is not set
+# CONFIG_USB_STV680 is not set
+# CONFIG_USB_ZC0301 is not set
+# CONFIG_USB_PWC is not set
+# CONFIG_USB_ZR364XX is not set
+# CONFIG_USB_STKWEBCAM is not set
+CONFIG_RADIO_ADAPTERS=y
+# CONFIG_RADIO_TEA5761 is not set
+# CONFIG_USB_DSBR is not set
+# CONFIG_USB_SI470X is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FB_OMAP=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=2
+# CONFIG_FB_OMAP_DMA_TUNE is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+# CONFIG_SND is not set
+
+#
+# Open Sound System
+#
+CONFIG_SOUND_PRIME=y
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW 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_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=m
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+# CONFIG_USB_DEVICE_CLASS is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_PERSIST is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=m
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+
+#
+# Enable Host or Gadget support to see Inventra options
+#
+# CONFIG_USB_MUSB_HDRC is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_GADGET is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+
+#
+# MMC/SD Host Controller Drivers
+#
+CONFIG_MMC_OMAP=y
+# CONFIG_MMC_SPI is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_OMAP=y
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+# CONFIG_OMAP_DSP is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT2_FS_POSIX_ACL is not set
+# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE 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_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+CONFIG_ROMFS_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+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_SUNRPC_BIND34 is not set
+# 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 is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_SAMPLES is not set
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+# CONFIG_CRYPTO_SEQIV is not set
+# CONFIG_CRYPTO_MANAGER is not set
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_XTS is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_TEST is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_LZO is not set
+CONFIG_CRYPTO_HW=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
--- /dev/null
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.23-rc6-omap1
+# Tue Sep 18 11:44:58 2007
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ZONE_DMA=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=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_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_KMOD=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+# CONFIG_ARCH_OMAP1 is not set
+CONFIG_ARCH_OMAP2=y
+# CONFIG_ARCH_OMAP3 is not set
+
+#
+# OMAP Feature Selections
+#
+CONFIG_OMAP_DEBUG_DEVICES=y
+# CONFIG_OMAP_RESET_CLOCKS is not set
+CONFIG_OMAP_BOOT_TAG=y
+# CONFIG_OMAP_BOOT_REASON is not set
+# CONFIG_OMAP_COMPONENT_VERSION is not set
+# CONFIG_OMAP_GPIO_SWITCH is not set
+CONFIG_OMAP_MUX=y
+CONFIG_OMAP_MUX_DEBUG=y
+CONFIG_OMAP_MUX_WARNINGS=y
+# CONFIG_OMAP_STI is not set
+CONFIG_OMAP_MCBSP=y
+# CONFIG_OMAP_MMU_FWK is not set
+# CONFIG_OMAP_MBOX_FWK is not set
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
+CONFIG_OMAP_DM_TIMER=y
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+# CONFIG_OMAP_DSP is not set
+# CONFIG_MACH_OMAP_GENERIC is not set
+
+#
+# OMAP Core Type
+#
+CONFIG_ARCH_OMAP24XX=y
+CONFIG_ARCH_OMAP2420=y
+# CONFIG_ARCH_OMAP2430 is not set
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_NOKIA_N800 is not set
+CONFIG_MACH_OMAP_H4=y
+# CONFIG_MACH_OMAP_H4_TUSB is not set
+# CONFIG_MACH_OMAP_H4_OTG is not set
+# CONFIG_MACH_OMAP2_H4_USB1 is not set
+# CONFIG_MACH_OMAP_APOLLON is not set
+# CONFIG_MACH_OMAP_APOLLON_PLUS is not set
+# CONFIG_MACH_OMAP_2430SDP is not set
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# 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_PABRT_NOIFAR=y
+CONFIG_CPU_CACHE_V6=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V6=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+# CONFIG_OUTER_CACHE is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=100
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/ram0 rw console=ttyS0,115200n8 initrd=0x80600000,8M ramdisk_size=8192"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_MISC=y
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+CONFIG_SUSPEND_UP_POSSIBLE=y
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+CONFIG_NET_KEY=y
+# CONFIG_NET_KEY_MIGRATE is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+CONFIG_IRDA=y
+
+#
+# IrDA protocols
+#
+CONFIG_IRLAN=y
+CONFIG_IRCOMM=y
+# CONFIG_IRDA_ULTRA is not set
+
+#
+# IrDA options
+#
+# CONFIG_IRDA_CACHE_LAST_LSAP is not set
+# CONFIG_IRDA_FAST_RR is not set
+# CONFIG_IRDA_DEBUG is not set
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+# CONFIG_IRTTY_SIR is not set
+
+#
+# Dongle support
+#
+
+#
+# Old SIR device drivers
+#
+# CONFIG_IRPORT_SIR is not set
+
+#
+# Old Serial dongle support
+#
+
+#
+# FIR device drivers
+#
+CONFIG_OMAP_IR=y
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+CONFIG_MTD_OMAP_NOR=y
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=16384
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+CONFIG_SMC91X=y
+# CONFIG_DM9000 is not set
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# 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
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+CONFIG_KEYBOARD_OMAP=y
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_OMAP_WATCHDOG=y
+CONFIG_HW_RANDOM=m
+CONFIG_HW_RANDOM_OMAP=m
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=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_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_ISP1301_OMAP is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_SENSORS_TLV320AIC23 is not set
+CONFIG_GPIOEXPANDER_OMAP=y
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+CONFIG_MENELAUS=y
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+# CONFIG_W1 is not set
+# CONFIG_HWMON is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+# CONFIG_NEW_LEDS is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+CONFIG_FB=y
+CONFIG_FIRMWARE_EDID=y
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_OMAP=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=2
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
+
+#
+# Enable Host or Gadget support to see Inventra options
+#
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+
+#
+# MMC/SD Host Controller Drivers
+#
+CONFIG_MMC_OMAP=y
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_QUOTA=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+# CONFIG_SUNRPC_BIND34 is not set
+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_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_ERRORS is not set
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_TEST is not set
+CONFIG_CRYPTO_HW=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+CONFIG_LIBCRC32C=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
--- /dev/null
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.23-rc6-omap1
+# Tue Sep 18 11:45:02 2007
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ZONE_DMA=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP1=y
+# CONFIG_ARCH_OMAP2 is not set
+# CONFIG_ARCH_OMAP3 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+# CONFIG_OMAP_BOOT_TAG is not set
+# CONFIG_OMAP_GPIO_SWITCH is not set
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_WARNINGS=y
+CONFIG_OMAP_MCBSP=y
+# CONFIG_OMAP_MMU_FWK is not set
+# CONFIG_OMAP_MBOX_FWK is not set
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+# CONFIG_OMAP_DSP is not set
+
+#
+# OMAP Core Type
+#
+# CONFIG_ARCH_OMAP730 is not set
+CONFIG_ARCH_OMAP15XX=y
+# CONFIG_ARCH_OMAP16XX is not set
+
+#
+# OMAP Board Type
+#
+CONFIG_MACH_OMAP_INNOVATOR=y
+# CONFIG_MACH_VOICEBLUE is not set
+# CONFIG_MACH_OMAP_PALMTE is not set
+# CONFIG_MACH_OMAP_PALMZ71 is not set
+# CONFIG_MACH_OMAP_PALMTT is not set
+# CONFIG_MACH_SX1 is not set
+# CONFIG_MACH_AMS_DELTA is not set
+# CONFIG_MACH_OMAP_GENERIC is not set
+
+#
+# OMAP CPU Speed
+#
+# CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER is not set
+CONFIG_OMAP_ARM_168MHZ=y
+# CONFIG_OMAP_ARM_150MHZ is not set
+# CONFIG_OMAP_ARM_120MHZ is not set
+# CONFIG_OMAP_ARM_60MHZ is not set
+# CONFIG_OMAP_ARM_30MHZ is not set
+# CONFIG_MACH_OMAP_APOLLON_PLUS is not set
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM925T=y
+CONFIG_CPU_32v4T=y
+CONFIG_CPU_ABRT_EV4T=y
+CONFIG_CPU_PABRT_NOIFAR=y
+CONFIG_CPU_CACHE_V4WT=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+CONFIG_CPU_DCACHE_WRITETHROUGH=y
+# CONFIG_OUTER_CACHE is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_PREEMPT=y
+CONFIG_HZ=100
+# CONFIG_AEABI is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+CONFIG_LEDS=y
+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
+# CONFIG_KEXEC is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+
+#
+# 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_PM_SLEEP=y
+CONFIG_SUSPEND_UP_POSSIBLE=y
+CONFIG_SUSPEND=y
+# CONFIG_APM_EMULATION is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_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_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=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
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+CONFIG_SMC91X=y
+# CONFIG_DM9000 is not set
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+CONFIG_USB_RTL8150=y
+CONFIG_USB_USBNET_MII=y
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_AX8817X=y
+CONFIG_USB_NET_CDCETHER=y
+# CONFIG_USB_NET_DM9601 is not set
+# CONFIG_USB_NET_GL620A is not set
+CONFIG_USB_NET_NET1080=y
+# CONFIG_USB_NET_PLUSB is not set
+# CONFIG_USB_NET_MCS7830 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_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_PPP_MPPE is not set
+# CONFIG_PPPOE is not set
+# CONFIG_PPPOL2TP is not set
+# CONFIG_SLIP is not set
+CONFIG_SLHC=y
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# 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_STOWAWAY is not set
+CONFIG_KEYBOARD_OMAP=y
+CONFIG_OMAP_PS2=m
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_HW_RANDOM=m
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=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_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_OMAP is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+# CONFIG_W1 is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_ABITUGURU3 is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_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_LM93 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_DME1737 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+# CONFIG_NEW_LEDS is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_OMAP=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=2
+# CONFIG_FB_OMAP_DMA_TUNE is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_SUSPEND=y
+# CONFIG_USB_PERSIST is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_MUSB_HDRC is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+CONFIG_USB_STORAGE_DATAFAB=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
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+
+#
+# MMC/SD Host Controller Drivers
+#
+CONFIG_MMC_OMAP=y
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_OMAP=y
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4DEV_FS 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_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+CONFIG_AUTOFS_FS=y
+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_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS 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_SUNRPC_BIND34 is not set
+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_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_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
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_PREEMPT=y
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_DEBUG_USER 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
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_TEST is not set
+CONFIG_CRYPTO_HW=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
--- /dev/null
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.23-rc6-omap1
+# Tue Sep 18 11:45:05 2007
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ZONE_DMA=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_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_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+CONFIG_ARCH_OMAP1=y
+# CONFIG_ARCH_OMAP2 is not set
+# CONFIG_ARCH_OMAP3 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+# CONFIG_OMAP_BOOT_TAG is not set
+# CONFIG_OMAP_GPIO_SWITCH is not set
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_WARNINGS=y
+# CONFIG_OMAP_STI is not set
+CONFIG_OMAP_MCBSP=y
+# CONFIG_OMAP_MMU_FWK is not set
+# CONFIG_OMAP_MBOX_FWK is not set
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
+# CONFIG_OMAP_DM_TIMER is not set
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+# CONFIG_OMAP_DSP is not set
+
+#
+# OMAP Core Type
+#
+# CONFIG_ARCH_OMAP730 is not set
+# CONFIG_ARCH_OMAP15XX is not set
+CONFIG_ARCH_OMAP16XX=y
+
+#
+# OMAP Board Type
+#
+CONFIG_MACH_OMAP_INNOVATOR=y
+# CONFIG_MACH_OMAP_H2 is not set
+# CONFIG_MACH_OMAP_H3 is not set
+# CONFIG_MACH_OMAP_OSK is not set
+# CONFIG_MACH_NOKIA770 is not set
+# CONFIG_MACH_OMAP_GENERIC is not set
+
+#
+# OMAP CPU Speed
+#
+# CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER is not set
+# CONFIG_OMAP_ARM_216MHZ is not set
+CONFIG_OMAP_ARM_192MHZ=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_MACH_OMAP_APOLLON_PLUS is not set
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_PABRT_NOIFAR=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB 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
+# CONFIG_OUTER_CACHE is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=100
+# CONFIG_AEABI is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+# 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
+# CONFIG_KEXEC is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+CONFIG_SUSPEND_UP_POSSIBLE=y
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=m
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# 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_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+CONFIG_SMC91X=y
+# CONFIG_DM9000 is not set
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_WAN is not set
+CONFIG_PPP=y
+CONFIG_PPP_MULTILINK=y
+# CONFIG_PPP_FILTER is not set
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_PPP_DEFLATE is not set
+# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPP_MPPE is not set
+# CONFIG_PPPOE is not set
+# CONFIG_PPPOL2TP is not set
+# CONFIG_SLIP is not set
+CONFIG_SLHC=y
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV 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_STOWAWAY is not set
+CONFIG_KEYBOARD_OMAP=y
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_HW_RANDOM=m
+CONFIG_HW_RANDOM_OMAP=m
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+# CONFIG_W1 is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_ABITUGURU3 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+# CONFIG_NEW_LEDS is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_OMAP=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=2
+# CONFIG_FB_OMAP_DMA_TUNE is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+CONFIG_HID_DEBUG=y
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
+
+#
+# Enable Host or Gadget support to see Inventra options
+#
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+# CONFIG_MMC is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=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_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+# CONFIG_ROOT_NFS is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_BIND34 is not set
+# 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 is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+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
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.25-rc3
-# Mon Mar 3 03:35:17 2008
+# Linux kernel version: 2.6.24-rc3-omap1
+# Fri Nov 23 12:24:12 2007
#
CONFIG_ARM=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
# CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_ARCH_SUPPORTS_AOUT=y
CONFIG_ZONE_DMA=y
CONFIG_VECTORS_BASE=0xffff0000
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
# CONFIG_POSIX_MQUEUE is not set
# CONFIG_BSD_PROCESS_ACCT is not set
# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
# CONFIG_AUDIT is not set
# CONFIG_IKCONFIG is not set
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_CGROUPS is not set
-CONFIG_GROUP_SCHED=y
CONFIG_FAIR_GROUP_SCHED=y
-# CONFIG_RT_GROUP_SCHED is not set
-CONFIG_USER_SCHED=y
-# CONFIG_CGROUP_SCHED is not set
-# CONFIG_SYSFS_DEPRECATED is not set
+CONFIG_FAIR_USER_SCHED=y
+# CONFIG_FAIR_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
# CONFIG_RELAY is not set
-CONFIG_NAMESPACES=y
-# CONFIG_UTS_NS is not set
-# CONFIG_IPC_NS is not set
-# CONFIG_USER_NS is not set
-# CONFIG_PID_NS is not set
CONFIG_BLK_DEV_INITRD=y
CONFIG_INITRAMFS_SOURCE=""
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_PRINTK=y
CONFIG_BUG=y
CONFIG_ELF_CORE=y
-CONFIG_COMPAT_BRK=y
CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
CONFIG_ANON_INODES=y
CONFIG_EPOLL=y
CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_VM_EVENT_COUNTERS=y
-CONFIG_SLAB=y
-# CONFIG_SLUB is not set
+CONFIG_SLUB_DEBUG=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
# CONFIG_SLOB is not set
-# CONFIG_PROFILING is not set
-# CONFIG_MARKERS is not set
-CONFIG_HAVE_OPROFILE=y
-# CONFIG_KPROBES is not set
-CONFIG_HAVE_KPROBES=y
-CONFIG_PROC_PAGE_MONITOR=y
-CONFIG_SLABINFO=y
CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
CONFIG_DEFAULT_CFQ=y
# CONFIG_DEFAULT_NOOP is not set
CONFIG_DEFAULT_IOSCHED="cfq"
-CONFIG_CLASSIC_RCU=y
-# CONFIG_PREEMPT_RCU is not set
#
# System Type
# CONFIG_ARCH_KS8695 is not set
# CONFIG_ARCH_NS9XXX is not set
# CONFIG_ARCH_MXC is not set
-# CONFIG_ARCH_ORION is not set
# CONFIG_ARCH_PNX4008 is not set
# CONFIG_ARCH_PXA is not set
# CONFIG_ARCH_RPC is not set
# CONFIG_ARCH_LH7A40X is not set
# CONFIG_ARCH_DAVINCI is not set
CONFIG_ARCH_OMAP=y
-# CONFIG_ARCH_MSM7X00A is not set
#
# TI OMAP Implementations
CONFIG_ARCH_OMAP_OTG=y
CONFIG_ARCH_OMAP1=y
# CONFIG_ARCH_OMAP2 is not set
+# CONFIG_ARCH_OMAP3 is not set
#
# OMAP Feature Selections
#
+CONFIG_OMAP_DEBUG_SRAM_PATCH=y
CONFIG_OMAP_RESET_CLOCKS=y
+# CONFIG_OMAP_BOOT_TAG is not set
+# CONFIG_OMAP_GPIO_SWITCH is not set
CONFIG_OMAP_MUX=y
# CONFIG_OMAP_MUX_DEBUG is not set
CONFIG_OMAP_MUX_WARNINGS=y
+# CONFIG_OMAP_STI is not set
CONFIG_OMAP_MCBSP=y
# CONFIG_OMAP_MMU_FWK is not set
+# CONFIG_OMAP_MBOX_FWK is not set
# CONFIG_OMAP_MPU_TIMER is not set
CONFIG_OMAP_32K_TIMER=y
CONFIG_OMAP_32K_TIMER_HZ=128
# CONFIG_OMAP_LL_DEBUG_UART2 is not set
# CONFIG_OMAP_LL_DEBUG_UART3 is not set
CONFIG_OMAP_SERIAL_WAKE=y
+# CONFIG_OMAP_DSP is not set
#
# OMAP Core Type
#
# OMAP Board Type
#
-CONFIG_MACH_OMAP_INNOVATOR=y
-CONFIG_MACH_OMAP_H2=y
-CONFIG_MACH_OMAP_H3=y
+# 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_NOKIA770=y
-CONFIG_MACH_OMAP_GENERIC=y
+# CONFIG_MACH_NOKIA770 is not set
+# CONFIG_MACH_OMAP_GENERIC is not set
#
# OMAP CPU Speed
CONFIG_CPU_ARM926T=y
CONFIG_CPU_32v5=y
CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_PABRT_NOIFAR=y
CONFIG_CPU_CACHE_VIVT=y
CONFIG_CPU_COPY_V4WB=y
CONFIG_CPU_TLB_V4WBI=y
#
CONFIG_TICK_ONESHOT=y
CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
+# CONFIG_HIGH_RES_TIMERS is not set
CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
# CONFIG_PREEMPT is not set
CONFIG_HZ=128
-CONFIG_AEABI=y
-CONFIG_OABI_COMPAT=y
+# CONFIG_AEABI is not set
# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_FLATMEM_MANUAL=y
CONFIG_CMDLINE="mem=32M console=ttyS0,115200 initrd=0x10400000,8M root=/dev/ram0 rw"
# CONFIG_XIP_KERNEL is not set
# CONFIG_KEXEC is not set
-# CONFIG_ATAGS_PROC is not set
#
# CPU Frequency scaling
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_LEGACY is not set
# CONFIG_PM_DEBUG is not set
CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND_UP_POSSIBLE=y
CONFIG_SUSPEND=y
-CONFIG_SUSPEND_FREEZER=y
# CONFIG_APM_EMULATION is not set
-CONFIG_ARCH_SUSPEND_POSSIBLE=y
#
# Networking
# CONFIG_XFRM_USER is not set
# CONFIG_XFRM_SUB_POLICY is not set
# CONFIG_XFRM_MIGRATE is not set
-# CONFIG_XFRM_STATISTICS is not set
# CONFIG_NET_KEY is not set
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
#
# CONFIG_NET_PKTGEN is not set
# CONFIG_HAMRADIO is not set
-# CONFIG_CAN is not set
# CONFIG_IRDA is not set
# CONFIG_BT is not set
# CONFIG_AF_RXRPC is not set
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=8192
-# CONFIG_BLK_DEV_XIP is not set
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set
CONFIG_MISC_DEVICES=y
# CONFIG_EEPROM_93CX6 is not set
-# CONFIG_ENCLOSURE_SERVICES is not set
-CONFIG_HAVE_IDE=y
CONFIG_IDE=m
CONFIG_BLK_DEV_IDE=m
#
# CONFIG_IDE_GENERIC is not set
# CONFIG_BLK_DEV_PLATFORM is not set
+# CONFIG_IDE_ARM is not set
# CONFIG_BLK_DEV_IDEDMA is not set
CONFIG_IDE_ARCH_OBSOLETE_INIT=y
# CONFIG_BLK_DEV_HD is not set
# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
# CONFIG_B44 is not set
CONFIG_NETDEV_1000=y
-# CONFIG_E1000E_ENABLED is not set
CONFIG_NETDEV_10000=y
#
# CONFIG_PPPOL2TP is not set
# CONFIG_SLIP is not set
CONFIG_SLHC=y
+# CONFIG_SHAPER is not set
# CONFIG_NETCONSOLE is not set
# CONFIG_NETPOLL is not set
# CONFIG_NET_POLL_CONTROLLER is not set
# CONFIG_SYNCLINK_CS is not set
# CONFIG_CARDMAN_4000 is not set
# CONFIG_CARDMAN_4040 is not set
-# CONFIG_IPWIRELESS is not set
# CONFIG_RAW_DRIVER is not set
# CONFIG_TCG_TPM is not set
CONFIG_I2C=y
#
# Miscellaneous I2C Chip support
#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
# CONFIG_DS1682 is not set
# CONFIG_SENSORS_EEPROM is not set
# CONFIG_SENSORS_PCF8574 is not set
-# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 is not set
# CONFIG_SENSORS_PCF8591 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_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_SENSORS_ADM1031 is not set
# CONFIG_SENSORS_ADM9240 is not set
# CONFIG_SENSORS_ADT7470 is not set
-# CONFIG_SENSORS_ADT7473 is not set
# CONFIG_SENSORS_ATXP1 is not set
# CONFIG_SENSORS_DS1621 is not set
# CONFIG_SENSORS_F71805F is not set
# CONFIG_SENSORS_SMSC47M1 is not set
# CONFIG_SENSORS_SMSC47M192 is not set
# CONFIG_SENSORS_SMSC47B397 is not set
-# CONFIG_SENSORS_ADS7828 is not set
# CONFIG_SENSORS_THMC50 is not set
# CONFIG_SENSORS_VT1211 is not set
# CONFIG_SENSORS_W83781D is not set
# CONFIG_SENSORS_W83792D is not set
# CONFIG_SENSORS_W83793 is not set
# CONFIG_SENSORS_W83L785TS is not set
-# CONFIG_SENSORS_W83L786NG is not set
# CONFIG_SENSORS_W83627HF is not set
# CONFIG_SENSORS_W83627EHF is not set
# CONFIG_HWMON_DEBUG_CHIP is not set
# Multifunction device drivers
#
# CONFIG_MFD_SM501 is not set
-# CONFIG_MFD_ASIC3 is not set
#
# Multimedia devices
# CONFIG_VGASTATE is not set
CONFIG_VIDEO_OUTPUT_CONTROL=m
CONFIG_FB=y
-CONFIG_FIRMWARE_EDID=y
+# CONFIG_FIRMWARE_EDID is not set
# CONFIG_FB_DDC is not set
-# CONFIG_FB_CFB_FILLRECT is not set
-# CONFIG_FB_CFB_COPYAREA is not set
-# CONFIG_FB_CFB_IMAGEBLIT is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
# CONFIG_FB_SYS_FILLRECT is not set
# CONFIG_FB_SYS_COPYAREA is not set
#
# CONFIG_FB_S1D13XXX is not set
# CONFIG_FB_VIRTUAL is not set
-# CONFIG_FB_OMAP is not set
+CONFIG_FB_OMAP=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=2
+# CONFIG_FB_OMAP_DMA_TUNE is not set
# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
# CONFIG_USB_ARCH_HAS_EHCI is not set
# CONFIG_USB is not set
+#
+# Enable Host or Gadget support to see Inventra options
+#
+
#
# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
#
+
+#
+# USB Gadget Support
+#
# CONFIG_USB_GADGET is not set
# CONFIG_MMC is not set
# CONFIG_NEW_LEDS is not set
CONFIG_RTC_LIB=y
# CONFIG_RTC_CLASS is not set
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
#
# File systems
#
# CONFIG_XFS_FS is not set
# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
-CONFIG_DNOTIFY=y
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
CONFIG_AUTOFS_FS=y
CONFIG_AUTOFS4_FS=y
# CONFIG_FUSE_FS is not set
# CONFIG_JFFS2_RUBIN is not set
# CONFIG_CRAMFS is not set
# CONFIG_VXFS_FS is not set
-# CONFIG_MINIX_FS is not set
# CONFIG_HPFS_FS is not set
# CONFIG_QNX4FS_FS is not set
-# CONFIG_ROMFS_FS is not set
# CONFIG_SYSV_FS is not set
# CONFIG_UFS_FS is not set
CONFIG_NETWORK_FILESYSTEMS=y
# CONFIG_NLS_KOI8_U is not set
# CONFIG_NLS_UTF8 is not set
# CONFIG_DLM is not set
+CONFIG_INSTRUMENTATION=y
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
#
# Kernel hacking
# CONFIG_DEBUG_FS is not set
# CONFIG_HEADERS_CHECK is not set
# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_SLUB_DEBUG_ON is not set
CONFIG_DEBUG_BUGVERBOSE=y
CONFIG_FRAME_POINTER=y
# CONFIG_SAMPLES is not set
# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
# CONFIG_SECURITY_FILE_CAPABILITIES is not set
-CONFIG_CRYPTO=y
-# CONFIG_CRYPTO_SEQIV is not set
-# CONFIG_CRYPTO_MANAGER is not set
-# CONFIG_CRYPTO_HMAC is not set
-# CONFIG_CRYPTO_XCBC is not set
-# CONFIG_CRYPTO_NULL is not set
-# CONFIG_CRYPTO_MD4 is not set
-# CONFIG_CRYPTO_MD5 is not set
-# CONFIG_CRYPTO_SHA1 is not set
-# CONFIG_CRYPTO_SHA256 is not set
-# CONFIG_CRYPTO_SHA512 is not set
-# CONFIG_CRYPTO_WP512 is not set
-# CONFIG_CRYPTO_TGR192 is not set
-# CONFIG_CRYPTO_GF128MUL is not set
-# CONFIG_CRYPTO_ECB is not set
-# CONFIG_CRYPTO_CBC is not set
-# CONFIG_CRYPTO_PCBC is not set
-# CONFIG_CRYPTO_LRW is not set
-# CONFIG_CRYPTO_XTS is not set
-# CONFIG_CRYPTO_CTR is not set
-# CONFIG_CRYPTO_GCM is not set
-# CONFIG_CRYPTO_CCM is not set
-# CONFIG_CRYPTO_CRYPTD is not set
-# CONFIG_CRYPTO_DES is not set
-# CONFIG_CRYPTO_FCRYPT is not set
-# CONFIG_CRYPTO_BLOWFISH is not set
-# CONFIG_CRYPTO_TWOFISH is not set
-# CONFIG_CRYPTO_SERPENT is not set
-# CONFIG_CRYPTO_AES is not set
-# CONFIG_CRYPTO_CAST5 is not set
-# CONFIG_CRYPTO_CAST6 is not set
-# CONFIG_CRYPTO_TEA is not set
-# CONFIG_CRYPTO_ARC4 is not set
-# CONFIG_CRYPTO_KHAZAD is not set
-# CONFIG_CRYPTO_ANUBIS is not set
-# CONFIG_CRYPTO_SEED is not set
-# CONFIG_CRYPTO_SALSA20 is not set
-# CONFIG_CRYPTO_DEFLATE is not set
-# CONFIG_CRYPTO_MICHAEL_MIC is not set
-# CONFIG_CRYPTO_CRC32C is not set
-# CONFIG_CRYPTO_CAMELLIA is not set
-# CONFIG_CRYPTO_TEST is not set
-# CONFIG_CRYPTO_AUTHENC is not set
-# CONFIG_CRYPTO_LZO is not set
-CONFIG_CRYPTO_HW=y
+# CONFIG_CRYPTO is not set
#
# Library routines
--- /dev/null
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.23-rc6-omap1
+# Tue Sep 18 11:45:12 2007
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ZONE_DMA=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_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_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+CONFIG_ARCH_OMAP1=y
+# CONFIG_ARCH_OMAP2 is not set
+# CONFIG_ARCH_OMAP3 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+# CONFIG_OMAP_BOOT_TAG is not set
+# CONFIG_OMAP_GPIO_SWITCH is not set
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_WARNINGS=y
+CONFIG_OMAP_MCBSP=y
+# CONFIG_OMAP_MMU_FWK is not set
+# CONFIG_OMAP_MBOX_FWK is not set
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
+CONFIG_OMAP_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
+# CONFIG_MACH_OMAP_FSAMPLE is not set
+
+#
+# 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
+# CONFIG_MACH_OMAP_APOLLON_PLUS is not set
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_PABRT_NOIFAR=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB 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
+# CONFIG_OUTER_CACHE is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_PREEMPT=y
+CONFIG_HZ=100
+# CONFIG_AEABI is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+CONFIG_LEDS=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
+# CONFIG_KEXEC is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_PM_LEGACY is not set
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND_UP_POSSIBLE=y
+CONFIG_SUSPEND=y
+# CONFIG_APM_EMULATION is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=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
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+CONFIG_MTD_OMAP_NOR=y
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_OMAP=y
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# 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_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+CONFIG_SMC91X=y
+# CONFIG_DM9000 is not set
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# 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
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV 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_STOWAWAY is not set
+CONFIG_KEYBOARD_OMAP=y
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_HW_RANDOM=m
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+# CONFIG_W1 is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_ABITUGURU3 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+# CONFIG_NEW_LEDS is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+CONFIG_FB_SYS_FILLRECT=y
+CONFIG_FB_SYS_COPYAREA=y
+CONFIG_FB_SYS_IMAGEBLIT=y
+CONFIG_FB_SYS_FOPS=y
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_OMAP 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
+# CONFIG_LOGO is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
+
+#
+# Enable Host or Gadget support to see Inventra options
+#
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+# CONFIG_MMC is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_OMAP=y
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 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_SUNRPC_BIND34 is not set
+# 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 is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+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
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
--- /dev/null
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.22-rc1-omap1
+# Sat May 19 11:04:27 2007
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ZONE_DMA=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP1=y
+# CONFIG_ARCH_OMAP2 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+# CONFIG_OMAP_BOOT_TAG is not set
+CONFIG_OMAP_GPIO_SWITCH=y
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_WARNINGS=y
+CONFIG_OMAP_MCBSP=y
+# CONFIG_OMAP_MMU_FWK is not set
+# CONFIG_OMAP_MBOX_FWK is not set
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+# CONFIG_OMAP_DSP is not set
+
+#
+# OMAP Core Type
+#
+# CONFIG_ARCH_OMAP730 is not set
+CONFIG_ARCH_OMAP15XX=y
+# CONFIG_ARCH_OMAP16XX is not set
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_INNOVATOR is not set
+# CONFIG_MACH_VOICEBLUE is not set
+CONFIG_MACH_OMAP_PALMTE=y
+# CONFIG_MACH_OMAP_PALMZ71 is not set
+# CONFIG_MACH_OMAP_PALMTT is not set
+# CONFIG_MACH_SX1 is not set
+# CONFIG_MACH_AMS_DELTA is not set
+# CONFIG_MACH_OMAP_GENERIC is not set
+
+#
+# OMAP CPU Speed
+#
+CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER=y
+# CONFIG_OMAP_ARM_168MHZ is not set
+# CONFIG_OMAP_ARM_150MHZ is not set
+# CONFIG_OMAP_ARM_120MHZ is not set
+# CONFIG_OMAP_ARM_60MHZ is not set
+# CONFIG_OMAP_ARM_30MHZ is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM925T=y
+CONFIG_CPU_32v4T=y
+CONFIG_CPU_ABRT_EV4T=y
+CONFIG_CPU_CACHE_V4WT=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB 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_OUTER_CACHE is not set
+
+#
+# Bus support
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=100
+# CONFIG_AEABI is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+# CONFIG_LEDS 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
+# CONFIG_KEXEC is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+
+#
+# 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
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNPACPI is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# ISDN subsystem
+#
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=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_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 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
+# CONFIG_WATCHDOG is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_NVRAM is not set
+CONFIG_OMAP_RTC=y
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+# CONFIG_HWMON is not set
+
+#
+# Misc devices
+#
+# CONFIG_BLINK is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+CONFIG_DAB=y
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_OMAP=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_LCD_MIPID is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=2
+# CONFIG_FB_OMAP_DMA_TUNE is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# HID Devices
+#
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
+# CONFIG_USB_MUSB_HDRC is not set
+# CONFIG_USB_GADGET_MUSB_HDRC is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+CONFIG_USB_GADGET_OMAP=y
+CONFIG_USB_OMAP=y
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+# CONFIG_USB_GADGET_DUALSPEED is not set
+CONFIG_USB_ZERO=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
+# CONFIG_USB_MIDI_GADGET is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+
+#
+# MMC/SD Host Controller Drivers
+#
+CONFIG_MMC_OMAP=y
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_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=850
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_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_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_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_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+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
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
--- /dev/null
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.19-rc3-omap1
+# Sun Oct 29 00:36:12 2006
+#
+CONFIG_ARM=y
+# CONFIG_GENERIC_TIME is not set
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_BLK_DEV_IO_TRACE is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+CONFIG_ARCH_OMAP=y
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP1=y
+# CONFIG_ARCH_OMAP2 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+# CONFIG_OMAP_BOOT_TAG is not set
+# CONFIG_OMAP_GPIO_SWITCH is not set
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_WARNINGS=y
+CONFIG_OMAP_MCBSP=y
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
+# CONFIG_OMAP_LL_DEBUG_UART1 is not set
+CONFIG_OMAP_LL_DEBUG_UART2=y
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+CONFIG_OMAP_DSP=y
+# CONFIG_OMAP_DSP_MBCMD_VERBOSE is not set
+# CONFIG_OMAP_DSP_TASK_MULTIOPEN is not set
+CONFIG_OMAP_DSP_FBEXPORT=y
+
+#
+# OMAP Core Type
+#
+# CONFIG_ARCH_OMAP730 is not set
+CONFIG_ARCH_OMAP15XX=y
+# CONFIG_ARCH_OMAP16XX is not set
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_INNOVATOR is not set
+# CONFIG_MACH_VOICEBLUE is not set
+# CONFIG_MACH_OMAP_PALMTE is not set
+# CONFIG_MACH_OMAP_PALMZ71 is not set
+CONFIG_MACH_OMAP_PALMTT=y
+# CONFIG_MACH_AMS_DELTA is not set
+# CONFIG_MACH_OMAP_GENERIC is not set
+
+#
+# OMAP CPU Speed
+#
+CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER=y
+# CONFIG_OMAP_ARM_168MHZ is not set
+# CONFIG_OMAP_ARM_150MHZ is not set
+# CONFIG_OMAP_ARM_120MHZ is not set
+# CONFIG_OMAP_ARM_60MHZ is not set
+# CONFIG_OMAP_ARM_30MHZ is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM925T=y
+CONFIG_CPU_32v4T=y
+CONFIG_CPU_ABRT_EV4T=y
+CONFIG_CPU_CACHE_V4WT=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+
+#
+# Bus support
+#
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+# CONFIG_NO_IDLE_HZ is not set
+CONFIG_HZ=100
+# CONFIG_AEABI is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_RESOURCES_64BIT is not set
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/mmcblk0p2 rw init=/init"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+# CONFIG_APM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_NETLINK is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+# CONFIG_NETDEVICES is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=320
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=320
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_TSDEV=y
+CONFIG_INPUT_TSDEV_SCREEN_X=320
+CONFIG_INPUT_TSDEV_SCREEN_Y=320
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ADS7846=y
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_TSC2102 is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_NVRAM is not set
+# CONFIG_OMAP_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_BITBANG=y
+CONFIG_SPI_OMAP_UWIRE=y
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_TSC2102 is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_LM70 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+
+#
+# LED devices
+#
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+CONFIG_LEDS_OMAP=y
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FIRMWARE_EDID=y
+CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FB_OMAP=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_LCD_MIPID is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=2
+# CONFIG_FB_OMAP_DMA_TUNE is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+# CONFIG_LOGO is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_DEVICE=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_LCD_DEVICE=y
+CONFIG_BACKLIGHT_OMAP=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
+
+#
+# Enable Host or Gadget support to see Inventra options
+#
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+
+#
+# RTC drivers
+#
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+CONFIG_RTC_DRV_OMAP=y
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_TEST is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# Synchronous Serial Interfaces (SSI)
+#
+# CONFIG_OMAP_UWIRE is not set
+# CONFIG_OMAP_TSC2101 is not set
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_INOTIFY is not set
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_FS is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_UNWIND_INFO is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_USER is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=y
+CONFIG_CRC16=y
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=y
+CONFIG_PLIST=y
--- /dev/null
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.22-rc1-omap1
+# Thu Jun 7 05:13:00 2007
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ZONE_DMA=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION="-z71"
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP1=y
+# CONFIG_ARCH_OMAP2 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+# CONFIG_OMAP_BOOT_TAG is not set
+# CONFIG_OMAP_GPIO_SWITCH is not set
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_WARNINGS=y
+CONFIG_OMAP_MCBSP=y
+# CONFIG_OMAP_MMU_FWK is not set
+# CONFIG_OMAP_MBOX_FWK is not set
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+# CONFIG_OMAP_LL_DEBUG_LCD is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+# CONFIG_OMAP_DSP is not set
+
+#
+# OMAP Core Type
+#
+# CONFIG_ARCH_OMAP730 is not set
+CONFIG_ARCH_OMAP15XX=y
+# CONFIG_ARCH_OMAP16XX is not set
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_INNOVATOR is not set
+# CONFIG_MACH_VOICEBLUE is not set
+# CONFIG_MACH_OMAP_PALMTE is not set
+CONFIG_MACH_OMAP_PALMZ71=y
+# CONFIG_MACH_OMAP_PALMTT is not set
+# CONFIG_MACH_SX1 is not set
+# CONFIG_MACH_AMS_DELTA is not set
+# CONFIG_MACH_OMAP_GENERIC is not set
+
+#
+# OMAP CPU Speed
+#
+CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER=y
+# CONFIG_OMAP_ARM_168MHZ is not set
+# CONFIG_OMAP_ARM_150MHZ is not set
+# CONFIG_OMAP_ARM_120MHZ is not set
+# CONFIG_OMAP_ARM_60MHZ is not set
+# CONFIG_OMAP_ARM_30MHZ is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM925T=y
+CONFIG_CPU_32v4T=y
+CONFIG_CPU_ABRT_EV4T=y
+CONFIG_CPU_CACHE_V4WT=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB 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_OUTER_CACHE is not set
+
+#
+# Bus support
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=100
+# CONFIG_AEABI is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+# CONFIG_LEDS 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
+# CONFIG_KEXEC is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+
+#
+# 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=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+CONFIG_NET_KEY=y
+# CONFIG_NET_KEY_MIGRATE is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNPACPI is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Network device support
+#
+# CONFIG_NETDEVICES is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=320
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=320
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_TSDEV=y
+CONFIG_INPUT_TSDEV_SCREEN_X=320
+CONFIG_INPUT_TSDEV_SCREEN_Y=320
+# CONFIG_INPUT_EVDEV 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_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ADS7846=y
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_UCB1400 is not set
+# CONFIG_TOUCHSCREEN_TSC210X is not set
+# CONFIG_TOUCHSCREEN_TSC2046 is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=16
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_BITBANG=y
+CONFIG_SPI_OMAP_UWIRE=y
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_AT25 is not set
+# CONFIG_SPI_TSC2101 is not set
+# CONFIG_SPI_TSC2102 is not set
+# CONFIG_SPI_TSC210X is not set
+# CONFIG_SPI_TSC2301 is not set
+# CONFIG_SPI_SPIDEV is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_LM70 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_TSC210X is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+# CONFIG_BLINK is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
+
+#
+# Graphics support
+#
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_OMAP=y
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+CONFIG_FB=y
+CONFIG_FIRMWARE_EDID=y
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_OMAP=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_LCD_MIPID is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=2
+# CONFIG_FB_OMAP_DMA_TUNE is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_LOGO is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# HID Devices
+#
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
+
+#
+# Enable Host or Gadget support to see Inventra options
+#
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+
+#
+# MMC/SD Host Controller Drivers
+#
+CONFIG_MMC_OMAP=y
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_OMAP=y
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_INOTIFY is not set
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+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
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=y
+CONFIG_CRC16=y
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
--- /dev/null
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.22-rc1-omap1
+# Thu Jun 7 05:16:10 2007
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ZONE_DMA=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+CONFIG_IKCONFIG=y
+# CONFIG_IKCONFIG_PROC is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_KALLSYMS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+# CONFIG_ELF_CORE is not set
+# CONFIG_BASE_FULL is not set
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+# CONFIG_SHMEM is not set
+# CONFIG_VM_EVENT_COUNTERS is not set
+# CONFIG_SLAB is not set
+# CONFIG_SLUB is not set
+CONFIG_SLOB=y
+CONFIG_RT_MUTEXES=y
+CONFIG_TINY_SHMEM=y
+CONFIG_BASE_SMALL=1
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+CONFIG_DEFAULT_DEADLINE=y
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="deadline"
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP1=y
+# CONFIG_ARCH_OMAP2 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+CONFIG_OMAP_BOOT_TAG=y
+# CONFIG_OMAP_BOOT_REASON is not set
+# CONFIG_OMAP_COMPONENT_VERSION is not set
+CONFIG_OMAP_GPIO_SWITCH=y
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_WARNINGS=y
+CONFIG_OMAP_MCBSP=y
+CONFIG_OMAP_MMU_FWK=y
+CONFIG_OMAP_MBOX_FWK=y
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
+# CONFIG_OMAP_LL_DEBUG_UART1 is not set
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+CONFIG_OMAP_LL_DEBUG_UART3=y
+# CONFIG_OMAP_LL_DEBUG_LCD is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+CONFIG_OMAP_DSP=y
+# CONFIG_OMAP_DSP_MBCMD_VERBOSE is not set
+# CONFIG_OMAP_DSP_TASK_MULTIOPEN is not set
+# CONFIG_OMAP_DSP_FBEXPORT is not set
+
+#
+# OMAP Core Type
+#
+# CONFIG_ARCH_OMAP730 is not set
+CONFIG_ARCH_OMAP15XX=y
+# CONFIG_ARCH_OMAP16XX is not set
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_INNOVATOR is not set
+# CONFIG_MACH_VOICEBLUE is not set
+# CONFIG_MACH_OMAP_PALMTE is not set
+# CONFIG_MACH_OMAP_PALMZ71 is not set
+# CONFIG_MACH_OMAP_PALMTT is not set
+CONFIG_MACH_SX1=y
+# CONFIG_MACH_AMS_DELTA is not set
+# CONFIG_MACH_OMAP_GENERIC is not set
+
+#
+# OMAP CPU Speed
+#
+# CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER is not set
+CONFIG_OMAP_ARM_168MHZ=y
+# CONFIG_OMAP_ARM_150MHZ is not set
+# CONFIG_OMAP_ARM_120MHZ is not set
+# CONFIG_OMAP_ARM_60MHZ is not set
+# CONFIG_OMAP_ARM_30MHZ is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM925T=y
+CONFIG_CPU_32v4T=y
+CONFIG_CPU_ABRT_EV4T=y
+CONFIG_CPU_CACHE_V4WT=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_OUTER_CACHE is not set
+
+#
+# Bus support
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_PREEMPT=y
+CONFIG_HZ=100
+# CONFIG_AEABI is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+# CONFIG_LEDS 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
+# CONFIG_KEXEC is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+
+#
+# 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
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+CONFIG_CONNECTOR=y
+# CONFIG_PROC_EVENTS is not set
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNPACPI is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=m
+CONFIG_BLK_DEV_RAM_COUNT=2
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# 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
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_FIXED_PHY is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+CONFIG_KEYBOARD_OMAP=y
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_CONSOLE is not set
+CONFIG_SERIAL_8250_NR_UARTS=3
+CONFIG_SERIAL_8250_RUNTIME_UARTS=3
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=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_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_SENSORS_TLV320AIC23 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+# CONFIG_HWMON is not set
+
+#
+# Misc devices
+#
+# CONFIG_BLINK is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_OMAP=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_LCD_MIPID is not set
+CONFIG_FB_OMAP_BOOTLOADER_INIT=y
+CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=2
+# CONFIG_FB_OMAP_DMA_TUNE is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FONTS=y
+# CONFIG_FONT_8x8 is not set
+# CONFIG_FONT_8x16 is not set
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+CONFIG_FONT_MINI_4x6=y
+# CONFIG_FONT_CLEAN_4x6 is not set
+# CONFIG_FONT_CLEAN_5x8 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+# CONFIG_SND_SEQUENCER is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=y
+CONFIG_SND_PCM_OSS=y
+CONFIG_SND_PCM_OSS_PLUGINS=y
+# CONFIG_SND_DYNAMIC_MINORS is not set
+# CONFIG_SND_SUPPORT_OLD_API is not set
+# CONFIG_SND_VERBOSE_PROCFS is not set
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# ALSA ARM devices
+#
+# CONFIG_SND_OMAP_AIC23 is not set
+# CONFIG_SND_OMAP_TSC2101 is not set
+CONFIG_SND_SX1=y
+# CONFIG_SND_OMAP_TSC2102 is not set
+# CONFIG_SND_OMAP24XX_EAC is not set
+
+#
+# System on Chip audio support
+#
+# CONFIG_SND_SOC is not set
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+
+#
+# HID Devices
+#
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
+# CONFIG_USB_MUSB_HDRC is not set
+# CONFIG_USB_GADGET_MUSB_HDRC is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+CONFIG_USB_GADGET_OMAP=y
+CONFIG_USB_OMAP=y
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+# CONFIG_USB_GADGET_DUALSPEED is not set
+# CONFIG_USB_ZERO is not set
+CONFIG_USB_ETH=y
+CONFIG_USB_ETH_RNDIS=y
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+
+#
+# MMC/SD Host Controller Drivers
+#
+CONFIG_MMC_OMAP=y
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_OMAP=y
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=866
+CONFIG_FAT_DEFAULT_IOCHARSET="koi8-r"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_CRAMFS=y
+# CONFIG_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_SUNRPC_BIND34 is not set
+# 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
+# CONFIG_SYSV68_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+CONFIG_NLS_CODEPAGE_866=y
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+CONFIG_NLS_CODEPAGE_1251=y
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+CONFIG_NLS_ISO8859_5=y
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+CONFIG_NLS_KOI8_R=y
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=y
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Profiling support
+#
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+# CONFIG_DETECT_SOFTLOCKUP is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+CONFIG_DEBUG_PREEMPT=y
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=y
+CONFIG_CRC16=y
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
# Power Management
obj-$(CONFIG_PM) += pm.o sleep.o
+# DSP
+obj-$(CONFIG_OMAP_MMU_FWK) += mmu_mach.o
+obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox_mach.o
+mailbox_mach-objs := mailbox.o
+mmu_mach-objs := mmu.o
+
led-y := leds.o
# Specific board support
*/
#include <linux/kernel.h>
+#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/mtd/partitions.h>
#include <linux/input.h>
#include <linux/i2c/tps65010.h>
+#include <linux/workqueue.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/tsc2101.h>
+#include <linux/clk.h>
#include <asm/hardware.h>
#include <asm/gpio.h>
#include <asm/mach/flash.h>
#include <asm/mach/map.h>
+#include <asm/arch/gpio.h>
#include <asm/arch/gpio-switch.h>
#include <asm/arch/mux.h>
#include <asm/arch/tc.h>
.id = -1,
};
+struct {
+ struct clk *mclk;
+ int initialized;
+} h2_tsc2101;
+
+#define TSC2101_MUX_MCLK_ON R10_1610_MCLK_ON
+#define TSC2101_MUX_MCLK_OFF R10_1610_MCLK_OFF
+
+static void h2_lcd_dev_init(struct spi_device *tsc2101)
+{
+ /* The LCD is connected to the GPIO pins of the TSC2101, so
+ * we have to tie them here. We can also register the LCD driver
+ * first only here, where we know that the TSC driver is ready.
+ */
+
+ h2_lcd_device.dev.platform_data = tsc2101;
+ platform_device_register(&h2_lcd_device);
+}
+
static struct omap_mcbsp_reg_cfg mcbsp_regs = {
.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),
+ 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,
+ 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),
-
.pcr0 = CLKXM | CLKRM | FSXP | FSRP | CLKXP | CLKRP,
/*.pcr0 = CLKXP | CLKRP,*/ /* mcbsp: slave */
};
static struct omap_alsa_codec_config alsa_config = {
.name = "H2 TSC2101",
.mcbsp_regs_alsa = &mcbsp_regs,
- .codec_configure_dev = NULL, /* tsc2101_configure, */
- .codec_set_samplerate = NULL, /* tsc2101_set_samplerate, */
- .codec_clock_setup = NULL, /* tsc2101_clock_setup, */
- .codec_clock_on = NULL, /* tsc2101_clock_on, */
- .codec_clock_off = NULL, /* tsc2101_clock_off, */
- .get_default_samplerate = NULL, /* tsc2101_get_default_samplerate, */
};
static struct platform_device h2_mcbsp1_device = {
},
};
+static void h2_audio_dev_init(struct spi_device *tsc2101)
+{
+ h2_mcbsp1_device.dev.platform_data = tsc2101;
+ platform_device_register(&h2_mcbsp1_device);
+}
+
+static int h2_tsc2101_init(struct spi_device *spi)
+{
+ int r;
+
+ if (h2_tsc2101.initialized) {
+ printk(KERN_ERR "tsc2101: already initialized\n");
+ return -ENODEV;
+ }
+
+ /* Get the MCLK */
+ h2_tsc2101.mclk = clk_get(&spi->dev, "mclk");
+ if (IS_ERR(h2_tsc2101.mclk)) {
+ dev_err(&spi->dev, "unable to get the clock MCLK\n");
+ return PTR_ERR(h2_tsc2101.mclk);
+ }
+ if ((r = clk_set_rate(h2_tsc2101.mclk, 12000000)) < 0) {
+ dev_err(&spi->dev, "unable to set rate to the MCLK\n");
+ goto err;
+ }
+
+ omap_cfg_reg(TSC2101_MUX_MCLK_OFF);
+ omap_cfg_reg(N15_1610_UWIRE_CS1);
+
+ h2_lcd_dev_init(spi);
+ h2_audio_dev_init(spi);
+
+ return 0;
+err:
+ clk_put(h2_tsc2101.mclk);
+ return r;
+}
+
+static void h2_tsc2101_cleanup(struct spi_device *spi)
+{
+ clk_put(h2_tsc2101.mclk);
+ omap_cfg_reg(TSC2101_MUX_MCLK_OFF);
+}
+
+static void h2_tsc2101_enable_mclk(struct spi_device *spi)
+{
+ omap_cfg_reg(TSC2101_MUX_MCLK_ON);
+ clk_enable(h2_tsc2101.mclk);
+}
+
+static void h2_tsc2101_disable_mclk(struct spi_device *spi)
+{
+ clk_disable(h2_tsc2101.mclk);
+ omap_cfg_reg(R10_1610_MCLK_OFF);
+}
+
+static struct tsc2101_platform_data h2_tsc2101_platform_data = {
+ .init = h2_tsc2101_init,
+ .cleanup = h2_tsc2101_cleanup,
+ .enable_mclk = h2_tsc2101_enable_mclk,
+ .disable_mclk = h2_tsc2101_disable_mclk,
+};
+
+static struct spi_board_info h2_spi_board_info[] __initdata = {
+ [0] = {
+ .modalias = "tsc2101",
+ .bus_num = 2,
+ .chip_select = 1,
+ .max_speed_hz = 16000000,
+ .platform_data = &h2_tsc2101_platform_data,
+ },
+};
+
static struct platform_device *h2_devices[] __initdata = {
&h2_nor_device,
&h2_nand_device,
&h2_smc91x_device,
&h2_irda_device,
&h2_kp_device,
- &h2_lcd_device,
- &h2_mcbsp1_device,
};
static void __init h2_init_smc91x(void)
{ OMAP_TAG_LCD, &h2_lcd_config },
};
+static struct omap_gpio_switch h2_gpio_switches[] __initdata = {
+ {
+ .name = "mmc_slot",
+ .gpio = OMAP_MPUIO(1),
+ .type = OMAP_GPIO_SWITCH_TYPE_COVER,
+ .debounce_rising = 100,
+ .debounce_falling = 0,
+ .notify = h2_mmc_slot_cover_handler,
+ .notify_data = NULL,
+ },
+};
+
#define H2_NAND_RB_GPIO_PIN 62
static int h2_nand_dev_ready(struct omap_nand_platform_data *data)
#endif
platform_add_devices(h2_devices, ARRAY_SIZE(h2_devices));
+ spi_register_board_info(h2_spi_board_info,
+ ARRAY_SIZE(h2_spi_board_info));
omap_board_config = h2_config;
omap_board_config_size = ARRAY_SIZE(h2_config);
omap_serial_init();
omap_register_i2c_bus(1, 100, h2_i2c_board_info,
ARRAY_SIZE(h2_i2c_board_info));
h2_mmc_init();
+ omap_register_gpio_switches(h2_gpio_switches,
+ ARRAY_SIZE(h2_gpio_switches));
}
static void __init h2_map_io(void)
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
#include <linux/input.h>
-#include <linux/spi/spi.h>
#include <linux/i2c/tps65010.h>
+#include <linux/clk.h>
+#include <linux/i2c.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/tsc210x.h>
#include <asm/setup.h>
#include <asm/page.h>
#include <asm/mach/flash.h>
#include <asm/mach/map.h>
+#include <media/v4l2-int-device.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/gpio-switch.h>
#include <asm/arch/gpioexpander.h>
#include <asm/arch/irqs.h>
#include <asm/arch/mux.h>
#include <asm/arch/mcbsp.h>
#include <asm/arch/omap-alsa.h>
+#include <../drivers/media/video/ov9640.h>
+
#define H3_TS_GPIO 48
static int h3_keymap[] = {
.id = -1,
};
+static struct tsc210x_config tsc_platform_data = {
+ .use_internal = 1,
+ .monitor = TSC_VBAT | TSC_TEMP,
+ .mclk = "mclk",
+};
+
static struct spi_board_info h3_spi_board_info[] __initdata = {
[0] = {
.modalias = "tsc2101",
.chip_select = 0,
.irq = OMAP_GPIO_IRQ(H3_TS_GPIO),
.max_speed_hz = 16000000,
- /* .platform_data = &tsc_platform_data, */
+ .platform_data = &tsc_platform_data,
},
};
{ OMAP_TAG_LCD, &h3_lcd_config },
};
-static struct i2c_board_info __initdata h3_i2c_board_info[] = {
- {
- I2C_BOARD_INFO("tps65013", 0x48),
- /* .irq = OMAP_GPIO_IRQ(??), */
- },
-};
-
static struct omap_gpio_switch h3_gpio_switches[] __initdata = {
{
.name = "mmc_slot",
return omap_get_gpio_datain(H3_NAND_RB_GPIO_PIN);
}
+#if defined(CONFIG_VIDEO_OV9640) || defined(CONFIG_VIDEO_OV9640_MODULE)
+/*
+ * 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 }
+};
+
+static int ov9640_sensor_power_set(int power)
+{
+ unsigned char expa;
+ int err;
+
+ /* read current state of GPIO EXPA outputs */
+ err = read_gpio_expa(&expa, 0x27);
+ if (err) {
+ printk(KERN_ERR "Error reading GPIO EXPA\n");
+ return err;
+ }
+ /* Clear GPIO EXPA P3 (CAMERA_MODULE_EN) to power-up/down sensor */
+ if (power)
+ expa |= 0x08;
+ else
+ expa &= ~0x08;
+
+ err = write_gpio_expa(expa, 0x27);
+ if (err) {
+ printk(KERN_ERR "Error writing to GPIO EXPA\n");
+ return err;
+ }
+
+ return err;
+}
+
+static struct v4l2_ifparm ifparm = {
+ .if_type = V4L2_IF_TYPE_BT656,
+ .u = {
+ .bt656 = {
+ .frame_start_on_rising_vs = 1,
+ .nobt_vs_inv = 1,
+ .mode = V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT,
+ .clock_min = OV9640_XCLK_MIN,
+ .clock_max = OV9640_XCLK_MAX,
+ },
+ },
+};
+
+static int ov9640_ifparm(struct v4l2_ifparm *p)
+{
+ *p = ifparm;
+
+ return 0;
+}
+
+static struct ov9640_platform_data h3_ov9640_platform_data = {
+ .power_set = ov9640_sensor_power_set,
+ .default_regs = ov9640_common,
+ .ifparm = ov9640_ifparm,
+};
+#endif
+
+static struct i2c_board_info __initdata h3_i2c_board_info[] = {
+ {
+ I2C_BOARD_INFO("tps65013", 0x48),
+ /* .irq = OMAP_GPIO_IRQ(??), */
+ },
+#if defined(CONFIG_VIDEO_OV9640) || defined(CONFIG_VIDEO_OV9640_MODULE)
+ {
+ I2C_BOARD_INFO("ov9640", 0x30),
+ .platform_data = &h3_ov9640_platform_data,
+ },
+#endif
+ {
+ I2C_BOARD_INFO("isp1301_omap", 0x2d),
+ .type = "isp1301_omap",
+ .irq = OMAP_GPIO_IRQ(14),
+ },
+};
+
static void __init h3_init(void)
{
/* Here we assume the NOR boot config: NOR on CS3 (possibly swapped
/* GPIO10 pullup/down register, Enable pullup on GPIO10 */
omap_cfg_reg(V2_1710_GPIO10);
+ /* TSC2101 */
+ omap_cfg_reg(W19_1610_GPIO48);
+ gpio_request(H3_TS_GPIO, "tsc_irq");
+ gpio_direction_input(H3_TS_GPIO);
+ omap_cfg_reg(N14_1610_UWIRE_CS0);
+
platform_add_devices(devices, ARRAY_SIZE(devices));
spi_register_board_info(h3_spi_board_info,
ARRAY_SIZE(h3_spi_board_info));
omap_register_i2c_bus(1, 100, h3_i2c_board_info,
ARRAY_SIZE(h3_i2c_board_info));
h3_mmc_init();
+ omap_register_gpio_switches(h3_gpio_switches,
+ ARRAY_SIZE(h3_gpio_switches));
}
static void __init h3_init_smc91x(void)
#include <linux/spi/ads7846.h>
#include <linux/workqueue.h>
#include <linux/delay.h>
+#include <linux/mutex.h>
#include <asm/hardware.h>
#include <asm/mach-types.h>
#include <asm/arch/dsp_common.h>
#include <asm/arch/aic23.h>
#include <asm/arch/omapfb.h>
+#include <asm/arch/hwa742.h>
#include <asm/arch/lcd_mipid.h>
#define ADS7846_PENDOWN_GPIO 15
},
};
+static struct {
+ struct clk *sys_ck;
+} hwa742;
+
+static int hwa742_get_clocks(void)
+{
+ hwa742.sys_ck = clk_get(NULL, "bclk");
+ if (IS_ERR(hwa742.sys_ck)) {
+ printk(KERN_ERR "can't get HWA742 clock\n");
+ return PTR_ERR(hwa742.sys_ck);
+ }
+ return 0;
+}
+
+static unsigned long hwa742_get_clock_rate(struct device *dev)
+{
+ return clk_get_rate(hwa742.sys_ck);
+}
+
+static void hwa742_power_up(struct device *dev)
+{
+ clk_enable(hwa742.sys_ck);
+}
+
+static void hwa742_power_down(struct device *dev)
+{
+ clk_disable(hwa742.sys_ck);
+}
+
+static struct hwa742_platform_data nokia770_hwa742_platform_data = {
+ .get_clock_rate = hwa742_get_clock_rate,
+ .power_up = hwa742_power_up,
+ .power_down = hwa742_power_down,
+ .te_connected = 1,
+};
+
+static void hwa742_dev_init(void)
+{
+ hwa742_get_clocks();
+ omapfb_set_ctrl_platform_data(&nokia770_hwa742_platform_data);
+}
/* assume no Mini-AB port */
#define AMPLIFIER_CTRL_GPIO 58
static struct clk *dspxor_ck;
-static DECLARE_MUTEX(audio_pwr_sem);
+static DEFINE_MUTEX(audio_pwr_mutex);
/*
* audio_pwr_state
* +--+-------------------------+---------------------------------------+
static int audio_pwr_state = -1;
/*
- * audio_pwr_up / down should be called under audio_pwr_sem
+ * audio_pwr_up / down should be called under audio_pwr_mutex
*/
static void nokia770_audio_pwr_up(void)
{
static void codec_delayed_power_down(struct work_struct *work)
{
- down(&audio_pwr_sem);
+ mutex_lock(&audio_pwr_mutex);
if (audio_pwr_state == -1)
aic23_power_down();
clk_disable(dspxor_ck);
- up(&audio_pwr_sem);
+ mutex_unlock(&audio_pwr_mutex);
}
static DECLARE_DELAYED_WORK(codec_power_down_work, codec_delayed_power_down);
static int
nokia770_audio_pwr_up_request(struct dsp_kfunc_device *kdev, int stage)
{
- down(&audio_pwr_sem);
+ mutex_lock(&audio_pwr_mutex);
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);
+ mutex_unlock(&audio_pwr_mutex);
return 0;
}
static int
nokia770_audio_pwr_down_request(struct dsp_kfunc_device *kdev, int stage)
{
- down(&audio_pwr_sem);
+ mutex_lock(&audio_pwr_mutex);
switch (stage) {
case 1:
if (audio_pwr_state == 0)
}
break;
}
- up(&audio_pwr_sem);
+ mutex_unlock(&audio_pwr_mutex);
return 0;
}
omap_serial_init();
omap_register_i2c_bus(1, 100, NULL, 0);
omap_dsp_init();
+ hwa742_dev_init();
ads7846_dev_init();
mipid_dev_init();
}
#include <asm/arch/common.h>
#include <asm/arch/mcbsp.h>
#include <asm/arch/omap-alsa.h>
+#include <asm/arch/gpio-switch.h>
static void __init omap_palmte_init_irq(void)
{
KEY(1, 1, KEY_DOWN),
KEY(1, 2, KEY_UP),
KEY(1, 3, KEY_RIGHT),
- KEY(1, 4, KEY_CENTER),
+ KEY(1, 4, KEY_ENTER),
0,
};
}
}
+static struct omap_gpio_switch palmte_switches[] __initdata = {
+ /* Speaker-enable pin is an output */
+ {
+ .name = "speaker-enable",
+ .gpio = PALMTE_SPEAKER_GPIO,
+ .type = OMAP_GPIO_SWITCH_TYPE_ACTIVITY,
+ .flags = OMAP_GPIO_SWITCH_FLAG_OUTPUT |
+ OMAP_GPIO_SWITCH_FLAG_INVERTED,
+ },
+ /* Indicates whether power is from DC-IN or battery */
+ {
+ .name = "dc-in",
+ .gpio = PALMTE_DC_GPIO,
+ .type = OMAP_GPIO_SWITCH_TYPE_CONNECTION,
+ .flags = OMAP_GPIO_SWITCH_FLAG_INVERTED,
+ },
+ /* Indicates whether a USB host is on the other end of the cable */
+ {
+ .name = "usb",
+ .gpio = PALMTE_USBDETECT_GPIO,
+ .type = OMAP_GPIO_SWITCH_TYPE_CONNECTION,
+ },
+ /* High when headphones jack is plugged in */
+ {
+ .name = "headphones",
+ .gpio = PALMTE_HEADPHONES_GPIO,
+ .type = OMAP_GPIO_SWITCH_TYPE_CONNECTION,
+ .notify = palmte_headphones_detect,
+ },
+};
+
static void __init palmte_misc_gpio_setup(void)
{
/* Set TSC2102 PINTDAV pin as input (used by TSC2102 driver) */
platform_add_devices(palmte_devices, ARRAY_SIZE(palmte_devices));
spi_register_board_info(palmte_spi_info, ARRAY_SIZE(palmte_spi_info));
+
+ omap_register_gpio_switches(palmte_switches,
+ ARRAY_SIZE(palmte_switches));
+
palmte_misc_gpio_setup();
omap_serial_init();
omap_register_i2c_bus(1, 100, NULL, 0);
KEY(1, 1, KEY_DOWN),
KEY(1, 2, KEY_UP),
KEY(1, 3, KEY_RIGHT),
- KEY(1, 4, KEY_CENTER),
+ KEY(1, 4, KEY_ENTER),
KEY(2, 0, KEY_CAMERA),
0,
};
#include <asm/mach/map.h>
#include <asm/arch/gpio.h>
+#include <asm/arch/gpio-switch.h>
#include <asm/arch/mux.h>
#include <asm/arch/irda.h>
#include <asm/arch/usb.h>
{ OMAP_TAG_UART, &sx1_uart_config },
};
+static struct omap_gpio_switch sx1_gpio_switches[] __initdata = {
+ {
+ .name = "mmc_slot",
+ .gpio = OMAP_MPUIO(3),
+ .type = OMAP_GPIO_SWITCH_TYPE_COVER,
+ .debounce_rising = 100,
+ .debounce_falling = 0,
+ .notify = sx1_mmc_slot_cover_handler,
+ .notify_data = NULL,
+ },
+};
+
/*-----------------------------------------*/
static void __init omap_sx1_init(void)
omap_serial_init();
omap_register_i2c_bus(1, 100, NULL, 0);
sx1_mmc_init();
+ omap_register_gpio_switches(sx1_gpio_switches,
+ ARRAY_SIZE(sx1_gpio_switches));
/* turn on USB power */
/* sx1_setusbpower(1); cant do it here because i2c is not ready */
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
+#include <linux/irq.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/notifier.h>
static void fpga_mask_irq(unsigned int irq)
{
- irq -= OMAP1510_IH_FPGA_BASE;
+ irq -= OMAP_FPGA_IRQ_BASE;
if (irq < 8)
__raw_writeb((__raw_readb(OMAP1510_FPGA_IMR_LO)
static void fpga_unmask_irq(unsigned int irq)
{
- irq -= OMAP1510_IH_FPGA_BASE;
+ irq -= OMAP_FPGA_IRQ_BASE;
if (irq < 8)
__raw_writeb((__raw_readb(OMAP1510_FPGA_IMR_LO) | (1 << irq)),
if (!stat)
return;
- for (fpga_irq = OMAP1510_IH_FPGA_BASE;
- (fpga_irq < (OMAP1510_IH_FPGA_BASE + NR_FPGA_IRQS)) && stat;
+ for (fpga_irq = OMAP_FPGA_IRQ_BASE;
+ (fpga_irq < OMAP_FPGA_IRQ_END) && stat;
fpga_irq++, stat >>= 1) {
if (stat & 1) {
d = irq_desc + fpga_irq;
__raw_writeb(0, OMAP1510_FPGA_IMR_HI);
__raw_writeb(0, INNOVATOR_FPGA_IMR2);
- for (i = OMAP1510_IH_FPGA_BASE; i < (OMAP1510_IH_FPGA_BASE + NR_FPGA_IRQS); i++) {
+ for (i = OMAP_FPGA_IRQ_BASE; i < OMAP_FPGA_IRQ_END; i++) {
if (i == OMAP1510_INT_FPGA_TS) {
/*
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap1/mmu.c
+ *
+ * Support for non-MPU OMAP1 MMUs.
+ *
+ * Copyright (C) 2002-2005 Nokia Corporation
+ *
+ * Written by Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ * and Paul Mundt <paul.mundt@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/rwsem.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include "mmu.h"
+#include <asm/tlbflush.h>
+#include <asm/arch/dsp_common.h>
+
+static void *dspvect_page;
+#define DSP_INIT_PAGE 0xfff000
+
+#define MMUFAULT_MASK (OMAP_MMU_FAULT_ST_PERM |\
+ OMAP_MMU_FAULT_ST_TLB_MISS |\
+ OMAP_MMU_FAULT_ST_TRANS)
+
+static unsigned int get_cam_l_va_mask(u16 pgsz)
+{
+ switch (pgsz) {
+ case OMAP_MMU_CAM_PAGESIZE_1MB:
+ return OMAP_MMU_CAM_L_VA_TAG_L1_MASK |
+ OMAP_MMU_CAM_L_VA_TAG_L2_MASK_1MB;
+ case OMAP_MMU_CAM_PAGESIZE_64KB:
+ return OMAP_MMU_CAM_L_VA_TAG_L1_MASK |
+ OMAP_MMU_CAM_L_VA_TAG_L2_MASK_64KB;
+ case OMAP_MMU_CAM_PAGESIZE_4KB:
+ return OMAP_MMU_CAM_L_VA_TAG_L1_MASK |
+ OMAP_MMU_CAM_L_VA_TAG_L2_MASK_4KB;
+ case OMAP_MMU_CAM_PAGESIZE_1KB:
+ return OMAP_MMU_CAM_L_VA_TAG_L1_MASK |
+ OMAP_MMU_CAM_L_VA_TAG_L2_MASK_1KB;
+ }
+ return 0;
+}
+
+#define get_cam_va_mask(pgsz) \
+ ((u32)OMAP_MMU_CAM_H_VA_TAG_H_MASK << 22 | \
+ (u32)get_cam_l_va_mask(pgsz) << 6)
+
+static int intmem_usecount;
+
+/* for safety */
+void dsp_mem_usecount_clear(void)
+{
+ if (intmem_usecount != 0) {
+ printk(KERN_WARNING
+ "MMU: unbalanced memory request/release detected.\n"
+ " intmem_usecount is not zero at where "
+ "it should be! ... fixed to be zero.\n");
+ intmem_usecount = 0;
+ omap_dsp_release_mem();
+ }
+}
+EXPORT_SYMBOL_GPL(dsp_mem_usecount_clear);
+
+void omap_mmu_itack(struct omap_mmu *mmu)
+{
+ omap_mmu_write_reg(mmu, OMAP_MMU_IT_ACK_IT_ACK, OMAP_MMU_IT_ACK);
+}
+EXPORT_SYMBOL(omap_mmu_itack);
+
+static int omap1_mmu_mem_enable(struct omap_mmu *mmu, void *addr)
+{
+ int ret = 0;
+
+ if (omap_mmu_internal_memory(mmu, addr)) {
+ if (intmem_usecount++ == 0)
+ ret = omap_dsp_request_mem();
+ }
+
+ return ret;
+}
+
+static int omap1_mmu_mem_disable(struct omap_mmu *mmu, void *addr)
+{
+ int ret = 0;
+
+ if (omap_mmu_internal_memory(mmu, addr)) {
+ if (--intmem_usecount == 0)
+ omap_dsp_release_mem();
+ } else
+ ret = -EIO;
+
+ return ret;
+}
+
+static inline void
+omap1_mmu_read_tlb(struct omap_mmu *mmu, struct cam_ram_regset *cr)
+{
+ /* read a TLB entry */
+ omap_mmu_write_reg(mmu, OMAP_MMU_LD_TLB_RD, OMAP_MMU_LD_TLB);
+
+ cr->cam_h = omap_mmu_read_reg(mmu, OMAP_MMU_READ_CAM_H);
+ cr->cam_l = omap_mmu_read_reg(mmu, OMAP_MMU_READ_CAM_L);
+ cr->ram_h = omap_mmu_read_reg(mmu, OMAP_MMU_READ_RAM_H);
+ cr->ram_l = omap_mmu_read_reg(mmu, OMAP_MMU_READ_RAM_L);
+}
+
+static inline void
+omap1_mmu_load_tlb(struct omap_mmu *mmu, struct cam_ram_regset *cr)
+{
+ /* Set the CAM and RAM entries */
+ omap_mmu_write_reg(mmu, cr->cam_h, OMAP_MMU_CAM_H);
+ omap_mmu_write_reg(mmu, cr->cam_l, OMAP_MMU_CAM_L);
+ omap_mmu_write_reg(mmu, cr->ram_h, OMAP_MMU_RAM_H);
+ omap_mmu_write_reg(mmu, cr->ram_l, OMAP_MMU_RAM_L);
+}
+
+static ssize_t omap1_mmu_show(struct omap_mmu *mmu, char *buf,
+ struct omap_mmu_tlb_lock *tlb_lock)
+{
+ int i, len;
+
+ len = sprintf(buf, "P: preserved, V: valid\n"
+ "ety P V size cam_va ram_pa ap\n");
+ /* 00: P V 4KB 0x300000 0x10171800 FA */
+
+ for (i = 0; i < mmu->nr_tlb_entries; i++) {
+ struct omap_mmu_tlb_entry ent;
+ struct cam_ram_regset cr;
+ struct omap_mmu_tlb_lock entry_lock;
+ char *pgsz_str, *ap_str;
+
+ /* read a TLB entry */
+ entry_lock.base = tlb_lock->base;
+ entry_lock.victim = i;
+ omap_mmu_read_tlb(mmu, &entry_lock, &cr);
+
+ ent.pgsz = cr.cam_l & OMAP_MMU_CAM_PAGESIZE_MASK;
+ ent.prsvd = cr.cam_l & OMAP_MMU_CAM_P;
+ ent.valid = cr.cam_l & OMAP_MMU_CAM_V;
+ ent.ap = cr.ram_l & OMAP_MMU_RAM_L_AP_MASK;
+ ent.va = (u32)(cr.cam_h & OMAP_MMU_CAM_H_VA_TAG_H_MASK) << 22 |
+ (u32)(cr.cam_l & get_cam_l_va_mask(ent.pgsz)) << 6;
+ ent.pa = (unsigned long)cr.ram_h << 16 |
+ (cr.ram_l & OMAP_MMU_RAM_L_RAM_LSB_MASK);
+
+ pgsz_str = (ent.pgsz == OMAP_MMU_CAM_PAGESIZE_1MB) ? " 1MB":
+ (ent.pgsz == OMAP_MMU_CAM_PAGESIZE_64KB) ? "64KB":
+ (ent.pgsz == OMAP_MMU_CAM_PAGESIZE_4KB) ? " 4KB":
+ (ent.pgsz == OMAP_MMU_CAM_PAGESIZE_1KB) ? " 1KB":
+ " ???";
+ ap_str = (ent.ap == OMAP_MMU_RAM_L_AP_RO) ? "RO":
+ (ent.ap == OMAP_MMU_RAM_L_AP_FA) ? "FA":
+ (ent.ap == OMAP_MMU_RAM_L_AP_NA) ? "NA":
+ "??";
+
+ if (i == tlb_lock->base)
+ len += sprintf(buf + len, "lock base = %d\n",
+ tlb_lock->base);
+ if (i == tlb_lock->victim)
+ len += sprintf(buf + len, "victim = %d\n",
+ tlb_lock->victim);
+ len += sprintf(buf + len,
+ /* 00: P V 4KB 0x300000 0x10171800 FA */
+ "%02d: %c %c %s 0x%06lx 0x%08lx %s\n",
+ i,
+ ent.prsvd ? 'P' : ' ',
+ ent.valid ? 'V' : ' ',
+ pgsz_str, ent.va, ent.pa, ap_str);
+ }
+
+ return len;
+}
+
+static int exmap_setup_preserved_entries(struct omap_mmu *mmu)
+{
+ int n = 0;
+
+ exmap_setup_preserved_mem_page(mmu, dspvect_page, DSP_INIT_PAGE, n++);
+
+ return n;
+}
+
+static void exmap_clear_preserved_entries(struct omap_mmu *mmu)
+{
+ exmap_clear_mem_page(mmu, DSP_INIT_PAGE);
+}
+
+static int omap1_mmu_startup(struct omap_mmu *mmu)
+{
+ dspvect_page = (void *)__get_dma_pages(GFP_KERNEL, 0);
+ if (dspvect_page == NULL) {
+ dev_err(mmu->dev, "MMU %s: failed to allocate memory "
+ "for vector table\n", mmu->name);
+ return -ENOMEM;
+ }
+
+ mmu->nr_exmap_preserved = exmap_setup_preserved_entries(mmu);
+
+ return 0;
+}
+
+static void omap1_mmu_shutdown(struct omap_mmu *mmu)
+{
+ exmap_clear_preserved_entries(mmu);
+
+ if (dspvect_page != NULL) {
+ unsigned long virt;
+
+ down_read(&mmu->exmap_sem);
+
+ virt = (unsigned long)omap_mmu_to_virt(mmu, DSP_INIT_PAGE);
+ flush_tlb_kernel_range(virt, virt + PAGE_SIZE);
+ free_page((unsigned long)dspvect_page);
+ dspvect_page = NULL;
+
+ up_read(&mmu->exmap_sem);
+ }
+}
+
+static inline unsigned long omap1_mmu_cam_va(struct cam_ram_regset *cr)
+{
+ unsigned int page_size = cr->cam_l & OMAP_MMU_CAM_PAGESIZE_MASK;
+
+ return (u32)(cr->cam_h & OMAP_MMU_CAM_H_VA_TAG_H_MASK) << 22 |
+ (u32)(cr->cam_l & get_cam_l_va_mask(page_size)) << 6;
+}
+
+static struct cam_ram_regset *
+omap1_mmu_cam_ram_alloc(struct omap_mmu *mmu, struct omap_mmu_tlb_entry *entry)
+{
+ struct cam_ram_regset *cr;
+
+ if (entry->va & ~(get_cam_va_mask(entry->pgsz))) {
+ dev_err(mmu->dev, "MMU %s: mapping vadr (0x%06lx) is not on"
+ " an aligned boundary\n", mmu->name, entry->va);
+ return ERR_PTR(-EINVAL);
+ }
+
+ cr = kmalloc(sizeof(struct cam_ram_regset), GFP_KERNEL);
+
+ cr->cam_h = entry->va >> 22;
+ cr->cam_l = (entry->va >> 6 & get_cam_l_va_mask(entry->pgsz)) |
+ entry->prsvd | entry->pgsz;
+ cr->ram_h = entry->pa >> 16;
+ cr->ram_l = (entry->pa & OMAP_MMU_RAM_L_RAM_LSB_MASK) | entry->ap;
+
+ return cr;
+}
+
+static inline int omap1_mmu_cam_ram_valid(struct cam_ram_regset *cr)
+{
+ return cr->cam_l & OMAP_MMU_CAM_V;
+}
+
+static void omap1_mmu_interrupt(struct omap_mmu *mmu)
+{
+ unsigned long status;
+ unsigned long adh, adl;
+ unsigned long dp;
+ unsigned long va;
+
+ status = omap_mmu_read_reg(mmu, OMAP_MMU_FAULT_ST);
+ adh = omap_mmu_read_reg(mmu, OMAP_MMU_FAULT_AD_H);
+ adl = omap_mmu_read_reg(mmu, OMAP_MMU_FAULT_AD_L);
+ dp = adh & OMAP_MMU_FAULT_AD_H_DP;
+ va = (((adh & OMAP_MMU_FAULT_AD_H_ADR_MASK) << 16) | adl);
+
+ /* if the fault is masked, nothing to do */
+ if ((status & MMUFAULT_MASK) == 0) {
+ pr_debug("MMU interrupt, but ignoring.\n");
+ /*
+ * note: in OMAP1710,
+ * when CACHE + DMA domain gets out of idle in DSP,
+ * MMU interrupt occurs but MMU_FAULT_ST is not set.
+ * in this case, we just ignore the interrupt.
+ */
+ if (status) {
+ pr_debug("%s%s%s%s\n",
+ (status & OMAP_MMU_FAULT_ST_PREF)?
+ " (prefetch err)" : "",
+ (status & OMAP_MMU_FAULT_ST_PERM)?
+ " (permission fault)" : "",
+ (status & OMAP_MMU_FAULT_ST_TLB_MISS)?
+ " (TLB miss)" : "",
+ (status & OMAP_MMU_FAULT_ST_TRANS) ?
+ " (translation fault)": "");
+ pr_debug("fault address = %#08lx\n", va);
+ }
+ enable_irq(mmu->irq);
+ return;
+ }
+
+ pr_info("%s%s%s%s\n",
+ (status & OMAP_MMU_FAULT_ST_PREF)?
+ (MMUFAULT_MASK & OMAP_MMU_FAULT_ST_PREF)?
+ " prefetch err":
+ " (prefetch err)":
+ "",
+ (status & OMAP_MMU_FAULT_ST_PERM)?
+ (MMUFAULT_MASK & OMAP_MMU_FAULT_ST_PERM)?
+ " permission fault":
+ " (permission fault)":
+ "",
+ (status & OMAP_MMU_FAULT_ST_TLB_MISS)?
+ (MMUFAULT_MASK & OMAP_MMU_FAULT_ST_TLB_MISS)?
+ " TLB miss":
+ " (TLB miss)":
+ "",
+ (status & OMAP_MMU_FAULT_ST_TRANS)?
+ (MMUFAULT_MASK & OMAP_MMU_FAULT_ST_TRANS)?
+ " translation fault":
+ " (translation fault)":
+ "");
+ pr_info("fault address = %#08lx\n", va);
+
+ mmu->fault_address = va;
+ schedule_work(&mmu->irq_work);
+}
+
+static pgprot_t omap1_mmu_pte_get_attr(struct omap_mmu_tlb_entry *entry)
+{
+ /* 4KB AP position as default */
+ u32 attr = entry->ap >> 4;
+ attr <<= ((entry->pgsz == OMAP_MMU_CAM_PAGESIZE_1MB) ? 6:0);
+ return attr;
+}
+
+struct omap_mmu_ops omap1_mmu_ops = {
+ .startup = omap1_mmu_startup,
+ .shutdown = omap1_mmu_shutdown,
+ .mem_enable = omap1_mmu_mem_enable,
+ .mem_disable = omap1_mmu_mem_disable,
+ .read_tlb = omap1_mmu_read_tlb,
+ .load_tlb = omap1_mmu_load_tlb,
+ .show = omap1_mmu_show,
+ .cam_va = omap1_mmu_cam_va,
+ .cam_ram_alloc = omap1_mmu_cam_ram_alloc,
+ .cam_ram_valid = omap1_mmu_cam_ram_valid,
+ .interrupt = omap1_mmu_interrupt,
+ .pte_get_attr = omap1_mmu_pte_get_attr,
+};
+EXPORT_SYMBOL_GPL(omap1_mmu_ops);
--- /dev/null
+#ifndef __MACH_OMAP1_MMU_H
+#define __MACH_OMAP1_MMU_H
+
+#include <asm/arch/mmu.h>
+#include <asm/io.h>
+
+#define MMU_LOCK_BASE_MASK (0x3f << 10)
+#define MMU_LOCK_VICTIM_MASK (0x3f << 4)
+
+#define OMAP_MMU_PREFETCH 0x00
+#define OMAP_MMU_WALKING_ST 0x04
+#define OMAP_MMU_CNTL 0x08
+#define OMAP_MMU_FAULT_AD_H 0x0c
+#define OMAP_MMU_FAULT_AD_L 0x10
+#define OMAP_MMU_FAULT_ST 0x14
+#define OMAP_MMU_IT_ACK 0x18
+#define OMAP_MMU_TTB_H 0x1c
+#define OMAP_MMU_TTB_L 0x20
+#define OMAP_MMU_LOCK 0x24
+#define OMAP_MMU_LD_TLB 0x28
+#define OMAP_MMU_CAM_H 0x2c
+#define OMAP_MMU_CAM_L 0x30
+#define OMAP_MMU_RAM_H 0x34
+#define OMAP_MMU_RAM_L 0x38
+#define OMAP_MMU_GFLUSH 0x3c
+#define OMAP_MMU_FLUSH_ENTRY 0x40
+#define OMAP_MMU_READ_CAM_H 0x44
+#define OMAP_MMU_READ_CAM_L 0x48
+#define OMAP_MMU_READ_RAM_H 0x4c
+#define OMAP_MMU_READ_RAM_L 0x50
+
+#define OMAP_MMU_CNTL_BURST_16MNGT_EN 0x0020
+#define OMAP_MMU_CNTL_WTL_EN 0x0004
+#define OMAP_MMU_CNTL_MMU_EN 0x0002
+#define OMAP_MMU_CNTL_RESET_SW 0x0001
+
+#define OMAP_MMU_FAULT_AD_H_DP 0x0100
+#define OMAP_MMU_FAULT_AD_H_ADR_MASK 0x00ff
+
+#define OMAP_MMU_FAULT_ST_PREF 0x0008
+#define OMAP_MMU_FAULT_ST_PERM 0x0004
+#define OMAP_MMU_FAULT_ST_TLB_MISS 0x0002
+#define OMAP_MMU_FAULT_ST_TRANS 0x0001
+
+#define OMAP_MMU_IT_ACK_IT_ACK 0x0001
+
+#define OMAP_MMU_CAM_H_VA_TAG_H_MASK 0x0003
+
+#define OMAP_MMU_CAM_L_VA_TAG_L1_MASK 0xc000
+#define OMAP_MMU_CAM_L_VA_TAG_L2_MASK_1MB 0x0000
+#define OMAP_MMU_CAM_L_VA_TAG_L2_MASK_64KB 0x3c00
+#define OMAP_MMU_CAM_L_VA_TAG_L2_MASK_4KB 0x3fc0
+#define OMAP_MMU_CAM_L_VA_TAG_L2_MASK_1KB 0x3ff0
+#define OMAP_MMU_CAM_L_P 0x0008
+#define OMAP_MMU_CAM_L_V 0x0004
+#define OMAP_MMU_CAM_L_PAGESIZE_MASK 0x0003
+#define OMAP_MMU_CAM_L_PAGESIZE_1MB 0x0000
+#define OMAP_MMU_CAM_L_PAGESIZE_64KB 0x0001
+#define OMAP_MMU_CAM_L_PAGESIZE_4KB 0x0002
+#define OMAP_MMU_CAM_L_PAGESIZE_1KB 0x0003
+
+#define OMAP_MMU_CAM_P OMAP_MMU_CAM_L_P
+#define OMAP_MMU_CAM_V OMAP_MMU_CAM_L_V
+#define OMAP_MMU_CAM_PAGESIZE_MASK OMAP_MMU_CAM_L_PAGESIZE_MASK
+#define OMAP_MMU_CAM_PAGESIZE_1MB OMAP_MMU_CAM_L_PAGESIZE_1MB
+#define OMAP_MMU_CAM_PAGESIZE_64KB OMAP_MMU_CAM_L_PAGESIZE_64KB
+#define OMAP_MMU_CAM_PAGESIZE_4KB OMAP_MMU_CAM_L_PAGESIZE_4KB
+#define OMAP_MMU_CAM_PAGESIZE_1KB OMAP_MMU_CAM_L_PAGESIZE_1KB
+#define OMAP_MMU_CAM_PAGESIZE_16MB -1 /* unused in omap1 */
+
+#define OMAP_MMU_RAM_L_RAM_LSB_MASK 0xfc00
+#define OMAP_MMU_RAM_L_AP_MASK 0x0300
+#define OMAP_MMU_RAM_L_AP_NA 0x0000
+#define OMAP_MMU_RAM_L_AP_RO 0x0200
+#define OMAP_MMU_RAM_L_AP_FA 0x0300
+
+#define OMAP_MMU_LD_TLB_RD 0x0002
+
+#define INIT_TLB_ENTRY(ent, v, p, ps) \
+do { \
+ (ent)->va = (v); \
+ (ent)->pa = (p); \
+ (ent)->pgsz = (ps); \
+ (ent)->prsvd = 0; \
+ (ent)->ap = OMAP_MMU_RAM_L_AP_FA; \
+ (ent)->tlb = 1; \
+} while (0)
+
+#define INIT_TLB_ENTRY_4KB_PRESERVED(ent, v, p) \
+do { \
+ (ent)->va = (v); \
+ (ent)->pa = (p); \
+ (ent)->pgsz = OMAP_MMU_CAM_PAGESIZE_4KB; \
+ (ent)->prsvd = OMAP_MMU_CAM_P; \
+ (ent)->ap = OMAP_MMU_RAM_L_AP_FA; \
+} while (0)
+
+struct omap_mmu_tlb_entry {
+ unsigned long va;
+ unsigned long pa;
+ unsigned int pgsz, prsvd, valid;
+
+ u16 ap;
+ unsigned int tlb;
+};
+
+static inline unsigned short
+omap_mmu_read_reg(struct omap_mmu *mmu, unsigned long reg)
+{
+ return __raw_readw(mmu->base + reg);
+}
+
+static inline void omap_mmu_write_reg(struct omap_mmu *mmu,
+ unsigned short val, unsigned long reg)
+{
+ __raw_writew(val, mmu->base + reg);
+}
+
+#endif /* __MACH_OMAP1_MMU_H */
config ARCH_OMAP2430
bool "OMAP2430 support"
depends on ARCH_OMAP24XX
+ select ARCH_OMAP_OTG
+
+config ARCH_OMAP34XX
+ bool "OMAP34xx Based System"
+ depends on ARCH_OMAP3
+
+config ARCH_OMAP3430
+ bool "OMAP3430 support"
+ depends on ARCH_OMAP3 && ARCH_OMAP34XX
+ select ARCH_OMAP_OTG
comment "OMAP Board Type"
- depends on ARCH_OMAP2
+ depends on ARCH_OMAP2 || ARCH_OMAP3
config MACH_OMAP_GENERIC
bool "Generic OMAP board"
depends on ARCH_OMAP2 && ARCH_OMAP24XX
+config MACH_NOKIA_N800
+ bool "Nokia N800"
+ depends on ARCH_OMAP2420
+ select VIDEO_TCM825X if VIDEO_OMAP2
+ select CBUS if VIDEO_TCM825X
+ select CBUS_RETU if VIDEO_TCM825X
+ select MENELAUS if VIDEO_TCM825X
+ select OMAP_GPIO_SWITCH
+
+config MACH_NOKIA_N810
+ bool "Nokia N810"
+ depends on MACH_NOKIA_N800
+
+config MACH_OMAP2_TUSB6010
+ bool
+ depends on ARCH_OMAP2 && ARCH_OMAP2420
+ default y if MACH_NOKIA_N800
+
config MACH_OMAP_H4
bool "OMAP 2420 H4 board"
- depends on ARCH_OMAP2 && ARCH_OMAP24XX
+ depends on ARCH_OMAP2 && ARCH_OMAP2420
select OMAP_DEBUG_DEVICES
+ select GPIOEXPANDER_OMAP
+
+config MACH_OMAP_H4_TUSB
+ bool "TUSB 6010 EVM board"
+ depends on MACH_OMAP_H4
+ select MACH_OMAP2_TUSB6010
+ help
+ Set this if you've got a TUSB6010 high speed USB board.
+ You may need to consult the schematics for your revisions
+ of the Menelaus and TUSB boards, and make changes to be
+ sure this is set up properly for your board stack.
+
+ Be sure to select OTG mode operation, not host-only or
+ peripheral-only.
+
+config MACH_OMAP_H4_OTG
+ bool "Use USB OTG connector, not device connector (S1.10)"
+ depends on MACH_OMAP_H4
+ help
+ Set this if you've set S1.10 (on the mainboard) to use the
+ Mini-AB (OTG) connector and OTG transceiver with the USB0
+ port, instead of the Mini-B ("download") connector with its
+ non-OTG transceiver.
+
+ Note that the "download" connector can be used to bootstrap
+ the system from the OMAP mask ROM. Also, since this is a
+ development platform, you can also force the OTG port into
+ a non-OTG operational mode.
+
+config MACH_OMAP2_H4_USB1
+ bool "Use USB1 port, not UART2 (S3.3)"
+ depends on MACH_OMAP_H4
+ help
+ Set this if you've set SW3.3 (on the CPU card) so that the
+ expansion connectors receive USB1 signals instead of UART2.
config MACH_OMAP_APOLLON
bool "OMAP 2420 Apollon board"
- depends on ARCH_OMAP2 && ARCH_OMAP24XX
+ depends on ARCH_OMAP2 && ARCH_OMAP2420
config MACH_OMAP_2430SDP
bool "OMAP 2430 SDP board"
+ depends on ARCH_OMAP2 && ARCH_OMAP2430
+
+config MACH_OMAP_2430OSK
+ bool "OMAP 2430 OSK board"
depends on ARCH_OMAP2 && ARCH_OMAP24XX
+config MACH_OMAP_3430SDP
+ bool "OMAP 3430 SDP board"
+ depends on ARCH_OMAP3 && ARCH_OMAP34XX
+
+config MACH_OMAP3EVM
+ bool "OMAP 3530 EVM board"
+ depends on ARCH_OMAP3 && ARCH_OMAP34XX
+
+config MACH_OMAP3_BEAGLE
+ bool "OMAP3 BEAGLE board"
+ depends on ARCH_OMAP3 && ARCH_OMAP34XX
#
# Common support
-obj-y := irq.o id.o io.o sram-fn.o memory.o control.o prcm.o clock.o mux.o \
- devices.o serial.o gpmc.o timer-gp.o
+obj-y := irq.o id.o io.o memory.o control.o prcm.o clock.o mux.o \
+ devices.o serial.o gpmc.o timer-gp.o powerdomain.o \
+ clockdomain.o
+
+# Functions loaded to SRAM
+obj-$(CONFIG_ARCH_OMAP2) += sram24xx.o
# Power Management
obj-$(CONFIG_PM) += pm.o sleep.o
obj-$(CONFIG_ARCH_OMAP2) += clock24xx.o
obj-$(CONFIG_ARCH_OMAP3) += clock34xx.o
+# DSP
+obj-$(CONFIG_OMAP_MMU_FWK) += mmu_mach.o
+obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox_mach.o
+mailbox_mach-objs := mailbox.o
+mmu_mach-objs := mmu.o
+
# Specific board support
obj-$(CONFIG_MACH_OMAP_GENERIC) += board-generic.o
-obj-$(CONFIG_MACH_OMAP_H4) += board-h4.o
-obj-$(CONFIG_MACH_OMAP_2430SDP) += board-2430sdp.o
-obj-$(CONFIG_MACH_OMAP_APOLLON) += board-apollon.o
+obj-$(CONFIG_MACH_OMAP_H4) += board-h4.o board-h4-mmc.o
+obj-$(CONFIG_MACH_OMAP_2430SDP) += board-2430sdp.o \
+ board-2430sdp-flash.o \
+ hsmmc.o \
+ usb-musb.o \
+ usb-ehci.o
+obj-$(CONFIG_MACH_OMAP_2430OSK) += board-2430osk.o
+obj-$(CONFIG_MACH_OMAP_3430SDP) += board-3430sdp.o \
+ hsmmc.o \
+ usb-musb.o \
+ usb-ehci.o \
+ board-3430sdp-flash.o
+obj-$(CONFIG_MACH_OMAP3EVM) += board-omap3evm.o \
+ hsmmc.o \
+ usb-musb.o usb-ehci.o \
+ board-omap3evm-flash.o
+obj-$(CONFIG_MACH_OMAP3_BEAGLE) += board-omap3beagle.o \
+ usb-musb.o usb-ehci.o \
+ hsmmc.o
+obj-$(CONFIG_MACH_OMAP_APOLLON) += board-apollon.o \
+ board-apollon-mmc.o \
+ board-apollon-keys.o
+obj-$(CONFIG_MACH_NOKIA_N800) += board-n800.o board-n800-flash.o \
+ board-n800-mmc.o board-n800-bt.o \
+ board-n800-audio.o board-n800-usb.o \
+ board-n800-dsp.o \
+ board-n800-camera.o
+obj-$(CONFIG_MACH_NOKIA_N810) += board-n810.o
+
+# TUSB 6010 chips
+obj-$(CONFIG_MACH_OMAP2_TUSB6010) += usb-tusb6010.o
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap2/board-2430osk.c
+ *
+ * Copyright (C) 2007 Mistral Software Pvt Ltd
+ *
+ * Modified from mach-omap2/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/delay.h>
+#include <linux/err.h>
+#include <linux/clk.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/board.h>
+#include <asm/arch/common.h>
+
+#include <asm/io.h>
+
+static void __init omap_2430osk_init_irq(void)
+{
+ omap2_init_common_hw();
+ omap_init_irq();
+ omap_gpio_init();
+}
+
+static struct omap_uart_config osk2430_uart_config __initdata = {
+ .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
+};
+
+static struct omap_board_config_kernel osk2430_config[] __initdata = {
+
+ {OMAP_TAG_UART, &osk2430_uart_config},
+};
+
+#if defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE)
+
+#define OMAP2_I2C_BASE1 0x48070000
+#define OMAP2_I2C_BASE2 0x48072000
+#define OMAP2_I2C_INT1 56
+#define OMAP2_I2C_INT2 57
+
+static u32 omap2_i2c1_clkrate = 400;
+static u32 omap2_i2c2_clkrate = 2600;
+
+static struct resource i2c_resources1[] = {
+ {
+ .start = OMAP2_I2C_BASE1,
+ .end = OMAP2_I2C_BASE1 + 0x3f,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = OMAP2_I2C_INT1,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct resource i2c_resources2[] = {
+ {
+ .start = OMAP2_I2C_BASE2,
+ .end = OMAP2_I2C_BASE2 + 0x3f,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = OMAP2_I2C_INT2,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device omap_i2c_device1 = {
+ .name = "i2c_omap",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(i2c_resources1),
+ .resource = i2c_resources1,
+ .dev = {
+ .platform_data = &omap2_i2c1_clkrate,
+ },
+};
+
+static struct platform_device omap_i2c_device2 = {
+ .name = "i2c_omap",
+ .id = 2,
+ .num_resources = ARRAY_SIZE(i2c_resources2),
+ .resource = i2c_resources2,
+ .dev = {
+ .platform_data = &omap2_i2c2_clkrate,
+ },
+};
+
+static void omap_init_i2c(void)
+{
+ (void) platform_device_register(&omap_i2c_device2);
+ (void) platform_device_register(&omap_i2c_device1);
+}
+
+#else
+
+static void omap_init_i2c(void) {}
+
+#endif
+
+static int __init omap2430_i2c_init(void)
+{
+ omap_init_i2c();
+ return 0;
+}
+
+static void __init omap_2430osk_init(void)
+{
+ omap_board_config = osk2430_config;
+ omap_board_config_size = ARRAY_SIZE(osk2430_config);
+ omap_serial_init();
+}
+
+static void __init omap_2430osk_map_io(void)
+{
+ omap2_set_globals_243x();
+ omap2_map_common_io();
+}
+
+arch_initcall(omap2430_i2c_init);
+
+MACHINE_START(OMAP_2430OSK, "OMAP2430 2430OSK board")
+ /* Maintainer: Syed Khasim */
+ .phys_io = 0x48000000,
+ .io_pg_offst = ((0xd8000000) >> 18) & 0xfffc,
+ .boot_params = 0x80000100,
+ .map_io = omap_2430osk_map_io,
+ .init_irq = omap_2430osk_init_irq,
+ .init_machine = omap_2430osk_init,
+ .timer = &omap_timer,
+MACHINE_END
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap2/board-2430sdp-flash.c
+ *
+ * Copyright (C) 2007 MontaVista Software, Inc. <source@mvista.com>
+ * Author: Kevin Hilman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <asm/mach/flash.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/onenand_regs.h>
+
+#include <asm/io.h>
+#include <asm/arch/onenand.h>
+#include <asm/arch/board.h>
+#include <asm/arch/gpmc.h>
+#include <asm/arch/nand.h>
+
+#define ONENAND_MAP 0x20000000
+#define GPMC_OFF_CONFIG1_0 0x60
+
+enum fstype {
+ NAND = 0,
+ NOR,
+ ONENAND,
+ UNKNOWN = -1
+};
+
+static enum fstype flash_type = NAND;
+
+static struct mtd_partition nand_partitions[] = {
+ {
+ .name = "X-Loader",
+ .offset = 0,
+ .size = 4*(64*2048), /* 0-3 blks reserved.
+ Mandated by ROM code */
+ .mask_flags = MTD_WRITEABLE /* force read-only */
+ },
+ {
+ .name = "U-Boot",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 4*(64*2048),
+ .mask_flags = MTD_WRITEABLE /* force read-only */
+ },
+ {
+ .name = "U-Boot Environment",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 2*(64*2048),
+ },
+ {
+ .name = "Kernel",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 32*(64*2048), /* 4*1M */
+ },
+ {
+ .name = "File System",
+ .offset = MTDPART_OFS_APPEND,
+ .size = MTDPART_SIZ_FULL,
+ },
+};
+static struct omap_nand_platform_data sdp_nand_data = {
+ .parts = nand_partitions,
+ .nr_parts = ARRAY_SIZE(nand_partitions),
+ .dma_channel = -1, /* disable DMA in OMAP OneNAND driver */
+};
+
+static struct platform_device sdp_nand_device = {
+ .name = "omap2-nand",
+ .id = -1,
+ .dev = {
+ .platform_data = &sdp_nand_data,
+ },
+};
+
+static struct mtd_partition onenand_partitions[] = {
+ {
+ .name = "(OneNAND)X-Loader",
+ .offset = 0,
+ .size = 4*(64*2048), /* 0-3 blks reserved.
+ Mandated by ROM code */
+ .mask_flags = MTD_WRITEABLE /* force read-only */
+ },
+ {
+ .name = "(OneNAND)U-Boot",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 2*(64*2048),
+ .mask_flags = MTD_WRITEABLE /* force read-only */
+ },
+ {
+ .name = "(OneNAND)U-Boot Environment",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 1*(64*2048),
+ },
+ {
+ .name = "(OneNAND)Kernel",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 4*(64*2048),
+ },
+ {
+ .name = "(OneNAND)File System",
+ .offset = MTDPART_OFS_APPEND,
+ .size = MTDPART_SIZ_FULL,
+ },
+};
+
+static struct omap_onenand_platform_data sdp_onenand_data = {
+ .parts = onenand_partitions,
+ .nr_parts = ARRAY_SIZE(onenand_partitions),
+ .dma_channel = -1, /* disable DMA in OMAP OneNAND driver */
+};
+
+static struct platform_device sdp_onenand_device = {
+ .name = "omap2-onenand",
+ .id = -1,
+ .dev = {
+ .platform_data = &sdp_onenand_data,
+ },
+};
+
+void __init sdp2430_flash_init(void)
+{
+ unsigned long gpmc_base_add, gpmc_cs_base_add;
+ unsigned char cs = 0;
+
+ gpmc_base_add = OMAP243X_GPMC_VIRT;
+ while (cs < GPMC_CS_NUM) {
+ int ret = 0;
+
+ /* Each GPMC set for a single CS is at offset 0x30 */
+ gpmc_cs_base_add =
+ (gpmc_base_add + GPMC_OFF_CONFIG1_0 + (cs*0x30));
+
+ /* xloader/Uboot would have programmed the NAND/oneNAND
+ * base address for us This is a ugly hack. The proper
+ * way of doing this is to pass the setup of u-boot up
+ * to kernel using kernel params - something on the
+ * lines of machineID. Check if Nand/oneNAND is
+ * configured */
+ ret = __raw_readl(gpmc_cs_base_add + GPMC_CS_CONFIG1);
+ if ((ret & 0xC00) == (0x800)) {
+ /* Found it!! */
+ printk(KERN_INFO "NAND: Found NAND on CS %d \n", cs);
+ flash_type = NAND;
+ break;
+ }
+ ret = __raw_readl(gpmc_cs_base_add + GPMC_CS_CONFIG7);
+ if ((ret & 0x3F) == (ONENAND_MAP >> 24)) {
+ /* Found it!! */
+ flash_type = ONENAND;
+ break;
+ }
+ cs++;
+ }
+ if (cs >= GPMC_CS_NUM) {
+ printk(KERN_INFO "MTD: Unable to find MTD configuration in "
+ "GPMC - not registering.\n");
+ return;
+ }
+
+ if (flash_type == NAND) {
+ sdp_nand_data.cs = cs;
+ sdp_nand_data.gpmc_cs_baseaddr = (void *) gpmc_cs_base_add;
+ sdp_nand_data.gpmc_baseaddr = (void *) gpmc_base_add;
+
+ if (platform_device_register(&sdp_nand_device) < 0) {
+ printk(KERN_ERR "Unable to register NAND device\n");
+ return;
+ }
+ }
+
+ if (flash_type == ONENAND) {
+ sdp_onenand_data.cs = cs;
+
+ if (platform_device_register(&sdp_onenand_device) < 0) {
+ printk(KERN_ERR "Unable to register OneNAND device\n");
+ return;
+ }
+ }
+}
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/delay.h>
+#include <linux/input.h>
#include <linux/err.h>
#include <linux/clk.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/ads7846.h>
+#include <linux/i2c/twl4030-rtc.h>
#include <asm/hardware.h>
#include <asm/mach-types.h>
#include <asm/arch/gpio.h>
#include <asm/arch/mux.h>
#include <asm/arch/board.h>
+#include <asm/arch/usb-musb.h>
+#include <asm/arch/hsmmc.h>
#include <asm/arch/common.h>
+#include <asm/arch/keypad.h>
#include <asm/arch/gpmc.h>
+#include <asm/arch/mcspi.h>
#include <asm/io.h>
-
#define SDP2430_FLASH_CS 0
#define SDP2430_SMC91X_CS 5
+/* GPIO used for TSC2046 (touchscreen)
+ *
+ * Also note that the tsc2046 is the same silicon as the ads7846, so
+ * that driver is used for the touchscreen. */
+#define TS_GPIO 24
+
+#define TWL4030_MSECURE_GPIO 118
+#define SECONDARY_LCD_GPIO 147
+
static struct mtd_partition sdp2430_partitions[] = {
/* bootloader (U-Boot, etc) in first sector */
{
[1] = {
.start = OMAP_GPIO_IRQ(OMAP24XX_ETHR_GPIO_IRQ),
.end = OMAP_GPIO_IRQ(OMAP24XX_ETHR_GPIO_IRQ),
- .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
},
};
+static struct platform_device sdp2430_lcd_device = {
+ .name = "sdp2430_lcd",
+ .id = -1,
+};
+
static struct platform_device sdp2430_smc91x_device = {
.name = "smc91x",
.id = -1,
.resource = sdp2430_smc91x_resources,
};
+/*
+ * Key mapping for 2430 SDP board
+ */
+
+static int sdp2430_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_D),
+ KEY(5, 0, KEY_V),
+ KEY(5, 1, KEY_W),
+ KEY(5, 2, KEY_L),
+ KEY(5, 3, KEY_S),
+ KEY(5, 4, KEY_H),
+ 0
+};
+
+static struct omap_kp_platform_data sdp2430_kp_data = {
+ .rows = 5,
+ .cols = 6,
+ .keymap = sdp2430_keymap,
+ .keymapsize = ARRAY_SIZE(sdp2430_keymap),
+ .rep = 1,
+};
+
+static struct platform_device sdp2430_kp_device = {
+ .name = "omap_twl4030keypad",
+ .id = -1,
+ .dev = {
+ .platform_data = &sdp2430_kp_data,
+ },
+};
+
+static int twl4030_rtc_init(void)
+{
+ int ret = 0;
+
+ ret = omap_request_gpio(TWL4030_MSECURE_GPIO);
+ if (ret < 0) {
+ printk(KERN_ERR "twl4030_rtc_init: can't reserve GPIO:%d !\n",
+ TWL4030_MSECURE_GPIO);
+ goto out;
+ }
+ /*
+ * TWL4030 will be in secure mode if msecure line from OMAP is low.
+ * Make msecure line high in order to change the TWL4030 RTC time
+ * and calender registers.
+ */
+ omap_set_gpio_direction(TWL4030_MSECURE_GPIO, 0); /*dir out */
+ omap_set_gpio_dataout(TWL4030_MSECURE_GPIO, 1);
+out:
+ return ret;
+}
+
+static void twl4030_rtc_exit(void)
+{
+ omap_free_gpio(TWL4030_MSECURE_GPIO);
+}
+
+static struct twl4030rtc_platform_data sdp2430_twl4030rtc_data = {
+ .init = &twl4030_rtc_init,
+ .exit = &twl4030_rtc_exit,
+};
+
+static struct platform_device sdp2430_twl4030rtc_device = {
+ .name = "twl4030_rtc",
+ .id = -1,
+ .dev = {
+ .platform_data = &sdp2430_twl4030rtc_data,
+ },
+};
+
static struct platform_device *sdp2430_devices[] __initdata = {
&sdp2430_smc91x_device,
&sdp2430_flash_device,
+ &sdp2430_kp_device,
+ &sdp2430_lcd_device,
+ &sdp2430_twl4030rtc_device,
+};
+
+static void ads7846_dev_init(void)
+{
+ if (omap_request_gpio(TS_GPIO) < 0)
+ printk(KERN_ERR "can't get ads746 pen down GPIO\n");
+
+ omap_set_gpio_direction(TS_GPIO, 1);
+
+ omap_set_gpio_debounce(TS_GPIO, 1);
+ omap_set_gpio_debounce_time(TS_GPIO, 0xa);
+}
+
+static int ads7846_get_pendown_state(void)
+{
+ return !omap_get_gpio_datain(TS_GPIO);
+}
+
+static struct ads7846_platform_data tsc2046_config __initdata = {
+ .get_pendown_state = ads7846_get_pendown_state,
+ .keep_vref_on = 1,
+};
+
+static struct omap2_mcspi_device_config tsc2046_mcspi_config = {
+ .turbo_mode = 0,
+ .single_channel = 0, /* 0: slave, 1: master */
+};
+
+static struct omap_lcd_config sdp2430_lcd_config __initdata = {
+ .ctrl_name = "internal",
+};
+
+static struct spi_board_info sdp2430_spi_board_info[] __initdata = {
+ [0] = {
+ /*
+ * TSC2046 operates at a max freqency of 2MHz, so
+ * operate slightly below at 1.5MHz
+ */
+ .modalias = "ads7846",
+ .bus_num = 1,
+ .chip_select = 0,
+ .max_speed_hz = 1500000,
+ .controller_data = &tsc2046_mcspi_config,
+ .irq = OMAP_GPIO_IRQ(TS_GPIO),
+ .platform_data = &tsc2046_config,
+ },
};
static inline void __init sdp2430_init_smc91x(void)
.enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
};
-static struct omap_board_config_kernel sdp2430_config[] = {
+static
+struct omap_serial_console_config sdp2430_serial_console_config __initdata = {
+ .console_uart = 1,
+ .console_speed = 115200,
+};
+
+static struct omap_mmc_config sdp2430_mmc_config __initdata = {
+ .mmc [0] = {
+ .enabled = 1,
+ .wire4 = 1,
+ },
+};
+
+static struct omap_board_config_kernel sdp2430_config[] __initdata = {
{OMAP_TAG_UART, &sdp2430_uart_config},
+ {OMAP_TAG_LCD, &sdp2430_lcd_config},
+ {OMAP_TAG_SERIAL_CONSOLE, &sdp2430_serial_console_config},
+ {OMAP_TAG_MMC, &sdp2430_mmc_config},
};
+static int __init omap2430_i2c_init(void)
+{
+ omap_register_i2c_bus(1, 400, NULL, 0);
+ omap_register_i2c_bus(2, 2600, NULL, 0);
+ return 0;
+}
+
static void __init omap_2430sdp_init(void)
{
platform_add_devices(sdp2430_devices, ARRAY_SIZE(sdp2430_devices));
omap_board_config = sdp2430_config;
omap_board_config_size = ARRAY_SIZE(sdp2430_config);
omap_serial_init();
+
+ sdp2430_flash_init();
+ usb_musb_init();
+
+ spi_register_board_info(sdp2430_spi_board_info,
+ ARRAY_SIZE(sdp2430_spi_board_info));
+ ads7846_dev_init();
+ hsmmc_init();
+
+ /* turn off secondary LCD backlight */
+ omap_set_gpio_direction(SECONDARY_LCD_GPIO, 0);
+ omap_set_gpio_dataout(SECONDARY_LCD_GPIO, 0);
}
static void __init omap_2430sdp_map_io(void)
{
+ omap2_set_globals_243x();
omap2_map_common_io();
}
+arch_initcall(omap2430_i2c_init);
+
MACHINE_START(OMAP_2430SDP, "OMAP2430 sdp2430 board")
/* Maintainer: Syed Khasim - Texas Instruments Inc */
.phys_io = 0x48000000,
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap2/board-3430sdp-flash.c
+ *
+ * Copyright (c) 2007 Texas Instruments
+ *
+ * Modified from mach-omap2/board-2430sdp-flash.c
+ * Author: Rohit Choraria <rohitkc@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/onenand_regs.h>
+#include <linux/types.h>
+#include <linux/io.h>
+
+#include <asm/mach/flash.h>
+#include <asm/arch/onenand.h>
+#include <asm/arch/board.h>
+#include <asm/arch/gpmc.h>
+
+static struct mtd_partition sdp_nor_partitions[] = {
+ /* bootloader (U-Boot, etc) in first sector */
+ {
+ .name = "Bootloader-NOR",
+ .offset = 0,
+ .size = SZ_256K,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ },
+ /* bootloader params in the next sector */
+ {
+ .name = "Params-NOR",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_256K,
+ .mask_flags = 0,
+ },
+ /* kernel */
+ {
+ .name = "Kernel-NOR",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_2M,
+ .mask_flags = 0
+ },
+ /* file system */
+ {
+ .name = "Filesystem-NOR",
+ .offset = MTDPART_OFS_APPEND,
+ .size = MTDPART_SIZ_FULL,
+ .mask_flags = 0
+ }
+};
+
+static struct flash_platform_data sdp_nor_data = {
+ .map_name = "cfi_probe",
+ .width = 2,
+ .parts = sdp_nor_partitions,
+ .nr_parts = ARRAY_SIZE(sdp_nor_partitions),
+};
+
+static struct resource sdp_nor_resource = {
+ .start = 0,
+ .end = 0,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device sdp_nor_device = {
+ .name = "omapflash",
+ .id = 0,
+ .dev = {
+ .platform_data = &sdp_nor_data,
+ },
+ .num_resources = 1,
+ .resource = &sdp_nor_resource,
+};
+
+static int sdp_onenand_setup(void __iomem *, int freq);
+
+static struct mtd_partition sdp_onenand_partitions[] = {
+ {
+ .name = "X-Loader-OneNAND",
+ .offset = 0,
+ .size = 4 * (64 * 2048),
+ .mask_flags = MTD_WRITEABLE /* force read-only */
+ },
+ {
+ .name = "U-Boot-OneNAND",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 2 * (64 * 2048),
+ .mask_flags = MTD_WRITEABLE /* force read-only */
+ },
+ {
+ .name = "U-Boot Environment-OneNAND",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 1 * (64 * 2048),
+ },
+ {
+ .name = "Kernel-OneNAND",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 16 * (64 * 2048),
+ },
+ {
+ .name = "File System-OneNAND",
+ .offset = MTDPART_OFS_APPEND,
+ .size = MTDPART_SIZ_FULL,
+ },
+};
+
+static struct omap_onenand_platform_data sdp_onenand_data = {
+ .parts = sdp_onenand_partitions,
+ .nr_parts = ARRAY_SIZE(sdp_onenand_partitions),
+ .onenand_setup = sdp_onenand_setup,
+ .dma_channel = -1, /* disable DMA in OMAP OneNAND driver */
+};
+
+static struct platform_device sdp_onenand_device = {
+ .name = "omap2-onenand",
+ .id = -1,
+ .dev = {
+ .platform_data = &sdp_onenand_data,
+ },
+};
+
+/*
+ * sdp_onenand_setup - The function configures the onenand flash.
+ * @onenand_base: Onenand base address
+ *
+ * @return int: Currently always returning zero.
+ */
+static int sdp_onenand_setup(void __iomem *onenand_base, int freq)
+{
+ /* Onenand setup does nothing at present */
+ return 0;
+}
+/**
+ * sdp3430_flash_init - Identify devices connected to GPMC and register.
+ *
+ * @return - void.
+ */
+void __init sdp3430_flash_init(void)
+{
+ u8 cs = 0;
+ u8 onenandcs = GPMC_CS_NUM + 1;
+
+ /* Configure start address and size of NOR device */
+ if (is_sil_rev_greater_than(OMAP3430_REV_ES1_0)) {
+ sdp_nor_resource.start = FLASH_BASE_SDPV2;
+ sdp_nor_resource.end = FLASH_BASE_SDPV2
+ + FLASH_SIZE_SDPV2 - 1;
+ } else {
+ sdp_nor_resource.start = FLASH_BASE_SDPV1;
+ sdp_nor_resource.end = FLASH_BASE_SDPV1
+ + FLASH_SIZE_SDPV1 - 1;
+ }
+
+ if (platform_device_register(&sdp_nor_device) < 0)
+ printk(KERN_ERR "Unable to register NOR device\n");
+
+ while (cs < GPMC_CS_NUM) {
+ u32 ret = 0;
+ ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
+
+ /*
+ * xloader/Uboot would have programmed the oneNAND
+ * base address for us This is a ugly hack. The proper
+ * way of doing this is to pass the setup of u-boot up
+ * to kernel using kernel params - something on the
+ * lines of machineID. Check if oneNAND is configured
+ */
+ if ((ret & 0x3F) == (ONENAND_MAP >> 24))
+ onenandcs = cs;
+ cs++;
+ }
+ if (onenandcs > GPMC_CS_NUM) {
+ printk(KERN_INFO "OneNAND: Unable to find configuration "
+ " in GPMC\n ");
+ return;
+ }
+
+ if (onenandcs < GPMC_CS_NUM) {
+ sdp_onenand_data.cs = onenandcs;
+ if (platform_device_register(&sdp_onenand_device) < 0)
+ printk(KERN_ERR "Unable to register OneNAND device\n");
+ }
+}
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap2/board-3430sdp.c
+ *
+ * Copyright (C) 2007 Texas Instruments
+ *
+ * Modified from mach-omap2/board-generic.c
+ *
+ * Initial code: Syed Mohammed Khasim
+ *
+ * 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/delay.h>
+#include <linux/input.h>
+#include <linux/workqueue.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/i2c/twl4030.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/mcspi.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/board.h>
+#include <asm/arch/usb-musb.h>
+#include <asm/arch/usb-ehci.h>
+#include <asm/arch/hsmmc.h>
+#include <asm/arch/common.h>
+#include <asm/arch/keypad.h>
+#include <asm/arch/dma.h>
+#include <asm/arch/gpmc.h>
+
+#include <asm/io.h>
+#include <asm/delay.h>
+
+#define SDP3430_SMC91X_CS 3
+
+#define ENABLE_VAUX3_DEDICATED 0x03
+#define ENABLE_VAUX3_DEV_GRP 0x20
+
+
+static struct resource sdp3430_smc91x_resources[] = {
+ [0] = {
+ .start = OMAP34XX_ETHR_START,
+ .end = OMAP34XX_ETHR_START + SZ_4K,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 0,
+ .end = 0,
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
+ },
+};
+
+static struct platform_device sdp3430_smc91x_device = {
+ .name = "smc91x",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(sdp3430_smc91x_resources),
+ .resource = sdp3430_smc91x_resources,
+};
+
+static int sdp3430_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_D),
+ KEY(5, 0, KEY_V),
+ KEY(5, 1, KEY_W),
+ KEY(5, 2, KEY_L),
+ KEY(5, 3, KEY_S),
+ KEY(5, 4, KEY_H),
+ 0
+};
+
+static struct omap_kp_platform_data sdp3430_kp_data = {
+ .rows = 5,
+ .cols = 6,
+ .keymap = sdp3430_keymap,
+ .keymapsize = ARRAY_SIZE(sdp3430_keymap),
+ .rep = 1,
+};
+
+static struct platform_device sdp3430_kp_device = {
+ .name = "omap_twl4030keypad",
+ .id = -1,
+ .dev = {
+ .platform_data = &sdp3430_kp_data,
+ },
+};
+
+static int ts_gpio;
+
+/**
+ * @brief ads7846_dev_init : Requests & sets GPIO line for pen-irq
+ *
+ * @return - void. If request gpio fails then Flag KERN_ERR.
+ */
+static void ads7846_dev_init(void)
+{
+ if (omap_request_gpio(ts_gpio) < 0) {
+ printk(KERN_ERR "can't get ads746 pen down GPIO\n");
+ return;
+ }
+
+ omap_set_gpio_direction(ts_gpio, 1);
+
+ omap_set_gpio_debounce(ts_gpio, 1);
+ omap_set_gpio_debounce_time(ts_gpio, 0xa);
+}
+
+static int ads7846_get_pendown_state(void)
+{
+ return !omap_get_gpio_datain(ts_gpio);
+}
+
+/*
+ * This enable(1)/disable(0) the voltage for TS: uses twl4030 calls
+ */
+static int ads7846_vaux_control(int vaux_cntrl)
+{
+ int ret = 0;
+
+#ifdef CONFIG_TWL4030_CORE
+ /* check for return value of ldo_use: if success it returns 0 */
+ if (vaux_cntrl == VAUX_ENABLE) {
+ if (ret != twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+ ENABLE_VAUX3_DEDICATED, TWL4030_VAUX3_DEDICATED))
+ return -EIO;
+ if (ret != twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+ ENABLE_VAUX3_DEV_GRP, TWL4030_VAUX3_DEV_GRP))
+ return -EIO;
+ } else if (vaux_cntrl == VAUX_DISABLE) {
+ if (ret != twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+ 0x00, TWL4030_VAUX3_DEDICATED))
+ return -EIO;
+ if (ret != twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+ 0x00, TWL4030_VAUX3_DEV_GRP))
+ return -EIO;
+ }
+#else
+ ret = -EIO;
+#endif
+ return ret;
+}
+
+static struct ads7846_platform_data tsc2046_config __initdata = {
+ .get_pendown_state = ads7846_get_pendown_state,
+ .keep_vref_on = 1,
+ .vaux_control = ads7846_vaux_control,
+};
+
+
+static struct omap2_mcspi_device_config tsc2046_mcspi_config = {
+ .turbo_mode = 0,
+ .single_channel = 1, /* 0: slave, 1: master */
+};
+
+static struct spi_board_info sdp3430_spi_board_info[] __initdata = {
+ [0] = {
+ /*
+ * TSC2046 operates at a max freqency of 2MHz, so
+ * operate slightly below at 1.5MHz
+ */
+ .modalias = "ads7846",
+ .bus_num = 1,
+ .chip_select = 0,
+ .max_speed_hz = 1500000,
+ .controller_data = &tsc2046_mcspi_config,
+ .irq = 0,
+ .platform_data = &tsc2046_config,
+ },
+};
+
+static struct platform_device sdp3430_lcd_device = {
+ .name = "sdp2430_lcd",
+ .id = -1,
+};
+
+static struct platform_device *sdp3430_devices[] __initdata = {
+ &sdp3430_smc91x_device,
+ &sdp3430_kp_device,
+ &sdp3430_lcd_device,
+};
+
+static inline void __init sdp3430_init_smc91x(void)
+{
+ int eth_cs;
+ unsigned long cs_mem_base;
+ int eth_gpio = 0;
+
+ eth_cs = SDP3430_SMC91X_CS;
+
+ if (gpmc_cs_request(eth_cs, SZ_16M, &cs_mem_base) < 0) {
+ printk(KERN_ERR "Failed to request GPMC mem for smc91x\n");
+ return;
+ }
+
+ sdp3430_smc91x_resources[0].start = cs_mem_base + 0x0;
+ sdp3430_smc91x_resources[0].end = cs_mem_base + 0xf;
+ udelay(100);
+
+ if (is_sil_rev_greater_than(OMAP3430_REV_ES1_0))
+ eth_gpio = OMAP34XX_ETHR_GPIO_IRQ_SDPV2;
+ else
+ eth_gpio = OMAP34XX_ETHR_GPIO_IRQ_SDPV1;
+
+ sdp3430_smc91x_resources[1].start = OMAP_GPIO_IRQ(eth_gpio);
+
+ if (omap_request_gpio(eth_gpio) < 0) {
+ printk(KERN_ERR "Failed to request GPIO%d for smc91x IRQ\n",
+ eth_gpio);
+ return;
+ }
+ omap_set_gpio_direction(eth_gpio, 1);
+}
+
+static void __init omap_3430sdp_init_irq(void)
+{
+ omap2_init_common_hw();
+ omap_init_irq();
+ omap_gpio_init();
+ sdp3430_init_smc91x();
+}
+
+static struct omap_uart_config sdp3430_uart_config __initdata = {
+ .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
+};
+
+static struct omap_lcd_config sdp3430_lcd_config __initdata = {
+ .ctrl_name = "internal",
+};
+
+static struct omap_mmc_config sdp3430_mmc_config __initdata = {
+ .mmc [0] = {
+ .enabled = 1,
+ .wire4 = 1,
+ },
+};
+
+static struct omap_board_config_kernel sdp3430_config[] __initdata = {
+ { OMAP_TAG_UART, &sdp3430_uart_config },
+ {OMAP_TAG_LCD, &sdp3430_lcd_config},
+ {OMAP_TAG_MMC, &sdp3430_mmc_config },
+};
+
+static int __init omap3430_i2c_init(void)
+{
+ omap_register_i2c_bus(1, 2600, NULL, 0);
+ omap_register_i2c_bus(2, 400, NULL, 0);
+ omap_register_i2c_bus(3, 400, NULL, 0);
+ return 0;
+}
+
+extern void __init sdp3430_flash_init(void);
+
+static void __init omap_3430sdp_init(void)
+{
+ platform_add_devices(sdp3430_devices, ARRAY_SIZE(sdp3430_devices));
+ omap_board_config = sdp3430_config;
+ omap_board_config_size = ARRAY_SIZE(sdp3430_config);
+ if (is_sil_rev_greater_than(OMAP3430_REV_ES1_0))
+ ts_gpio = OMAP34XX_TS_GPIO_IRQ_SDPV2;
+ else
+ ts_gpio = OMAP34XX_TS_GPIO_IRQ_SDPV1;
+ sdp3430_spi_board_info[0].irq = OMAP_GPIO_IRQ(ts_gpio);
+ spi_register_board_info(sdp3430_spi_board_info,
+ ARRAY_SIZE(sdp3430_spi_board_info));
+ ads7846_dev_init();
+ sdp3430_flash_init();
+ omap_serial_init();
+ usb_musb_init();
+ usb_ehci_init();
+ hsmmc_init();
+}
+
+static void __init omap_3430sdp_map_io(void)
+{
+ omap2_set_globals_343x();
+ omap2_map_common_io();
+}
+arch_initcall(omap3430_i2c_init);
+
+MACHINE_START(OMAP_3430SDP, "OMAP3430 3430SDP board")
+ /* Maintainer: Syed Khasim - Texas Instruments Inc */
+ .phys_io = 0x48000000,
+ .io_pg_offst = ((0xd8000000) >> 18) & 0xfffc,
+ .boot_params = 0x80000100,
+ .map_io = omap_3430sdp_map_io,
+ .init_irq = omap_3430sdp_init_irq,
+ .init_machine = omap_3430sdp_init,
+ .timer = &omap_timer,
+MACHINE_END
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap2/board-apollon-keys.c
+ *
+ * Copyright (C) 2007 Samsung Electronics
+ * Author: 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 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/gpio_keys.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/mux.h>
+
+#define SW_ENTER_GPIO16 16
+#define SW_UP_GPIO17 17
+#define SW_DOWN_GPIO58 58
+#define SW_LEFT_GPIO95 95
+#define SW_RIGHT_GPIO96 96
+#define SW_ESC_GPIO97 97
+
+static struct gpio_keys_button apollon_gpio_keys_buttons[] = {
+ [0] = {
+ .code = KEY_ENTER,
+ .gpio = SW_ENTER_GPIO16,
+ .desc = "enter sw",
+ },
+ [1] = {
+ .code = KEY_UP,
+ .gpio = SW_UP_GPIO17,
+ .desc = "up sw",
+ },
+ [2] = {
+ .code = KEY_DOWN,
+ .gpio = SW_DOWN_GPIO58,
+ .desc = "down sw",
+ },
+ [3] = {
+ .code = KEY_LEFT,
+ .gpio = SW_LEFT_GPIO95,
+ .desc = "left sw",
+ },
+ [4] = {
+ .code = KEY_RIGHT,
+ .gpio = SW_RIGHT_GPIO96,
+ .desc = "right sw",
+ },
+ [5] = {
+ .code = KEY_ESC,
+ .gpio = SW_ESC_GPIO97,
+ .desc = "esc sw",
+ },
+};
+
+static struct gpio_keys_platform_data apollon_gpio_keys = {
+ .buttons = apollon_gpio_keys_buttons,
+ .nbuttons = ARRAY_SIZE(apollon_gpio_keys_buttons),
+};
+
+static struct platform_device apollon_gpio_keys_device = {
+ .name = "gpio-keys",
+ .id = -1,
+ .dev = {
+ .platform_data = &apollon_gpio_keys,
+ },
+};
+
+static void __init apollon_sw_init(void)
+{
+ /* Enter SW - Y11 */
+ omap_cfg_reg(Y11_242X_GPIO16);
+ /* Up SW - AA12 */
+ omap_cfg_reg(AA12_242X_GPIO17);
+ /* Down SW - AA8 */
+ omap_cfg_reg(AA8_242X_GPIO58);
+
+ if (apollon_plus()) {
+ /* Left SW - P18 */
+ omap_cfg_reg(P18_24XX_GPIO95);
+ /* Right SW - M18 */
+ omap_cfg_reg(M18_24XX_GPIO96);
+ /* Esc SW - L14 */
+ omap_cfg_reg(L14_24XX_GPIO97);
+ } else
+ apollon_gpio_keys.nbuttons = 3;
+}
+
+static int __init omap_apollon_keys_init(void)
+{
+ apollon_sw_init();
+
+ return platform_device_register(&apollon_gpio_keys_device);
+}
+
+arch_initcall(omap_apollon_keys_init);
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap2/board-apollon-mmc.c
+ *
+ * Copyright (C) 2005-2007 Samsung Electronics
+ * Author: 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/mmc.h>
+
+#ifdef CONFIG_MMC_OMAP
+
+static struct device *mmc_device;
+
+static int apollon_mmc_set_power(struct device *dev, int slot, int power_on,
+ int vdd)
+{
+#ifdef CONFIG_MMC_DEBUG
+ dev_dbg(dev, "Set slot %d power: %s (vdd %d)\n", slot + 1,
+ power_on ? "on" : "off", vdd);
+#endif
+ if (slot != 0) {
+ dev_err(dev, "No such slot %d\n", slot + 1);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int apollon_mmc_set_bus_mode(struct device *dev, int slot, int bus_mode)
+{
+#ifdef CONFIG_MMC_DEBUG
+ dev_dbg(dev, "Set slot %d bus_mode %s\n", slot + 1,
+ bus_mode == MMC_BUSMODE_OPENDRAIN ? "open-drain" : "push-pull");
+#endif
+ if (slot != 0) {
+ dev_err(dev, "No such slot %d\n", slot + 1);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int apollon_mmc_late_init(struct device *dev)
+{
+ mmc_device = dev;
+
+ return 0;
+}
+
+static void apollon_mmc_cleanup(struct device *dev)
+{
+}
+
+static struct omap_mmc_platform_data apollon_mmc_data = {
+ .nr_slots = 1,
+ .switch_slot = NULL,
+ .init = apollon_mmc_late_init,
+ .cleanup = apollon_mmc_cleanup,
+ .slots[0] = {
+ .set_power = apollon_mmc_set_power,
+ .set_bus_mode = apollon_mmc_set_bus_mode,
+ .get_ro = NULL,
+ .get_cover_state = NULL,
+ .ocr_mask = MMC_VDD_30_31 | MMC_VDD_31_32 |
+ MMC_VDD_32_33 | MMC_VDD_33_34,
+ .name = "mmcblk",
+ },
+};
+
+void __init apollon_mmc_init(void)
+{
+ omap_set_mmc_info(1, &apollon_mmc_data);
+}
+
+#else /* !CONFIG_MMC_OMAP */
+
+void __init apollon_mmc_init(void)
+{
+}
+
+#endif /* CONFIG_MMC_OMAP */
/*
* linux/arch/arm/mach-omap2/board-apollon.c
*
- * Copyright (C) 2005,2006 Samsung Electronics
+ * Copyright (C) 2005-2008 Samsung Electronics
* Author: Kyungmin Park <kyungmin.park@samsung.com>
*
- * Modified from mach-omap/omap2/board-h4.c
+ * Modified from mach-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.
#include <linux/leds.h>
#include <linux/err.h>
#include <linux/clk.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/tsc210x.h>
+#include <asm/io.h>
#include <asm/hardware.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/arch/board.h>
#include <asm/arch/common.h>
#include <asm/arch/gpmc.h>
-#include <asm/arch/control.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
+#define LED3_GPIO92 92
+#define LED4_GPIO93 93
#define APOLLON_FLASH_CS 0
#define APOLLON_ETH_CS 1
+#define APOLLON_NOR_CS 3
+
+#define APOLLON_ONENAND_CS2_ADDRESS (0x00000e40 | (0x10000000 >> 24))
+#define APOLLON_EXT_CS3_ADDRESS (0x00000c40 | (0x18000000 >> 24))
static struct mtd_partition apollon_partitions[] = {
{
.resource = apollon_flash_resource,
};
+static struct mtd_partition apollon_nor_partitions[] = {
+ {
+ .name = "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_4M - SZ_256K,
+ },
+ {
+ .name = "application",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_8M + SZ_2M,
+ },
+ {
+ .name = "reserved",
+ .offset = MTDPART_OFS_APPEND,
+ .size = MTDPART_SIZ_FULL,
+ },
+};
+
+static struct flash_platform_data apollon_nor_data = {
+ .map_name = "cfi_probe",
+ .width = 2,
+ .parts = apollon_nor_partitions,
+ .nr_parts = ARRAY_SIZE(apollon_nor_partitions),
+};
+
+static struct resource apollon_nor_resource[] = {
+ [0] = {
+ .flags = IORESOURCE_MEM,
+ }
+};
+
+static struct platform_device apollon_nor_device = {
+ .name = "omapflash",
+ .id = -1,
+ .dev = {
+ .platform_data = &apollon_nor_data,
+ },
+ .num_resources = ARRAY_SIZE(apollon_nor_resource),
+ .resource = apollon_nor_resource,
+};
+
static void __init apollon_flash_init(void)
{
unsigned long base;
}
apollon_flash_resource[0].start = base;
apollon_flash_resource[0].end = base + SZ_128K - 1;
+
+ if (gpmc_cs_request(APOLLON_NOR_CS, SZ_32M, &base) < 0) {
+ printk(KERN_ERR "Cannot request NOR GPMC CS\n");
+ return;
+ }
+ apollon_nor_resource[0].start = base;
+ apollon_nor_resource[0].end = base + SZ_32M - 1;
}
static struct resource apollon_smc91x_resources[] = {
.id = -1,
};
-static struct omap_led_config apollon_led_config[] = {
+static struct gpio_led apollon_led_config[] = {
{
- .cdev = {
- .name = "apollon:led0",
- },
- .gpio = LED0_GPIO13,
+ .name = "d2",
+ .gpio = LED0_GPIO13,
+ .default_trigger = "heartbeat",
},
{
- .cdev = {
- .name = "apollon:led1",
- },
- .gpio = LED1_GPIO14,
+ .name = "d3",
+ .gpio = LED1_GPIO14,
},
{
- .cdev = {
- .name = "apollon:led2",
- },
- .gpio = LED2_GPIO15,
+ .name = "d4",
+ .gpio = LED2_GPIO15,
+ },
+ {
+ .name = "d5",
+ .gpio = LED3_GPIO92,
+ },
+ {
+ .name = "d6",
+ .gpio = LED4_GPIO93,
},
};
-static struct omap_led_platform_data apollon_led_data = {
- .nr_leds = ARRAY_SIZE(apollon_led_config),
+static struct gpio_led_platform_data apollon_led_data = {
+ .num_leds = ARRAY_SIZE(apollon_led_config),
.leds = apollon_led_config,
};
static struct platform_device apollon_led_device = {
- .name = "omap-led",
+ .name = "leds-gpio",
.id = -1,
.dev = {
.platform_data = &apollon_led_data,
static struct platform_device *apollon_devices[] __initdata = {
&apollon_onenand_device,
+ &apollon_nor_device,
&apollon_smc91x_device,
&apollon_lcd_device,
&apollon_led_device,
static inline void __init apollon_init_smc91x(void)
{
unsigned long base;
-
unsigned int rate;
struct clk *gpmc_fck;
int eth_cs;
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG6, 0x000003C2);
}
- if (gpmc_cs_request(APOLLON_ETH_CS, SZ_16M, &base) < 0) {
+ if (gpmc_cs_request(eth_cs, SZ_16M, &base) < 0) {
printk(KERN_ERR "Failed to request GPMC CS for smc91x\n");
goto out;
}
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);
- gpmc_cs_free(APOLLON_ETH_CS);
+ gpmc_cs_free(eth_cs);
goto out;
}
omap_set_gpio_direction(APOLLON_ETHR_GPIO_IRQ, 1);
apollon_init_smc91x();
}
+static struct tsc210x_config tsc_platform_data = {
+ .use_internal = 1,
+ .monitor = TSC_TEMP,
+ .mclk = "sys_clkout",
+};
+
+static struct spi_board_info apollon_spi_board_info[] = {
+ [0] = {
+ .modalias = "tsc2101",
+ .irq = OMAP_GPIO_IRQ(85),
+ .bus_num = 1,
+ .chip_select = 0,
+ .mode = SPI_MODE_1,
+ .max_speed_hz = 6000000,
+ .platform_data = &tsc_platform_data,
+ },
+};
+
static struct omap_uart_config apollon_uart_config __initdata = {
.enabled_uarts = (1 << 0) | (0 << 1) | (0 << 2),
};
+/*
+ * Note: If you want to detect card feature, please assign GPIO 37
+ */
static struct omap_mmc_config apollon_mmc_config __initdata = {
.mmc [0] = {
.enabled = 1,
.wire4 = 1,
- .wp_pin = -1,
- .power_pin = -1,
- .switch_pin = -1,
+ /* Use internal loop-back in MMC/SDIO Module Input Clock selection */
+ .internal_clock = 1,
},
};
.ctrl_name = "internal",
};
-static struct omap_board_config_kernel apollon_config[] = {
+static struct omap_board_config_kernel apollon_config[] __initdata = {
{ OMAP_TAG_UART, &apollon_uart_config },
{ OMAP_TAG_MMC, &apollon_mmc_config },
{ OMAP_TAG_USB, &apollon_usb_config },
{
/* 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)
-{
- 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,
- IRQF_SHARED, "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,
- IRQF_SHARED, "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,
- IRQF_SHARED, "down sw",
- &apollon_sw_interrupt))
- return;
+ if (apollon_plus()) {
+ /* LED3 - M15 */
+ omap_cfg_reg(M15_24XX_GPIO92);
+ /* LED4 - P20 */
+ omap_cfg_reg(P20_24XX_GPIO93);
+ } else
+ apollon_led_data.num_leds = 3;
}
static void __init apollon_usb_init(void)
omap_set_gpio_dataout(12, 0);
}
-static void __init omap_apollon_init(void)
+static void __init apollon_tsc_init(void)
{
- u32 v;
+ /* TSC2101 */
+ omap_cfg_reg(N15_24XX_GPIO85);
+ omap_request_gpio(85);
+ omap_set_gpio_direction(85, 1);
+
+ omap_cfg_reg(W14_24XX_SYS_CLKOUT); /* mclk */
+}
+static void __init apollon_cs_init(void)
+{
+ unsigned long base;
+ unsigned int rate;
+ struct clk *l3ck;
+ u32 value;
+ int cs, sync = 0;
+
+ l3ck = clk_get(NULL, "core_l3_ck");
+ if (IS_ERR(l3ck))
+ rate = 100000000;
+ else
+ rate = clk_get_rate(l3ck);
+
+ /* CS2: OneNAND */
+ cs = 2;
+ value = gpmc_cs_read_reg(0, GPMC_CS_CONFIG1);
+ gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, value);
+ value = gpmc_cs_read_reg(0, GPMC_CS_CONFIG2);
+ gpmc_cs_write_reg(cs, GPMC_CS_CONFIG2, value);
+ value = gpmc_cs_read_reg(0, GPMC_CS_CONFIG3);
+ gpmc_cs_write_reg(cs, GPMC_CS_CONFIG3, value);
+ value = gpmc_cs_read_reg(0, GPMC_CS_CONFIG4);
+ gpmc_cs_write_reg(cs, GPMC_CS_CONFIG4, value);
+ value = gpmc_cs_read_reg(0, GPMC_CS_CONFIG5);
+ gpmc_cs_write_reg(cs, GPMC_CS_CONFIG5, value);
+ value = gpmc_cs_read_reg(0, GPMC_CS_CONFIG6);
+ gpmc_cs_write_reg(cs, GPMC_CS_CONFIG6, value);
+
+ gpmc_cs_write_reg(cs, GPMC_CS_CONFIG7, APOLLON_ONENAND_CS2_ADDRESS);
+
+ /* CS3: External NOR */
+ cs = APOLLON_NOR_CS;
+ if (rate >= 160000000) {
+ sync = 1;
+ gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, 0xe5011211);
+ gpmc_cs_write_reg(cs, GPMC_CS_CONFIG2, 0x00090b01);
+ gpmc_cs_write_reg(cs, GPMC_CS_CONFIG3, 0x00020201);
+ gpmc_cs_write_reg(cs, GPMC_CS_CONFIG4, 0x09030b03);
+ gpmc_cs_write_reg(cs, GPMC_CS_CONFIG5, 0x010a0a0c);
+ gpmc_cs_write_reg(cs, GPMC_CS_CONFIG6, 0x00000000);
+ } else if (rate >= 130000000) {
+ /* Not yet know ... Use the async values */
+ gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, 0x00021201);
+ gpmc_cs_write_reg(cs, GPMC_CS_CONFIG2, 0x00121601);
+ gpmc_cs_write_reg(cs, GPMC_CS_CONFIG3, 0x00040401);
+ gpmc_cs_write_reg(cs, GPMC_CS_CONFIG4, 0x12061605);
+ gpmc_cs_write_reg(cs, GPMC_CS_CONFIG5, 0x01151317);
+ gpmc_cs_write_reg(cs, GPMC_CS_CONFIG6, 0x00000000);
+ } else {/* rate = 100000000 */
+ sync = 1;
+ gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, 0xe1001202);
+ gpmc_cs_write_reg(cs, GPMC_CS_CONFIG2, 0x00151501);
+ gpmc_cs_write_reg(cs, GPMC_CS_CONFIG3, 0x00050501);
+ gpmc_cs_write_reg(cs, GPMC_CS_CONFIG4, 0x0e070e07);
+ gpmc_cs_write_reg(cs, GPMC_CS_CONFIG5, 0x01131F1F);
+ gpmc_cs_write_reg(cs, GPMC_CS_CONFIG6, 0x00000000);
+ }
+
+ gpmc_cs_write_reg(cs, GPMC_CS_CONFIG7, APOLLON_EXT_CS3_ADDRESS);
+
+ if (gpmc_cs_request(cs, SZ_32M, &base) < 0) {
+ printk(KERN_ERR "Failed to request GPMC CS for external\n");
+ return;
+ }
+
+ /* Synchronous mode */
+ if (sync) {
+ void __iomem *addr = ioremap(base, SZ_32M);
+ writew(0xaa, addr + 0xaaa);
+ writew(0x55, addr + 0x554);
+ writew(0xc0, addr + 0x24aaa);
+ iounmap(addr);
+ }
+
+ gpmc_cs_free(cs);
+}
+
+static void __init omap_apollon_init(void)
+{
+ apollon_cs_init();
apollon_led_init();
- apollon_sw_init();
apollon_flash_init();
apollon_usb_init();
-
- /* REVISIT: where's the correct place */
- omap_cfg_reg(W19_24XX_SYS_NIRQ);
-
- /* Use Interal loop-back in MMC/SDIO Module Input Clock selection */
- v = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0);
- v |= (1 << 24);
- omap_ctrl_writel(v, OMAP2_CONTROL_DEVCONF0);
+ apollon_tsc_init();
/*
* Make sure the serial ports are muxed on at this point.
omap_board_config = apollon_config;
omap_board_config_size = ARRAY_SIZE(apollon_config);
omap_serial_init();
+ omap_register_i2c_bus(1, 100, NULL, 0);
+ omap_register_i2c_bus(2, 100, NULL, 0);
+
+ spi_register_board_info(apollon_spi_board_info,
+ ARRAY_SIZE(apollon_spi_board_info));
+
+ apollon_mmc_init();
}
static void __init omap_apollon_map_io(void)
{
+ omap2_set_globals_242x();
omap2_map_common_io();
}
},
};
-static struct omap_board_config_kernel generic_config[] = {
+static struct omap_board_config_kernel generic_config[] __initdata = {
{ OMAP_TAG_UART, &generic_uart_config },
{ OMAP_TAG_MMC, &generic_mmc_config },
};
omap_board_config = generic_config;
omap_board_config_size = ARRAY_SIZE(generic_config);
omap_serial_init();
+ omap_register_i2c_bus(1, 100, NULL, 0);
+ omap_register_i2c_bus(2, 100, NULL, 0);
}
static void __init omap_generic_map_io(void)
{
+ omap2_set_globals_242x(); /* should be 242x, 243x, or 343x */
omap2_map_common_io();
}
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap2/board-h4-mmc.c
+ *
+ * Copyright (C) 2007 Instituto Nokia de Tecnologia - INdT
+ * Authors: David Cohen <david.cohen@indt.org.br>
+ * Carlos Eduardo Aguiar <carlos.aguiar@indt.org.br>
+ *
+ * This code is based on linux/arch/arm/mach-omap2/board-n800-mmc.c, which is:
+ * Copyright (C) 2006 Nokia Corporation
+ * Author: Juha Yrjola
+ *
+ * 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 <asm/arch/mmc.h>
+#include <asm/arch/menelaus.h>
+
+#include <asm/mach-types.h>
+#include <linux/delay.h>
+
+#ifdef CONFIG_MMC_OMAP
+
+/* Bit mask for slots detection interrupts */
+#define SD1_CD_ST (1 << 0)
+#define SD2_CD_ST (1 << 1)
+
+static int slot1_cover_open;
+static int slot2_cover_open;
+static struct device *mmc_device;
+
+/*
+ * VMMC --> slot 1
+ * VDCDC3_APE, VMCS2_APE --> slot 2
+ */
+
+static int h4_mmc_switch_slot(struct device *dev, int slot)
+{
+ int r = 0;
+
+#ifdef CONFIG_MMC_DEBUG
+ dev_dbg(dev, "Choose slot %d\n", slot + 1);
+#endif
+ if (slot == 0) {
+ r = menelaus_enable_slot(2, 0);
+ r |= menelaus_enable_slot(1, 1);
+ } else {
+ r = menelaus_enable_slot(1, 0);
+ r |= menelaus_enable_slot(2, 1);
+ }
+
+ return r ? -ENODEV : 0;
+}
+
+static int h4_mmc_set_power(struct device *dev, int slot, int power_on,
+ int vdd)
+{
+ int mV = 0;
+
+#ifdef CONFIG_MMC_DEBUG
+ dev_dbg(dev, "Set slot %d power: %s (vdd %d)\n", slot + 1,
+ power_on ? "on" : "off", vdd);
+#endif
+ if (slot == 0) {
+ if (!power_on)
+ return menelaus_set_vmmc(3000);
+ switch (1 << vdd) {
+ case MMC_VDD_33_34:
+ case MMC_VDD_32_33:
+ case MMC_VDD_31_32:
+ mV = 3100;
+ break;
+ case MMC_VDD_30_31:
+ mV = 3000;
+ break;
+ case MMC_VDD_28_29:
+ mV = 2800;
+ break;
+ case MMC_VDD_165_195:
+ mV = 1850;
+ break;
+ default:
+ BUG();
+ }
+ return menelaus_set_vmmc(mV);
+ } else {
+ if (!power_on)
+ return menelaus_set_vdcdc(3, 3000);
+ switch (1 << vdd) {
+ case MMC_VDD_33_34:
+ case MMC_VDD_32_33:
+ mV = 3300;
+ break;
+ case MMC_VDD_30_31:
+ case MMC_VDD_29_30:
+ mV = 3000;
+ break;
+ case MMC_VDD_28_29:
+ case MMC_VDD_27_28:
+ mV = 2800;
+ break;
+ case MMC_VDD_24_25:
+ case MMC_VDD_23_24:
+ mV = 2400;
+ break;
+ case MMC_VDD_22_23:
+ case MMC_VDD_21_22:
+ mV = 2200;
+ break;
+ case MMC_VDD_20_21:
+ mV = 2000;
+ break;
+ case MMC_VDD_165_195:
+ mV = 1800;
+ break;
+ default:
+ BUG();
+ }
+ return menelaus_set_vdcdc(3, mV);
+ }
+ return 0;
+}
+
+static int h4_mmc_set_bus_mode(struct device *dev, int slot, int bus_mode)
+{
+ int r = 0;
+
+#ifdef CONFIG_MMC_DEBUG
+ dev_dbg(dev, "Set slot %d bus mode %s\n", slot + 1,
+ bus_mode == MMC_BUSMODE_OPENDRAIN ? "open-drain" : "push-pull");
+#endif
+ BUG_ON(slot != 0 && slot != 1);
+ slot++;
+ switch (bus_mode) {
+ case MMC_BUSMODE_OPENDRAIN:
+ r = menelaus_set_mmc_opendrain(slot, 1);
+ break;
+ case MMC_BUSMODE_PUSHPULL:
+ r = menelaus_set_mmc_opendrain(slot, 0);
+ break;
+ default:
+ BUG();
+ }
+ if (r != 0 && printk_ratelimit()) {
+ dev_err(dev, "MMC: unable to set bus mode for slot %d\n",
+ slot);
+ }
+ return r;
+}
+
+static int h4_mmc_slot1_cover_state(struct device *dev, int slot)
+{
+ BUG_ON(slot != 0);
+ return slot1_cover_open;
+}
+
+static int h4_mmc_slot2_cover_state(struct device *dev, int slot)
+{
+ BUG_ON(slot != 1);
+ return slot2_cover_open;
+}
+
+static void h4_mmc_slot_callback(void *data, u8 card_mask)
+{
+ int cover_open;
+
+ cover_open = (card_mask & SD1_CD_ST) ? 0 : 1;
+ if (cover_open != slot1_cover_open) {
+ slot1_cover_open = cover_open;
+ omap_mmc_notify_cover_event(mmc_device, 0, slot1_cover_open);
+ }
+
+ cover_open = (card_mask & SD2_CD_ST) ? 0 : 1;
+ if (cover_open != slot2_cover_open) {
+ slot2_cover_open = cover_open;
+ omap_mmc_notify_cover_event(mmc_device, 1, slot2_cover_open);
+ }
+}
+
+static int h4_mmc_late_init(struct device *dev)
+{
+ int r;
+
+ mmc_device = dev;
+
+ r = menelaus_set_mmc_slot(1, 0, 0, 1);
+ if (r < 0)
+ goto out;
+ r = menelaus_set_mmc_slot(2, 0, 0, 1);
+ if (r < 0)
+ goto out;
+
+ r = menelaus_get_slot_pin_states();
+ if (r < 0)
+ goto out;
+
+ if (r & SD1_CD_ST)
+ slot1_cover_open = 1;
+ else
+ slot1_cover_open = 0;
+
+ /* Slot pin bits seem to be inversed until first swith change,
+ * but just for slot 2
+ */
+ if ((r == 0xf) || (r == (0xf & ~SD2_CD_ST)))
+ r = ~r;
+
+ if (r & SD2_CD_ST)
+ slot2_cover_open = 1;
+ else
+ slot2_cover_open = 0;
+
+ r = menelaus_register_mmc_callback(h4_mmc_slot_callback, NULL);
+
+out:
+ return r;
+}
+
+static void h4_mmc_cleanup(struct device *dev)
+{
+ menelaus_unregister_mmc_callback();
+}
+
+static struct omap_mmc_platform_data h4_mmc_data = {
+ .nr_slots = 2,
+ .switch_slot = h4_mmc_switch_slot,
+ .init = h4_mmc_late_init,
+ .cleanup = h4_mmc_cleanup,
+ .slots[0] = {
+ .set_power = h4_mmc_set_power,
+ .set_bus_mode = h4_mmc_set_bus_mode,
+ .get_ro = NULL,
+ .get_cover_state= h4_mmc_slot1_cover_state,
+ .ocr_mask = MMC_VDD_165_195 |
+ MMC_VDD_28_29 | MMC_VDD_30_31 |
+ MMC_VDD_32_33 | MMC_VDD_33_34,
+ .name = "slot1",
+ },
+ .slots[1] = {
+ .set_power = h4_mmc_set_power,
+ .set_bus_mode = h4_mmc_set_bus_mode,
+ .get_ro = NULL,
+ .get_cover_state= h4_mmc_slot2_cover_state,
+ .ocr_mask = MMC_VDD_165_195 | MMC_VDD_20_21 |
+ MMC_VDD_21_22 | MMC_VDD_22_23 | MMC_VDD_23_24 |
+ MMC_VDD_24_25 | MMC_VDD_27_28 | MMC_VDD_28_29 |
+ MMC_VDD_29_30 | MMC_VDD_30_31 | MMC_VDD_32_33 |
+ MMC_VDD_33_34,
+ .name = "slot2",
+ },
+};
+
+void __init h4_mmc_init(void)
+{
+ omap_set_mmc_info(1, &h4_mmc_data);
+}
+
+#else
+
+void __init h4_mmc_init(void)
+{
+}
+
+#endif
+
#include <linux/input.h>
#include <linux/err.h>
#include <linux/clk.h>
+#include <linux/i2c.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/tsc210x.h>
+
+#include <media/v4l2-int-device.h>
#include <asm/hardware.h>
#include <asm/mach-types.h>
#include <asm/io.h>
+#include <../drivers/media/video/ov9640.h>
+
#define H4_FLASH_CS 0
#define H4_SMC91X_CS 1
/* Select between the IrDA and aGPS module
*/
+#if defined(CONFIG_OMAP_IR) || defined(CONFIG_OMAP_IR_MODULE)
static int h4_select_irda(struct device *dev, int state)
{
unsigned char expa;
return 0;
}
+#else
+static int h4_select_irda(struct device *dev, int state) { return 0; }
+static int h4_transceiver_mode(struct device *dev, int mode) { return 0; }
+#endif
static struct omap_irda_config h4_irda_data = {
.transceiver_cap = IR_SIRMODE | IR_MIRMODE | IR_FIRMODE,
OMAP2_SYSBOOT_1_MASK | OMAP2_SYSBOOT_0_MASK));
}
+/* FIXME: This function should be moved to some other file, gpmc.c? */
+
/* H4-2420's always used muxed mode, H4-2422's always use non-muxed
*
* Note: OMAP-GIT doesn't correctly do is_cpu_omap2422 and is_cpu_omap2423
}
static struct omap_uart_config h4_uart_config __initdata = {
+#ifdef CONFIG_MACH_OMAP2_H4_USB1
+ .enabled_uarts = ((1 << 0) | (1 << 1)),
+#else
.enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
+#endif
};
static struct omap_mmc_config h4_mmc_config __initdata = {
.mmc [0] = {
.enabled = 1,
.wire4 = 1,
- .wp_pin = -1,
- .power_pin = -1,
- .switch_pin = -1,
+ },
+ .mmc [1] = {
+ .enabled = 1,
+ .wire4 = 1,
},
};
+extern struct omap_mmc_platform_data h4_mmc_data;
+
static struct omap_lcd_config h4_lcd_config __initdata = {
.ctrl_name = "internal",
};
-static struct omap_board_config_kernel h4_config[] = {
+static struct omap_usb_config h4_usb_config __initdata = {
+#ifdef CONFIG_MACH_OMAP2_H4_USB1
+ /* NOTE: usb1 could also be used with 3 wire signaling */
+ .pins[1] = 4,
+#endif
+
+#ifdef CONFIG_MACH_OMAP_H4_OTG
+ /* S1.10 ON -- USB OTG port
+ * usb0 switched to Mini-AB port and isp1301 transceiver;
+ * S2.POS3 = OFF, S2.POS4 = ON ... to allow battery charging
+ */
+ .otg = 1,
+ .pins[0] = 4,
+#ifdef CONFIG_USB_GADGET_OMAP
+ /* use OTG cable, or standard A-to-MiniB */
+ .hmc_mode = 0x14, /* 0:dev/otg 1:host 2:disable */
+#elif defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+ /* use OTG cable, or NONSTANDARD (B-to-MiniB) */
+ .hmc_mode = 0x11, /* 0:host 1:host 2:disable */
+#endif /* XX */
+
+#else
+ /* S1.10 OFF -- usb "download port"
+ * usb0 switched to Mini-B port and isp1105 transceiver;
+ * S2.POS3 = ON, S2.POS4 = OFF ... to enable battery charging
+ */
+ .register_dev = 1,
+ .pins[0] = 3,
+/* .hmc_mode = 0x14,*/ /* 0:dev 1:host 2:disable */
+ .hmc_mode = 0x00, /* 0:dev|otg 1:disable 2:disable */
+#endif
+};
+
+/* ----------------------------------------------------------------------- */
+
+static struct tsc210x_config tsc_platform_data = {
+ .use_internal = 1,
+ .monitor = TSC_VBAT | TSC_TEMP,
+ /* REVISIT temp calibration data -- board-specific; from EEPROM? */
+ .mclk = "sys_clkout",
+};
+
+static struct spi_board_info h4_spi_board_info[] __initdata = {
+ {
+ .modalias = "tsc2101",
+ .bus_num = 1,
+ .chip_select = 0,
+ .mode = SPI_MODE_1,
+ .irq = OMAP_GPIO_IRQ(93),
+ .max_speed_hz = 16000000,
+ .platform_data = &tsc_platform_data,
+ },
+
+ /* nCS1 -- to lcd board, but unused
+ * nCS2 -- to WLAN/miniPCI
+ */
+};
+
+/* ----------------------------------------------------------------------- */
+
+static struct omap_board_config_kernel h4_config[] __initdata = {
{ OMAP_TAG_UART, &h4_uart_config },
{ OMAP_TAG_MMC, &h4_mmc_config },
{ OMAP_TAG_LCD, &h4_lcd_config },
+ { OMAP_TAG_USB, &h4_usb_config },
+};
+
+#ifdef CONFIG_MACH_OMAP_H4_TUSB
+
+#include <linux/usb/musb.h>
+
+static struct musb_hdrc_platform_data tusb_data = {
+ .mode = MUSB_OTG,
+ .min_power = 25, /* x2 = 50 mA drawn from VBUS as peripheral */
+
+ /* 1.8V supplied by Menelaus, other voltages supplied by VBAT;
+ * so no switching.
+ */
+};
+
+static void __init tusb_evm_setup(void)
+{
+ static char announce[] __initdata =
+ KERN_INFO "TUSB 6010 EVM\n";
+ int irq;
+ unsigned dmachan = 0;
+
+ /* There are at least 32 different combinations of boards that
+ * are loosely called "H4", with a 2420 ... different OMAP chip
+ * revisions (with pin mux changes for DMAREQ, GPMC errata, etc),
+ * modifications of the CPU board, mainboard, EVM, TUSB etc.
+ * Plus omap2422, omap2423, etc.
+ *
+ * So you might need to tweak this setup to make the TUSB EVM
+ * behave on your particular setup ...
+ */
+
+ /* Already set up: GPMC AD[0..15], CLK, nOE, nWE, nADV_ALE */
+ omap_cfg_reg(E2_GPMC_NCS2);
+ omap_cfg_reg(L2_GPMC_NCS7);
+ omap_cfg_reg(M1_GPMC_WAIT2);
+
+ switch ((system_rev >> 8) & 0x0f) {
+ case 0: /* ES 1.0 */
+ case 1: /* ES 2.0 */
+ /* Assume early board revision without optional ES2.0
+ * rework to swap J15 & AA10 so DMAREQ0 works
+ */
+ omap_cfg_reg(AA10_242X_GPIO13);
+ irq = 13;
+ /* omap_cfg_reg(J15_24XX_DMAREQ0); */
+ break;
+ default:
+ /* Later Menelaus boards can support all 6 DMA request
+ * lines, at the price of boot flash A23-A26.
+ */
+ omap_cfg_reg(J15_24XX_GPIO99);
+ irq = 99;
+ dmachan = (1 << 1) | (1 << 0);
+#if !(defined(CONFIG_MTD_OMAP_NOR) || defined(CONFIG_MTD_OMAP_NOR_MODULE))
+ dmachan |= (1 << 5) | (1 << 4) (1 << 3) | (1 << 2);
+#endif
+ break;
+ }
+
+ if (tusb6010_setup_interface(&tusb_data,
+ TUSB6010_REFCLK_24, /* waitpin */ 2,
+ /* async cs */ 2, /* sync cs */ 7,
+ irq, dmachan) == 0)
+ printk(announce);
+}
+
+#endif
+
+#if defined(CONFIG_VIDEO_OV9640) || defined(CONFIG_VIDEO_OV9640_MODULE)
+/*
+ * 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, 0x8F }, /* COM7, CLKRC, COM8 */
+ { 0x01, 0x80 }, { 0x02, 0x80 }, { 0x04, 0x00 }, /* BLUE, RED, COM1 */
+ { 0x0E, 0x81 }, { 0x0F, 0x4F }, { 0x14, 0x4A }, /* 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, 0x8F }, { 0x00, 0x7F }, /* GST15, COM8 */
+ { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+
+static int ov9640_sensor_power_set(int power)
+{
+ unsigned char expa;
+ int err;
+
+ /* read current state of GPIO EXPA outputs */
+ if ((err = read_gpio_expa(&expa, 0x20))) {
+ printk(KERN_ERR "Error reading GPIO EXPA 0x20\n");
+ return err;
+ }
+
+ expa = power ? expa | 0x80 : expa & ~0x08;
+
+ /* Set GPIO EXPA P3 (CAMERA_MODULE_EN) to power-up sensor */
+ if ((err = write_gpio_expa(expa, 0x20))) {
+ printk(KERN_ERR "Error writing to GPIO EXPA 0x20\n");
+ return err;
+ }
+
+ if (power) {
+ /* read current state of GPIO EXPA outputs */
+ if ((err = read_gpio_expa(&expa, 0x22))) {
+ printk(KERN_ERR "Error reading GPIO EXPA\n");
+ return err;
+ }
+ /* Clear GPIO EXPA P7 (CAM_RST) */
+ if ((err = write_gpio_expa(expa & ~0x80, 0x22))) {
+ printk(KERN_ERR "Error writing to GPIO EXPA\n");
+ return err;
+ }
+ }
+
+ return err;
+}
+
+static struct v4l2_ifparm ifparm = {
+ .if_type = V4L2_IF_TYPE_BT656,
+ .u = {
+ .bt656 = {
+ .frame_start_on_rising_vs = 1,
+ .nobt_vs_inv = 1,
+ .mode = V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT,
+ .clock_min = OV9640_XCLK_MIN,
+ .clock_max = OV9640_XCLK_MAX,
+ },
+ },
+};
+
+static int ov9640_ifparm(struct v4l2_ifparm *p)
+{
+ *p = ifparm;
+
+ return 0;
+}
+
+static struct ov9640_platform_data h4_ov9640_platform_data = {
+ .power_set = ov9640_sensor_power_set,
+ .default_regs = ov9640_common,
+ .ifparm = ov9640_ifparm,
+};
+#endif
+
+static struct i2c_board_info __initdata h4_i2c_board_info[] = {
+ {
+ I2C_BOARD_INFO("rtc-rs5c372", 0x32),
+ .type = "rv5c387a",
+ /* no IRQ wired to OMAP; nINTB goes to AGPS */
+ },
+ {
+ I2C_BOARD_INFO("menelaus", 0x72),
+ .irq = INT_24XX_SYS_NIRQ,
+ },
+ {
+ I2C_BOARD_INFO("isp1301_omap", 0x2d),
+ .type = "isp1301_omap",
+ .irq = OMAP_GPIO_IRQ(125),
+ },
+#if defined(CONFIG_VIDEO_OV9640) || defined(CONFIG_VIDEO_OV9640_MODULE)
+ {
+ I2C_BOARD_INFO("ov9640", 0x30),
+ .platform_data = &h4_ov9640_platform_data,
+ },
+#endif
};
static void __init omap_h4_init(void)
}
#endif
+#ifdef CONFIG_MACH_OMAP2_H4_USB1
+ /* S3.3 controls whether these pins are for UART2 or USB1 */
+ omap_cfg_reg(N14_24XX_USB1_SE0);
+ omap_cfg_reg(P15_24XX_USB1_DAT);
+ omap_cfg_reg(W20_24XX_USB1_TXEN);
+ omap_cfg_reg(V19_24XX_USB1_RCV);
+#endif
+
+ /* Menelaus interrupt */
+ omap_cfg_reg(W19_24XX_SYS_NIRQ);
+
platform_add_devices(h4_devices, ARRAY_SIZE(h4_devices));
omap_board_config = h4_config;
omap_board_config_size = ARRAY_SIZE(h4_config);
omap_serial_init();
+ h4_mmc_init();
+ omap_register_i2c_bus(1, 100, h4_i2c_board_info,
+ ARRAY_SIZE(h4_i2c_board_info));
+
+ /* smc91x, debug leds, ps/2, extra uarts */
+ h4_init_debug();
+
+#ifdef CONFIG_MACH_OMAP_H4_TUSB
+ tusb_evm_setup();
+#endif
+
+ /* defaults seem ok for:
+ * omap_cfg_reg(U18_24XX_SPI1_SCK);
+ * omap_cfg_reg(V20_24XX_SPI1_MOSI);
+ * omap_cfg_reg(T18_24XX_SPI1_MISO);
+ * omap_cfg_reg(U19_24XX_SPI1_NCS0);
+ */
+
+ /* TSC2101 */
+ omap_cfg_reg(P20_24XX_GPIO93);
+ gpio_request(93, "tsc_irq");
+ gpio_direction_input(93);
+
+ omap_cfg_reg(W14_24XX_SYS_CLKOUT); /* mclk */
+ /* defaults seem ok for:
+ * omap_cfg_reg(Y15_EAC_AC_SCLK); // bclk
+ * omap_cfg_reg(R14_EAC_AC_FS);
+ * omap_cfg_reg(V15_EAC_AC_DOUT);
+ * omap_cfg_reg(W15_EAC_AC_DIN);
+ */
+
+ spi_register_board_info(h4_spi_board_info,
+ ARRAY_SIZE(h4_spi_board_info));
}
static void __init omap_h4_map_io(void)
{
+ omap2_set_globals_242x();
omap2_map_common_io();
}
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap2/board-n800-audio.c
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Contact: Juha Yrjola
+ * Jarkko Nikula <jarkko.nikula@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/spi/tsc2301.h>
+
+#include <asm/io.h>
+#include <asm/arch/eac.h>
+
+#include <asm/arch/dsp_common.h>
+
+#if defined(CONFIG_SPI_TSC2301_AUDIO) && defined(CONFIG_SND_OMAP24XX_EAC)
+#define AUDIO_ENABLED
+
+static struct clk *sys_clkout2;
+static struct clk *sys_clkout2_src;
+static struct clk *func96m_clk;
+static struct device *eac_device;
+static struct device *tsc2301_device;
+
+static int enable_audio;
+static int audio_ok;
+static spinlock_t audio_lock;
+
+/*
+ * Leaving EAC and sys_clkout2 pins multiplexed to those subsystems results
+ * in about 2 mA extra current leak when audios are powered down. The
+ * workaround is to multiplex them to protected mode (with pull-ups enabled)
+ * whenever audio is not being used.
+ */
+static int eac_mux_disabled = 0;
+static int clkout2_mux_disabled = 0;
+static u32 saved_mux[2];
+
+static void n800_enable_eac_mux(void)
+{
+ if (!eac_mux_disabled)
+ return;
+ __raw_writel(saved_mux[1], IO_ADDRESS(0x48000124));
+ eac_mux_disabled = 0;
+}
+
+static void n800_disable_eac_mux(void)
+{
+ if (eac_mux_disabled) {
+ WARN_ON(eac_mux_disabled);
+ return;
+ }
+ saved_mux[1] = __raw_readl(IO_ADDRESS(0x48000124));
+ __raw_writel(0x1f1f1f1f, IO_ADDRESS(0x48000124));
+ eac_mux_disabled = 1;
+}
+
+static void n800_enable_clkout2_mux(void)
+{
+ if (!clkout2_mux_disabled)
+ return;
+ __raw_writel(saved_mux[0], IO_ADDRESS(0x480000e8));
+ clkout2_mux_disabled = 0;
+}
+
+static void n800_disable_clkout2_mux(void)
+{
+ u32 l;
+
+ if (clkout2_mux_disabled) {
+ WARN_ON(clkout2_mux_disabled);
+ return;
+ }
+ saved_mux[0] = __raw_readl(IO_ADDRESS(0x480000e8));
+ l = saved_mux[0] & ~0xff;
+ l |= 0x1f;
+ __raw_writel(l, IO_ADDRESS(0x480000e8));
+ clkout2_mux_disabled = 1;
+}
+
+static int n800_eac_enable_ext_clocks(struct device *dev)
+{
+ BUG_ON(tsc2301_device == NULL);
+ n800_enable_eac_mux();
+ tsc2301_mixer_enable_mclk(tsc2301_device);
+
+ return 0;
+}
+
+static void n800_eac_disable_ext_clocks(struct device *dev)
+{
+ BUG_ON(tsc2301_device == NULL);
+ tsc2301_mixer_disable_mclk(tsc2301_device);
+ n800_disable_eac_mux();
+}
+
+static int n800_audio_set_power(void *pdata, int dac, int adc)
+{
+ BUG_ON(pdata != tsc2301_device);
+ tsc2301_mixer_set_power(tsc2301_device, dac, adc);
+
+ return 0;
+}
+
+static int n800_audio_register_controls(void *pdata, struct snd_card *card)
+{
+ BUG_ON(pdata != tsc2301_device);
+ return tsc2301_mixer_register_controls(tsc2301_device, card);
+}
+
+static struct eac_codec n800_eac_codec = {
+ .mclk_src = EAC_MCLK_EXT_2x12288000,
+ .codec_mode = EAC_CODEC_I2S_MASTER,
+ .codec_conf.i2s.polarity_changed_mode = 0,
+ .codec_conf.i2s.sync_delay_enable = 0,
+ .default_rate = 48000,
+ .set_power = n800_audio_set_power,
+ .register_controls = n800_audio_register_controls,
+ .short_name = "TSC2301",
+};
+
+static int n800_register_codec(void)
+{
+ int r, do_enable = 0;
+ unsigned long flags;
+
+ n800_eac_codec.private_data = tsc2301_device;
+ r = eac_register_codec(eac_device, &n800_eac_codec);
+ if (r < 0)
+ return r;
+ spin_lock_irqsave(&audio_lock, flags);
+ audio_ok = 1;
+ if (enable_audio)
+ do_enable = 1;
+ spin_unlock_irqrestore(&audio_lock, flags);
+ if (do_enable)
+ eac_set_mode(eac_device, 1, 1);
+ return 0;
+}
+
+static void n800_unregister_codec(void)
+{
+ audio_ok = 0;
+ eac_unregister_codec(eac_device);
+ eac_set_mode(eac_device, 0, 0);
+}
+
+static int n800_eac_init(struct device *dev)
+{
+ int r;
+
+ BUG_ON(eac_device != NULL);
+ eac_device = dev;
+ if (tsc2301_device != NULL) {
+ r = n800_register_codec();
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
+static void n800_eac_cleanup(struct device *dev)
+{
+ eac_device = NULL;
+ if (tsc2301_device != NULL)
+ n800_unregister_codec();
+}
+
+static int n800_codec_get_clocks(struct device *dev)
+{
+ sys_clkout2_src = clk_get(dev, "sys_clkout2_src");
+ if (IS_ERR(sys_clkout2_src)) {
+ dev_err(dev, "Could not get sys_clkout2_src clock\n");
+ return -ENODEV;
+ }
+ sys_clkout2 = clk_get(dev, "sys_clkout2");
+ if (IS_ERR(sys_clkout2)) {
+ dev_err(dev, "Could not get sys_clkout2 clock\n");
+ clk_put(sys_clkout2_src);
+ return -ENODEV;
+ }
+ /* configure 12 MHz output on SYS_CLKOUT2. Therefore we must use
+ * 96 MHz as its parent in order to get 12 MHz */
+ func96m_clk = clk_get(dev, "func_96m_ck");
+ if (IS_ERR(func96m_clk)) {
+ dev_err(dev, "Could not get func 96M clock\n");
+ clk_put(sys_clkout2);
+ clk_put(sys_clkout2_src);
+ return -ENODEV;
+ }
+
+ clk_set_parent(sys_clkout2_src, func96m_clk);
+ clk_set_rate(sys_clkout2, 12000000);
+
+ return 0;
+}
+
+static void n800_codec_put_clocks(struct device *dev)
+{
+ clk_put(func96m_clk);
+ clk_put(sys_clkout2);
+ clk_put(sys_clkout2_src);
+}
+
+static int n800_codec_enable_clock(struct device *dev)
+{
+ n800_enable_clkout2_mux();
+ return clk_enable(sys_clkout2);
+}
+
+static void n800_codec_disable_clock(struct device *dev)
+{
+ clk_disable(sys_clkout2);
+ n800_disable_clkout2_mux();
+}
+
+static int n800_codec_init(struct device *dev)
+{
+ int r;
+
+ BUG_ON(tsc2301_device != NULL);
+ tsc2301_device = dev;
+ if ((r = n800_codec_get_clocks(dev)) < 0)
+ return r;
+ if (eac_device != NULL) {
+ r = n800_register_codec();
+ if (r < 0) {
+ n800_codec_put_clocks(dev);
+ return r;
+ }
+ }
+ return 0;
+}
+
+static void n800_codec_cleanup(struct device *dev)
+{
+ tsc2301_device = NULL;
+ if (eac_device != NULL)
+ n800_unregister_codec();
+ n800_codec_put_clocks(dev);
+}
+
+static struct eac_platform_data n800_eac_data = {
+ .init = n800_eac_init,
+ .cleanup = n800_eac_cleanup,
+ .enable_ext_clocks = n800_eac_enable_ext_clocks,
+ .disable_ext_clocks = n800_eac_disable_ext_clocks,
+};
+
+static const struct tsc2301_mixer_gpio n800_mixer_gpios[] = {
+ {
+ .name = "Headset Amplifier",
+ .gpio = 1,
+ .deactivate_on_pd = 1,
+ }, {
+ .name = "Speaker Amplifier",
+ .gpio = 2,
+ .def_enable = 1,
+ .deactivate_on_pd = 1,
+ }, {
+ .name = "Headset Mic Select",
+ .gpio = 3,
+ }
+};
+
+static struct platform_device retu_headset_device = {
+ .name = "retu-headset",
+ .id = -1,
+ .dev = {
+ .release = NULL,
+ },
+};
+
+void __init n800_audio_init(struct tsc2301_platform_data *tc)
+{
+ spin_lock_init(&audio_lock);
+
+ if (platform_device_register(&retu_headset_device) < 0)
+ return;
+ omap_init_eac(&n800_eac_data);
+
+ tc->pll_pdc = 7;
+ tc->pll_a = 7;
+ tc->pll_n = 9;
+ tc->pll_output = 1;
+ tc->mclk_ratio = TSC2301_MCLK_256xFS;
+ tc->i2s_sample_rate = TSC2301_I2S_SR_48000;
+ tc->i2s_format = TSC2301_I2S_FORMAT0;
+ tc->power_down_blocks = TSC2301_REG_PD_MISC_MOPD;
+ tc->mixer_gpios = n800_mixer_gpios;
+ tc->n_mixer_gpios = ARRAY_SIZE(n800_mixer_gpios);
+ tc->codec_init = n800_codec_init;
+ tc->codec_cleanup = n800_codec_cleanup;
+ tc->enable_clock = n800_codec_enable_clock;
+ tc->disable_clock = n800_codec_disable_clock;
+}
+
+#else
+
+void __init n800_audio_init(struct tsc2301_platform_data *tc)
+{
+}
+
+#endif
+
+#ifdef CONFIG_OMAP_DSP
+
+int n800_audio_enable(struct dsp_kfunc_device *kdev, int stage)
+{
+#ifdef AUDIO_ENABLED
+ unsigned long flags;
+ int do_enable = 0;
+
+ spin_lock_irqsave(&audio_lock, flags);
+
+ pr_debug("DSP power up request (audio codec %sinitialized)\n",
+ audio_ok ? "" : "not ");
+
+ if (enable_audio)
+ goto out;
+ enable_audio = 1;
+ if (audio_ok)
+ do_enable = 1;
+out:
+ spin_unlock_irqrestore(&audio_lock, flags);
+ if (do_enable)
+ eac_set_mode(eac_device, 1, 1);
+#endif
+ return 0;
+}
+
+int n800_audio_disable(struct dsp_kfunc_device *kdev, int stage)
+{
+#ifdef AUDIO_ENABLED
+ unsigned long flags;
+ int do_disable = 0;
+
+ spin_lock_irqsave(&audio_lock, flags);
+
+ pr_debug("DSP power down request (audio codec %sinitialized)\n",
+ audio_ok ? "" : "not ");
+
+ if (!enable_audio)
+ goto out;
+ enable_audio = 0;
+ if (audio_ok)
+ do_disable = 1;
+out:
+ spin_unlock_irqrestore(&audio_lock, flags);
+ if (do_disable)
+ eac_set_mode(eac_device, 0, 0);
+#endif
+ return 0;
+}
+
+#endif /* CONFIG_OMAP_DSP */
--- /dev/null
+/*
+ * Nokia N800 platform-specific data for Bluetooth
+ *
+ * Copyright (C) 2005, 2006 Nokia Corporation
+ * Contact: Ville Tervo <ville.tervo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <asm/arch/board.h>
+
+static struct platform_device n800_bt_device = {
+ .name = "hci_h4p",
+ .id = -1,
+ .num_resources = 0,
+};
+
+void __init n800_bt_init(void)
+{
+ const struct omap_bluetooth_config *bt_config;
+
+ bt_config = (void *) omap_get_config(OMAP_TAG_NOKIA_BT,
+ struct omap_bluetooth_config);
+ n800_bt_device.dev.platform_data = (void *) bt_config;
+ if (platform_device_register(&n800_bt_device) < 0)
+ BUG();
+}
+
--- /dev/null
+/*
+ * arch/arm/mach-omap2/board-n800-camera.c
+ *
+ * Copyright (C) 2007 Nokia Corporation
+ *
+ * Contact: Sakari Ailus <sakari.ailus@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-int-device.h>
+
+#include <asm/arch/menelaus.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/board.h>
+
+#include <../drivers/cbus/retu.h>
+#include <../drivers/media/video/tcm825x.h>
+
+#if defined (CONFIG_VIDEO_TCM825X) || defined (CONFIG_VIDEO_TCM825X_MODULE)
+
+#define OMAP24XX_CAMERA_JAM_HACK
+
+#ifdef OMAP24XX_CAMERA_JAM_HACK
+/*
+ * We don't need to check every pixel to assume that the frame is
+ * corrupt and the sensor is jammed. CHECK_X and CHECK_Y are the
+ * number of u32s to check per line / row, plus there are two lines in
+ * the bottom of the frame.
+ */
+#define CHECK_X 8
+#define CHECK_Y 6
+/*
+ * Start checking after this many frames since resetting the sensor.
+ * Sometimes the first frame(s) is(/are) black which could trigger
+ * unwanted reset(s).
+ */
+#define JAM_CHECK_AFTER 3
+/*
+ * If the sensor is quickly brought into bright conditions from dark,
+ * it may temporarily be saturated, leaving out the normal background
+ * noise. This many saturated frames may go through before the sensor
+ * is considered jammed.
+ */
+#define SATURATED_MAX 30
+#endif
+
+#define N800_CAM_SENSOR_RESET_GPIO 53
+
+static int sensor_okay;
+#ifdef OMAP24XX_CAMERA_JAM_HACK
+static int frames_after_reset;
+static int saturated_count;
+#endif
+
+const static struct tcm825x_reg tcm825x_default_regs_[] = {
+ /* initial settings for 2.5 V */
+ {0x00, 0x03}, {0x03, 0x29}, {0xaa, 0x2a}, {0xc0, 0x2b},
+ {0x10, 0x2c}, {0x4c, 0x2d}, {0x9c, 0x3f},
+
+ /* main settings */
+ {0x00, 0x00}, {0x30, 0x01}, {0x0e, 0x02}, /* initial */
+ {0x0f, 0x04}, {0x02, 0x05}, {0x0d, 0x06}, {0xc0, 0x07},
+ {0x38, 0x08}, {0x50, 0x09}, {0x80, 0x0a}, {0x40, 0x0b},
+ {0x40, 0x0c}, {0x00, 0x0d}, {0x04, 0x0e}, {0x04, 0x0f},
+ {0x22, 0x10}, {0x96, 0x11}, {0xf0, 0x12}, {0x08, 0x13},
+ {0x08, 0x14}, {0x30, 0x15}, {0x30, 0x16}, {0x01, 0x17},
+ {0x40, 0x18}, {0x87, 0x19}, {0x2b, 0x1a}, {0x84, 0x1b},
+ {0x52, 0x1c}, {0x44, 0x1d}, {0x68, 0x1e}, {0x00, 0x1f},
+ {0x00, 0x20}, {0x01, 0x21}, {0x27, 0x22}, {0x40, 0x23},
+ {0x27, 0x24}, {0x5f, 0x25}, {0x00, 0x26}, {0x16, 0x27},
+ {0x23, 0x28}, /* initial */ /* initial */ /* initial */
+ /* initial */ /* initial */ {0x00, 0x2e}, {0x00, 0x2f},
+ {0x00, 0x30}, {0x00, 0x31}, {0x00, 0x32}, {0x00, 0x33},
+ {0x00, 0x34}, {0x00, 0x35}, {0x00, 0x36}, {0x00, 0x37},
+ {0x00, 0x38}, {0x8c, 0x39}, {0xc8, 0x3A}, {0x80, 0x3b},
+ {0x00, 0x3c}, {0x17, 0x3d}, {0x85, 0x3e}, /* initial */
+ {0xa0, 0x40}, {0x00, 0x41}, {0x00, 0x42}, {0x00, 0x43},
+ {0x08, 0x44}, {0x12, 0x45}, {0x00, 0x46}, {0x20, 0x47},
+ {0x30, 0x48}, {0x18, 0x49}, {0x20, 0x4a}, {0x4d, 0x4b},
+ {0x0c, 0x4c}, {0xe0, 0x4d}, {0x20, 0x4e}, {0x89, 0x4f},
+ {0x21, 0x50}, {0x80, 0x51}, {0x02, 0x52}, {0x00, 0x53},
+ {0x30, 0x54}, {0x90, 0x55}, {0x40, 0x56}, {0x06, 0x57},
+ {0x0f, 0x58}, {0x23, 0x59}, {0x08, 0x5A}, {0x04, 0x5b},
+ {0x08, 0x5c}, {0x08, 0x5d}, {0x08, 0x5e}, {0x08, 0x5f},
+ {TCM825X_VAL_TERM, TCM825X_REG_TERM}
+};
+
+static int tcm825x_is_okay(void)
+{
+ return sensor_okay;
+}
+
+/*
+ * VSIM1 --> CAM_IOVDD --> IOVDD (1.8 V)
+ */
+static int tcm825x_power_on(void)
+{
+ int ret;
+
+ /* Set VMEM to 1.5V and VIO to 2.5V */
+ ret = menelaus_set_vmem(1500);
+ if (ret < 0) {
+ /* Try once more, it seems the sensor power up causes
+ * some problems on the I2C bus. */
+ ret = menelaus_set_vmem(1500);
+ if (ret < 0)
+ return ret;
+ }
+ msleep(1);
+
+ ret = menelaus_set_vio(2500);
+ if (ret < 0)
+ return ret;
+
+ /* Set VSim1 on */
+ retu_write_reg(RETU_REG_CTRL_SET, 0x0080);
+ msleep(1);
+
+ omap_set_gpio_dataout(N800_CAM_SENSOR_RESET_GPIO, 1);
+ msleep(1);
+
+ saturated_count = 0;
+ frames_after_reset = 0;
+
+ return 0;
+}
+
+static int tcm825x_power_off(void)
+{
+ int ret;
+
+ omap_set_gpio_dataout(N800_CAM_SENSOR_RESET_GPIO, 0);
+ msleep(1);
+
+ /* Set VSim1 off */
+ retu_write_reg(RETU_REG_CTRL_CLR, 0x0080);
+ msleep(1);
+
+ /* Set VIO_MODE to off */
+ ret = menelaus_set_vio(0);
+ if (ret < 0)
+ return ret;
+ msleep(1);
+
+ /* Set VMEM_MODE to off */
+ ret = menelaus_set_vmem(0);
+ if (ret < 0)
+ return ret;
+ msleep(1);
+
+ return 0;
+}
+
+static int tcm825x_power_set(int power)
+{
+ BUG_ON(!sensor_okay);
+
+ if (power)
+ return tcm825x_power_on();
+ else
+ return tcm825x_power_off();
+}
+
+static const struct tcm825x_reg *tcm825x_default_regs(void)
+{
+ return tcm825x_default_regs_;
+}
+
+#ifdef OMAP24XX_CAMERA_JAM_HACK
+/*
+ * Check for jammed sensor, in which case all horizontal lines are
+ * equal. Handle also case where sensor could be saturated awhile in
+ * case of rapid increase of brightness.
+ */
+static int tcm825x_needs_reset(struct v4l2_int_device *s, void *buf,
+ struct v4l2_pix_format *pix)
+{
+ int i, j;
+ uint32_t xor, xor2;
+ uint32_t offset;
+ uint32_t dx_offset;
+ uint32_t saturated_pattern;
+ int is_saturated = 1;
+
+ switch (pix->pixelformat) {
+ default:
+ case V4L2_PIX_FMT_RGB565:
+ saturated_pattern = 0xffffffff; /* guess */
+ break;
+ case V4L2_PIX_FMT_UYVY:
+ saturated_pattern = 0xe080e080;
+ break;
+ }
+
+ /* This won't work for height under 2 at all. */
+ if (pix->height < 2)
+ return 0;
+ /* Check that there is enough image data. */
+ if (pix->width * TCM825X_BYTES_PER_PIXEL < sizeof(uint32_t))
+ return 0;
+ /*
+ * Don't check for jamming immediately. Sometimes frames
+ * immediately after reset are black.
+ */
+ if (frames_after_reset < JAM_CHECK_AFTER) {
+ frames_after_reset++;
+ return 0;
+ }
+
+ dx_offset = ((pix->width - sizeof(uint32_t) / TCM825X_BYTES_PER_PIXEL)
+ * TCM825X_BYTES_PER_PIXEL) / (CHECK_X - 1);
+ dx_offset = dx_offset - dx_offset % TCM825X_BYTES_PER_PIXEL;
+ /*
+ * Check two lines in the bottom first. They're unlikely to be
+ * saturated and quick to check.
+ */
+ offset = (pix->height - 2) * pix->bytesperline;
+ xor = xor2 = 0;
+ for (j = 0; j < CHECK_X; j++) {
+ uint32_t *val = buf + offset;
+ uint32_t *val2 = buf + offset + pix->bytesperline;
+ xor ^= *val;
+ if (*val != saturated_pattern)
+ is_saturated = 0;
+ xor2 ^= *val2;
+ if (xor2 != xor) {
+ saturated_count = 0;
+ return 0;
+ }
+ offset += dx_offset;
+ }
+ /* Check the rest of the picture. */
+ offset = 0;
+ for (i = 0; i < CHECK_Y; i++) {
+ uint32_t offset2 = offset;
+ xor2 = 0;
+ for (j = 0; j < CHECK_X; j++) {
+ uint32_t *val = buf + offset2;
+ xor2 ^= *val;
+ offset2 += dx_offset;
+ }
+ if (xor2 != xor) {
+ saturated_count = 0;
+ return 0;
+ }
+ offset += pix->bytesperline * ((pix->height - 2) / CHECK_Y);
+ }
+
+ if (is_saturated && saturated_count++ < SATURATED_MAX)
+ return 0;
+
+ return -EIO;
+}
+#else
+static int tcm825x_needs_reset(struct v4l2_int_device *s, void *buf,
+ struct v4l2_pix_format *pix)
+{
+ return 0;
+}
+#endif
+
+static const struct v4l2_ifparm ifparm = {
+ .if_type = V4L2_IF_TYPE_BT656,
+ .u = {
+ .bt656 = {
+ .frame_start_on_rising_vs = 1,
+ .latch_clk_inv = 1,
+ .mode = V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT,
+ .clock_min = TCM825X_XCLK_MIN,
+ .clock_max = TCM825X_XCLK_MAX,
+ },
+ },
+};
+
+static int tcm825x_ifparm(struct v4l2_ifparm *p)
+{
+ *p = ifparm;
+
+ return 0;
+}
+
+const struct tcm825x_platform_data n800_tcm825x_platform_data = {
+ .is_okay = tcm825x_is_okay,
+ .power_set = tcm825x_power_set,
+ .default_regs = tcm825x_default_regs,
+ .needs_reset = tcm825x_needs_reset,
+ .ifparm = tcm825x_ifparm,
+};
+
+void __init n800_cam_init(void)
+{
+ int r;
+
+ r = omap_request_gpio(N800_CAM_SENSOR_RESET_GPIO);
+ if (r < 0) {
+ printk(KERN_WARNING "%s: failed to request gpio\n",
+ __FUNCTION__);
+ return;
+ }
+
+ omap_set_gpio_dataout(N800_CAM_SENSOR_RESET_GPIO, 0);
+ omap_set_gpio_direction(N800_CAM_SENSOR_RESET_GPIO, 0);
+
+ sensor_okay = 1;
+}
+
+#else
+void __init n800_cam_init(void)
+{
+}
+
+#endif
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap2/board-n800-dsp.c
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/board.h>
+#include <asm/arch/dsp_common.h>
+
+#if defined(CONFIG_OMAP_DSP)
+
+/*
+ * dsp peripheral device: AUDIO
+ */
+static struct dsp_kfunc_device n800_audio_device = {
+ .name = "audio",
+ .type = DSP_KFUNC_DEV_TYPE_AUDIO,
+ .enable = n800_audio_enable,
+ .disable = n800_audio_disable,
+};
+
+/*
+ * dsp peripheral device: TIMER
+ */
+static int dsp_timer_probe(struct dsp_kfunc_device *kdev, int stage)
+{
+ char clockname[20];
+
+ strcpy(clockname, kdev->name);
+ strcat(clockname, "_fck");
+
+ kdev->fck = clk_get(NULL, clockname);
+ if (IS_ERR(kdev->fck)) {
+ printk(KERN_ERR "couldn't acquire %s\n", clockname);
+ return PTR_ERR(kdev->fck);
+ }
+ pr_debug("%s probed successfully\n", clockname);
+
+ strcpy(clockname, kdev->name);
+ strcat(clockname, "_ick");
+ kdev->ick = clk_get(NULL, clockname);
+ if (IS_ERR(kdev->ick)) {
+ printk(KERN_ERR "couldn't acquire %s\n", clockname);
+ goto fail;
+ }
+ pr_debug("%s probed successfully\n", clockname);
+
+ return 0;
+ fail:
+ clk_put(kdev->fck);
+
+ return PTR_ERR(kdev->ick);
+}
+
+static int dsp_timer_remove(struct dsp_kfunc_device *kdev, int stage)
+{
+ clk_put(kdev->ick);
+ clk_put(kdev->fck);
+ pr_debug("%s removed successfully\n", kdev->name);
+ return 0;
+}
+
+static int dsp_timer_enable(struct dsp_kfunc_device *kdev, int stage)
+{
+ pr_debug("%s enabled(%d)\n", kdev->name, stage);
+
+ spin_lock(&kdev->lock);
+
+ if (kdev->enabled)
+ goto out;
+ kdev->enabled = 1;
+
+ clk_enable(kdev->fck);
+ clk_enable(kdev->ick);
+ out:
+ spin_unlock(&kdev->lock);
+
+ return 0;
+}
+
+static int dsp_timer_disable(struct dsp_kfunc_device *kdev, int stage)
+{
+ pr_debug("%s disabled(%d)\n", kdev->name, stage);
+
+ spin_lock(&kdev->lock);
+
+ if (kdev->enabled == 0)
+ goto out;
+ kdev->enabled = 0;
+
+ clk_disable(kdev->ick);
+ clk_disable(kdev->fck);
+ out:
+ spin_unlock(&kdev->lock);
+
+ return 0;
+}
+
+static struct dsp_kfunc_device n800_timer_device = {
+ .name = "gpt5",
+ .type = DSP_KFUNC_DEV_TYPE_COMMON,
+ .probe = dsp_timer_probe,
+ .remove = dsp_timer_remove,
+ .enable = dsp_timer_enable,
+ .disable = dsp_timer_disable,
+};
+
+static struct dsp_kfunc_device *n800_kfunc_dev[] = {
+ &n800_audio_device,
+ &n800_timer_device,
+};
+
+void __init n800_dsp_init(void)
+{
+ int i, ret;
+ struct dsp_kfunc_device **p = n800_kfunc_dev;
+
+ for (i = 0; i < ARRAY_SIZE(n800_kfunc_dev); i++) {
+ ret = dsp_kfunc_device_register(p[i]);
+ if (ret) {
+ printk(KERN_ERR
+ "KFUNC device registration failed: %s\n",
+ p[i]->name);
+ }
+ }
+}
+
+#else
+void __init n800_dsp_init(void) { }
+#endif /* CONFIG_OMAP_DSP */
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap2/board-n800-flash.c
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Author: Juha Yrjola
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <asm/mach/flash.h>
+#include <linux/mtd/onenand_regs.h>
+
+#include <asm/io.h>
+#include <asm/arch/onenand.h>
+#include <asm/arch/board.h>
+#include <asm/arch/gpmc.h>
+
+static struct mtd_partition n800_partitions[8];
+
+static int n800_onenand_setup(void __iomem *, int freq);
+
+static struct omap_onenand_platform_data n800_onenand_data = {
+ .cs = 0,
+ .gpio_irq = 26,
+ .parts = n800_partitions,
+ .nr_parts = 0, /* filled later */
+ .onenand_setup = n800_onenand_setup,
+};
+
+static struct platform_device n800_onenand_device = {
+ .name = "omap2-onenand",
+ .id = -1,
+ .dev = {
+ .platform_data = &n800_onenand_data,
+ },
+};
+
+static unsigned short omap2_onenand_readw(void __iomem *addr)
+{
+ return readw(addr);
+}
+
+static void omap2_onenand_writew(unsigned short value, void __iomem *addr)
+{
+ writew(value, addr);
+}
+
+static int omap2_onenand_set_sync_mode(int cs, void __iomem *onenand_base,
+ int freq)
+{
+ struct gpmc_timings t;
+ int min_gpmc_clk_period, t_ces, t_avds, t_avdh, t_avdp, t_wpl, t_wea;
+ int tick_ns, div, fclk_offset_ns, fclk_offset, gpmc_clk_ns, latency;
+ int err;
+ u32 reg;
+
+again:
+ switch (freq) {
+ case 83:
+ min_gpmc_clk_period = 12; /* 83 MHz */
+ t_ces = 5;
+ t_avds = 5;
+ t_avdh = 6;
+ t_avdp = 12;
+ t_wpl = 40;
+ t_wea = 15;
+ break;
+ case 66:
+ min_gpmc_clk_period = 15; /* 66 MHz */
+ t_ces = 6;
+ t_avds = 5;
+ t_avdh = 6;
+ t_avdp = 12;
+ t_wpl = 40;
+ t_wea = 15;
+ break;
+ default:
+ min_gpmc_clk_period = 18; /* 54 MHz */
+ t_ces = 7;
+ t_avds = 7;
+ t_avdh = 7;
+ t_avdp = 12;
+ t_wpl = 40;
+ t_wea = 15;
+ break;
+ }
+
+ tick_ns = gpmc_ticks_to_ns(1);
+ div = gpmc_cs_calc_divider(cs, min_gpmc_clk_period);
+ gpmc_clk_ns = gpmc_ticks_to_ns(div);
+ if (gpmc_clk_ns >= 25) /* 40 MHz*/
+ latency = 3;
+ else
+ latency = 4;
+
+ if (div == 1) {
+ reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG2);
+ reg |= (1 << 7);
+ gpmc_cs_write_reg(cs, GPMC_CS_CONFIG2, reg);
+ reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG3);
+ reg |= (1 << 7);
+ gpmc_cs_write_reg(cs, GPMC_CS_CONFIG3, reg);
+ reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG4);
+ reg |= (1 << 7);
+ reg |= (1 << 23);
+ gpmc_cs_write_reg(cs, GPMC_CS_CONFIG4, reg);
+ } else {
+ reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG2);
+ reg &= ~(1 << 7);
+ gpmc_cs_write_reg(cs, GPMC_CS_CONFIG2, reg);
+ reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG3);
+ reg &= ~(1 << 7);
+ gpmc_cs_write_reg(cs, GPMC_CS_CONFIG3, reg);
+ reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG4);
+ reg &= ~(1 << 7);
+ reg &= ~(1 << 23);
+ gpmc_cs_write_reg(cs, GPMC_CS_CONFIG4, reg);
+ }
+
+ /* Set syncronous read timings */
+ memset(&t, 0, sizeof(t));
+ t.sync_clk = min_gpmc_clk_period;
+ t.cs_on = 0;
+ t.adv_on = 0;
+ fclk_offset_ns = gpmc_round_ns_to_ticks(max_t(int, t_ces, t_avds));
+ fclk_offset = gpmc_ns_to_ticks(fclk_offset_ns);
+ t.page_burst_access = gpmc_clk_ns;
+
+ /* Read */
+ t.adv_rd_off = gpmc_ticks_to_ns(fclk_offset + gpmc_ns_to_ticks(t_avdh));
+ t.oe_on = t.adv_rd_off;
+ t.access = gpmc_ticks_to_ns(fclk_offset + (latency + 1) * div);
+ t.oe_off = t.access + gpmc_round_ns_to_ticks(1);
+ t.cs_rd_off = t.oe_off;
+ t.rd_cycle = gpmc_ticks_to_ns(fclk_offset + (latency + 1) * div + div);
+
+ /* Write */
+ t.adv_wr_off = t.adv_on + gpmc_round_ns_to_ticks(t_avdp);
+ t.we_on = t.adv_wr_off + gpmc_round_ns_to_ticks(t_avdh);
+ t.we_off = t.we_on + gpmc_round_ns_to_ticks(t_wpl);
+ t.cs_wr_off = t.we_off + gpmc_round_ns_to_ticks(1);
+ t.wr_cycle = t.we_off + gpmc_round_ns_to_ticks(t_wea);
+
+ /* Configure GPMC for synchronous read */
+ gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1,
+ GPMC_CONFIG1_WRAPBURST_SUPP |
+ GPMC_CONFIG1_READMULTIPLE_SUPP |
+ GPMC_CONFIG1_READTYPE_SYNC |
+ GPMC_CONFIG1_CLKACTIVATIONTIME(fclk_offset) |
+ GPMC_CONFIG1_PAGE_LEN(2) |
+ GPMC_CONFIG1_WAIT_READ_MON |
+ GPMC_CONFIG1_WAIT_PIN_SEL(0) |
+ GPMC_CONFIG1_DEVICESIZE_16 |
+ GPMC_CONFIG1_DEVICETYPE_NOR |
+ GPMC_CONFIG1_MUXADDDATA);
+
+ err = gpmc_cs_set_timings(cs, &t);
+ if (err)
+ return err;
+
+ if (!freq) {
+ /* Very first call freq is not known */
+ reg = omap2_onenand_readw(onenand_base + ONENAND_REG_VERSION_ID);
+ switch ((reg >> 4) & 0xf) {
+ case 0:
+ freq = 40;
+ break;
+ case 1:
+ freq = 54;
+ break;
+ case 2:
+ freq = 66;
+ break;
+ case 3:
+ freq = 83;
+ break;
+ }
+ if (freq && freq != 54)
+ goto again;
+ }
+
+ /* Configure OneNAND for sync read */
+ reg = omap2_onenand_readw(onenand_base + ONENAND_REG_SYS_CFG1);
+ reg &= ~((0x7 << ONENAND_SYS_CFG1_BRL_SHIFT) | (0x7 << 9));
+ reg |= (latency << ONENAND_SYS_CFG1_BRL_SHIFT) |
+ ONENAND_SYS_CFG1_SYNC_READ |
+ ONENAND_SYS_CFG1_BL_16;
+ omap2_onenand_writew(reg, onenand_base + ONENAND_REG_SYS_CFG1);
+
+ return 0;
+}
+
+static int n800_onenand_setup(void __iomem *onenand_base, int freq)
+{
+ struct omap_onenand_platform_data *datap = &n800_onenand_data;
+ struct device *dev = &n800_onenand_device.dev;
+
+ /* Set sync timings in GPMC */
+ if (omap2_onenand_set_sync_mode(datap->cs, onenand_base, freq) < 0) {
+ dev_err(dev, "Unable to set synchronous mode\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+void __init n800_flash_init(void)
+{
+ const struct omap_partition_config *part;
+ int i = 0;
+
+ while ((part = omap_get_nr_config(OMAP_TAG_PARTITION,
+ struct omap_partition_config, i)) != NULL) {
+ struct mtd_partition *mpart;
+
+ mpart = n800_partitions + i;
+ mpart->name = (char *) part->name;
+ mpart->size = part->size;
+ mpart->offset = part->offset;
+ mpart->mask_flags = part->mask_flags;
+ i++;
+ if (i == ARRAY_SIZE(n800_partitions)) {
+ printk(KERN_ERR "Too many partitions supplied\n");
+ return;
+ }
+ }
+ n800_onenand_data.nr_parts = i;
+ if (platform_device_register(&n800_onenand_device) < 0) {
+ printk(KERN_ERR "Unable to register OneNAND device\n");
+ return;
+ }
+}
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap2/board-n800-mmc.c
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Author: Juha Yrjola
+ *
+ * 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 <asm/arch/mmc.h>
+#include <asm/arch/menelaus.h>
+#include <asm/arch/gpio.h>
+
+#include <asm/mach-types.h>
+#include <linux/delay.h>
+
+#ifdef CONFIG_MMC_OMAP
+
+static const int slot_switch_gpio = 96;
+
+static const int n810_slot2_pw_vddf = 23;
+static const int n810_slot2_pw_vdd = 9;
+
+static int slot1_cover_open;
+static int slot2_cover_open;
+static struct device *mmc_device;
+
+/*
+ * VMMC --> slot 1 (N800 & N810)
+ * VDCDC3_APE, VMCS2_APE --> slot 2 on N800
+ * GPIO96 --> Menelaus GPIO2
+ * GPIO23 --> controls slot2 VSD (N810 only)
+ * GPIO9 --> controls slot2 VIO_SD (N810 only)
+ */
+
+static int n800_mmc_switch_slot(struct device *dev, int slot)
+{
+#ifdef CONFIG_MMC_DEBUG
+ dev_dbg(dev, "Choose slot %d\n", slot + 1);
+#endif
+ if (slot == 0)
+ omap_set_gpio_dataout(slot_switch_gpio, 0);
+ else
+ omap_set_gpio_dataout(slot_switch_gpio, 1);
+ return 0;
+}
+
+static int n800_mmc_set_power_menelaus(struct device *dev, int slot,
+ int power_on, int vdd)
+{
+ int mV;
+
+#ifdef CONFIG_MMC_DEBUG
+ dev_dbg(dev, "Set slot %d power: %s (vdd %d)\n", slot + 1,
+ power_on ? "on" : "off", vdd);
+#endif
+ if (slot == 0) {
+ if (!power_on)
+ return menelaus_set_vmmc(0);
+ switch (1 << vdd) {
+ case MMC_VDD_33_34:
+ case MMC_VDD_32_33:
+ case MMC_VDD_31_32:
+ mV = 3100;
+ break;
+ case MMC_VDD_30_31:
+ mV = 3000;
+ break;
+ case MMC_VDD_28_29:
+ mV = 2800;
+ break;
+ case MMC_VDD_165_195:
+ mV = 1850;
+ break;
+ default:
+ BUG();
+ }
+ return menelaus_set_vmmc(mV);
+ } else {
+ if (!power_on)
+ return menelaus_set_vdcdc(3, 0);
+ switch (1 << vdd) {
+ case MMC_VDD_33_34:
+ case MMC_VDD_32_33:
+ mV = 3300;
+ break;
+ case MMC_VDD_30_31:
+ case MMC_VDD_29_30:
+ mV = 3000;
+ break;
+ case MMC_VDD_28_29:
+ case MMC_VDD_27_28:
+ mV = 2800;
+ break;
+ case MMC_VDD_24_25:
+ case MMC_VDD_23_24:
+ mV = 2400;
+ break;
+ case MMC_VDD_22_23:
+ case MMC_VDD_21_22:
+ mV = 2200;
+ break;
+ case MMC_VDD_20_21:
+ mV = 2000;
+ break;
+ case MMC_VDD_165_195:
+ mV = 1800;
+ break;
+ default:
+ BUG();
+ }
+ return menelaus_set_vdcdc(3, mV);
+ }
+ return 0;
+}
+
+static void nokia_mmc_set_power_internal(struct device *dev,
+ int power_on)
+{
+ dev_dbg(dev, "Set internal slot power %s\n",
+ power_on ? "on" : "off");
+
+ if (power_on) {
+ omap_set_gpio_dataout(n810_slot2_pw_vddf, 1);
+ udelay(30);
+ omap_set_gpio_dataout(n810_slot2_pw_vdd, 1);
+ udelay(100);
+ } else {
+ omap_set_gpio_dataout(n810_slot2_pw_vdd, 0);
+ msleep(50);
+ omap_set_gpio_dataout(n810_slot2_pw_vddf, 0);
+ msleep(50);
+ }
+}
+
+static int n800_mmc_set_power(struct device *dev, int slot, int power_on,
+ int vdd)
+{
+ if (machine_is_nokia_n800() || slot == 0)
+ return n800_mmc_set_power_menelaus(dev, slot, power_on, vdd);
+
+ nokia_mmc_set_power_internal(dev, power_on);
+
+ return 0;
+}
+
+static int n800_mmc_set_bus_mode(struct device *dev, int slot, int bus_mode)
+{
+ int r;
+
+ dev_dbg(dev, "Set slot %d bus mode %s\n", slot + 1,
+ bus_mode == MMC_BUSMODE_OPENDRAIN ? "open-drain" : "push-pull");
+ BUG_ON(slot != 0 && slot != 1);
+ slot++;
+ switch (bus_mode) {
+ case MMC_BUSMODE_OPENDRAIN:
+ r = menelaus_set_mmc_opendrain(slot, 1);
+ break;
+ case MMC_BUSMODE_PUSHPULL:
+ r = menelaus_set_mmc_opendrain(slot, 0);
+ break;
+ default:
+ BUG();
+ }
+ if (r != 0 && printk_ratelimit())
+ dev_err(dev, "MMC: unable to set bus mode for slot %d\n",
+ slot);
+ return r;
+}
+
+static int n800_mmc_get_cover_state(struct device *dev, int slot)
+{
+ slot++;
+ BUG_ON(slot != 1 && slot != 2);
+ if (slot == 1)
+ return slot1_cover_open;
+ else
+ return slot2_cover_open;
+}
+
+static void n800_mmc_callback(void *data, u8 card_mask)
+{
+ int bit, *openp, index;
+
+ if (machine_is_nokia_n800()) {
+ bit = 1 << 1;
+ openp = &slot2_cover_open;
+ index = 1;
+ } else {
+ bit = 1;
+ openp = &slot1_cover_open;
+ index = 0;
+ }
+
+ if (card_mask & bit)
+ *openp = 1;
+ else
+ *openp = 0;
+
+ omap_mmc_notify_cover_event(mmc_device, index, *openp);
+}
+
+void n800_mmc_slot1_cover_handler(void *arg, int closed_state)
+{
+ if (mmc_device == NULL)
+ return;
+
+ slot1_cover_open = !closed_state;
+ omap_mmc_notify_cover_event(mmc_device, 0, closed_state);
+}
+
+static int n800_mmc_late_init(struct device *dev)
+{
+ int r, bit, *openp;
+ int vs2sel;
+
+ mmc_device = dev;
+
+ r = menelaus_set_slot_sel(1);
+ if (r < 0)
+ return r;
+
+ if (machine_is_nokia_n800())
+ vs2sel = 0;
+ else
+ vs2sel = 2;
+
+ r = menelaus_set_mmc_slot(2, 0, vs2sel, 1);
+ if (r < 0)
+ return r;
+
+ n800_mmc_set_power(dev, 0, MMC_POWER_ON, 16); /* MMC_VDD_28_29 */
+ n800_mmc_set_power(dev, 1, MMC_POWER_ON, 16);
+
+ r = menelaus_set_mmc_slot(1, 1, 0, 1);
+ if (r < 0)
+ return r;
+ r = menelaus_set_mmc_slot(2, 1, vs2sel, 1);
+ if (r < 0)
+ return r;
+
+ r = menelaus_get_slot_pin_states();
+ if (r < 0)
+ return r;
+
+ if (machine_is_nokia_n800()) {
+ bit = 1 << 1;
+ openp = &slot2_cover_open;
+ } else {
+ bit = 1;
+ openp = &slot1_cover_open;
+ slot2_cover_open = 0;
+ }
+
+ /* All slot pin bits seem to be inversed until first swith change */
+ if (r == 0xf || r == (0xf & ~bit))
+ r = ~r;
+
+ if (r & bit)
+ *openp = 1;
+ else
+ *openp = 0;
+
+ r = menelaus_register_mmc_callback(n800_mmc_callback, NULL);
+
+ return r;
+}
+
+static void n800_mmc_shutdown(struct device *dev)
+{
+ int vs2sel;
+
+ if (machine_is_nokia_n800())
+ vs2sel = 0;
+ else
+ vs2sel = 2;
+
+ menelaus_set_mmc_slot(1, 0, 0, 0);
+ menelaus_set_mmc_slot(2, 0, vs2sel, 0);
+}
+
+static void n800_mmc_cleanup(struct device *dev)
+{
+ menelaus_unregister_mmc_callback();
+
+ omap_free_gpio(slot_switch_gpio);
+
+ if (machine_is_nokia_n810()) {
+ omap_free_gpio(n810_slot2_pw_vddf);
+ omap_free_gpio(n810_slot2_pw_vdd);
+ }
+}
+
+static struct omap_mmc_platform_data n800_mmc_data = {
+ .nr_slots = 2,
+ .switch_slot = n800_mmc_switch_slot,
+ .init = n800_mmc_late_init,
+ .cleanup = n800_mmc_cleanup,
+ .shutdown = n800_mmc_shutdown,
+ .max_freq = 24000000,
+ .slots[0] = {
+ .set_power = n800_mmc_set_power,
+ .set_bus_mode = n800_mmc_set_bus_mode,
+ .get_ro = NULL,
+ .get_cover_state= n800_mmc_get_cover_state,
+ .ocr_mask = MMC_VDD_165_195 | MMC_VDD_30_31 |
+ MMC_VDD_32_33 | MMC_VDD_33_34,
+ .name = "internal",
+ },
+ .slots[1] = {
+ .set_power = n800_mmc_set_power,
+ .set_bus_mode = n800_mmc_set_bus_mode,
+ .get_ro = NULL,
+ .get_cover_state= n800_mmc_get_cover_state,
+ .ocr_mask = MMC_VDD_165_195 | MMC_VDD_20_21 |
+ MMC_VDD_21_22 | MMC_VDD_22_23 | MMC_VDD_23_24 |
+ MMC_VDD_24_25 | MMC_VDD_27_28 | MMC_VDD_28_29 |
+ MMC_VDD_29_30 | MMC_VDD_30_31 | MMC_VDD_32_33 |
+ MMC_VDD_33_34,
+ .name = "external",
+ },
+};
+
+void __init n800_mmc_init(void)
+
+{
+ if (machine_is_nokia_n810()) {
+ n800_mmc_data.slots[0].name = "external";
+
+ /*
+ * Some Samsung Movinand chips do not like open-ended
+ * multi-block reads and fall to braind-dead state
+ * while doing so. Reducing the number of blocks in
+ * the transfer or delays in clock disable do not help
+ */
+ n800_mmc_data.slots[1].name = "internal";
+ n800_mmc_data.slots[1].ban_openended = 1;
+ }
+
+ omap_set_mmc_info(1, &n800_mmc_data);
+ if (omap_request_gpio(slot_switch_gpio) < 0)
+ BUG();
+ omap_set_gpio_dataout(slot_switch_gpio, 0);
+ omap_set_gpio_direction(slot_switch_gpio, 0);
+
+ if (machine_is_nokia_n810()) {
+ if (omap_request_gpio(n810_slot2_pw_vddf) < 0)
+ BUG();
+ omap_set_gpio_dataout(n810_slot2_pw_vddf, 0);
+ omap_set_gpio_direction(n810_slot2_pw_vddf, 0);
+
+ if (omap_request_gpio(n810_slot2_pw_vdd) < 0)
+ BUG();
+ omap_set_gpio_dataout(n810_slot2_pw_vdd, 0);
+ omap_set_gpio_direction(n810_slot2_pw_vdd, 0);
+ }
+}
+#else
+
+void __init n800_mmc_init(void)
+{
+}
+
+void n800_mmc_slot1_cover_handler(void *arg, int state)
+{
+}
+
+#endif
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap2/board-n800-usb.c
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Author: Juha Yrjola
+ *
+ * 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/delay.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/usb/musb.h>
+#include <asm/arch/gpmc.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/pm.h>
+
+#define TUSB_ASYNC_CS 1
+#define TUSB_SYNC_CS 4
+#define GPIO_TUSB_INT 58
+#define GPIO_TUSB_ENABLE 0
+
+static int tusb_set_power(int state);
+static int tusb_set_clock(struct clk *osc_ck, int state);
+
+#if defined(CONFIG_USB_MUSB_OTG)
+# define BOARD_MODE MUSB_OTG
+#elif defined(CONFIG_USB_MUSB_PERIPHERAL)
+# define BOARD_MODE MUSB_PERIPHERAL
+#else /* defined(CONFIG_USB_MUSB_HOST) */
+# define BOARD_MODE MUSB_HOST
+#endif
+
+static struct musb_hdrc_platform_data tusb_data = {
+ .mode = BOARD_MODE,
+ .multipoint = 1,
+ .set_power = tusb_set_power,
+ .set_clock = tusb_set_clock,
+ .min_power = 25, /* x2 = 50 mA drawn from VBUS as peripheral */
+ .power = 100, /* Max 100 mA VBUS for host mode */
+ .clock = "osc_ck",
+};
+
+/*
+ * Enable or disable power to TUSB6010. When enabling, turn on 3.3 V and
+ * 1.5 V voltage regulators of PM companion chip. Companion chip will then
+ * provide then PGOOD signal to TUSB6010 which will release it from reset.
+ */
+static int tusb_set_power(int state)
+{
+ int i, retval = 0;
+
+ if (state) {
+ omap_set_gpio_dataout(GPIO_TUSB_ENABLE, 1);
+ msleep(1);
+
+ /* Wait until TUSB6010 pulls INT pin down */
+ i = 100;
+ while (i && omap_get_gpio_datain(GPIO_TUSB_INT)) {
+ msleep(1);
+ i--;
+ }
+
+ if (!i) {
+ printk(KERN_ERR "tusb: powerup failed\n");
+ retval = -ENODEV;
+ }
+ } else {
+ omap_set_gpio_dataout(GPIO_TUSB_ENABLE, 0);
+ msleep(10);
+ }
+
+ return retval;
+}
+
+static int osc_ck_on;
+
+static int tusb_set_clock(struct clk *osc_ck, int state)
+{
+ if (state) {
+ if (osc_ck_on > 0)
+ return -ENODEV;
+
+ omap2_block_sleep();
+ clk_enable(osc_ck);
+ osc_ck_on = 1;
+ } else {
+ if (osc_ck_on == 0)
+ return -ENODEV;
+
+ clk_disable(osc_ck);
+ osc_ck_on = 0;
+ omap2_allow_sleep();
+ }
+
+ return 0;
+}
+
+void __init n800_usb_init(void)
+{
+ int ret = 0;
+ static char announce[] __initdata = KERN_INFO "TUSB 6010\n";
+
+ /* PM companion chip power control pin */
+ ret = omap_request_gpio(GPIO_TUSB_ENABLE);
+ if (ret != 0) {
+ printk(KERN_ERR "Could not get TUSB power GPIO%i\n",
+ GPIO_TUSB_ENABLE);
+ return;
+ }
+ omap_set_gpio_direction(GPIO_TUSB_ENABLE, 0);
+
+ tusb_set_power(0);
+
+ ret = tusb6010_setup_interface(&tusb_data, TUSB6010_REFCLK_19, 2,
+ TUSB_ASYNC_CS, TUSB_SYNC_CS,
+ GPIO_TUSB_INT, 0x3f);
+ if (ret != 0)
+ goto err;
+
+ printk(announce);
+
+ return;
+
+err:
+ omap_free_gpio(GPIO_TUSB_ENABLE);
+}
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap2/board-n800.c
+ *
+ * Copyright (C) 2005-2007 Nokia Corporation
+ * Author: Juha Yrjola <juha.yrjola@nokia.com>
+ *
+ * Modified from mach-omap2/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/clk.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/tsc2301.h>
+#include <linux/spi/tsc2005.h>
+#include <linux/input.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/i2c.h>
+#include <linux/i2c/lm8323.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/usb.h>
+#include <asm/arch/board.h>
+#include <asm/arch/common.h>
+#include <asm/arch/mcspi.h>
+#include <asm/arch/menelaus.h>
+#include <asm/arch/lcd_mipid.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/gpio-switch.h>
+#include <asm/arch/omapfb.h>
+#include <asm/arch/blizzard.h>
+
+#include <../drivers/cbus/tahvo.h>
+#include <../drivers/media/video/tcm825x.h>
+
+#define N800_BLIZZARD_POWERDOWN_GPIO 15
+#define N800_STI_GPIO 62
+#define N800_KEYB_IRQ_GPIO 109
+#define N800_DAV_IRQ_GPIO 103
+#define N800_TSC2301_RESET_GPIO 118
+
+#ifdef CONFIG_MACH_NOKIA_N810
+static s16 rx44_keymap[LM8323_KEYMAP_SIZE] = {
+ [0x01] = KEY_Q,
+ [0x02] = KEY_K,
+ [0x03] = KEY_O,
+ [0x04] = KEY_P,
+ [0x05] = KEY_BACKSPACE,
+ [0x06] = KEY_A,
+ [0x07] = KEY_S,
+ [0x08] = KEY_D,
+ [0x09] = KEY_F,
+ [0x0a] = KEY_G,
+ [0x0b] = KEY_H,
+ [0x0c] = KEY_J,
+
+ [0x11] = KEY_W,
+ [0x12] = KEY_F4,
+ [0x13] = KEY_L,
+ [0x14] = KEY_APOSTROPHE,
+ [0x16] = KEY_Z,
+ [0x17] = KEY_X,
+ [0x18] = KEY_C,
+ [0x19] = KEY_V,
+ [0x1a] = KEY_B,
+ [0x1b] = KEY_N,
+ [0x1c] = KEY_LEFTSHIFT, /* Actually, this is both shift keys */
+ [0x1f] = KEY_F7,
+
+ [0x21] = KEY_E,
+ [0x22] = KEY_SEMICOLON,
+ [0x23] = KEY_MINUS,
+ [0x24] = KEY_EQUAL,
+ [0x2b] = KEY_FN,
+ [0x2c] = KEY_M,
+ [0x2f] = KEY_F8,
+
+ [0x31] = KEY_R,
+ [0x32] = KEY_RIGHTCTRL,
+ [0x34] = KEY_SPACE,
+ [0x35] = KEY_COMMA,
+ [0x37] = KEY_UP,
+ [0x3c] = KEY_COMPOSE,
+ [0x3f] = KEY_F6,
+
+ [0x41] = KEY_T,
+ [0x44] = KEY_DOT,
+ [0x46] = KEY_RIGHT,
+ [0x4f] = KEY_F5,
+ [0x51] = KEY_Y,
+ [0x53] = KEY_DOWN,
+ [0x55] = KEY_ENTER,
+ [0x5f] = KEY_ESC,
+
+ [0x61] = KEY_U,
+ [0x64] = KEY_LEFT,
+
+ [0x71] = KEY_I,
+ [0x75] = KEY_KPENTER,
+};
+
+static struct lm8323_platform_data lm8323_pdata = {
+ .repeat = 0, /* Repeat is handled in userspace for now. */
+ .keymap = rx44_keymap,
+
+ .name = "Internal keyboard",
+ .pwm1_name = "keyboard",
+ .pwm2_name = "cover",
+};
+#endif
+
+void __init nokia_n800_init_irq(void)
+{
+ omap2_init_common_hw();
+ omap_init_irq();
+ omap_gpio_init();
+
+#ifdef CONFIG_OMAP_STI
+ if (omap_request_gpio(N800_STI_GPIO) < 0) {
+ printk(KERN_ERR "Failed to request GPIO %d for STI\n",
+ N800_STI_GPIO);
+ return;
+ }
+
+ omap_set_gpio_direction(N800_STI_GPIO, 0);
+ omap_set_gpio_dataout(N800_STI_GPIO, 0);
+#endif
+}
+
+#if defined(CONFIG_MENELAUS) && defined(CONFIG_SENSORS_TMP105)
+
+static int n800_tmp105_set_power(int enable)
+{
+ return menelaus_set_vaux(enable ? 2800 : 0);
+}
+
+#else
+
+#define n800_tmp105_set_power NULL
+
+#endif
+
+static struct omap_uart_config n800_uart_config __initdata = {
+ .enabled_uarts = (1 << 0) | (1 << 2),
+};
+
+#include "../../../drivers/cbus/retu.h"
+
+static struct omap_fbmem_config n800_fbmem0_config __initdata = {
+ .size = 752 * 1024,
+};
+
+static struct omap_fbmem_config n800_fbmem1_config __initdata = {
+ .size = 752 * 1024,
+};
+
+static struct omap_fbmem_config n800_fbmem2_config __initdata = {
+ .size = 752 * 1024,
+};
+
+static struct omap_tmp105_config n800_tmp105_config __initdata = {
+ .tmp105_irq_pin = 125,
+ .set_power = n800_tmp105_set_power,
+};
+
+static void mipid_shutdown(struct mipid_platform_data *pdata)
+{
+ if (pdata->nreset_gpio != -1) {
+ pr_info("shutdown LCD\n");
+ omap_set_gpio_dataout(pdata->nreset_gpio, 0);
+ msleep(120);
+ }
+}
+
+static struct mipid_platform_data n800_mipid_platform_data = {
+ .shutdown = mipid_shutdown,
+};
+
+static void __init mipid_dev_init(void)
+{
+ const struct omap_lcd_config *conf;
+
+ conf = omap_get_config(OMAP_TAG_LCD, struct omap_lcd_config);
+ if (conf != NULL) {
+ n800_mipid_platform_data.nreset_gpio = conf->nreset_gpio;
+ n800_mipid_platform_data.data_lines = conf->data_lines;
+ }
+}
+
+static struct {
+ struct clk *sys_ck;
+} blizzard;
+
+static int blizzard_get_clocks(void)
+{
+ blizzard.sys_ck = clk_get(0, "osc_ck");
+ if (IS_ERR(blizzard.sys_ck)) {
+ printk(KERN_ERR "can't get Blizzard clock\n");
+ return PTR_ERR(blizzard.sys_ck);
+ }
+ return 0;
+}
+
+static unsigned long blizzard_get_clock_rate(struct device *dev)
+{
+ return clk_get_rate(blizzard.sys_ck);
+}
+
+static void blizzard_enable_clocks(int enable)
+{
+ if (enable)
+ clk_enable(blizzard.sys_ck);
+ else
+ clk_disable(blizzard.sys_ck);
+}
+
+static void blizzard_power_up(struct device *dev)
+{
+ /* Vcore to 1.475V */
+ tahvo_set_clear_reg_bits(0x07, 0, 0xf);
+ msleep(10);
+
+ blizzard_enable_clocks(1);
+ omap_set_gpio_dataout(N800_BLIZZARD_POWERDOWN_GPIO, 1);
+}
+
+static void blizzard_power_down(struct device *dev)
+{
+ omap_set_gpio_dataout(N800_BLIZZARD_POWERDOWN_GPIO, 0);
+ blizzard_enable_clocks(0);
+
+ /* Vcore to 1.005V */
+ tahvo_set_clear_reg_bits(0x07, 0xf, 0);
+}
+
+static struct blizzard_platform_data n800_blizzard_data = {
+ .power_up = blizzard_power_up,
+ .power_down = blizzard_power_down,
+ .get_clock_rate = blizzard_get_clock_rate,
+ .te_connected = 1,
+};
+
+static void __init blizzard_dev_init(void)
+{
+ int r;
+
+ r = omap_request_gpio(N800_BLIZZARD_POWERDOWN_GPIO);
+ if (r < 0)
+ return;
+ omap_set_gpio_direction(N800_BLIZZARD_POWERDOWN_GPIO, 0);
+ omap_set_gpio_dataout(N800_BLIZZARD_POWERDOWN_GPIO, 1);
+
+ blizzard_get_clocks();
+ omapfb_set_ctrl_platform_data(&n800_blizzard_data);
+}
+
+static struct omap_mmc_config n800_mmc_config __initdata = {
+ .mmc [0] = {
+ .enabled = 1,
+ .wire4 = 1,
+ },
+};
+
+extern struct omap_mmc_platform_data n800_mmc_data;
+
+static struct omap_board_config_kernel n800_config[] __initdata = {
+ { OMAP_TAG_UART, &n800_uart_config },
+ { OMAP_TAG_FBMEM, &n800_fbmem0_config },
+ { OMAP_TAG_FBMEM, &n800_fbmem1_config },
+ { OMAP_TAG_FBMEM, &n800_fbmem2_config },
+ { OMAP_TAG_TMP105, &n800_tmp105_config },
+ { OMAP_TAG_MMC, &n800_mmc_config },
+};
+
+static struct tsc2301_platform_data tsc2301_config = {
+ .reset_gpio = N800_TSC2301_RESET_GPIO,
+ .keymap = {
+ -1, /* Event for bit 0 */
+ KEY_UP, /* Event for bit 1 (up) */
+ KEY_F5, /* Event for bit 2 (home) */
+ -1, /* Event for bit 3 */
+ KEY_LEFT, /* Event for bit 4 (left) */
+ KEY_ENTER, /* Event for bit 5 (enter) */
+ KEY_RIGHT, /* Event for bit 6 (right) */
+ -1, /* Event for bit 7 */
+ KEY_ESC, /* Event for bit 8 (cycle) */
+ KEY_DOWN, /* Event for bit 9 (down) */
+ KEY_F4, /* Event for bit 10 (menu) */
+ -1, /* Event for bit 11 */
+ KEY_F8, /* Event for bit 12 (Zoom-) */
+ KEY_F6, /* Event for bit 13 (FS) */
+ KEY_F7, /* Event for bit 14 (Zoom+) */
+ -1, /* Event for bit 15 */
+ },
+ .kp_rep = 0,
+ .keyb_name = "Internal keypad",
+};
+
+static void tsc2301_dev_init(void)
+{
+ int r;
+ int gpio = N800_KEYB_IRQ_GPIO;
+
+ r = gpio_request(gpio, "tsc2301 KBD IRQ");
+ if (r >= 0) {
+ gpio_direction_input(gpio);
+ tsc2301_config.keyb_int = OMAP_GPIO_IRQ(gpio);
+ } else {
+ printk(KERN_ERR "unable to get KBD GPIO");
+ }
+
+ gpio = N800_DAV_IRQ_GPIO;
+ r = gpio_request(gpio, "tsc2301 DAV IRQ");
+ if (r >= 0) {
+ gpio_direction_input(gpio);
+ tsc2301_config.dav_int = OMAP_GPIO_IRQ(gpio);
+ } else {
+ printk(KERN_ERR "unable to get DAV GPIO");
+ }
+}
+
+static int __init tea5761_dev_init(void)
+{
+ const struct omap_tea5761_config *info;
+ int enable_gpio = 0;
+
+ info = omap_get_config(OMAP_TAG_TEA5761, struct omap_tea5761_config);
+ if (info)
+ enable_gpio = info->enable_gpio;
+
+ if (enable_gpio) {
+ pr_debug("Enabling tea5761 at GPIO %d\n",
+ enable_gpio);
+
+ if (omap_request_gpio(enable_gpio) < 0) {
+ printk(KERN_ERR "Can't request GPIO %d\n",
+ enable_gpio);
+ return -ENODEV;
+ }
+
+ omap_set_gpio_direction(enable_gpio, 0);
+ udelay(50);
+ omap_set_gpio_dataout(enable_gpio, 1);
+ }
+
+ return 0;
+}
+
+static struct omap2_mcspi_device_config tsc2301_mcspi_config = {
+ .turbo_mode = 0,
+ .single_channel = 1,
+};
+
+static struct omap2_mcspi_device_config mipid_mcspi_config = {
+ .turbo_mode = 0,
+ .single_channel = 1,
+};
+
+static struct omap2_mcspi_device_config cx3110x_mcspi_config = {
+ .turbo_mode = 0,
+ .single_channel = 1,
+};
+
+#ifdef CONFIG_TOUCHSCREEN_TSC2005
+static struct tsc2005_platform_data tsc2005_config = {
+ .reset_gpio = 94,
+ .dav_gpio = 106
+};
+
+static struct omap2_mcspi_device_config tsc2005_mcspi_config = {
+ .turbo_mode = 0,
+ .single_channel = 1,
+};
+#endif
+
+static struct spi_board_info n800_spi_board_info[] __initdata = {
+ {
+ .modalias = "lcd_mipid",
+ .bus_num = 1,
+ .chip_select = 1,
+ .max_speed_hz = 4000000,
+ .controller_data= &mipid_mcspi_config,
+ .platform_data = &n800_mipid_platform_data,
+ }, {
+ .modalias = "cx3110x",
+ .bus_num = 2,
+ .chip_select = 0,
+ .max_speed_hz = 48000000,
+ .controller_data= &cx3110x_mcspi_config,
+ },
+ {
+ .modalias = "tsc2301",
+ .bus_num = 1,
+ .chip_select = 0,
+ .max_speed_hz = 6000000,
+ .controller_data= &tsc2301_mcspi_config,
+ .platform_data = &tsc2301_config,
+ },
+};
+
+static struct spi_board_info n810_spi_board_info[] __initdata = {
+ {
+ .modalias = "lcd_mipid",
+ .bus_num = 1,
+ .chip_select = 1,
+ .max_speed_hz = 4000000,
+ .controller_data = &mipid_mcspi_config,
+ .platform_data = &n800_mipid_platform_data,
+ },
+ {
+ .modalias = "cx3110x",
+ .bus_num = 2,
+ .chip_select = 0,
+ .max_speed_hz = 48000000,
+ .controller_data = &cx3110x_mcspi_config,
+ },
+ {
+ .modalias = "tsc2005",
+ .bus_num = 1,
+ .chip_select = 0,
+ .max_speed_hz = 6000000,
+ .controller_data = &tsc2005_mcspi_config,
+ .platform_data = &tsc2005_config,
+ },
+};
+
+static void __init tsc2005_set_config(void)
+{
+ const struct omap_lcd_config *conf;
+
+ conf = omap_get_config(OMAP_TAG_LCD, struct omap_lcd_config);
+ if (conf != NULL) {
+#ifdef CONFIG_TOUCHSCREEN_TSC2005
+ if (strcmp(conf->panel_name, "lph8923") == 0) {
+ tsc2005_config.ts_x_plate_ohm = 180;
+ tsc2005_config.ts_hw_avg = 0;
+ tsc2005_config.ts_ignore_last = 0;
+ tsc2005_config.ts_touch_pressure = 1500;
+ tsc2005_config.ts_stab_time = 100;
+ tsc2005_config.ts_pressure_max = 2048;
+ tsc2005_config.ts_pressure_fudge = 2;
+ tsc2005_config.ts_x_max = 4096;
+ tsc2005_config.ts_x_fudge = 4;
+ tsc2005_config.ts_y_max = 4096;
+ tsc2005_config.ts_y_fudge = 7;
+ } else if (strcmp(conf->panel_name, "ls041y3") == 0) {
+ tsc2005_config.ts_x_plate_ohm = 280;
+ tsc2005_config.ts_hw_avg = 0;
+ tsc2005_config.ts_ignore_last = 0;
+ tsc2005_config.ts_touch_pressure = 1500;
+ tsc2005_config.ts_stab_time = 1000;
+ tsc2005_config.ts_pressure_max = 2048;
+ tsc2005_config.ts_pressure_fudge = 2;
+ tsc2005_config.ts_x_max = 4096;
+ tsc2005_config.ts_x_fudge = 4;
+ tsc2005_config.ts_y_max = 4096;
+ tsc2005_config.ts_y_fudge = 7;
+ } else {
+ printk(KERN_ERR "Unknown panel type, set default "
+ "touchscreen configuration\n");
+ tsc2005_config.ts_x_plate_ohm = 200;
+ tsc2005_config.ts_stab_time = 100;
+ }
+#endif
+ }
+}
+
+#if defined(CONFIG_CBUS_RETU) && defined(CONFIG_LEDS_OMAP_PWM)
+
+void retu_keypad_led_set_power(struct omap_pwm_led_platform_data *self,
+ int on_off)
+{
+ if (on_off) {
+ retu_write_reg(RETU_REG_CTRL_SET, 1 << 6);
+ msleep(2);
+ retu_write_reg(RETU_REG_CTRL_SET, 1 << 3);
+ } else {
+ retu_write_reg(RETU_REG_CTRL_CLR, (1 << 6) | (1 << 3));
+ }
+}
+
+static struct omap_pwm_led_platform_data n800_keypad_led_data = {
+ .name = "keypad",
+ .intensity_timer = 10,
+ .blink_timer = 9,
+ .set_power = retu_keypad_led_set_power,
+};
+
+static struct platform_device n800_keypad_led_device = {
+ .name = "omap_pwm_led",
+ .id = -1,
+ .dev = {
+ .platform_data = &n800_keypad_led_data,
+ },
+};
+#endif
+
+#if defined(CONFIG_TOUCHSCREEN_TSC2301)
+static void __init n800_ts_set_config(void)
+{
+ const struct omap_lcd_config *conf;
+
+ conf = omap_get_config(OMAP_TAG_LCD, struct omap_lcd_config);
+ if (conf != NULL) {
+ if (strcmp(conf->panel_name, "lph8923") == 0) {
+ tsc2301_config.ts_x_plate_ohm = 180;
+ tsc2301_config.ts_hw_avg = 8;
+ tsc2301_config.ts_max_pressure = 2048;
+ tsc2301_config.ts_touch_pressure = 400;
+ tsc2301_config.ts_stab_time = 100;
+ tsc2301_config.ts_pressure_fudge = 2;
+ tsc2301_config.ts_x_max = 4096;
+ tsc2301_config.ts_x_fudge = 4;
+ tsc2301_config.ts_y_max = 4096;
+ tsc2301_config.ts_y_fudge = 7;
+ } else if (strcmp(conf->panel_name, "ls041y3") == 0) {
+ tsc2301_config.ts_x_plate_ohm = 280;
+ tsc2301_config.ts_hw_avg = 8;
+ tsc2301_config.ts_touch_pressure = 400;
+ tsc2301_config.ts_max_pressure = 2048;
+ tsc2301_config.ts_stab_time = 1000;
+ tsc2301_config.ts_pressure_fudge = 2;
+ tsc2301_config.ts_x_max = 4096;
+ tsc2301_config.ts_x_fudge = 4;
+ tsc2301_config.ts_y_max = 4096;
+ tsc2301_config.ts_y_fudge = 7;
+ } else {
+ printk(KERN_ERR "Unknown panel type, set default "
+ "touchscreen configuration\n");
+ tsc2301_config.ts_x_plate_ohm = 200;
+ tsc2301_config.ts_stab_time = 100;
+ }
+ }
+}
+#else
+static inline void n800_ts_set_config(void)
+{
+}
+#endif
+
+static struct omap_gpio_switch n800_gpio_switches[] __initdata = {
+ {
+ .name = "bat_cover",
+ .gpio = -1,
+ .debounce_rising = 100,
+ .debounce_falling = 0,
+ .notify = n800_mmc_slot1_cover_handler,
+ .notify_data = NULL,
+ }, {
+ .name = "headphone",
+ .gpio = -1,
+ .debounce_rising = 200,
+ .debounce_falling = 200,
+ }, {
+ .name = "cam_act",
+ .gpio = -1,
+ .debounce_rising = 200,
+ .debounce_falling = 200,
+ }, {
+ .name = "cam_turn",
+ .gpio = -1,
+ .debounce_rising = 100,
+ .debounce_falling = 100,
+ },
+};
+
+static struct platform_device *n800_devices[] __initdata = {
+#if defined(CONFIG_CBUS_RETU) && defined(CONFIG_LEDS_OMAP_PWM)
+ &n800_keypad_led_device,
+#endif
+};
+
+#ifdef CONFIG_MENELAUS
+static int n800_auto_sleep_regulators(void)
+{
+ u32 val;
+ int ret;
+
+ val = EN_VPLL_SLEEP | EN_VMMC_SLEEP \
+ | EN_VAUX_SLEEP | EN_VIO_SLEEP \
+ | EN_VMEM_SLEEP | EN_DC3_SLEEP \
+ | EN_VC_SLEEP | EN_DC2_SLEEP;
+
+ ret = menelaus_set_regulator_sleep(1, val);
+ if (ret < 0) {
+ printk(KERN_ERR "Could not set regulators to sleep on "
+ "menelaus: %u\n", ret);
+ return ret;
+ }
+ return 0;
+}
+
+static int n800_auto_voltage_scale(void)
+{
+ int ret;
+
+ ret = menelaus_set_vcore_hw(1400, 1050);
+ if (ret < 0) {
+ printk(KERN_ERR "Could not set VCORE voltage on "
+ "menelaus: %u\n", ret);
+ return ret;
+ }
+ return 0;
+}
+
+static int n800_menelaus_init(struct device *dev)
+{
+ int ret;
+
+ ret = n800_auto_voltage_scale();
+ if (ret < 0)
+ return ret;
+ ret = n800_auto_sleep_regulators();
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+static struct menelaus_platform_data n800_menelaus_platform_data = {
+ .late_init = n800_menelaus_init,
+};
+#endif
+
+static struct i2c_board_info __initdata n800_i2c_board_info_1[] = {
+ {
+ I2C_BOARD_INFO("menelaus", 0x72),
+ .irq = INT_24XX_SYS_NIRQ,
+ .platform_data = &n800_menelaus_platform_data,
+ },
+};
+
+extern struct tcm825x_platform_data n800_tcm825x_platform_data;
+
+static struct i2c_board_info __initdata n800_i2c_board_info_2[] = {
+#if defined (CONFIG_VIDEO_TCM825X) || defined (CONFIG_VIDEO_TCM825X_MODULE)
+ {
+ I2C_BOARD_INFO(TCM825X_NAME, TCM825X_I2C_ADDR),
+ .platform_data = &n800_tcm825x_platform_data,
+ },
+#endif
+#if defined(CONFIG_RADIO_TEA5761) || defined(CONFIG_RADIO_TEA5761_MODULE)
+ {
+ I2C_BOARD_INFO("tea5761", 0x10),
+ },
+#endif
+#ifdef CONFIG_MACH_NOKIA_N810
+ {
+ I2C_BOARD_INFO("lm8323", 0x45),
+ .type = "lm8323",
+ .irq = OMAP_GPIO_IRQ(109),
+ .platform_data = &lm8323_pdata,
+ },
+#endif
+ {
+ I2C_BOARD_INFO("tsl2563", 0x29),
+ .type = "tsl2563",
+ },
+ {
+ I2C_BOARD_INFO("lp5521", 0x32),
+ .type = "lp5521",
+ },
+};
+
+void __init nokia_n800_common_init(void)
+{
+ platform_add_devices(n800_devices, ARRAY_SIZE(n800_devices));
+
+ n800_flash_init();
+ n800_mmc_init();
+ n800_bt_init();
+ n800_dsp_init();
+ n800_usb_init();
+ n800_cam_init();
+ if (machine_is_nokia_n800())
+ spi_register_board_info(n800_spi_board_info,
+ ARRAY_SIZE(n800_spi_board_info));
+ if (machine_is_nokia_n810()) {
+ tsc2005_set_config();
+ spi_register_board_info(n810_spi_board_info,
+ ARRAY_SIZE(n810_spi_board_info));
+ }
+ omap_serial_init();
+ omap_register_i2c_bus(1, 400, n800_i2c_board_info_1,
+ ARRAY_SIZE(n800_i2c_board_info_1));
+ omap_register_i2c_bus(2, 400, n800_i2c_board_info_2,
+ ARRAY_SIZE(n800_i2c_board_info_2));
+ mipid_dev_init();
+ blizzard_dev_init();
+}
+
+static void __init nokia_n800_init(void)
+{
+ nokia_n800_common_init();
+
+ n800_audio_init(&tsc2301_config);
+ n800_ts_set_config();
+ tsc2301_dev_init();
+ tea5761_dev_init();
+ omap_register_gpio_switches(n800_gpio_switches,
+ ARRAY_SIZE(n800_gpio_switches));
+}
+
+void __init nokia_n800_map_io(void)
+{
+ omap_board_config = n800_config;
+ omap_board_config_size = ARRAY_SIZE(n800_config);
+
+ omap2_set_globals_242x();
+ omap2_map_common_io();
+}
+
+MACHINE_START(NOKIA_N800, "Nokia N800")
+ .phys_io = 0x48000000,
+ .io_pg_offst = ((0xd8000000) >> 18) & 0xfffc,
+ .boot_params = 0x80000100,
+ .map_io = nokia_n800_map_io,
+ .init_irq = nokia_n800_init_irq,
+ .init_machine = nokia_n800_init,
+ .timer = &omap_timer,
+MACHINE_END
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap2/board-n800.h
+ *
+ * Copyright (C) 2005-2007 Nokia Corporation
+ * Author: Lauri Leukkunen <lauri.leukkunen@nokia.com>
+ *
+ * Modified from mach-omap2/board-n800.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.
+ */
+
+#ifndef __ARCH_ARM_MACH_OMAP2_BOARD_N800_H
+#define __ARCH_ARM_MACH_OMAP2_BOARD_N800_H
+
+void __init nokia_n800_common_init(void);
+void __init nokia_n800_map_io(void);
+void __init nokia_n800_init_irq(void);
+
+#endif
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap2/board-n810.c
+ *
+ * Copyright (C) 2007 Nokia
+ * Author: Lauri Leukkunen <lauri.leukkunen@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/i2c.h>
+#include <linux/i2c/lm8323.h>
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/arch/board.h>
+#include <asm/arch/common.h>
+
+#include "board-n800.h"
+
+static void __init nokia_n810_init(void)
+{
+ nokia_n800_common_init();
+}
+
+MACHINE_START(NOKIA_N810, "Nokia N810")
+ .phys_io = 0x48000000,
+ .io_pg_offst = ((0xd8000000) >> 18) & 0xfffc,
+ .boot_params = 0x80000100,
+ .map_io = nokia_n800_map_io,
+ .init_irq = nokia_n800_init_irq,
+ .init_machine = nokia_n810_init,
+ .timer = &omap_timer,
+MACHINE_END
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap2/board-omap3beagle.c
+ *
+ * Copyright (C) 2008 Texas Instruments
+ *
+ * Modified from mach-omap2/board-3430sdp.c
+ *
+ * Initial code: Syed Mohammed Khasim
+ *
+ * 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/delay.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.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/board.h>
+#include <asm/arch/usb-musb.h>
+#include <asm/arch/usb-ehci.h>
+#include <asm/arch/hsmmc.h>
+#include <asm/arch/common.h>
+
+static struct omap_uart_config omap3_beagle_uart_config __initdata = {
+ .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
+};
+
+static int __init omap3_beagle_i2c_init(void)
+{
+ omap_register_i2c_bus(1, 2600, NULL, 0);
+ omap_register_i2c_bus(2, 400, NULL, 0);
+ omap_register_i2c_bus(3, 400, NULL, 0);
+ return 0;
+}
+
+static void __init omap3_beagle_init_irq(void)
+{
+ omap2_init_common_hw();
+ omap_init_irq();
+ omap_gpio_init();
+}
+
+static struct omap_mmc_config omap3beagle_mmc_config __initdata = {
+ .mmc [0] = {
+ .enabled = 1,
+ .wire4 = 1,
+ },
+};
+
+static struct omap_board_config_kernel omap3_beagle_config[] __initdata = {
+ { OMAP_TAG_UART, &omap3_beagle_uart_config },
+ { OMAP_TAG_MMC, &omap3beagle_mmc_config },
+};
+
+static void __init omap3_beagle_init(void)
+{
+ omap_board_config = omap3_beagle_config;
+ omap_board_config_size = ARRAY_SIZE(omap3_beagle_config);
+ omap_serial_init();
+ hsmmc_init();
+ usb_musb_init();
+ usb_ehci_init();
+}
+
+arch_initcall(omap3_beagle_i2c_init);
+
+static void __init omap3_beagle_map_io(void)
+{
+ omap2_set_globals_343x();
+ omap2_map_common_io();
+}
+
+MACHINE_START(OMAP3_BEAGLE, "OMAP3 Beagle Board")
+ /* Maintainer: Syed Mohammed Khasim - http://beagleboard.org */
+ .phys_io = 0x48000000,
+ .io_pg_offst = ((0xd8000000) >> 18) & 0xfffc,
+ .boot_params = 0x80000100,
+ .map_io = omap3_beagle_map_io,
+ .init_irq = omap3_beagle_init_irq,
+ .init_machine = omap3_beagle_init,
+ .timer = &omap_timer,
+MACHINE_END
--- /dev/null
+/*
+ * board-omap3evm-flash.c
+ *
+ * Copyright (c) 2008 Texas Instruments,
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/onenand_regs.h>
+#include <linux/types.h>
+#include <linux/io.h>
+
+#include <asm/mach/flash.h>
+#include <asm/arch/onenand.h>
+#include <asm/arch/board.h>
+#include <asm/arch/gpmc.h>
+#include <asm/arch/nand.h>
+
+static int omap3evm_onenand_setup(void __iomem *);
+
+static struct mtd_partition omap3evm_onenand_partitions[] = {
+ {
+ .name = "xloader",
+ .offset = 0,
+ .size = 4*(64*2048),
+ .mask_flags = MTD_WRITEABLE
+ },
+ {
+ .name = "uboot",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 15*(64*2048),
+ .mask_flags = MTD_WRITEABLE
+ },
+ {
+ .name = "params",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 1*(64*2048),
+ },
+ {
+ .name = "linux",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 40*(64*2048),
+ },
+ {
+ .name = "jffs2",
+ .offset = MTDPART_OFS_APPEND,
+ .size = MTDPART_SIZ_FULL,
+ },
+};
+
+static struct omap_onenand_platform_data omap3evm_onenand_data = {
+ .parts = omap3evm_onenand_partitions,
+ .nr_parts = ARRAY_SIZE(omap3evm_onenand_partitions),
+ .onenand_setup = omap3evm_onenand_setup,
+ .dma_channel = -1, /* disable DMA in OMAP OneNAND driver */
+};
+
+static struct platform_device omap3evm_onenand_device = {
+ .name = "omap2-onenand",
+ .id = -1,
+ .dev = {
+ .platform_data = &omap3evm_onenand_data,
+ },
+};
+
+/*
+ * omap3evm_onenand_setup - Set the onenand sync mode
+ * @onenand_base: The onenand base address in GPMC memory map
+ *
+ */
+
+static int omap3evm_onenand_setup(void __iomem *onenand_base)
+ {
+ /* nothing is required to be setup for onenand as of now */
+ return 0;
+}
+
+void __init omap3evm_flash_init(void)
+{
+ u8 cs = 0;
+ u8 onenandcs = GPMC_CS_NUM + 1;
+
+ while (cs < GPMC_CS_NUM) {
+ u32 ret = 0;
+ ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
+
+ /*
+ * xloader/Uboot would have programmed the oneNAND
+ * base address for us This is a ugly hack. The proper
+ * way of doing this is to pass the setup of u-boot up
+ * to kernel using kernel params - something on the
+ * lines of machineID. Check if oneNAND is configured
+ */
+ if ((ret & 0x3F) == (ONENAND_MAP >> 24))
+ onenandcs = cs;
+ cs++;
+ }
+ if (onenandcs > GPMC_CS_NUM) {
+ printk(KERN_INFO "OneNAND: Unable to find configuration "
+ " in GPMC\n ");
+ return;
+ }
+
+ if (onenandcs < GPMC_CS_NUM) {
+ omap3evm_onenand_data.cs = onenandcs;
+ if (platform_device_register(&omap3evm_onenand_device) < 0)
+ printk(KERN_ERR "Unable to register OneNAND device\n");
+ }
+}
+
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap2/board-omap3evm.c
+ *
+ * Copyright (C) 2008 Texas Instruments
+ *
+ * Modified from mach-omap2/board-3430sdp.c
+ *
+ * Initial code: Syed Mohammed Khasim
+ *
+ * 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/delay.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.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/board.h>
+#include <asm/arch/hsmmc.h>
+#include <asm/arch/usb-musb.h>
+#include <asm/arch/usb-ehci.h>
+#include <asm/arch/common.h>
+#include <asm/arch/mcspi.h>
+
+static struct omap_uart_config omap3_evm_uart_config __initdata = {
+ .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
+};
+
+static int __init omap3_evm_i2c_init(void)
+{
+ omap_register_i2c_bus(1, 2600, NULL, 0);
+ omap_register_i2c_bus(2, 400, NULL, 0);
+ omap_register_i2c_bus(3, 400, NULL, 0);
+ return 0;
+}
+
+static struct omap_mmc_config omap3_evm_mmc_config __initdata = {
+ .mmc [0] = {
+ .enabled = 1,
+ .wire4 = 1,
+ },
+};
+
+static struct platform_device omap3_evm_lcd_device = {
+ .name = "omap3evm_lcd",
+ .id = -1,
+};
+
+static struct omap_lcd_config omap3_evm_lcd_config __initdata = {
+ .ctrl_name = "internal",
+};
+
+static struct platform_device omap3_evm_twl4030rtc_device = {
+ .name = "twl4030_rtc",
+ .id = -1,
+};
+
+static void ads7846_dev_init(void)
+{
+ if (omap_request_gpio(OMAP3_EVM_TS_GPIO) < 0)
+ printk(KERN_ERR "can't get ads7846 pen down GPIO\n");
+
+ omap_set_gpio_direction(OMAP3_EVM_TS_GPIO, 1);
+
+ omap_set_gpio_debounce(OMAP3_EVM_TS_GPIO, 1);
+ omap_set_gpio_debounce_time(OMAP3_EVM_TS_GPIO, 0xa);
+}
+
+static int ads7846_get_pendown_state(void)
+{
+ return !omap_get_gpio_datain(OMAP3_EVM_TS_GPIO);
+}
+
+struct ads7846_platform_data ads7846_config = {
+ .get_pendown_state = ads7846_get_pendown_state,
+ .keep_vref_on = 1,
+};
+
+static struct omap2_mcspi_device_config ads7846_mcspi_config = {
+ .turbo_mode = 0,
+ .single_channel = 1, /* 0: slave, 1: master */
+};
+
+struct spi_board_info omap3evm_spi_board_info[] = {
+ [0] = {
+ .modalias = "ads7846",
+ .bus_num = 1,
+ .chip_select = 0,
+ .max_speed_hz = 1500000,
+ .controller_data = &ads7846_mcspi_config,
+ .irq = OMAP_GPIO_IRQ(OMAP3_EVM_TS_GPIO),
+ .platform_data = &ads7846_config,
+ },
+};
+
+static void __init omap3_evm_init_irq(void)
+{
+ omap2_init_common_hw();
+ omap_init_irq();
+ omap_gpio_init();
+}
+
+static struct omap_board_config_kernel omap3_evm_config[] __initdata = {
+ { OMAP_TAG_UART, &omap3_evm_uart_config },
+ { OMAP_TAG_MMC, &omap3_evm_mmc_config },
+ { OMAP_TAG_LCD, &omap3_evm_lcd_config },
+};
+
+static struct platform_device *omap3_evm_devices[] __initdata = {
+ &omap3_evm_lcd_device,
+#ifdef CONFIG_RTC_DRV_TWL4030
+ &omap3_evm_twl4030rtc_device,
+#endif
+};
+
+static void __init omap3_evm_init(void)
+{
+ platform_add_devices(omap3_evm_devices, ARRAY_SIZE(omap3_evm_devices));
+ omap_board_config = omap3_evm_config;
+ omap_board_config_size = ARRAY_SIZE(omap3_evm_config);
+
+ spi_register_board_info(omap3evm_spi_board_info,
+ ARRAY_SIZE(omap3evm_spi_board_info));
+
+ omap_serial_init();
+ hsmmc_init();
+ usb_musb_init();
+ usb_ehci_init();
+ omap3evm_flash_init();
+ ads7846_dev_init();
+}
+
+arch_initcall(omap3_evm_i2c_init);
+
+static void __init omap3_evm_map_io(void)
+{
+ omap2_set_globals_343x();
+ omap2_map_common_io();
+}
+
+MACHINE_START(OMAP3EVM, "OMAP3 EVM")
+ /* Maintainer: Syed Mohammed Khasim - Texas Instruments */
+ .phys_io = 0x48000000,
+ .io_pg_offst = ((0xd8000000) >> 18) & 0xfffc,
+ .boot_params = 0x80000100,
+ .map_io = omap3_evm_map_io,
+ .init_irq = omap3_evm_init_irq,
+ .init_machine = omap3_evm_init,
+ .timer = &omap_timer,
+MACHINE_END
#define MAX_CLOCK_ENABLE_WAIT 100000
+/* DPLL rate rounding: minimum DPLL multiplier, divider values */
+#define DPLL_MIN_MULTIPLIER 1
+#define DPLL_MIN_DIVIDER 1
+
+/* Possible error results from _dpll_test_mult */
+#define DPLL_MULT_UNDERFLOW (1 << 0)
+
+/*
+ * Scale factor to mitigate roundoff errors in DPLL rate rounding.
+ * The higher the scale factor, the greater the risk of arithmetic overflow,
+ * but the closer the rounded rate to the target rate. DPLL_SCALE_FACTOR
+ * must be a power of DPLL_SCALE_BASE.
+ */
+#define DPLL_SCALE_FACTOR 64
+#define DPLL_SCALE_BASE 2
+#define DPLL_ROUNDING_VAL ((DPLL_SCALE_BASE / 2) * \
+ (DPLL_SCALE_FACTOR / DPLL_SCALE_BASE))
+
u8 cpu_mask;
/*-------------------------------------------------------------------------
- * Omap2 specific clock functions
+ * OMAP2/3 specific clock functions
*-------------------------------------------------------------------------*/
+/**
+ * omap2_init_clk_clkdm - look up a clockdomain name, store pointer in clk
+ * @clk: OMAP clock struct ptr to use
+ *
+ * Convert a clockdomain name stored in a struct clk 'clk' into a
+ * clockdomain pointer, and save it into the struct clk. Intended to be
+ * called during clk_register(). No return value.
+ */
+void omap2_init_clk_clkdm(struct clk *clk)
+{
+ struct clockdomain *clkdm;
+
+ if (!clk->clkdm_name)
+ return;
+
+ clkdm = clkdm_lookup(clk->clkdm_name);
+ if (clkdm) {
+ pr_debug("clock: associated clk %s to clkdm %s\n",
+ clk->name, clk->clkdm_name);
+ clk->clkdm = clkdm;
+ } else {
+ pr_debug("clock: could not associate clk %s to "
+ "clkdm %s\n", clk->name, clk->clkdm_name);
+ }
+}
+
/**
* omap2_init_clksel_parent - set a clksel clk's parent field from the hardware
* @clk: OMAP clock struct ptr to use
{
long long dpll_clk;
u32 dpll_mult, dpll_div, dpll;
- const struct dpll_data *dd;
+ struct dpll_data *dd;
dd = clk->dpll_data;
/* REVISIT: What do we return on error? */
/* REVISIT: What are the appropriate exclusions for 34XX? */
/* OMAP3: ignore DSS-mod clocks */
if (cpu_is_omap34xx() &&
- (((u32)reg & ~0xff) == (u32)OMAP_CM_REGADDR(OMAP3430_DSS_MOD, 0)))
+ (((u32)reg & ~0xff) == (u32)OMAP_CM_REGADDR(OMAP3430_DSS_MOD, 0) ||
+ ((((u32)reg & ~0xff) == (u32)OMAP_CM_REGADDR(CORE_MOD, 0)) &&
+ clk->enable_bit == OMAP3430_EN_SSI_SHIFT)))
return;
/* Check if both functional and interface clocks
_omap2_clk_disable(clk);
if (likely((u32)clk->parent))
omap2_clk_disable(clk->parent);
+ if (clk->clkdm)
+ omap2_clkdm_clk_disable(clk->clkdm, clk);
+
}
}
return ret;
}
+ if (clk->clkdm)
+ omap2_clkdm_clk_enable(clk->clkdm, clk);
+
ret = _omap2_clk_enable(clk);
- if (unlikely(ret != 0) && clk->parent) {
- omap2_clk_disable(clk->parent);
- clk->usecount--;
+ if (unlikely(ret != 0)) {
+ if (clk->clkdm)
+ omap2_clkdm_clk_disable(clk->clkdm, clk);
+
+ if (clk->parent) {
+ omap2_clk_disable(clk->parent);
+ clk->usecount--;
+ }
}
}
int omap2_clksel_set_rate(struct clk *clk, unsigned long rate)
{
- u32 field_mask, field_val, reg_val, validrate, new_div = 0;
+ u32 field_mask, field_val, validrate, new_div = 0;
void __iomem *div_addr;
validrate = omap2_clksel_round_rate_div(clk, rate, &new_div);
if (field_val == ~0)
return -EINVAL;
- reg_val = __raw_readl(div_addr);
- reg_val &= ~field_mask;
- reg_val |= (field_val << __ffs(field_mask));
- __raw_writel(reg_val, div_addr);
+ cm_rmw_reg_bits(field_mask, field_val << __ffs(field_mask), div_addr);
+
wmb();
clk->rate = clk->parent->rate / new_div;
wmb();
if (clk->flags & DELAYED_APP && cpu_is_omap24xx()) {
- __raw_writel(OMAP24XX_VALID_CONFIG, OMAP24XX_PRCM_CLKCFG_CTRL);
+ __raw_writel(OMAP24XX_VALID_CONFIG,
+ OMAP24XX_PRCM_CLKCFG_CTRL);
wmb();
}
return 0;
}
+/* DPLL rate rounding code */
+
+/**
+ * omap2_dpll_set_rate_tolerance: set the error tolerance during rate rounding
+ * @clk: struct clk * of the DPLL
+ * @tolerance: maximum rate error tolerance
+ *
+ * Set the maximum DPLL rate error tolerance for the rate rounding
+ * algorithm. The rate tolerance is an attempt to balance DPLL power
+ * saving (the least divider value "n") vs. rate fidelity (the least
+ * difference between the desired DPLL target rate and the rounded
+ * rate out of the algorithm). So, increasing the tolerance is likely
+ * to decrease DPLL power consumption and increase DPLL rate error.
+ * Returns -EINVAL if provided a null clock ptr or a clk that is not a
+ * DPLL; or 0 upon success.
+ */
+int omap2_dpll_set_rate_tolerance(struct clk *clk, unsigned int tolerance)
+{
+ if (!clk || !clk->dpll_data)
+ return -EINVAL;
+
+ clk->dpll_data->rate_tolerance = tolerance;
+
+ return 0;
+}
+
+static unsigned long _dpll_compute_new_rate(unsigned long parent_rate, unsigned int m, unsigned int n)
+{
+ unsigned long long num;
+
+ num = (unsigned long long)parent_rate * m;
+ do_div(num, n);
+ return num;
+}
+
+/*
+ * _dpll_test_mult - test a DPLL multiplier value
+ * @m: pointer to the DPLL m (multiplier) value under test
+ * @n: current DPLL n (divider) value under test
+ * @new_rate: pointer to storage for the resulting rounded rate
+ * @target_rate: the desired DPLL rate
+ * @parent_rate: the DPLL's parent clock rate
+ *
+ * This code tests a DPLL multiplier value, ensuring that the
+ * resulting rate will not be higher than the target_rate, and that
+ * the multiplier value itself is valid for the DPLL. Initially, the
+ * integer pointed to by the m argument should be prescaled by
+ * multiplying by DPLL_SCALE_FACTOR. The code will replace this with
+ * a non-scaled m upon return. This non-scaled m will result in a
+ * new_rate as close as possible to target_rate (but not greater than
+ * target_rate) given the current (parent_rate, n, prescaled m)
+ * triple. Returns DPLL_MULT_UNDERFLOW in the event that the
+ * non-scaled m attempted to underflow, which can allow the calling
+ * function to bail out early; or 0 upon success.
+ */
+static int _dpll_test_mult(int *m, int n, unsigned long *new_rate,
+ unsigned long target_rate,
+ unsigned long parent_rate)
+{
+ int flags = 0, carry = 0;
+
+ /* Unscale m and round if necessary */
+ if (*m % DPLL_SCALE_FACTOR >= DPLL_ROUNDING_VAL)
+ carry = 1;
+ *m = (*m / DPLL_SCALE_FACTOR) + carry;
+
+ /*
+ * The new rate must be <= the target rate to avoid programming
+ * a rate that is impossible for the hardware to handle
+ */
+ *new_rate = _dpll_compute_new_rate(parent_rate, *m, n);
+ if (*new_rate > target_rate) {
+ (*m)--;
+ *new_rate = 0;
+ }
+
+ /* Guard against m underflow */
+ if (*m < DPLL_MIN_MULTIPLIER) {
+ *m = DPLL_MIN_MULTIPLIER;
+ *new_rate = 0;
+ flags = DPLL_MULT_UNDERFLOW;
+ }
+
+ if (*new_rate == 0)
+ *new_rate = _dpll_compute_new_rate(parent_rate, *m, n);
+
+ return flags;
+}
+
+/**
+ * omap2_dpll_round_rate - round a target rate for an OMAP DPLL
+ * @clk: struct clk * for a DPLL
+ * @target_rate: desired DPLL clock rate
+ *
+ * Given a DPLL, a desired target rate, and a rate tolerance, round
+ * the target rate to a possible, programmable rate for this DPLL.
+ * Rate tolerance is assumed to be set by the caller before this
+ * function is called. Attempts to select the minimum possible n
+ * within the tolerance to reduce power consumption. Stores the
+ * computed (m, n) in the DPLL's dpll_data structure so set_rate()
+ * will not need to call this (expensive) function again. Returns ~0
+ * if the target rate cannot be rounded, either because the rate is
+ * too low or because the rate tolerance is set too tightly; or the
+ * rounded rate upon success.
+ */
+long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate)
+{
+ int m, n, r, e, scaled_max_m;
+ unsigned long scaled_rt_rp, new_rate;
+ int min_e = -1, min_e_m = -1, min_e_n = -1;
+
+ if (!clk || !clk->dpll_data)
+ return ~0;
+
+ pr_debug("clock: starting DPLL round_rate for clock %s, target rate "
+ "%ld\n", clk->name, target_rate);
+
+ scaled_rt_rp = target_rate / (clk->parent->rate / DPLL_SCALE_FACTOR);
+ scaled_max_m = clk->dpll_data->max_multiplier * DPLL_SCALE_FACTOR;
+
+ clk->dpll_data->last_rounded_rate = 0;
+
+ for (n = clk->dpll_data->max_divider; n >= DPLL_MIN_DIVIDER; n--) {
+
+ /* Compute the scaled DPLL multiplier, based on the divider */
+ m = scaled_rt_rp * n;
+
+ /*
+ * Since we're counting n down, a m overflow means we can
+ * can immediately skip to the next n
+ */
+ if (m > scaled_max_m)
+ continue;
+
+ r = _dpll_test_mult(&m, n, &new_rate, target_rate,
+ clk->parent->rate);
+
+ e = target_rate - new_rate;
+ pr_debug("clock: n = %d: m = %d: rate error is %d "
+ "(new_rate = %ld)\n", n, m, e, new_rate);
+
+ if (min_e == -1 ||
+ min_e >= (int)(abs(e) - clk->dpll_data->rate_tolerance)) {
+ min_e = e;
+ min_e_m = m;
+ min_e_n = n;
+
+ pr_debug("clock: found new least error %d\n", min_e);
+ }
+
+ /*
+ * Since we're counting n down, a m underflow means we
+ * can bail out completely (since as n decreases in
+ * the next iteration, there's no way that m can
+ * increase beyond the current m)
+ */
+ if (r & DPLL_MULT_UNDERFLOW)
+ break;
+ }
+
+ if (min_e < 0) {
+ pr_debug("clock: error: target rate or tolerance too low\n");
+ return ~0;
+ }
+
+ clk->dpll_data->last_rounded_m = min_e_m;
+ clk->dpll_data->last_rounded_n = min_e_n;
+ clk->dpll_data->last_rounded_rate =
+ _dpll_compute_new_rate(clk->parent->rate, min_e_m, min_e_n);
+
+ pr_debug("clock: final least error: e = %d, m = %d, n = %d\n",
+ min_e, min_e_m, min_e_n);
+ pr_debug("clock: final rate: %ld (target rate: %ld)\n",
+ clk->dpll_data->last_rounded_rate, target_rate);
+
+ return clk->dpll_data->last_rounded_rate;
+}
+
/*-------------------------------------------------------------------------
* Omap2 clock reset and init functions
*-------------------------------------------------------------------------*/
#include <asm/arch/clock.h>
+/* The maximum error between a target DPLL rate and the rounded rate in Hz */
+#define DEFAULT_DPLL_RATE_TOLERANCE 50000
+
int omap2_clk_enable(struct clk *clk);
void omap2_clk_disable(struct clk *clk);
long omap2_clk_round_rate(struct clk *clk, unsigned long rate);
int omap2_clk_set_rate(struct clk *clk, unsigned long rate);
int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent);
+int omap2_dpll_rate_tolerance_set(struct clk *clk, unsigned int tolerance);
+long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate);
#ifdef CONFIG_OMAP_RESET_CLOCKS
void omap2_clk_disable_unused(struct clk *clk);
#endif
void omap2_clksel_recalc(struct clk *clk);
+void omap2_init_clk_clkdm(struct clk *clk);
void omap2_init_clksel_parent(struct clk *clk);
u32 omap2_clksel_get_divisor(struct clk *clk);
u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate,
static int omap2_enable_osc_ck(struct clk *clk)
{
- u32 pcc;
- pcc = __raw_readl(OMAP24XX_PRCM_CLKSRC_CTRL);
-
- __raw_writel(pcc & ~OMAP_AUTOEXTCLKMODE_MASK,
- OMAP24XX_PRCM_CLKSRC_CTRL);
+ prm_rmw_reg_bits(OMAP_AUTOEXTCLKMODE_MASK, 0,
+ OMAP24XX_PRCM_CLKSRC_CTRL);
return 0;
}
static void omap2_disable_osc_ck(struct clk *clk)
{
- u32 pcc;
-
- pcc = __raw_readl(OMAP24XX_PRCM_CLKSRC_CTRL);
-
- __raw_writel(pcc | OMAP_AUTOEXTCLKMODE_MASK,
- OMAP24XX_PRCM_CLKSRC_CTRL);
-}
-
-#ifdef OLD_CK
-/* Recalculate SYST_CLK */
-static void omap2_sys_clk_recalc(struct clk * clk)
-{
- u32 div = PRCM_CLKSRC_CTRL;
- div &= (1 << 7) | (1 << 6); /* Test if ext clk divided by 1 or 2 */
- div >>= clk->rate_offset;
- clk->rate = (clk->parent->rate / div);
- propagate_rate(clk);
+ prm_rmw_reg_bits(OMAP_AUTOEXTCLKMODE_MASK, OMAP_AUTOEXTCLKMODE_MASK,
+ OMAP24XX_PRCM_CLKSRC_CTRL);
}
-#endif /* OLD_CK */
/* Enable an APLL if off */
static int omap2_clk_fixed_enable(struct clk *clk)
* Uses the current prcm set to tell if a rate is valid.
* You can go slower, but not faster within a given rate set.
*/
-static u32 omap2_dpll_round_rate(unsigned long target_rate)
+long omap2_dpllcore_round_rate(unsigned long target_rate)
{
u32 high, low, core_clk_src;
}
-static void omap2_dpll_recalc(struct clk *clk)
+static void omap2_dpllcore_recalc(struct clk *clk)
{
clk->rate = omap2_get_dpll_rate_24xx(clk);
propagate_rate(clk);
}
-static int omap2_reprogram_dpll(struct clk *clk, unsigned long rate)
+static int omap2_reprogram_dpllcore(struct clk *clk, unsigned long rate)
{
u32 cur_rate, low, mult, div, valid_rate, done_rate;
u32 bypass = 0;
} else if ((rate == (cur_rate * 2)) && (mult == 1)) {
omap2_reprogram_sdrc(CORE_CLK_SRC_DPLL_X2, 1);
} else if (rate != cur_rate) {
- valid_rate = omap2_dpll_round_rate(rate);
+ valid_rate = omap2_dpllcore_round_rate(rate);
if (valid_rate != rate)
goto dpll_exit;
omap2_init_memory_params(omap2_dll_force_needed());
omap2_reprogram_sdrc(done_rate, 0);
}
- omap2_dpll_recalc(&dpll_ck);
+ omap2_dpllcore_recalc(&dpll_ck);
ret = 0;
dpll_exit:
local_irq_restore(flags);
}
- omap2_dpll_recalc(&dpll_ck);
+ omap2_dpllcore_recalc(&dpll_ck);
return 0;
}
+#ifdef CONFIG_CPU_FREQ
+/*
+ * Walk PRCM rate table and fillout cpufreq freq_table
+ */
+static struct cpufreq_frequency_table freq_table[ARRAY_SIZE(rate_table)];
+
+void omap2_clk_init_cpufreq_table(struct cpufreq_frequency_table **table)
+{
+ struct prcm_config *prcm;
+ int i = 0;
+
+ for (prcm = rate_table; prcm->mpu_speed; prcm++) {
+ if (!(prcm->flags & cpu_mask))
+ continue;
+ if (prcm->xtal_speed != sys_ck.rate)
+ continue;
+
+ /* don't put bypass rates in table */
+ if (prcm->dpll_speed == prcm->xtal_speed)
+ continue;
+
+ freq_table[i].index = i;
+ freq_table[i].frequency = prcm->mpu_speed / 1000;
+ i++;
+ }
+
+ if (i == 0) {
+ printk(KERN_WARNING "%s: failed to initialize frequency table\n",
+ __FUNCTION__);
+ return;
+ }
+
+ freq_table[i].index = i;
+ freq_table[i].frequency = CPUFREQ_TABLE_END;
+
+ *table = &freq_table[0];
+}
+#endif
+
static struct clk_functions omap2_clk_functions = {
.clk_enable = omap2_clk_enable,
.clk_disable = omap2_clk_disable,
.clk_set_rate = omap2_clk_set_rate,
.clk_set_parent = omap2_clk_set_parent,
.clk_disable_unused = omap2_clk_disable_unused,
+#ifdef CONFIG_CPU_FREQ
+ .clk_init_cpufreq_table = omap2_clk_init_cpufreq_table,
+#endif
};
static u32 omap2_get_apll_clkin(void)
static void omap2_sys_clk_recalc(struct clk *clk);
static void omap2_osc_clk_recalc(struct clk *clk);
static void omap2_sys_clk_recalc(struct clk *clk);
-static void omap2_dpll_recalc(struct clk *clk);
+static void omap2_dpllcore_recalc(struct clk *clk);
static int omap2_clk_fixed_enable(struct clk *clk);
static void omap2_clk_fixed_disable(struct clk *clk);
static int omap2_enable_osc_ck(struct clk *clk);
static void omap2_disable_osc_ck(struct clk *clk);
-static int omap2_reprogram_dpll(struct clk *clk, unsigned long rate);
+static int omap2_reprogram_dpllcore(struct clk *clk, unsigned long rate);
/* 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
* deal with this
*/
-static const struct dpll_data dpll_dd = {
+static struct dpll_data dpll_dd = {
.mult_div1_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1),
.mult_mask = OMAP24XX_DPLL_MULT_MASK,
.div1_mask = OMAP24XX_DPLL_DIV_MASK,
+ .max_multiplier = 1024,
+ .max_divider = 16,
+ .rate_tolerance = DEFAULT_DPLL_RATE_TOLERANCE
};
+/*
+ * XXX Cannot add round_rate here yet, as this is still a composite clock,
+ * not just a DPLL
+ */
static struct clk dpll_ck = {
.name = "dpll_ck",
.parent = &sys_ck, /* Can be func_32k also */
.dpll_data = &dpll_dd,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
RATE_PROPAGATES | ALWAYS_ENABLED,
- .recalc = &omap2_dpll_recalc,
- .set_rate = &omap2_reprogram_dpll,
+ .recalc = &omap2_dpllcore_recalc,
+ .set_rate = &omap2_reprogram_dpllcore,
};
static struct clk apll96_ck = {
/*
* OMAP3-specific clock framework functions
*
- * Copyright (C) 2007 Texas Instruments, Inc.
- * Copyright (C) 2007 Nokia Corporation
+ * Copyright (C) 2007-2008 Texas Instruments, Inc.
+ * Copyright (C) 2007-2008 Nokia Corporation
*
* Written by Paul Walmsley
+ * Testing and integration fixes by Jouni Högander
*
* Parts of this code are based on code written by
* Richard Woodruff, Tony Lindgren, Tuukka Tikkanen, Karthik Dasu
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/io.h>
+#include <linux/limits.h>
#include <asm/arch/clock.h>
#include <asm/arch/sram.h>
#include "cm.h"
#include "cm-regbits-34xx.h"
-/* CM_CLKEN_PLL*.EN* bit values */
-#define DPLL_LOCKED 0x7
+/* CM_AUTOIDLE_PLL*.AUTO_* bit values */
+#define DPLL_AUTOIDLE_DISABLE 0x0
+#define DPLL_AUTOIDLE_LOW_POWER_STOP 0x1
+
+#define MAX_DPLL_WAIT_TRIES 1000000
/**
* omap3_dpll_recalc - recalculate DPLL rate
propagate_rate(clk);
}
+/* _omap3_dpll_write_clken - write clken_bits arg to a DPLL's enable bits */
+static void _omap3_dpll_write_clken(struct clk *clk, u8 clken_bits)
+{
+ const struct dpll_data *dd;
+
+ dd = clk->dpll_data;
+
+ cm_rmw_reg_bits(dd->enable_mask, clken_bits << __ffs(dd->enable_mask),
+ dd->control_reg);
+}
+
+/* _omap3_wait_dpll_status: wait for a DPLL to enter a specific state */
+static int _omap3_wait_dpll_status(struct clk *clk, u8 state)
+{
+ const struct dpll_data *dd;
+ int i = 0;
+ int ret = -EINVAL;
+ u32 idlest_mask;
+
+ dd = clk->dpll_data;
+
+ state <<= dd->idlest_bit;
+ idlest_mask = 1 << dd->idlest_bit;
+
+ while (((__raw_readl(dd->idlest_reg) & idlest_mask) != state) &&
+ i < MAX_DPLL_WAIT_TRIES) {
+ i++;
+ udelay(1);
+ }
+
+ if (i == MAX_DPLL_WAIT_TRIES) {
+ printk(KERN_ERR "clock: %s failed transition to '%s'\n",
+ clk->name, (state) ? "locked" : "bypassed");
+ } else {
+ pr_debug("clock: %s transition to '%s' in %d loops\n",
+ clk->name, (state) ? "locked" : "bypassed", i);
+
+ ret = 0;
+ }
+
+ return ret;
+}
+
+/* From 3430 TRM ES2 4.7.6.2 */
+static u16 _omap3_dpll_compute_freqsel(struct clk *clk, u8 n)
+{
+ unsigned long fint;
+ u16 f = 0;
+
+ fint = clk->parent->rate / (n + 1);
+
+ pr_debug("clock: fint is %lu\n", fint);
+
+ if (fint >= 750000 && fint <= 1000000)
+ f = 0x3;
+ else if (fint > 1000000 && fint <= 1250000)
+ f = 0x4;
+ else if (fint > 1250000 && fint <= 1500000)
+ f = 0x5;
+ else if (fint > 1500000 && fint <= 1750000)
+ f = 0x6;
+ else if (fint > 1750000 && fint <= 2100000)
+ f = 0x7;
+ else if (fint > 7500000 && fint <= 10000000)
+ f = 0xB;
+ else if (fint > 10000000 && fint <= 12500000)
+ f = 0xC;
+ else if (fint > 12500000 && fint <= 15000000)
+ f = 0xD;
+ else if (fint > 15000000 && fint <= 17500000)
+ f = 0xE;
+ else if (fint > 17500000 && fint <= 21000000)
+ f = 0xF;
+ else
+ pr_debug("clock: unknown freqsel setting for %d\n", n);
+
+ return f;
+}
+
+/* Non-CORE DPLL (e.g., DPLLs that do not control SDRC) clock functions */
+
+/*
+ * _omap3_noncore_dpll_lock - instruct a DPLL to lock and wait for readiness
+ * @clk: pointer to a DPLL struct clk
+ *
+ * Instructs a non-CORE DPLL to lock. Waits for the DPLL to report
+ * readiness before returning. Will save and restore the DPLL's
+ * autoidle state across the enable, per the CDP code. If the DPLL
+ * locked successfully, return 0; if the DPLL did not lock in the time
+ * allotted, or DPLL3 was passed in, return -EINVAL.
+ */
+static int _omap3_noncore_dpll_lock(struct clk *clk)
+{
+ u8 ai;
+ int r;
+
+ if (clk == &dpll3_ck)
+ return -EINVAL;
+
+ pr_debug("clock: locking DPLL %s\n", clk->name);
+
+ ai = omap3_dpll_autoidle_read(clk);
+
+ _omap3_dpll_write_clken(clk, DPLL_LOCKED);
+
+ if (ai) {
+ /*
+ * If no downstream clocks are enabled, CM_IDLEST bit
+ * may never become active, so don't wait for DPLL to lock.
+ */
+ r = 0;
+ omap3_dpll_allow_idle(clk);
+ } else {
+ r = _omap3_wait_dpll_status(clk, 1);
+ omap3_dpll_deny_idle(clk);
+ };
+
+ return r;
+}
+
+/*
+ * omap3_noncore_dpll_bypass - instruct a DPLL to bypass and wait for readiness
+ * @clk: pointer to a DPLL struct clk
+ *
+ * Instructs a non-CORE DPLL to enter low-power bypass mode. In
+ * bypass mode, the DPLL's rate is set equal to its parent clock's
+ * rate. Waits for the DPLL to report readiness before returning.
+ * Will save and restore the DPLL's autoidle state across the enable,
+ * per the CDP code. If the DPLL entered bypass mode successfully,
+ * return 0; if the DPLL did not enter bypass in the time allotted, or
+ * DPLL3 was passed in, or the DPLL does not support low-power bypass,
+ * return -EINVAL.
+ */
+static int _omap3_noncore_dpll_bypass(struct clk *clk)
+{
+ int r;
+ u8 ai;
+
+ if (clk == &dpll3_ck)
+ return -EINVAL;
+
+ if (!(clk->dpll_data->modes & (1 << DPLL_LOW_POWER_BYPASS)))
+ return -EINVAL;
+
+ pr_debug("clock: configuring DPLL %s for low-power bypass\n",
+ clk->name);
+
+ ai = omap3_dpll_autoidle_read(clk);
+
+ _omap3_dpll_write_clken(clk, DPLL_LOW_POWER_BYPASS);
+
+ r = _omap3_wait_dpll_status(clk, 0);
+
+ if (ai)
+ omap3_dpll_allow_idle(clk);
+ else
+ omap3_dpll_deny_idle(clk);
+
+ return r;
+}
+
+/*
+ * _omap3_noncore_dpll_stop - instruct a DPLL to stop
+ * @clk: pointer to a DPLL struct clk
+ *
+ * Instructs a non-CORE DPLL to enter low-power stop. Will save and
+ * restore the DPLL's autoidle state across the stop, per the CDP
+ * code. If DPLL3 was passed in, or the DPLL does not support
+ * low-power stop, return -EINVAL; otherwise, return 0.
+ */
+static int _omap3_noncore_dpll_stop(struct clk *clk)
+{
+ u8 ai;
+
+ if (clk == &dpll3_ck)
+ return -EINVAL;
+
+ if (!(clk->dpll_data->modes & (1 << DPLL_LOW_POWER_STOP)))
+ return -EINVAL;
+
+ pr_debug("clock: stopping DPLL %s\n", clk->name);
+
+ ai = omap3_dpll_autoidle_read(clk);
+
+ _omap3_dpll_write_clken(clk, DPLL_LOW_POWER_STOP);
+
+ if (ai)
+ omap3_dpll_allow_idle(clk);
+ else
+ omap3_dpll_deny_idle(clk);
+
+ return 0;
+}
+
+/**
+ * omap3_noncore_dpll_enable - instruct a DPLL to enter bypass or lock mode
+ * @clk: pointer to a DPLL struct clk
+ *
+ * Instructs a non-CORE DPLL to enable, e.g., to enter bypass or lock.
+ * The choice of modes depends on the DPLL's programmed rate: if it is
+ * the same as the DPLL's parent clock, it will enter bypass;
+ * otherwise, it will enter lock. This code will wait for the DPLL to
+ * indicate readiness before returning, unless the DPLL takes too long
+ * to enter the target state. Intended to be used as the struct clk's
+ * enable function. If DPLL3 was passed in, or the DPLL does not
+ * support low-power stop, or if the DPLL took too long to enter
+ * bypass or lock, return -EINVAL; otherwise, return 0.
+ */
+static int omap3_noncore_dpll_enable(struct clk *clk)
+{
+ int r;
+
+ if (clk == &dpll3_ck)
+ return -EINVAL;
+
+ if (clk->parent->rate == clk_get_rate(clk))
+ r = _omap3_noncore_dpll_bypass(clk);
+ else
+ r = _omap3_noncore_dpll_lock(clk);
+
+ return r;
+}
+
+/**
+ * omap3_noncore_dpll_enable - instruct a DPLL to enter bypass or lock mode
+ * @clk: pointer to a DPLL struct clk
+ *
+ * Instructs a non-CORE DPLL to enable, e.g., to enter bypass or lock.
+ * The choice of modes depends on the DPLL's programmed rate: if it is
+ * the same as the DPLL's parent clock, it will enter bypass;
+ * otherwise, it will enter lock. This code will wait for the DPLL to
+ * indicate readiness before returning, unless the DPLL takes too long
+ * to enter the target state. Intended to be used as the struct clk's
+ * enable function. If DPLL3 was passed in, or the DPLL does not
+ * support low-power stop, or if the DPLL took too long to enter
+ * bypass or lock, return -EINVAL; otherwise, return 0.
+ */
+static void omap3_noncore_dpll_disable(struct clk *clk)
+{
+ if (clk == &dpll3_ck)
+ return;
+
+ _omap3_noncore_dpll_stop(clk);
+}
+
+
+/* Non-CORE DPLL rate set code */
+
+/*
+ * omap3_noncore_dpll_program - set non-core DPLL M,N values directly
+ * @clk: struct clk * of DPLL to set
+ * @m: DPLL multiplier to set
+ * @n: DPLL divider to set
+ * @freqsel: FREQSEL value to set
+ *
+ * Program the DPLL with the supplied M, N values, and wait for the DPLL to
+ * lock.. Returns -EINVAL upon error, or 0 upon success.
+ */
+static int omap3_noncore_dpll_program(struct clk *clk, u16 m, u8 n, u16 freqsel)
+{
+ struct dpll_data *dd;
+ u32 v;
+
+ if (!clk)
+ return -EINVAL;
+
+ dd = clk->dpll_data;
+ if (!dd)
+ return -EINVAL;
+
+ /*
+ * According to the 12-5 CDP code from TI, "Limitation 2.5"
+ * on 3430ES1 prevents us from changing DPLL multipliers or dividers
+ * on DPLL4.
+ */
+ if (is_sil_rev_equal_to(OMAP3430_REV_ES1_0) &&
+ !strcmp("dpll4_ck", clk->name)) {
+ printk(KERN_ERR "clock: DPLL4 cannot change rate due to "
+ "silicon 'Limitation 2.5' on 3430ES1.\n");
+ return -EINVAL;
+ }
+
+ /* 3430 ES2 TRM: 4.7.6.9 DPLL Programming Sequence */
+ _omap3_noncore_dpll_bypass(clk);
+
+ v = __raw_readl(dd->mult_div1_reg);
+ v &= ~(dd->mult_mask | dd->div1_mask);
+
+ /* Set mult (M), div1 (N), freqsel */
+ v |= m << __ffs(dd->mult_mask);
+ v |= n << __ffs(dd->div1_mask);
+ v |= freqsel << __ffs(dd->freqsel_mask);
+
+ __raw_writel(v, dd->mult_div1_reg);
+
+ /* We let the clock framework set the other output dividers later */
+
+ /* REVISIT: Set ramp-up delay? */
+
+ _omap3_noncore_dpll_lock(clk);
+
+ return 0;
+}
+
+/**
+ * omap3_noncore_dpll_set_rate - set non-core DPLL rate
+ * @clk: struct clk * of DPLL to set
+ * @rate: rounded target rate
+ *
+ * Program the DPLL with the rounded target rate. Returns -EINVAL upon
+ * error, or 0 upon success.
+ */
+static int omap3_noncore_dpll_set_rate(struct clk *clk, unsigned long rate)
+{
+ u16 freqsel;
+ struct dpll_data *dd;
+
+ if (!clk || !rate)
+ return -EINVAL;
+
+ dd = clk->dpll_data;
+ if (!dd)
+ return -EINVAL;
+
+ if (rate == omap2_get_dpll_rate(clk))
+ return 0;
+
+ if (dd->last_rounded_rate != rate)
+ omap2_dpll_round_rate(clk, rate);
+
+ if (dd->last_rounded_rate == 0)
+ return -EINVAL;
+
+ freqsel = _omap3_dpll_compute_freqsel(clk, dd->last_rounded_n);
+ if (!freqsel)
+ WARN_ON(1);
+
+ omap3_noncore_dpll_program(clk, dd->last_rounded_m, dd->last_rounded_n,
+ freqsel);
+
+ omap3_dpll_recalc(clk);
+
+ return 0;
+}
+
+/* DPLL autoidle read/set code */
+
+
+/**
+ * omap3_dpll_autoidle_read - read a DPLL's autoidle bits
+ * @clk: struct clk * of the DPLL to read
+ *
+ * Return the DPLL's autoidle bits, shifted down to bit 0. Returns
+ * -EINVAL if passed a null pointer or if the struct clk does not
+ * appear to refer to a DPLL.
+ */
+static u32 omap3_dpll_autoidle_read(struct clk *clk)
+{
+ const struct dpll_data *dd;
+ u32 v;
+
+ if (!clk || !clk->dpll_data)
+ return -EINVAL;
+
+ dd = clk->dpll_data;
+
+ v = __raw_readl(dd->autoidle_reg);
+ v &= dd->autoidle_mask;
+ v >>= __ffs(dd->autoidle_mask);
+
+ return v;
+}
+
+/**
+ * omap3_dpll_allow_idle - enable DPLL autoidle bits
+ * @clk: struct clk * of the DPLL to operate on
+ *
+ * Enable DPLL automatic idle control. This automatic idle mode
+ * switching takes effect only when the DPLL is locked, at least on
+ * OMAP3430. The DPLL will enter low-power stop when its downstream
+ * clocks are gated. No return value.
+ */
+static void omap3_dpll_allow_idle(struct clk *clk)
+{
+ const struct dpll_data *dd;
+
+ if (!clk || !clk->dpll_data)
+ return;
+
+ dd = clk->dpll_data;
+
+ /*
+ * REVISIT: CORE DPLL can optionally enter low-power bypass
+ * by writing 0x5 instead of 0x1. Add some mechanism to
+ * optionally enter this mode.
+ */
+ cm_rmw_reg_bits(dd->autoidle_mask,
+ DPLL_AUTOIDLE_LOW_POWER_STOP << __ffs(dd->autoidle_mask),
+ dd->autoidle_reg);
+}
+
+/**
+ * omap3_dpll_deny_idle - prevent DPLL from automatically idling
+ * @clk: struct clk * of the DPLL to operate on
+ *
+ * Disable DPLL automatic idle control. No return value.
+ */
+static void omap3_dpll_deny_idle(struct clk *clk)
+{
+ const struct dpll_data *dd;
+
+ if (!clk || !clk->dpll_data)
+ return;
+
+ dd = clk->dpll_data;
+
+ cm_rmw_reg_bits(dd->autoidle_mask,
+ DPLL_AUTOIDLE_DISABLE << __ffs(dd->autoidle_mask),
+ dd->autoidle_reg);
+}
+
+/* Clock control for DPLL outputs */
+
/**
* omap3_clkoutx2_recalc - recalculate DPLL X2 output virtual clock rate
* @clk: DPLL output struct clk
propagate_rate(clk);
}
+/* Common clock code */
+
/*
* As it is structured now, this will prevent an OMAP2/3 multiboot
* kernel from compiling. This will need further attention.
for (clkp = onchip_34xx_clks;
clkp < onchip_34xx_clks + ARRAY_SIZE(onchip_34xx_clks);
clkp++) {
- if ((*clkp)->flags & cpu_clkflg)
+ if ((*clkp)->flags & cpu_clkflg) {
clk_register(*clkp);
+ omap2_init_clk_clkdm(*clkp);
+ }
}
/* REVISIT: Not yet ready for OMAP3 */
/*
* OMAP3 clock framework
*
- * Virtual clocks are introduced as a convenient tools.
- * They are sources for other clocks and not supposed
- * to be requested from drivers directly.
- *
* Copyright (C) 2007-2008 Texas Instruments, Inc.
* Copyright (C) 2007-2008 Nokia Corporation
*
* Written by Paul Walmsley
+ * With many device clock fixes by Kevin Hilman and Jouni Högander
+ * DPLL bypass clock support added by Roman Tereshonkov
+ *
+ */
+
+/*
+ * Virtual clocks are introduced as convenient tools.
+ * They are sources for other clocks and not supposed
+ * to be requested from drivers directly.
*/
#ifndef __ARCH_ARM_MACH_OMAP2_CLOCK34XX_H
static void omap3_dpll_recalc(struct clk *clk);
static void omap3_clkoutx2_recalc(struct clk *clk);
+static void omap3_dpll_allow_idle(struct clk *clk);
+static void omap3_dpll_deny_idle(struct clk *clk);
+static u32 omap3_dpll_autoidle_read(struct clk *clk);
+static int omap3_noncore_dpll_enable(struct clk *clk);
+static void omap3_noncore_dpll_disable(struct clk *clk);
+static int omap3_noncore_dpll_set_rate(struct clk *clk, unsigned long rate);
+
+/* Maximum DPLL multiplier, divider values for OMAP3 */
+#define OMAP3_MAX_DPLL_MULT 2048
+#define OMAP3_MAX_DPLL_DIV 128
/*
* DPLL1 supplies clock to the MPU.
* DPLL5 supplies other peripheral clocks (USBHOST, USIM).
*/
+/* CM_CLKEN_PLL*.EN* bit values - not all are available for every DPLL */
+#define DPLL_LOW_POWER_STOP 0x1
+#define DPLL_LOW_POWER_BYPASS 0x5
+#define DPLL_LOCKED 0x7
+
/* PRM CLOCKS */
/* According to timer32k.c, this is a 32768Hz clock, not a 32000Hz clock. */
/* DPLL1 */
/* MPU clock source */
/* Type: DPLL */
-static const struct dpll_data dpll1_dd = {
+static struct dpll_data dpll1_dd = {
.mult_div1_reg = OMAP_CM_REGADDR(MPU_MOD, OMAP3430_CM_CLKSEL1_PLL),
.mult_mask = OMAP3430_MPU_DPLL_MULT_MASK,
.div1_mask = OMAP3430_MPU_DPLL_DIV_MASK,
+ .freqsel_mask = OMAP3430_MPU_DPLL_FREQSEL_MASK,
.control_reg = OMAP_CM_REGADDR(MPU_MOD, OMAP3430_CM_CLKEN_PLL),
.enable_mask = OMAP3430_EN_MPU_DPLL_MASK,
+ .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
.auto_recal_bit = OMAP3430_EN_MPU_DPLL_DRIFTGUARD_SHIFT,
.recal_en_bit = OMAP3430_MPU_DPLL_RECAL_EN_SHIFT,
.recal_st_bit = OMAP3430_MPU_DPLL_ST_SHIFT,
+ .autoidle_reg = OMAP_CM_REGADDR(MPU_MOD, OMAP3430_CM_AUTOIDLE_PLL),
+ .autoidle_mask = OMAP3430_AUTO_MPU_DPLL_MASK,
+ .idlest_reg = OMAP_CM_REGADDR(MPU_MOD, OMAP3430_CM_IDLEST_PLL),
+ .idlest_bit = OMAP3430_ST_MPU_CLK_SHIFT,
+ .max_multiplier = OMAP3_MAX_DPLL_MULT,
+ .max_divider = OMAP3_MAX_DPLL_DIV,
+ .rate_tolerance = DEFAULT_DPLL_RATE_TOLERANCE
};
static struct clk dpll1_ck = {
.parent = &sys_ck,
.dpll_data = &dpll1_dd,
.flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
+ .round_rate = &omap2_dpll_round_rate,
+ .set_rate = &omap3_noncore_dpll_set_rate,
.recalc = &omap3_dpll_recalc,
};
/* IVA2 clock source */
/* Type: DPLL */
-static const struct dpll_data dpll2_dd = {
+static struct dpll_data dpll2_dd = {
.mult_div1_reg = OMAP_CM_REGADDR(OMAP3430_IVA2_MOD, OMAP3430_CM_CLKSEL1_PLL),
.mult_mask = OMAP3430_IVA2_DPLL_MULT_MASK,
.div1_mask = OMAP3430_IVA2_DPLL_DIV_MASK,
+ .freqsel_mask = OMAP3430_IVA2_DPLL_FREQSEL_MASK,
.control_reg = OMAP_CM_REGADDR(OMAP3430_IVA2_MOD, OMAP3430_CM_CLKEN_PLL),
.enable_mask = OMAP3430_EN_IVA2_DPLL_MASK,
+ .modes = (1 << DPLL_LOW_POWER_STOP) | (1 << DPLL_LOCKED) |
+ (1 << DPLL_LOW_POWER_BYPASS),
.auto_recal_bit = OMAP3430_EN_IVA2_DPLL_DRIFTGUARD_SHIFT,
.recal_en_bit = OMAP3430_PRM_IRQENABLE_MPU_IVA2_DPLL_RECAL_EN_SHIFT,
.recal_st_bit = OMAP3430_PRM_IRQSTATUS_MPU_IVA2_DPLL_ST_SHIFT,
+ .autoidle_reg = OMAP_CM_REGADDR(OMAP3430_IVA2_MOD, OMAP3430_CM_AUTOIDLE_PLL),
+ .autoidle_mask = OMAP3430_AUTO_IVA2_DPLL_MASK,
+ .idlest_reg = OMAP_CM_REGADDR(OMAP3430_IVA2_MOD, OMAP3430_CM_IDLEST_PLL),
+ .idlest_bit = OMAP3430_ST_IVA2_CLK_SHIFT,
+ .max_multiplier = OMAP3_MAX_DPLL_MULT,
+ .max_divider = OMAP3_MAX_DPLL_DIV,
+ .rate_tolerance = DEFAULT_DPLL_RATE_TOLERANCE
};
static struct clk dpll2_ck = {
.name = "dpll2_ck",
.parent = &sys_ck,
.dpll_data = &dpll2_dd,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
+ .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES,
+ .enable = &omap3_noncore_dpll_enable,
+ .disable = &omap3_noncore_dpll_disable,
+ .round_rate = &omap2_dpll_round_rate,
+ .set_rate = &omap3_noncore_dpll_set_rate,
.recalc = &omap3_dpll_recalc,
};
.recalc = &omap2_clksel_recalc,
};
-/* DPLL3 */
-/* Source clock for all interfaces and for some device fclks */
-/* Type: DPLL */
-static const struct dpll_data dpll3_dd = {
+/*
+ * DPLL3
+ * Source clock for all interfaces and for some device fclks
+ * REVISIT: Also supports fast relock bypass - not included below
+ */
+static struct dpll_data dpll3_dd = {
.mult_div1_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1),
.mult_mask = OMAP3430_CORE_DPLL_MULT_MASK,
.div1_mask = OMAP3430_CORE_DPLL_DIV_MASK,
+ .freqsel_mask = OMAP3430_CORE_DPLL_FREQSEL_MASK,
.control_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKEN),
.enable_mask = OMAP3430_EN_CORE_DPLL_MASK,
.auto_recal_bit = OMAP3430_EN_CORE_DPLL_DRIFTGUARD_SHIFT,
.recal_en_bit = OMAP3430_CORE_DPLL_RECAL_EN_SHIFT,
.recal_st_bit = OMAP3430_CORE_DPLL_ST_SHIFT,
+ .autoidle_reg = OMAP_CM_REGADDR(PLL_MOD, CM_AUTOIDLE),
+ .autoidle_mask = OMAP3430_AUTO_CORE_DPLL_MASK,
+ .max_multiplier = OMAP3_MAX_DPLL_MULT,
+ .max_divider = OMAP3_MAX_DPLL_DIV,
+ .rate_tolerance = DEFAULT_DPLL_RATE_TOLERANCE
};
static struct clk dpll3_ck = {
.parent = &sys_ck,
.dpll_data = &dpll3_dd,
.flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
+ .round_rate = &omap2_dpll_round_rate,
+ .set_rate = &omap3_noncore_dpll_set_rate,
.recalc = &omap3_dpll_recalc,
};
};
static const struct clksel core_ck_clksel[] = {
- { .parent = &sys_ck, .rates = dpll_bypass_rates },
+ { .parent = &sys_ck, .rates = dpll_bypass_rates },
{ .parent = &dpll3_m2_ck, .rates = dpll_locked_rates },
{ .parent = NULL }
};
.name = "core_ck",
.init = &omap2_init_clksel_parent,
.clksel_reg = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST),
- .clksel_mask = OMAP3430_ST_CORE_CLK,
+ .clksel_mask = OMAP3430_ST_CORE_CLK_MASK,
.clksel = core_ck_clksel,
.flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
PARENT_CONTROLS_CLOCK,
};
static const struct clksel dpll3_m2x2_ck_clksel[] = {
- { .parent = &sys_ck, .rates = dpll_bypass_rates },
+ { .parent = &sys_ck, .rates = dpll_bypass_rates },
{ .parent = &dpll3_x2_ck, .rates = dpll_locked_rates },
{ .parent = NULL }
};
.name = "dpll3_m2x2_ck",
.init = &omap2_init_clksel_parent,
.clksel_reg = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST),
- .clksel_mask = OMAP3430_ST_CORE_CLK,
+ .clksel_mask = OMAP3430_ST_CORE_CLK_MASK,
.clksel = dpll3_m2x2_ck_clksel,
.flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
PARENT_CONTROLS_CLOCK,
};
static const struct clksel emu_core_alwon_ck_clksel[] = {
- { .parent = &sys_ck, .rates = dpll_bypass_rates },
+ { .parent = &sys_ck, .rates = dpll_bypass_rates },
{ .parent = &dpll3_m3x2_ck, .rates = dpll_locked_rates },
{ .parent = NULL }
};
.parent = &dpll3_m3x2_ck,
.init = &omap2_init_clksel_parent,
.clksel_reg = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST),
- .clksel_mask = OMAP3430_ST_CORE_CLK,
+ .clksel_mask = OMAP3430_ST_CORE_CLK_MASK,
.clksel = emu_core_alwon_ck_clksel,
.flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
PARENT_CONTROLS_CLOCK,
/* DPLL4 */
/* Supplies 96MHz, 54Mhz TV DAC, DSS fclk, CAM sensor clock, emul trace clk */
/* Type: DPLL */
-static const struct dpll_data dpll4_dd = {
+static struct dpll_data dpll4_dd = {
.mult_div1_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL2),
.mult_mask = OMAP3430_PERIPH_DPLL_MULT_MASK,
.div1_mask = OMAP3430_PERIPH_DPLL_DIV_MASK,
+ .freqsel_mask = OMAP3430_PERIPH_DPLL_FREQSEL_MASK,
.control_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKEN),
.enable_mask = OMAP3430_EN_PERIPH_DPLL_MASK,
+ .modes = (1 << DPLL_LOW_POWER_STOP) | (1 << DPLL_LOCKED),
.auto_recal_bit = OMAP3430_EN_PERIPH_DPLL_DRIFTGUARD_SHIFT,
.recal_en_bit = OMAP3430_PERIPH_DPLL_RECAL_EN_SHIFT,
.recal_st_bit = OMAP3430_PERIPH_DPLL_ST_SHIFT,
+ .autoidle_reg = OMAP_CM_REGADDR(PLL_MOD, CM_AUTOIDLE),
+ .autoidle_mask = OMAP3430_AUTO_PERIPH_DPLL_MASK,
+ .idlest_reg = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST),
+ .idlest_bit = OMAP3430_ST_PERIPH_CLK_SHIFT,
+ .max_multiplier = OMAP3_MAX_DPLL_MULT,
+ .max_divider = OMAP3_MAX_DPLL_DIV,
+ .rate_tolerance = DEFAULT_DPLL_RATE_TOLERANCE
};
static struct clk dpll4_ck = {
.name = "dpll4_ck",
.parent = &sys_ck,
.dpll_data = &dpll4_dd,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
+ .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES,
+ .enable = &omap3_noncore_dpll_enable,
+ .disable = &omap3_noncore_dpll_disable,
+ .round_rate = &omap2_dpll_round_rate,
+ .set_rate = &omap3_noncore_dpll_set_rate,
.recalc = &omap3_dpll_recalc,
};
};
static const struct clksel omap_96m_alwon_fck_clksel[] = {
- { .parent = &sys_ck, .rates = dpll_bypass_rates },
+ { .parent = &sys_ck, .rates = dpll_bypass_rates },
{ .parent = &dpll4_m2x2_ck, .rates = dpll_locked_rates },
{ .parent = NULL }
};
.parent = &dpll4_m2x2_ck,
.init = &omap2_init_clksel_parent,
.clksel_reg = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST),
- .clksel_mask = OMAP3430_ST_PERIPH_CLK,
+ .clksel_mask = OMAP3430_ST_PERIPH_CLK_MASK,
.clksel = omap_96m_alwon_fck_clksel,
.flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
PARENT_CONTROLS_CLOCK,
};
static const struct clksel cm_96m_fck_clksel[] = {
- { .parent = &sys_ck, .rates = dpll_bypass_rates },
+ { .parent = &sys_ck, .rates = dpll_bypass_rates },
{ .parent = &dpll4_m2x2_ck, .rates = dpll_locked_rates },
{ .parent = NULL }
};
.parent = &dpll4_m2x2_ck,
.init = &omap2_init_clksel_parent,
.clksel_reg = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST),
- .clksel_mask = OMAP3430_ST_PERIPH_CLK,
+ .clksel_mask = OMAP3430_ST_PERIPH_CLK_MASK,
.clksel = cm_96m_fck_clksel,
.flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
PARENT_CONTROLS_CLOCK,
};
static const struct clksel virt_omap_54m_fck_clksel[] = {
- { .parent = &sys_ck, .rates = dpll_bypass_rates },
+ { .parent = &sys_ck, .rates = dpll_bypass_rates },
{ .parent = &dpll4_m3x2_ck, .rates = dpll_locked_rates },
{ .parent = NULL }
};
.parent = &dpll4_m3x2_ck,
.init = &omap2_init_clksel_parent,
.clksel_reg = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST),
- .clksel_mask = OMAP3430_ST_PERIPH_CLK,
+ .clksel_mask = OMAP3430_ST_PERIPH_CLK_MASK,
.clksel = virt_omap_54m_fck_clksel,
.flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
PARENT_CONTROLS_CLOCK,
/* Supplies 120MHz clock, USIM source clock */
/* Type: DPLL */
/* 3430ES2 only */
-static const struct dpll_data dpll5_dd = {
+static struct dpll_data dpll5_dd = {
.mult_div1_reg = OMAP_CM_REGADDR(PLL_MOD, OMAP3430ES2_CM_CLKSEL4),
.mult_mask = OMAP3430ES2_PERIPH2_DPLL_MULT_MASK,
.div1_mask = OMAP3430ES2_PERIPH2_DPLL_DIV_MASK,
+ .freqsel_mask = OMAP3430ES2_PERIPH2_DPLL_FREQSEL_MASK,
.control_reg = OMAP_CM_REGADDR(PLL_MOD, OMAP3430ES2_CM_CLKEN2),
.enable_mask = OMAP3430ES2_EN_PERIPH2_DPLL_MASK,
+ .modes = (1 << DPLL_LOW_POWER_STOP) | (1 << DPLL_LOCKED),
.auto_recal_bit = OMAP3430ES2_EN_PERIPH2_DPLL_DRIFTGUARD_SHIFT,
.recal_en_bit = OMAP3430ES2_SND_PERIPH_DPLL_RECAL_EN_SHIFT,
.recal_st_bit = OMAP3430ES2_SND_PERIPH_DPLL_ST_SHIFT,
+ .autoidle_reg = OMAP_CM_REGADDR(PLL_MOD, OMAP3430ES2_CM_AUTOIDLE2_PLL),
+ .autoidle_mask = OMAP3430ES2_AUTO_PERIPH2_DPLL_MASK,
+ .idlest_reg = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST2),
+ .idlest_bit = OMAP3430ES2_ST_PERIPH2_CLK_SHIFT,
+ .max_multiplier = OMAP3_MAX_DPLL_MULT,
+ .max_divider = OMAP3_MAX_DPLL_DIV,
+ .rate_tolerance = DEFAULT_DPLL_RATE_TOLERANCE
};
static struct clk dpll5_ck = {
.name = "dpll5_ck",
.parent = &sys_ck,
.dpll_data = &dpll5_dd,
- .flags = CLOCK_IN_OMAP3430ES2 | RATE_PROPAGATES |
- ALWAYS_ENABLED,
+ .flags = CLOCK_IN_OMAP3430ES2 | RATE_PROPAGATES,
+ .enable = &omap3_noncore_dpll_enable,
+ .disable = &omap3_noncore_dpll_disable,
+ .round_rate = &omap2_dpll_round_rate,
+ .set_rate = &omap3_noncore_dpll_set_rate,
.recalc = &omap3_dpll_recalc,
};
.clksel_reg = OMAP_CM_REGADDR(PLL_MOD, OMAP3430ES2_CM_CLKSEL5),
.clksel_mask = OMAP3430ES2_DIV_120M_MASK,
.clksel = div16_dpll5_clksel,
- .flags = CLOCK_IN_OMAP3430ES2 | RATE_PROPAGATES,
+ .flags = CLOCK_IN_OMAP3430ES2 | RATE_PROPAGATES |
+ PARENT_CONTROLS_CLOCK,
.recalc = &omap2_clksel_recalc,
};
static const struct clksel omap_120m_fck_clksel[] = {
- { .parent = &sys_ck, .rates = dpll_bypass_rates },
+ { .parent = &sys_ck, .rates = dpll_bypass_rates },
{ .parent = &dpll5_m2_ck, .rates = dpll_locked_rates },
{ .parent = NULL }
};
static struct clk omap_120m_fck = {
.name = "omap_120m_fck",
.parent = &dpll5_m2_ck,
- .init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST2),
- .clksel_mask = OMAP3430ES2_ST_PERIPH2_CLK_MASK,
- .clksel = omap_120m_fck_clksel,
+ .init = &omap2_init_clksel_parent,
+ .clksel_reg = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST2),
+ .clksel_mask = OMAP3430ES2_ST_PERIPH2_CLK_MASK,
+ .clksel = omap_120m_fck_clksel,
.flags = CLOCK_IN_OMAP3430ES2 | RATE_PROPAGATES |
PARENT_CONTROLS_CLOCK,
- .recalc = &omap2_clksel_recalc,
+ .recalc = &omap2_clksel_recalc,
};
/* CM EXTERNAL CLOCK OUTPUTS */
* called 'dpll1_fck'
*/
static const struct clksel mpu_clksel[] = {
- { .parent = &dpll1_fck, .rates = dpll_bypass_rates },
+ { .parent = &dpll1_fck, .rates = dpll_bypass_rates },
{ .parent = &dpll1_x2m2_ck, .rates = dpll_locked_rates },
{ .parent = NULL }
};
.clksel = mpu_clksel,
.flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
PARENT_CONTROLS_CLOCK,
+ .clkdm_name = "mpu_clkdm",
.recalc = &omap2_clksel_recalc,
};
.recalc = &omap2_clksel_recalc,
};
+/* XXX What about neon_clkdm ? */
+
/*
* REVISIT: This clock is never specifically defined in the 3430 TRM,
* although it is referenced - so this is a guess
*/
static const struct clksel iva2_clksel[] = {
- { .parent = &dpll2_fck, .rates = dpll_bypass_rates },
+ { .parent = &dpll2_fck, .rates = dpll_bypass_rates },
{ .parent = &dpll2_m2_ck, .rates = dpll_locked_rates },
{ .parent = NULL }
};
.name = "iva2_ck",
.parent = &dpll2_m2_ck,
.init = &omap2_init_clksel_parent,
+ .enable_reg = OMAP_CM_REGADDR(OMAP3430_IVA2_MOD, CM_FCLKEN),
+ .enable_bit = OMAP3430_CM_FCLKEN_IVA2_EN_IVA2_SHIFT,
.clksel_reg = OMAP_CM_REGADDR(OMAP3430_IVA2_MOD,
OMAP3430_CM_IDLEST_PLL),
.clksel_mask = OMAP3430_ST_IVA2_CLK_MASK,
.clksel = iva2_clksel,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
- PARENT_CONTROLS_CLOCK,
+ .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES,
+ .clkdm_name = "iva2_clkdm",
.recalc = &omap2_clksel_recalc,
};
.clksel = div2_core_clksel,
.flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
PARENT_CONTROLS_CLOCK,
+ .clkdm_name = "core_l3_clkdm",
.recalc = &omap2_clksel_recalc,
};
.clksel = div2_l3_clksel,
.flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
PARENT_CONTROLS_CLOCK,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &omap2_clksel_recalc,
};
{ .parent = NULL }
};
-static struct clk gfx_l3_fck = {
- .name = "gfx_l3_fck",
+/* Virtual parent clock for gfx_l3_ick and gfx_l3_fck */
+static struct clk gfx_l3_ck = {
+ .name = "gfx_l3_ck",
.parent = &l3_ick,
.init = &omap2_init_clksel_parent,
.enable_reg = OMAP_CM_REGADDR(GFX_MOD, CM_ICLKEN),
.enable_bit = OMAP_EN_GFX_SHIFT,
+ .flags = CLOCK_IN_OMAP3430ES1,
+ .recalc = &followparent_recalc,
+};
+
+static struct clk gfx_l3_fck = {
+ .name = "gfx_l3_fck",
+ .parent = &gfx_l3_ck,
+ .init = &omap2_init_clksel_parent,
.clksel_reg = OMAP_CM_REGADDR(GFX_MOD, CM_CLKSEL),
.clksel_mask = OMAP_CLKSEL_GFX_MASK,
.clksel = gfx_l3_clksel,
- .flags = CLOCK_IN_OMAP3430ES1 | RATE_PROPAGATES,
+ .flags = CLOCK_IN_OMAP3430ES1 | RATE_PROPAGATES |
+ PARENT_CONTROLS_CLOCK,
+ .clkdm_name = "gfx_3430es1_clkdm",
.recalc = &omap2_clksel_recalc,
};
static struct clk gfx_l3_ick = {
.name = "gfx_l3_ick",
- .parent = &l3_ick,
- .enable_reg = OMAP_CM_REGADDR(GFX_MOD, CM_ICLKEN),
- .enable_bit = OMAP_EN_GFX_SHIFT,
- .flags = CLOCK_IN_OMAP3430ES1,
+ .parent = &gfx_l3_ck,
+ .flags = CLOCK_IN_OMAP3430ES1 | PARENT_CONTROLS_CLOCK,
+ .clkdm_name = "gfx_3430es1_clkdm",
.recalc = &followparent_recalc,
};
static struct clk gfx_cg1_ck = {
.name = "gfx_cg1_ck",
.parent = &gfx_l3_fck, /* REVISIT: correct? */
+ .init = &omap2_init_clk_clkdm,
.enable_reg = OMAP_CM_REGADDR(GFX_MOD, CM_FCLKEN),
.enable_bit = OMAP3430ES1_EN_2D_SHIFT,
.flags = CLOCK_IN_OMAP3430ES1,
+ .clkdm_name = "gfx_3430es1_clkdm",
.recalc = &followparent_recalc,
};
static struct clk gfx_cg2_ck = {
.name = "gfx_cg2_ck",
.parent = &gfx_l3_fck, /* REVISIT: correct? */
+ .init = &omap2_init_clk_clkdm,
.enable_reg = OMAP_CM_REGADDR(GFX_MOD, CM_FCLKEN),
.enable_bit = OMAP3430ES1_EN_3D_SHIFT,
.flags = CLOCK_IN_OMAP3430ES1,
+ .clkdm_name = "gfx_3430es1_clkdm",
.recalc = &followparent_recalc,
};
.clksel_mask = OMAP3430ES2_CLKSEL_SGX_MASK,
.clksel = sgx_clksel,
.flags = CLOCK_IN_OMAP3430ES2,
+ .clkdm_name = "sgx_clkdm",
.recalc = &omap2_clksel_recalc,
};
static struct clk sgx_ick = {
.name = "sgx_ick",
.parent = &l3_ick,
+ .init = &omap2_init_clk_clkdm,
.enable_reg = OMAP_CM_REGADDR(OMAP3430ES2_SGX_MOD, CM_ICLKEN),
.enable_bit = OMAP3430ES2_EN_SGX_SHIFT,
.flags = CLOCK_IN_OMAP3430ES2,
+ .clkdm_name = "sgx_clkdm",
.recalc = &followparent_recalc,
};
static struct clk d2d_26m_fck = {
.name = "d2d_26m_fck",
.parent = &sys_ck,
+ .init = &omap2_init_clk_clkdm,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
.enable_bit = OMAP3430ES1_EN_D2D_SHIFT,
.flags = CLOCK_IN_OMAP3430ES1,
+ .clkdm_name = "d2d_clkdm",
.recalc = &followparent_recalc,
};
.clksel_mask = OMAP3430_CLKSEL_GPT10_MASK,
.clksel = omap343x_gpt_clksel,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &omap2_clksel_recalc,
};
.clksel_mask = OMAP3430_CLKSEL_GPT11_MASK,
.clksel = omap343x_gpt_clksel,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &omap2_clksel_recalc,
};
.parent = &omap_96m_fck,
.flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
PARENT_CONTROLS_CLOCK,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
.enable_bit = OMAP3430ES2_EN_MMC3_SHIFT,
.flags = CLOCK_IN_OMAP3430ES2,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
.enable_bit = OMAP3430_EN_MMC2_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
.enable_bit = OMAP3430_EN_MSPRO_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
.enable_bit = OMAP3430_EN_MMC1_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
.enable_bit = OMAP3430_EN_I2C3_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &followparent_recalc,
};
static struct clk i2c2_fck = {
.name = "i2c_fck",
- .id = 2,
+ .id = 2,
.parent = &core_96m_fck,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
.enable_bit = OMAP3430_EN_I2C2_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
.enable_bit = OMAP3430_EN_I2C1_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &followparent_recalc,
};
.clksel_mask = OMAP2_MCBSP5_CLKS_MASK,
.clksel = mcbsp_15_clksel,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &omap2_clksel_recalc,
};
.clksel_mask = OMAP2_MCBSP1_CLKS_MASK,
.clksel = mcbsp_15_clksel,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &omap2_clksel_recalc,
};
.parent = &omap_48m_fck,
.flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
PARENT_CONTROLS_CLOCK,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &followparent_recalc,
};
.parent = &omap_12m_fck,
.flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
PARENT_CONTROLS_CLOCK,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &followparent_recalc,
};
.clksel_mask = OMAP3430_CLKSEL_SSI_MASK,
.clksel = ssi_ssr_clksel,
.flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &omap2_clksel_recalc,
};
/* CORE_L3_ICK based clocks */
+/*
+ * XXX must add clk_enable/clk_disable for these if standard code won't
+ * handle it
+ */
static struct clk core_l3_ick = {
.name = "core_l3_ick",
.parent = &l3_ick,
+ .init = &omap2_init_clk_clkdm,
.flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
PARENT_CONTROLS_CLOCK,
+ .clkdm_name = "core_l3_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_HSOTGUSB_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "core_l3_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_SDRC_SHIFT,
.flags = CLOCK_IN_OMAP343X | ENABLE_ON_INIT,
+ .clkdm_name = "core_l3_clkdm",
.recalc = &followparent_recalc,
};
.parent = &core_l3_ick,
.flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK |
ENABLE_ON_INIT,
+ .clkdm_name = "core_l3_clkdm",
.recalc = &followparent_recalc,
};
static struct clk core_l4_ick = {
.name = "core_l4_ick",
.parent = &l4_ick,
+ .init = &omap2_init_clk_clkdm,
.flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
PARENT_CONTROLS_CLOCK,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN3),
.enable_bit = OMAP3430ES2_EN_USBTLL_SHIFT,
.flags = CLOCK_IN_OMAP3430ES2,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430ES2_EN_MMC3_SHIFT,
.flags = CLOCK_IN_OMAP3430ES2,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_ICR_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_AES2_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_SHA12_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_DES2_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_MMC2_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_MMC1_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_MSPRO_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_HDQ_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_MCSPI4_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_MCSPI3_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_MCSPI2_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_MCSPI1_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_I2C3_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_I2C2_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_I2C1_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_UART2_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_UART1_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_GPT11_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_GPT10_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_MCBSP5_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_MCBSP1_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430ES1_EN_FAC_SHIFT,
.flags = CLOCK_IN_OMAP3430ES1,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_MAILBOXES_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &followparent_recalc,
};
static struct clk ssi_l4_ick = {
.name = "ssi_l4_ick",
.parent = &l4_ick,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES,
+ .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
+ PARENT_CONTROLS_CLOCK,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_SSI_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &followparent_recalc,
};
/* DSS */
static const struct clksel dss1_alwon_fck_clksel[] = {
- { .parent = &sys_ck, .rates = dpll_bypass_rates },
+ { .parent = &sys_ck, .rates = dpll_bypass_rates },
{ .parent = &dpll4_m4x2_ck, .rates = dpll_locked_rates },
{ .parent = NULL }
};
.enable_reg = OMAP_CM_REGADDR(OMAP3430_DSS_MOD, CM_FCLKEN),
.enable_bit = OMAP3430_EN_DSS1_SHIFT,
.clksel_reg = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST),
- .clksel_mask = OMAP3430_ST_PERIPH_CLK,
+ .clksel_mask = OMAP3430_ST_PERIPH_CLK_MASK,
.clksel = dss1_alwon_fck_clksel,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "dss_clkdm",
.recalc = &omap2_clksel_recalc,
};
static struct clk dss_tv_fck = {
.name = "dss_tv_fck",
.parent = &omap_54m_fck,
+ .init = &omap2_init_clk_clkdm,
.enable_reg = OMAP_CM_REGADDR(OMAP3430_DSS_MOD, CM_FCLKEN),
.enable_bit = OMAP3430_EN_TV_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "dss_clkdm",
.recalc = &followparent_recalc,
};
static struct clk dss_96m_fck = {
.name = "dss_96m_fck",
.parent = &omap_96m_fck,
+ .init = &omap2_init_clk_clkdm,
.enable_reg = OMAP_CM_REGADDR(OMAP3430_DSS_MOD, CM_FCLKEN),
.enable_bit = OMAP3430_EN_TV_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "dss_clkdm",
.recalc = &followparent_recalc,
};
static struct clk dss2_alwon_fck = {
.name = "dss2_alwon_fck",
.parent = &sys_ck,
+ .init = &omap2_init_clk_clkdm,
.enable_reg = OMAP_CM_REGADDR(OMAP3430_DSS_MOD, CM_FCLKEN),
.enable_bit = OMAP3430_EN_DSS2_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "dss_clkdm",
.recalc = &followparent_recalc,
};
/* Handles both L3 and L4 clocks */
.name = "dss_ick",
.parent = &l4_ick,
+ .init = &omap2_init_clk_clkdm,
.enable_reg = OMAP_CM_REGADDR(OMAP3430_DSS_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_CM_ICLKEN_DSS_EN_DSS_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "dss_clkdm",
.recalc = &followparent_recalc,
};
/* CAM */
static const struct clksel cam_mclk_clksel[] = {
- { .parent = &sys_ck, .rates = dpll_bypass_rates },
+ { .parent = &sys_ck, .rates = dpll_bypass_rates },
{ .parent = &dpll4_m5x2_ck, .rates = dpll_locked_rates },
{ .parent = NULL }
};
.parent = &dpll4_m5x2_ck,
.init = &omap2_init_clksel_parent,
.clksel_reg = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST),
- .clksel_mask = OMAP3430_ST_PERIPH_CLK,
+ .clksel_mask = OMAP3430_ST_PERIPH_CLK_MASK,
.clksel = cam_mclk_clksel,
.enable_reg = OMAP_CM_REGADDR(OMAP3430_CAM_MOD, CM_FCLKEN),
.enable_bit = OMAP3430_EN_CAM_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "cam_clkdm",
.recalc = &omap2_clksel_recalc,
};
-static struct clk cam_l3_ick = {
- .name = "cam_l3_ick",
- .parent = &l3_ick,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_CAM_MOD, CM_ICLKEN),
- .enable_bit = OMAP3430_EN_CAM_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .recalc = &followparent_recalc,
-};
-
-static struct clk cam_l4_ick = {
- .name = "cam_l4_ick",
+static struct clk cam_ick = {
+ /* Handles both L3 and L4 clocks */
+ .name = "cam_ick",
.parent = &l4_ick,
+ .init = &omap2_init_clk_clkdm,
.enable_reg = OMAP_CM_REGADDR(OMAP3430_CAM_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_CAM_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "cam_clkdm",
.recalc = &followparent_recalc,
};
static struct clk usbhost_120m_fck = {
.name = "usbhost_120m_fck",
.parent = &omap_120m_fck,
+ .init = &omap2_init_clk_clkdm,
.enable_reg = OMAP_CM_REGADDR(OMAP3430ES2_USBHOST_MOD, CM_FCLKEN),
.enable_bit = OMAP3430ES2_EN_USBHOST2_SHIFT,
.flags = CLOCK_IN_OMAP3430ES2,
+ .clkdm_name = "usbhost_clkdm",
.recalc = &followparent_recalc,
};
static struct clk usbhost_48m_fck = {
.name = "usbhost_48m_fck",
.parent = &omap_48m_fck,
+ .init = &omap2_init_clk_clkdm,
.enable_reg = OMAP_CM_REGADDR(OMAP3430ES2_USBHOST_MOD, CM_FCLKEN),
.enable_bit = OMAP3430ES2_EN_USBHOST1_SHIFT,
.flags = CLOCK_IN_OMAP3430ES2,
+ .clkdm_name = "usbhost_clkdm",
.recalc = &followparent_recalc,
};
-static struct clk usbhost_l3_ick = {
- .name = "usbhost_l3_ick",
- .parent = &l3_ick,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430ES2_USBHOST_MOD, CM_ICLKEN),
- .enable_bit = OMAP3430ES2_EN_USBHOST_SHIFT,
- .flags = CLOCK_IN_OMAP3430ES2,
- .recalc = &followparent_recalc,
-};
-
-static struct clk usbhost_l4_ick = {
- .name = "usbhost_l4_ick",
+static struct clk usbhost_ick = {
+ /* Handles both L3 and L4 clocks */
+ .name = "usbhost_ick",
.parent = &l4_ick,
+ .init = &omap2_init_clk_clkdm,
.enable_reg = OMAP_CM_REGADDR(OMAP3430ES2_USBHOST_MOD, CM_ICLKEN),
.enable_bit = OMAP3430ES2_EN_USBHOST_SHIFT,
.flags = CLOCK_IN_OMAP3430ES2,
+ .clkdm_name = "usbhost_clkdm",
.recalc = &followparent_recalc,
};
static struct clk usbhost_sar_fck = {
.name = "usbhost_sar_fck",
.parent = &osc_sys_ck,
+ .init = &omap2_init_clk_clkdm,
.enable_reg = OMAP_PRM_REGADDR(OMAP3430ES2_USBHOST_MOD, PM_PWSTCTRL),
.enable_bit = OMAP3430ES2_SAVEANDRESTORE_SHIFT,
.flags = CLOCK_IN_OMAP3430ES2,
+ .clkdm_name = "usbhost_clkdm",
.recalc = &followparent_recalc,
};
.recalc = &omap2_clksel_recalc,
};
+/* XXX should gpt1's clksel have wkup_32k_fck as the 32k opt? */
static struct clk gpt1_fck = {
.name = "gpt1_fck",
.init = &omap2_init_clksel_parent,
.clksel_mask = OMAP3430_CLKSEL_GPT1_MASK,
.clksel = omap343x_gpt_clksel,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "wkup_clkdm",
.recalc = &omap2_clksel_recalc,
};
static struct clk wkup_32k_fck = {
.name = "wkup_32k_fck",
+ .init = &omap2_init_clk_clkdm,
.parent = &omap_32k_fck,
.flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
+ .clkdm_name = "wkup_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_FCLKEN),
.enable_bit = OMAP3430_EN_GPIO1_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "wkup_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_FCLKEN),
.enable_bit = OMAP3430_EN_WDT2_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "wkup_clkdm",
.recalc = &followparent_recalc,
};
.name = "wkup_l4_ick",
.parent = &sys_ck,
.flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
+ .clkdm_name = "wkup_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
.enable_bit = OMAP3430ES2_EN_USIMOCP_SHIFT,
.flags = CLOCK_IN_OMAP3430ES2,
+ .clkdm_name = "wkup_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_WDT2_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "wkup_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_WDT1_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "wkup_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_GPIO1_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "wkup_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_32KSYNC_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "wkup_clkdm",
.recalc = &followparent_recalc,
};
+/* XXX This clock no longer exists in 3430 TRM rev F */
static struct clk gpt12_ick = {
.name = "gpt12_ick",
.parent = &wkup_l4_ick,
.enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_GPT12_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "wkup_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_GPT1_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "wkup_clkdm",
.recalc = &followparent_recalc,
};
static struct clk per_96m_fck = {
.name = "per_96m_fck",
.parent = &omap_96m_alwon_fck,
+ .init = &omap2_init_clk_clkdm,
.flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
PARENT_CONTROLS_CLOCK,
+ .clkdm_name = "per_clkdm",
.recalc = &followparent_recalc,
};
static struct clk per_48m_fck = {
.name = "per_48m_fck",
.parent = &omap_48m_fck,
+ .init = &omap2_init_clk_clkdm,
.flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
PARENT_CONTROLS_CLOCK,
+ .clkdm_name = "per_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
.enable_bit = OMAP3430_EN_UART3_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "per_clkdm",
.recalc = &followparent_recalc,
};
.clksel_mask = OMAP3430_CLKSEL_GPT2_MASK,
.clksel = omap343x_gpt_clksel,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "per_clkdm",
.recalc = &omap2_clksel_recalc,
};
.clksel_mask = OMAP3430_CLKSEL_GPT3_MASK,
.clksel = omap343x_gpt_clksel,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "per_clkdm",
.recalc = &omap2_clksel_recalc,
};
.clksel_mask = OMAP3430_CLKSEL_GPT4_MASK,
.clksel = omap343x_gpt_clksel,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "per_clkdm",
.recalc = &omap2_clksel_recalc,
};
.clksel_mask = OMAP3430_CLKSEL_GPT5_MASK,
.clksel = omap343x_gpt_clksel,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "per_clkdm",
.recalc = &omap2_clksel_recalc,
};
.clksel_mask = OMAP3430_CLKSEL_GPT6_MASK,
.clksel = omap343x_gpt_clksel,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "per_clkdm",
.recalc = &omap2_clksel_recalc,
};
.clksel_mask = OMAP3430_CLKSEL_GPT7_MASK,
.clksel = omap343x_gpt_clksel,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "per_clkdm",
.recalc = &omap2_clksel_recalc,
};
.clksel_mask = OMAP3430_CLKSEL_GPT8_MASK,
.clksel = omap343x_gpt_clksel,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "per_clkdm",
.recalc = &omap2_clksel_recalc,
};
.clksel_mask = OMAP3430_CLKSEL_GPT9_MASK,
.clksel = omap343x_gpt_clksel,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "per_clkdm",
.recalc = &omap2_clksel_recalc,
};
static struct clk per_32k_alwon_fck = {
.name = "per_32k_alwon_fck",
.parent = &omap_32k_fck,
+ .clkdm_name = "per_clkdm",
.flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
.recalc = &followparent_recalc,
};
.name = "gpio6_fck",
.parent = &per_32k_alwon_fck,
.enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
- .enable_bit = OMAP3430_EN_GPT6_SHIFT,
+ .enable_bit = OMAP3430_EN_GPIO6_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "per_clkdm",
.recalc = &followparent_recalc,
};
.name = "gpio5_fck",
.parent = &per_32k_alwon_fck,
.enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
- .enable_bit = OMAP3430_EN_GPT5_SHIFT,
+ .enable_bit = OMAP3430_EN_GPIO5_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "per_clkdm",
.recalc = &followparent_recalc,
};
.name = "gpio4_fck",
.parent = &per_32k_alwon_fck,
.enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
- .enable_bit = OMAP3430_EN_GPT4_SHIFT,
+ .enable_bit = OMAP3430_EN_GPIO4_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "per_clkdm",
.recalc = &followparent_recalc,
};
.name = "gpio3_fck",
.parent = &per_32k_alwon_fck,
.enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
- .enable_bit = OMAP3430_EN_GPT3_SHIFT,
+ .enable_bit = OMAP3430_EN_GPIO3_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "per_clkdm",
.recalc = &followparent_recalc,
};
.name = "gpio2_fck",
.parent = &per_32k_alwon_fck,
.enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
- .enable_bit = OMAP3430_EN_GPT2_SHIFT,
+ .enable_bit = OMAP3430_EN_GPIO2_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "per_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
.enable_bit = OMAP3430_EN_WDT3_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "per_clkdm",
.recalc = &followparent_recalc,
};
.parent = &l4_ick,
.flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
PARENT_CONTROLS_CLOCK,
+ .clkdm_name = "per_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_GPIO6_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "per_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_GPIO5_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "per_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_GPIO4_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "per_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_GPIO3_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "per_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_GPIO2_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "per_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_WDT3_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "per_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_UART3_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "per_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_GPT9_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "per_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_GPT8_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "per_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_GPT7_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "per_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_GPT6_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "per_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_GPT5_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "per_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_GPT4_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "per_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_GPT3_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "per_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_GPT2_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "per_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_MCBSP2_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "per_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_MCBSP3_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "per_clkdm",
.recalc = &followparent_recalc,
};
.enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_MCBSP4_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "per_clkdm",
.recalc = &followparent_recalc,
};
static const struct clksel mcbsp_234_clksel[] = {
{ .parent = &per_96m_fck, .rates = common_mcbsp_96m_rates },
- { .parent = &mcbsp_clks, .rates = common_mcbsp_mcbsp_rates },
+ { .parent = &mcbsp_clks, .rates = common_mcbsp_mcbsp_rates },
{ .parent = NULL }
};
.clksel_mask = OMAP2_MCBSP2_CLKS_MASK,
.clksel = mcbsp_234_clksel,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "per_clkdm",
.recalc = &omap2_clksel_recalc,
};
.clksel_mask = OMAP2_MCBSP3_CLKS_MASK,
.clksel = mcbsp_234_clksel,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "per_clkdm",
.recalc = &omap2_clksel_recalc,
};
.clksel_mask = OMAP2_MCBSP4_CLKS_MASK,
.clksel = mcbsp_234_clksel,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "per_clkdm",
.recalc = &omap2_clksel_recalc,
};
.clksel_mask = OMAP3430_MUX_CTRL_MASK,
.clksel = emu_src_clksel,
.flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
+ .clkdm_name = "emu_clkdm",
.recalc = &omap2_clksel_recalc,
};
.clksel_mask = OMAP3430_CLKSEL_PCLK_MASK,
.clksel = pclk_emu_clksel,
.flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
+ .clkdm_name = "emu_clkdm",
.recalc = &omap2_clksel_recalc,
};
.clksel_mask = OMAP3430_CLKSEL_PCLKX2_MASK,
.clksel = pclkx2_emu_clksel,
.flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
+ .clkdm_name = "emu_clkdm",
.recalc = &omap2_clksel_recalc,
};
.clksel_mask = OMAP3430_CLKSEL_ATCLK_MASK,
.clksel = atclk_emu_clksel,
.flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
+ .clkdm_name = "emu_clkdm",
.recalc = &omap2_clksel_recalc,
};
.clksel_mask = OMAP3430_TRACE_MUX_CTRL_MASK,
.clksel = emu_src_clksel,
.flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
+ .clkdm_name = "emu_clkdm",
.recalc = &omap2_clksel_recalc,
};
.clksel_mask = OMAP3430_CLKSEL_TRACECLK_MASK,
.clksel = traceclk_clksel,
.flags = CLOCK_IN_OMAP343X | ALWAYS_ENABLED,
+ .clkdm_name = "emu_clkdm",
.recalc = &omap2_clksel_recalc,
};
.name = "sr_l4_ick",
.parent = &l4_ick,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &followparent_recalc,
};
/* SECURE_32K_FCK clocks */
+/* XXX This clock no longer exists in 3430 TRM rev F */
static struct clk gpt12_fck = {
.name = "gpt12_fck",
.parent = &secure_32k_fck,
&l3_ick,
&l4_ick,
&rm_ick,
+ &gfx_l3_ck,
&gfx_l3_fck,
&gfx_l3_ick,
&gfx_cg1_ck,
&dss2_alwon_fck,
&dss_ick,
&cam_mclk,
- &cam_l3_ick,
- &cam_l4_ick,
+ &cam_ick,
&usbhost_120m_fck,
&usbhost_48m_fck,
- &usbhost_l3_ick,
- &usbhost_l4_ick,
+ &usbhost_ick,
&usbhost_sar_fck,
&usim_fck,
&gpt1_fck,
--- /dev/null
+/*
+ * OMAP2/3 clockdomain framework functions
+ *
+ * Copyright (C) 2008 Texas Instruments, Inc.
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Written by Paul Walmsley and Jouni Högander
+ *
+ * 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.
+ */
+#ifdef CONFIG_OMAP_DEBUG_CLOCKDOMAIN
+# define DEBUG
+#endif
+
+#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 <linux/limits.h>
+
+#include <linux/io.h>
+
+#include <linux/bitops.h>
+
+#include <asm/arch/clock.h>
+
+#include "prm.h"
+#include "prm-regbits-24xx.h"
+#include "cm.h"
+
+#include <asm/arch/powerdomain.h>
+#include <asm/arch/clockdomain.h>
+
+/* clkdm_list contains all registered struct clockdomains */
+static LIST_HEAD(clkdm_list);
+
+/* clkdm_mutex protects clkdm_list add and del ops */
+static DEFINE_MUTEX(clkdm_mutex);
+
+/* array of powerdomain deps to be added/removed when clkdm in hwsup mode */
+static struct clkdm_pwrdm_autodep *autodeps;
+
+
+/* Private functions */
+
+/*
+ * _autodep_lookup - resolve autodep pwrdm names to pwrdm pointers; store
+ * @autodep: struct clkdm_pwrdm_autodep * to resolve
+ *
+ * Resolve autodep powerdomain names to powerdomain pointers via
+ * pwrdm_lookup() and store the pointers in the autodep structure. An
+ * "autodep" is a powerdomain sleep/wakeup dependency that is
+ * automatically added and removed whenever clocks in the associated
+ * clockdomain are enabled or disabled (respectively) when the
+ * clockdomain is in hardware-supervised mode. Meant to be called
+ * once at clockdomain layer initialization, since these should remain
+ * fixed for a particular architecture. No return value.
+ */
+static void _autodep_lookup(struct clkdm_pwrdm_autodep *autodep)
+{
+ struct powerdomain *pwrdm;
+
+ if (!autodep)
+ return;
+
+ if (!omap_chip_is(autodep->omap_chip))
+ return;
+
+ pwrdm = pwrdm_lookup(autodep->pwrdm_name);
+ if (!pwrdm) {
+ pr_debug("clockdomain: _autodep_lookup: powerdomain %s "
+ "does not exist\n", autodep->pwrdm_name);
+ WARN_ON(1);
+ return;
+ }
+ autodep->pwrdm = pwrdm;
+
+ return;
+}
+
+/*
+ * _clkdm_add_autodeps - add auto sleepdeps/wkdeps to clkdm upon clock enable
+ * @clkdm: struct clockdomain *
+ *
+ * Add the "autodep" sleep & wakeup dependencies to clockdomain 'clkdm'
+ * in hardware-supervised mode. Meant to be called from clock framework
+ * when a clock inside clockdomain 'clkdm' is enabled. No return value.
+ */
+static void _clkdm_add_autodeps(struct clockdomain *clkdm)
+{
+ struct clkdm_pwrdm_autodep *autodep;
+
+ for (autodep = autodeps; autodep->pwrdm_name; autodep++) {
+ if (!autodep->pwrdm)
+ continue;
+
+ pr_debug("clockdomain: adding %s sleepdep/wkdep for "
+ "pwrdm %s\n", autodep->pwrdm_name,
+ clkdm->pwrdm->name);
+
+ pwrdm_add_sleepdep(clkdm->pwrdm, autodep->pwrdm);
+ pwrdm_add_wkdep(clkdm->pwrdm, autodep->pwrdm);
+ }
+}
+
+/*
+ * _clkdm_add_autodeps - remove auto sleepdeps/wkdeps from clkdm
+ * @clkdm: struct clockdomain *
+ *
+ * Remove the "autodep" sleep & wakeup dependencies from clockdomain 'clkdm'
+ * in hardware-supervised mode. Meant to be called from clock framework
+ * when a clock inside clockdomain 'clkdm' is disabled. No return value.
+ */
+static void _clkdm_del_autodeps(struct clockdomain *clkdm)
+{
+ struct clkdm_pwrdm_autodep *autodep;
+
+ for (autodep = autodeps; autodep->pwrdm_name; autodep++) {
+ if (!autodep->pwrdm)
+ continue;
+
+ pr_debug("clockdomain: removing %s sleepdep/wkdep for "
+ "pwrdm %s\n", autodep->pwrdm_name,
+ clkdm->pwrdm->name);
+
+ pwrdm_del_sleepdep(clkdm->pwrdm, autodep->pwrdm);
+ pwrdm_del_wkdep(clkdm->pwrdm, autodep->pwrdm);
+ }
+}
+
+
+struct clockdomain *_clkdm_lookup(const char *name)
+{
+ struct clockdomain *clkdm, *temp_clkdm;
+
+ if (!name)
+ return NULL;
+
+ clkdm = NULL;
+
+ list_for_each_entry(temp_clkdm, &clkdm_list, node) {
+ if (!strcmp(name, temp_clkdm->name)) {
+ clkdm = temp_clkdm;
+ break;
+ }
+ }
+
+ return clkdm;
+}
+
+
+/* Public functions */
+
+/**
+ * clkdm_init - set up the clockdomain layer
+ * @clkdms: optional pointer to an array of clockdomains to register
+ * @init_autodeps: optional pointer to an array of autodeps to register
+ *
+ * Set up internal state. If a pointer to an array of clockdomains
+ * was supplied, loop through the list of clockdomains, register all
+ * that are available on the current platform. Similarly, if a
+ * pointer to an array of clockdomain-powerdomain autodependencies was
+ * provided, register those. No return value.
+ */
+void clkdm_init(struct clockdomain **clkdms, struct clkdm_pwrdm_autodep *init_autodeps)
+{
+ struct clockdomain **c = NULL;
+ struct clkdm_pwrdm_autodep *autodep = NULL;
+
+ if (clkdms)
+ for (c = clkdms; *c; c++)
+ clkdm_register(*c);
+
+ autodeps = init_autodeps;
+ if (autodeps)
+ for (autodep = autodeps; autodep->pwrdm_name; autodep++)
+ _autodep_lookup(autodep);
+}
+
+/**
+ * clkdm_register - register a clockdomain
+ * @clkdm: struct clockdomain * to register
+ *
+ * Adds a clockdomain to the internal clockdomain list.
+ * Returns -EINVAL if given a null pointer, -EEXIST if a clockdomain is
+ * already registered by the provided name, or 0 upon success.
+ */
+int clkdm_register(struct clockdomain *clkdm)
+{
+ int ret = -EINVAL;
+ struct powerdomain *pwrdm;
+
+ if (!clkdm || !clkdm->name)
+ return -EINVAL;
+
+ if (!omap_chip_is(clkdm->omap_chip))
+ return -EINVAL;
+
+ pwrdm = pwrdm_lookup(clkdm->pwrdm_name);
+ if (!pwrdm) {
+ pr_debug("clockdomain: clkdm_register %s: powerdomain %s "
+ "does not exist\n", clkdm->name, clkdm->pwrdm_name);
+ return -EINVAL;
+ }
+ clkdm->pwrdm = pwrdm;
+
+ mutex_lock(&clkdm_mutex);
+ /* Verify that the clockdomain is not already registered */
+ if (_clkdm_lookup(clkdm->name)) {
+ ret = -EEXIST;
+ goto cr_unlock;
+ };
+
+ list_add(&clkdm->node, &clkdm_list);
+
+ pwrdm_add_clkdm(pwrdm, clkdm);
+
+ pr_debug("clockdomain: registered %s\n", clkdm->name);
+ ret = 0;
+
+cr_unlock:
+ mutex_unlock(&clkdm_mutex);
+
+ return ret;
+}
+
+/**
+ * clkdm_unregister - unregister a clockdomain
+ * @clkdm: struct clockdomain * to unregister
+ *
+ * Removes a clockdomain from the internal clockdomain list. Returns
+ * -EINVAL if clkdm argument is NULL.
+ */
+int clkdm_unregister(struct clockdomain *clkdm)
+{
+ if (!clkdm)
+ return -EINVAL;
+
+ pwrdm_del_clkdm(clkdm->pwrdm, clkdm);
+
+ mutex_lock(&clkdm_mutex);
+ list_del(&clkdm->node);
+ mutex_unlock(&clkdm_mutex);
+
+ pr_debug("clockdomain: unregistered %s\n", clkdm->name);
+
+ return 0;
+}
+
+/**
+ * clkdm_lookup - look up a clockdomain by name, return a pointer
+ * @name: name of clockdomain
+ *
+ * Find a registered clockdomain by its name. Returns a pointer to the
+ * struct clockdomain if found, or NULL otherwise.
+ */
+struct clockdomain *clkdm_lookup(const char *name)
+{
+ struct clockdomain *clkdm, *temp_clkdm;
+
+ if (!name)
+ return NULL;
+
+ clkdm = NULL;
+
+ mutex_lock(&clkdm_mutex);
+ list_for_each_entry(temp_clkdm, &clkdm_list, node) {
+ if (!strcmp(name, temp_clkdm->name)) {
+ clkdm = temp_clkdm;
+ break;
+ }
+ }
+ mutex_unlock(&clkdm_mutex);
+
+ return clkdm;
+}
+
+/**
+ * clkdm_for_each - call function on each registered clockdomain
+ * @fn: callback function *
+ *
+ * Call the supplied function for each registered clockdomain.
+ * The callback function can return anything but 0 to bail
+ * out early from the iterator. The callback function is called with
+ * the clkdm_mutex held, so no clockdomain structure manipulation
+ * functions should be called from the callback, although hardware
+ * clockdomain control functions are fine. Returns the last return
+ * value of the callback function, which should be 0 for success or
+ * anything else to indicate failure; or -EINVAL if the function pointer
+ * is null.
+ */
+int clkdm_for_each(int (*fn)(struct clockdomain *clkdm))
+{
+ struct clockdomain *clkdm;
+ int ret = 0;
+
+ if (!fn)
+ return -EINVAL;
+
+ mutex_lock(&clkdm_mutex);
+ list_for_each_entry(clkdm, &clkdm_list, node) {
+ ret = (*fn)(clkdm);
+ if (ret)
+ break;
+ }
+ mutex_unlock(&clkdm_mutex);
+
+ return ret;
+}
+
+
+/* Hardware clockdomain control */
+
+/**
+ * omap2_clkdm_clktrctrl_read - read the clkdm's current state transition mode
+ * @clk: struct clk * of a clockdomain
+ *
+ * Return the clockdomain's current state transition mode from the
+ * corresponding domain CM_CLKSTCTRL register. Returns -EINVAL if clk
+ * is NULL or the current mode upon success.
+ */
+static int omap2_clkdm_clktrctrl_read(struct clockdomain *clkdm)
+{
+ u32 v;
+
+ if (!clkdm)
+ return -EINVAL;
+
+ v = cm_read_mod_reg(clkdm->pwrdm->prcm_offs, CM_CLKSTCTRL);
+ v &= clkdm->clktrctrl_mask;
+ v >>= __ffs(clkdm->clktrctrl_mask);
+
+ return v;
+}
+
+/**
+ * omap2_clkdm_sleep - force clockdomain sleep transition
+ * @clkdm: struct clockdomain *
+ *
+ * Instruct the CM to force a sleep transition on the specified
+ * clockdomain 'clkdm'. Returns -EINVAL if clk is NULL or if
+ * clockdomain does not support software-initiated sleep; 0 upon
+ * success.
+ */
+int omap2_clkdm_sleep(struct clockdomain *clkdm)
+{
+ if (!clkdm)
+ return -EINVAL;
+
+ if (!(clkdm->flags & CLKDM_CAN_FORCE_SLEEP)) {
+ pr_debug("clockdomain: %s does not support forcing "
+ "sleep via software\n", clkdm->name);
+ return -EINVAL;
+ }
+
+ pr_debug("clockdomain: forcing sleep on %s\n", clkdm->name);
+
+ if (cpu_is_omap24xx()) {
+
+ cm_set_mod_reg_bits(OMAP24XX_FORCESTATE,
+ clkdm->pwrdm->prcm_offs, PM_PWSTCTRL);
+
+ } else if (cpu_is_omap34xx()) {
+
+ u32 v = (OMAP34XX_CLKSTCTRL_FORCE_SLEEP <<
+ __ffs(clkdm->clktrctrl_mask));
+
+ cm_rmw_mod_reg_bits(clkdm->clktrctrl_mask, v,
+ clkdm->pwrdm->prcm_offs, CM_CLKSTCTRL);
+
+ } else {
+ BUG();
+ };
+
+ return 0;
+}
+
+/**
+ * omap2_clkdm_wakeup - force clockdomain wakeup transition
+ * @clkdm: struct clockdomain *
+ *
+ * Instruct the CM to force a wakeup transition on the specified
+ * clockdomain 'clkdm'. Returns -EINVAL if clkdm is NULL or if the
+ * clockdomain does not support software-controlled wakeup; 0 upon
+ * success.
+ */
+int omap2_clkdm_wakeup(struct clockdomain *clkdm)
+{
+ if (!clkdm)
+ return -EINVAL;
+
+ if (!(clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)) {
+ pr_debug("clockdomain: %s does not support forcing "
+ "wakeup via software\n", clkdm->name);
+ return -EINVAL;
+ }
+
+ pr_debug("clockdomain: forcing wakeup on %s\n", clkdm->name);
+
+ if (cpu_is_omap24xx()) {
+
+ cm_clear_mod_reg_bits(OMAP24XX_FORCESTATE,
+ clkdm->pwrdm->prcm_offs, PM_PWSTCTRL);
+
+ } else if (cpu_is_omap34xx()) {
+
+ u32 v = (OMAP34XX_CLKSTCTRL_FORCE_WAKEUP <<
+ __ffs(clkdm->clktrctrl_mask));
+
+ cm_rmw_mod_reg_bits(clkdm->clktrctrl_mask, v,
+ clkdm->pwrdm->prcm_offs, CM_CLKSTCTRL);
+
+ } else {
+ BUG();
+ };
+
+ return 0;
+}
+
+/**
+ * omap2_clkdm_allow_idle - enable hwsup idle transitions for clkdm
+ * @clkdm: struct clockdomain *
+ *
+ * Allow the hardware to automatically switch the clockdomain into
+ * active or idle states, as needed by downstream clocks. If the
+ * clockdomain has any downstream clocks enabled in the clock
+ * framework, wkdep/sleepdep autodependencies are added; this is so
+ * device drivers can read and write to the device. No return value.
+ */
+void omap2_clkdm_allow_idle(struct clockdomain *clkdm)
+{
+ u32 v;
+
+ if (!clkdm)
+ return;
+
+ if (!(clkdm->flags & CLKDM_CAN_ENABLE_AUTO)) {
+ pr_debug("clock: automatic idle transitions cannot be enabled "
+ "on clockdomain %s\n", clkdm->name);
+ return;
+ }
+
+ pr_debug("clockdomain: enabling automatic idle transitions for %s\n",
+ clkdm->name);
+
+ if (atomic_read(&clkdm->usecount) > 0)
+ _clkdm_add_autodeps(clkdm);
+
+ if (cpu_is_omap24xx())
+ v = OMAP24XX_CLKSTCTRL_ENABLE_AUTO;
+ else if (cpu_is_omap34xx())
+ v = OMAP34XX_CLKSTCTRL_ENABLE_AUTO;
+ else
+ BUG();
+
+
+ cm_rmw_mod_reg_bits(clkdm->clktrctrl_mask,
+ v << __ffs(clkdm->clktrctrl_mask),
+ clkdm->pwrdm->prcm_offs,
+ CM_CLKSTCTRL);
+}
+
+/**
+ * omap2_clkdm_deny_idle - disable hwsup idle transitions for clkdm
+ * @clkdm: struct clockdomain *
+ *
+ * Prevent the hardware from automatically switching the clockdomain
+ * into inactive or idle states. If the clockdomain has downstream
+ * clocks enabled in the clock framework, wkdep/sleepdep
+ * autodependencies are removed. No return value.
+ */
+void omap2_clkdm_deny_idle(struct clockdomain *clkdm)
+{
+ u32 v;
+
+ if (!clkdm)
+ return;
+
+ if (!(clkdm->flags & CLKDM_CAN_DISABLE_AUTO)) {
+ pr_debug("clockdomain: automatic idle transitions cannot be "
+ "disabled on %s\n", clkdm->name);
+ return;
+ }
+
+ pr_debug("clockdomain: disabling automatic idle transitions for %s\n",
+ clkdm->name);
+
+ if (cpu_is_omap24xx())
+ v = OMAP24XX_CLKSTCTRL_DISABLE_AUTO;
+ else if (cpu_is_omap34xx())
+ v = OMAP34XX_CLKSTCTRL_DISABLE_AUTO;
+ else
+ BUG();
+
+ cm_rmw_mod_reg_bits(clkdm->clktrctrl_mask,
+ v << __ffs(clkdm->clktrctrl_mask),
+ clkdm->pwrdm->prcm_offs, CM_CLKSTCTRL);
+
+ if (atomic_read(&clkdm->usecount) > 0)
+ _clkdm_del_autodeps(clkdm);
+}
+
+
+/* Clockdomain-to-clock framework interface code */
+
+/**
+ * omap2_clkdm_clk_enable - add an enabled downstream clock to this clkdm
+ * @clkdm: struct clockdomain *
+ * @clk: struct clk * of the enabled downstream clock
+ *
+ * Increment the usecount of this clockdomain 'clkdm' and ensure that
+ * it is awake. Intended to be called by clk_enable() code. If the
+ * clockdomain is in software-supervised idle mode, force the
+ * clockdomain to wake. If the clockdomain is in hardware-supervised
+ * idle mode, add clkdm-pwrdm autodependencies, to ensure that devices
+ * in the clockdomain can be read from/written to by on-chip processors.
+ * Returns -EINVAL if passed null pointers; returns 0 upon success or
+ * if the clockdomain is in hwsup idle mode.
+ */
+int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk)
+{
+ int v;
+
+ /*
+ * XXX Rewrite this code to maintain a list of enabled
+ * downstream clocks for debugging purposes?
+ */
+
+ if (!clkdm || !clk)
+ return -EINVAL;
+
+ if (atomic_inc_return(&clkdm->usecount) > 1)
+ return 0;
+
+ /* Clockdomain now has one enabled downstream clock */
+
+ pr_debug("clockdomain: clkdm %s: clk %s now enabled\n", clkdm->name,
+ clk->name);
+
+ v = omap2_clkdm_clktrctrl_read(clkdm);
+
+ if ((cpu_is_omap34xx() && v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) ||
+ (cpu_is_omap24xx() && v == OMAP24XX_CLKSTCTRL_ENABLE_AUTO))
+ _clkdm_add_autodeps(clkdm);
+ else
+ omap2_clkdm_wakeup(clkdm);
+
+ return 0;
+}
+
+/**
+ * omap2_clkdm_clk_disable - remove an enabled downstream clock from this clkdm
+ * @clkdm: struct clockdomain *
+ * @clk: struct clk * of the disabled downstream clock
+ *
+ * Decrement the usecount of this clockdomain 'clkdm'. Intended to be
+ * called by clk_disable() code. If the usecount goes to 0, put the
+ * clockdomain to sleep (software-supervised mode) or remove the
+ * clkdm-pwrdm autodependencies (hardware-supervised mode). Returns
+ * -EINVAL if passed null pointers; -ERANGE if the clkdm usecount
+ * underflows and debugging is enabled; or returns 0 upon success or
+ * if the clockdomain is in hwsup idle mode.
+ */
+int omap2_clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk)
+{
+ int v;
+
+ /*
+ * XXX Rewrite this code to maintain a list of enabled
+ * downstream clocks for debugging purposes?
+ */
+
+ if (!clkdm || !clk)
+ return -EINVAL;
+
+#ifdef DEBUG
+ if (atomic_read(&clkdm->usecount) == 0) {
+ WARN_ON(1); /* underflow */
+ return -ERANGE;
+ }
+#endif
+
+ if (atomic_dec_return(&clkdm->usecount) > 0)
+ return 0;
+
+ /* All downstream clocks of this clockdomain are now disabled */
+
+ pr_debug("clockdomain: clkdm %s: clk %s now disabled\n", clkdm->name,
+ clk->name);
+
+ v = omap2_clkdm_clktrctrl_read(clkdm);
+
+ if ((cpu_is_omap34xx() && v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) ||
+ (cpu_is_omap24xx() && v == OMAP24XX_CLKSTCTRL_ENABLE_AUTO))
+ _clkdm_del_autodeps(clkdm);
+ else
+ omap2_clkdm_sleep(clkdm);
+
+ return 0;
+}
+
--- /dev/null
+/*
+ * OMAP2/3 clockdomains
+ *
+ * Copyright (C) 2008 Texas Instruments, Inc.
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Written by Paul Walmsley
+ */
+
+#ifndef __ARCH_ARM_MACH_OMAP2_CLOCKDOMAINS_H
+#define __ARCH_ARM_MACH_OMAP2_CLOCKDOMAINS_H
+
+#include <asm/arch/clockdomain.h>
+
+/*
+ * OMAP2/3-common clockdomains
+ */
+
+/* This is an implicit clockdomain - it is never defined as such in TRM */
+static struct clockdomain wkup_clkdm = {
+ .name = "wkup_clkdm",
+ .pwrdm_name = "wkup_pwrdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX | CHIP_IS_OMAP3430),
+};
+
+/*
+ * 2420-only clockdomains
+ */
+
+#if defined(CONFIG_ARCH_OMAP2420)
+
+static struct clockdomain mpu_2420_clkdm = {
+ .name = "mpu_clkdm",
+ .pwrdm_name = "mpu_pwrdm",
+ .flags = CLKDM_CAN_HWSUP,
+ .clktrctrl_mask = OMAP24XX_AUTOSTATE_MPU_MASK,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420),
+};
+
+static struct clockdomain iva1_2420_clkdm = {
+ .name = "iva1_clkdm",
+ .pwrdm_name = "dsp_pwrdm",
+ .flags = CLKDM_CAN_HWSUP_SWSUP,
+ .clktrctrl_mask = OMAP2420_AUTOSTATE_IVA_MASK,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420),
+};
+
+#endif /* CONFIG_ARCH_OMAP2420 */
+
+
+/*
+ * 2430-only clockdomains
+ */
+
+#if defined(CONFIG_ARCH_OMAP2430)
+
+static struct clockdomain mpu_2430_clkdm = {
+ .name = "mpu_clkdm",
+ .pwrdm_name = "mpu_pwrdm",
+ .flags = CLKDM_CAN_HWSUP_SWSUP,
+ .clktrctrl_mask = OMAP24XX_AUTOSTATE_MPU_MASK,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430),
+};
+
+static struct clockdomain mdm_clkdm = {
+ .name = "mdm_clkdm",
+ .pwrdm_name = "mdm_pwrdm",
+ .flags = CLKDM_CAN_HWSUP_SWSUP,
+ .clktrctrl_mask = OMAP2430_AUTOSTATE_MDM_MASK,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430),
+};
+
+#endif /* CONFIG_ARCH_OMAP2430 */
+
+
+/*
+ * 24XX-only clockdomains
+ */
+
+#if defined(CONFIG_ARCH_OMAP24XX)
+
+static struct clockdomain dsp_clkdm = {
+ .name = "dsp_clkdm",
+ .pwrdm_name = "dsp_pwrdm",
+ .flags = CLKDM_CAN_HWSUP_SWSUP,
+ .clktrctrl_mask = OMAP24XX_AUTOSTATE_DSP_MASK,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX),
+};
+
+static struct clockdomain gfx_24xx_clkdm = {
+ .name = "gfx_clkdm",
+ .pwrdm_name = "gfx_pwrdm",
+ .flags = CLKDM_CAN_HWSUP_SWSUP,
+ .clktrctrl_mask = OMAP24XX_AUTOSTATE_GFX_MASK,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX),
+};
+
+static struct clockdomain core_l3_24xx_clkdm = {
+ .name = "core_l3_clkdm",
+ .pwrdm_name = "core_pwrdm",
+ .flags = CLKDM_CAN_HWSUP,
+ .clktrctrl_mask = OMAP24XX_AUTOSTATE_L3_MASK,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX),
+};
+
+static struct clockdomain core_l4_24xx_clkdm = {
+ .name = "core_l4_clkdm",
+ .pwrdm_name = "core_pwrdm",
+ .flags = CLKDM_CAN_HWSUP,
+ .clktrctrl_mask = OMAP24XX_AUTOSTATE_L4_MASK,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX),
+};
+
+static struct clockdomain dss_24xx_clkdm = {
+ .name = "dss_clkdm",
+ .pwrdm_name = "core_pwrdm",
+ .flags = CLKDM_CAN_HWSUP,
+ .clktrctrl_mask = OMAP24XX_AUTOSTATE_DSS_MASK,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX),
+};
+
+#endif /* CONFIG_ARCH_OMAP24XX */
+
+
+/*
+ * 34xx clockdomains
+ */
+
+#if defined(CONFIG_ARCH_OMAP34XX)
+
+static struct clockdomain mpu_34xx_clkdm = {
+ .name = "mpu_clkdm",
+ .pwrdm_name = "mpu_pwrdm",
+ .flags = CLKDM_CAN_HWSUP | CLKDM_CAN_FORCE_WAKEUP,
+ .clktrctrl_mask = OMAP3430_CLKTRCTRL_MPU_MASK,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct clockdomain neon_clkdm = {
+ .name = "neon_clkdm",
+ .pwrdm_name = "neon_pwrdm",
+ .flags = CLKDM_CAN_HWSUP_SWSUP,
+ .clktrctrl_mask = OMAP3430_CLKTRCTRL_NEON_MASK,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct clockdomain iva2_clkdm = {
+ .name = "iva2_clkdm",
+ .pwrdm_name = "iva2_pwrdm",
+ .flags = CLKDM_CAN_HWSUP_SWSUP,
+ .clktrctrl_mask = OMAP3430_CLKTRCTRL_IVA2_MASK,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct clockdomain gfx_3430es1_clkdm = {
+ .name = "gfx_clkdm",
+ .pwrdm_name = "gfx_pwrdm",
+ .flags = CLKDM_CAN_HWSUP_SWSUP,
+ .clktrctrl_mask = OMAP3430ES1_CLKTRCTRL_GFX_MASK,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES1),
+};
+
+static struct clockdomain sgx_clkdm = {
+ .name = "sgx_clkdm",
+ .pwrdm_name = "sgx_pwrdm",
+ .flags = CLKDM_CAN_HWSUP_SWSUP,
+ .clktrctrl_mask = OMAP3430ES2_CLKTRCTRL_SGX_MASK,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES2),
+};
+
+static struct clockdomain d2d_clkdm = {
+ .name = "d2d_clkdm",
+ .pwrdm_name = "core_pwrdm",
+ .flags = CLKDM_CAN_HWSUP,
+ .clktrctrl_mask = OMAP3430ES1_CLKTRCTRL_D2D_MASK,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES1),
+};
+
+static struct clockdomain core_l3_34xx_clkdm = {
+ .name = "core_l3_clkdm",
+ .pwrdm_name = "core_pwrdm",
+ .flags = CLKDM_CAN_HWSUP,
+ .clktrctrl_mask = OMAP3430_CLKTRCTRL_L3_MASK,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct clockdomain core_l4_34xx_clkdm = {
+ .name = "core_l4_clkdm",
+ .pwrdm_name = "core_pwrdm",
+ .flags = CLKDM_CAN_HWSUP,
+ .clktrctrl_mask = OMAP3430_CLKTRCTRL_L4_MASK,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct clockdomain dss_34xx_clkdm = {
+ .name = "dss_clkdm",
+ .pwrdm_name = "dss_pwrdm",
+ .flags = CLKDM_CAN_HWSUP_SWSUP,
+ .clktrctrl_mask = OMAP3430_CLKTRCTRL_DSS_MASK,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct clockdomain cam_clkdm = {
+ .name = "cam_clkdm",
+ .pwrdm_name = "cam_pwrdm",
+ .flags = CLKDM_CAN_HWSUP_SWSUP,
+ .clktrctrl_mask = OMAP3430_CLKTRCTRL_CAM_MASK,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct clockdomain usbhost_clkdm = {
+ .name = "usbhost_clkdm",
+ .pwrdm_name = "usbhost_pwrdm",
+ .flags = CLKDM_CAN_HWSUP_SWSUP,
+ .clktrctrl_mask = OMAP3430ES2_CLKTRCTRL_USBHOST_MASK,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES2),
+};
+
+static struct clockdomain per_clkdm = {
+ .name = "per_clkdm",
+ .pwrdm_name = "per_pwrdm",
+ .flags = CLKDM_CAN_HWSUP_SWSUP,
+ .clktrctrl_mask = OMAP3430_CLKTRCTRL_PER_MASK,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct clockdomain emu_clkdm = {
+ .name = "emu_clkdm",
+ .pwrdm_name = "emu_pwrdm",
+ .flags = CLKDM_CAN_ENABLE_AUTO | CLKDM_CAN_SWSUP,
+ .clktrctrl_mask = OMAP3430_CLKTRCTRL_EMU_MASK,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+#endif /* CONFIG_ARCH_OMAP34XX */
+
+/*
+ * Clockdomain-powerdomain hwsup dependencies (34XX only)
+ */
+
+static struct clkdm_pwrdm_autodep clkdm_pwrdm_autodeps[] = {
+ {
+ .pwrdm_name = "mpu_pwrdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+ },
+ {
+ .pwrdm_name = "iva2_pwrdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+ },
+ { NULL }
+};
+
+/*
+ *
+ */
+
+static struct clockdomain *clockdomains_omap[] = {
+
+ &wkup_clkdm,
+
+#ifdef CONFIG_ARCH_OMAP2420
+ &mpu_2420_clkdm,
+ &iva1_2420_clkdm,
+#endif
+
+#ifdef CONFIG_ARCH_OMAP2430
+ &mpu_2430_clkdm,
+ &mdm_clkdm,
+#endif
+
+#ifdef CONFIG_ARCH_OMAP24XX
+ &dsp_clkdm,
+ &gfx_24xx_clkdm,
+ &core_l3_24xx_clkdm,
+ &core_l4_24xx_clkdm,
+ &dss_24xx_clkdm,
+#endif
+
+#ifdef CONFIG_ARCH_OMAP34XX
+ &mpu_34xx_clkdm,
+ &neon_clkdm,
+ &iva2_clkdm,
+ &gfx_3430es1_clkdm,
+ &sgx_clkdm,
+ &d2d_clkdm,
+ &core_l3_34xx_clkdm,
+ &core_l4_34xx_clkdm,
+ &dss_34xx_clkdm,
+ &cam_clkdm,
+ &usbhost_clkdm,
+ &per_clkdm,
+ &emu_clkdm,
+#endif
+
+ NULL,
+};
+
+#endif
#define OMAP24XX_CLKSEL_MPU_MASK (0x1f << 0)
/* CM_CLKSTCTRL_MPU */
-#define OMAP24XX_AUTOSTATE_MPU (1 << 0)
+#define OMAP24XX_AUTOSTATE_MPU_SHIFT 0
+#define OMAP24XX_AUTOSTATE_MPU_MASK (1 << 0)
/* CM_FCLKEN1_CORE specific bits*/
#define OMAP24XX_EN_TV_SHIFT 2
#define OMAP24XX_CLKSEL_GPT2_MASK (0x3 << 2)
/* CM_CLKSTCTRL_CORE */
-#define OMAP24XX_AUTOSTATE_DSS (1 << 2)
-#define OMAP24XX_AUTOSTATE_L4 (1 << 1)
-#define OMAP24XX_AUTOSTATE_L3 (1 << 0)
+#define OMAP24XX_AUTOSTATE_DSS_SHIFT 2
+#define OMAP24XX_AUTOSTATE_DSS_MASK (1 << 2)
+#define OMAP24XX_AUTOSTATE_L4_SHIFT 1
+#define OMAP24XX_AUTOSTATE_L4_MASK (1 << 1)
+#define OMAP24XX_AUTOSTATE_L3_SHIFT 0
+#define OMAP24XX_AUTOSTATE_L3_MASK (1 << 0)
/* CM_FCLKEN_GFX */
#define OMAP24XX_EN_3D_SHIFT 2
/* CM_CLKSEL_GFX specific bits */
/* CM_CLKSTCTRL_GFX */
-#define OMAP24XX_AUTOSTATE_GFX (1 << 0)
+#define OMAP24XX_AUTOSTATE_GFX_SHIFT 0
+#define OMAP24XX_AUTOSTATE_GFX_MASK (1 << 0)
/* CM_FCLKEN_WKUP specific bits */
#define OMAP24XX_CLKSEL_DSP_MASK (0x1f << 0)
/* CM_CLKSTCTRL_DSP */
-#define OMAP2420_AUTOSTATE_IVA (1 << 8)
-#define OMAP24XX_AUTOSTATE_DSP (1 << 0)
+#define OMAP2420_AUTOSTATE_IVA_SHIFT 8
+#define OMAP2420_AUTOSTATE_IVA_MASK (1 << 8)
+#define OMAP24XX_AUTOSTATE_DSP_SHIFT 0
+#define OMAP24XX_AUTOSTATE_DSP_MASK (1 << 0)
/* CM_FCLKEN_MDM */
/* 2430 only */
/* CM_CLKSTCTRL_MDM */
/* 2430 only */
-#define OMAP2430_AUTOSTATE_MDM (1 << 0)
+#define OMAP2430_AUTOSTATE_MDM_SHIFT 0
+#define OMAP2430_AUTOSTATE_MDM_MASK (1 << 0)
#endif
/* CM_FCLKEN_IVA2 */
#define OMAP3430_CM_FCLKEN_IVA2_EN_IVA2 (1 << 0)
+#define OMAP3430_CM_FCLKEN_IVA2_EN_IVA2_SHIFT 0
/* CM_CLKEN_PLL_IVA2 */
#define OMAP3430_IVA2_DPLL_RAMPTIME_SHIFT 8
#define OMAP3430_ST_IVA2 (1 << 0)
/* CM_IDLEST_PLL_IVA2 */
-#define OMAP3430_ST_IVA2_CLK (1 << 0)
+#define OMAP3430_ST_IVA2_CLK_SHIFT 0
+#define OMAP3430_ST_IVA2_CLK_MASK (1 << 0)
/* CM_AUTOIDLE_PLL_IVA2 */
#define OMAP3430_AUTO_IVA2_DPLL_SHIFT 0
#define OMAP3430_CLKTRCTRL_IVA2_MASK (0x3 << 0)
/* CM_CLKSTST_IVA2 */
-#define OMAP3430_CLKACTIVITY_IVA2 (1 << 0)
+#define OMAP3430_CLKACTIVITY_IVA2_SHIFT 0
+#define OMAP3430_CLKACTIVITY_IVA2_MASK (1 << 0)
/* CM_REVISION specific bits */
#define OMAP3430_ST_MPU (1 << 0)
/* CM_IDLEST_PLL_MPU */
-#define OMAP3430_ST_MPU_CLK (1 << 0)
-#define OMAP3430_ST_IVA2_CLK_MASK (1 << 0)
-
-/* CM_IDLEST_PLL_MPU */
+#define OMAP3430_ST_MPU_CLK_SHIFT 0
#define OMAP3430_ST_MPU_CLK_MASK (1 << 0)
/* CM_AUTOIDLE_PLL_MPU */
#define OMAP3430_CLKTRCTRL_MPU_MASK (0x3 << 0)
/* CM_CLKSTST_MPU */
-#define OMAP3430_CLKACTIVITY_MPU (1 << 0)
+#define OMAP3430_CLKACTIVITY_MPU_SHIFT 0
+#define OMAP3430_CLKACTIVITY_MPU_MASK (1 << 0)
/* CM_FCLKEN1_CORE specific bits */
#define OMAP3430_CLKTRCTRL_L3_MASK (0x3 << 0)
/* CM_CLKSTST_CORE */
-#define OMAP3430ES1_CLKACTIVITY_D2D (1 << 2)
-#define OMAP3430_CLKACTIVITY_L4 (1 << 1)
-#define OMAP3430_CLKACTIVITY_L3 (1 << 0)
+#define OMAP3430ES1_CLKACTIVITY_D2D_SHIFT 2
+#define OMAP3430ES1_CLKACTIVITY_D2D_MASK (1 << 2)
+#define OMAP3430_CLKACTIVITY_L4_SHIFT 1
+#define OMAP3430_CLKACTIVITY_L4_MASK (1 << 1)
+#define OMAP3430_CLKACTIVITY_L3_SHIFT 0
+#define OMAP3430_CLKACTIVITY_L3_MASK (1 << 0)
/* CM_FCLKEN_GFX */
#define OMAP3430ES1_EN_3D (1 << 2)
#define OMAP3430ES1_CLKTRCTRL_GFX_MASK (0x3 << 0)
/* CM_CLKSTST_GFX */
-#define OMAP3430ES1_CLKACTIVITY_GFX (1 << 0)
+#define OMAP3430ES1_CLKACTIVITY_GFX_SHIFT 0
+#define OMAP3430ES1_CLKACTIVITY_GFX_MASK (1 << 0)
/* CM_FCLKEN_SGX */
#define OMAP3430ES2_EN_SGX_SHIFT 1
#define OMAP3430ES2_CLKSEL_SGX_SHIFT 0
#define OMAP3430ES2_CLKSEL_SGX_MASK (0x7 << 0)
+/* CM_CLKSTCTRL_SGX */
+#define OMAP3430ES2_CLKTRCTRL_SGX_SHIFT 0
+#define OMAP3430ES2_CLKTRCTRL_SGX_MASK (0x3 << 0)
+
+/* CM_CLKSTST_SGX */
+#define OMAP3430ES2_CLKACTIVITY_SGX_SHIFT 0
+#define OMAP3430ES2_CLKACTIVITY_SGX_MASK (1 << 0)
+
/* CM_FCLKEN_WKUP specific bits */
#define OMAP3430ES2_EN_USIMOCP_SHIFT 9
#define OMAP3430_ST_12M_CLK (1 << 4)
#define OMAP3430_ST_48M_CLK (1 << 3)
#define OMAP3430_ST_96M_CLK (1 << 2)
-#define OMAP3430_ST_PERIPH_CLK (1 << 1)
-#define OMAP3430_ST_CORE_CLK (1 << 0)
+#define OMAP3430_ST_PERIPH_CLK_SHIFT 1
+#define OMAP3430_ST_PERIPH_CLK_MASK (1 << 1)
+#define OMAP3430_ST_CORE_CLK_SHIFT 0
+#define OMAP3430_ST_CORE_CLK_MASK (1 << 0)
/* CM_IDLEST2_CKGEN */
#define OMAP3430ES2_ST_120M_CLK_SHIFT 1
#define OMAP3430_AUTO_CORE_DPLL_SHIFT 0
#define OMAP3430_AUTO_CORE_DPLL_MASK (0x7 << 0)
+/* CM_AUTOIDLE2_PLL */
+#define OMAP3430ES2_AUTO_PERIPH2_DPLL_SHIFT 0
+#define OMAP3430ES2_AUTO_PERIPH2_DPLL_MASK (0x7 << 0)
+
/* CM_CLKSEL1_PLL */
/* Note that OMAP3430_CORE_DPLL_CLKOUT_DIV_MASK was (0x3 << 27) on 3430ES1 */
#define OMAP3430_CORE_DPLL_CLKOUT_DIV_SHIFT 27
#define OMAP3430_CLKTRCTRL_DSS_MASK (0x3 << 0)
/* CM_CLKSTST_DSS */
-#define OMAP3430_CLKACTIVITY_DSS (1 << 0)
+#define OMAP3430_CLKACTIVITY_DSS_SHIFT 0
+#define OMAP3430_CLKACTIVITY_DSS_MASK (1 << 0)
/* CM_FCLKEN_CAM specific bits */
#define OMAP3430_CLKTRCTRL_CAM_MASK (0x3 << 0)
/* CM_CLKSTST_CAM */
-#define OMAP3430_CLKACTIVITY_CAM (1 << 0)
+#define OMAP3430_CLKACTIVITY_CAM_SHIFT 0
+#define OMAP3430_CLKACTIVITY_CAM_MASK (1 << 0)
/* CM_FCLKEN_PER specific bits */
#define OMAP3430_CLKTRCTRL_PER_MASK (0x3 << 0)
/* CM_CLKSTST_PER */
-#define OMAP3430_CLKACTIVITY_PER (1 << 0)
+#define OMAP3430_CLKACTIVITY_PER_SHIFT 0
+#define OMAP3430_CLKACTIVITY_PER_MASK (1 << 0)
/* CM_CLKSEL1_EMU */
#define OMAP3430_DIV_DPLL4_SHIFT 24
#define OMAP3430_CLKTRCTRL_EMU_MASK (0x3 << 0)
/* CM_CLKSTST_EMU */
-#define OMAP3430_CLKACTIVITY_EMU (1 << 0)
+#define OMAP3430_CLKACTIVITY_EMU_SHIFT 0
+#define OMAP3430_CLKACTIVITY_EMU_MASK (1 << 0)
/* CM_CLKSEL2_EMU specific bits */
#define OMAP3430_CORE_DPLL_EMU_MULT_SHIFT 8
#define OMAP3430ES2_CLKTRCTRL_USBHOST_SHIFT 0
#define OMAP3430ES2_CLKTRCTRL_USBHOST_MASK (3 << 0)
-
+/* CM_CLKSTST_USBHOST */
+#define OMAP3430ES2_CLKACTIVITY_USBHOST_SHIFT 0
+#define OMAP3430ES2_CLKACTIVITY_USBHOST_MASK (1 << 0)
#endif
* published by the Free Software Foundation.
*/
+#include <asm/io.h>
+
#include "prcm-common.h"
#ifndef __ASSEMBLER__
#define OMAP3430_CM_CLKOUT_CTRL OMAP_CM_REGADDR(OMAP3430_CCR_MOD, 0x0070)
+#ifndef __ASSEMBLER__
+
+/* Read-modify-write bits in a CM register */
+static __inline__ u32 __attribute__((unused)) cm_rmw_reg_bits(u32 mask,
+ u32 bits, void __iomem *va)
+{
+ u32 v;
+
+ v = __raw_readl(va);
+ v &= ~mask;
+ v |= bits;
+ __raw_writel(v, va);
+
+ return v;
+}
+
+#endif
+
/*
* Module specific CM registers from CM_BASE + domain offset
* Use cm_{read,write}_mod_reg() with these registers.
#define CM_CLKSEL2 0x0044
#define CM_CLKSTCTRL 0x0048
-
/* Architecture-specific registers */
#define OMAP24XX_CM_FCLKEN2 0x0004
#define OMAP3430ES2_CM_FCLKEN3 0x0008
#define OMAP3430_CM_IDLEST_PLL CM_IDLEST2
#define OMAP3430_CM_AUTOIDLE_PLL CM_AUTOIDLE2
+#define OMAP3430ES2_CM_AUTOIDLE2_PLL CM_AUTOIDLE2
#define OMAP3430_CM_CLKSEL1 CM_CLKSEL
#define OMAP3430_CM_CLKSEL1_PLL CM_CLKSEL
#define OMAP3430_CM_CLKSEL2_PLL CM_CLKSEL2
/* Clock management domain register get/set */
#ifndef __ASSEMBLER__
-static inline void cm_write_mod_reg(u32 val, s16 module, s16 idx)
+static __inline__ void __attribute__((unused)) cm_write_mod_reg(u32 val,
+ s16 module, s16 idx)
{
__raw_writel(val, OMAP_CM_REGADDR(module, idx));
}
-static inline u32 cm_read_mod_reg(s16 module, s16 idx)
+static __inline__ u32 __attribute__((unused)) cm_read_mod_reg(s16 module,
+ s16 idx)
{
return __raw_readl(OMAP_CM_REGADDR(module, idx));
}
+
+/* Read-modify-write bits in a CM register (by domain) */
+static __inline__ u32 __attribute__((unused)) cm_rmw_mod_reg_bits(u32 mask,
+ u32 bits, s16 module, s16 idx)
+{
+ return cm_rmw_reg_bits(mask, bits, OMAP_CM_REGADDR(module, idx));
+}
+
+static __inline__ u32 __attribute__((unused)) cm_set_mod_reg_bits(u32 bits,
+ s16 module, s16 idx)
+{
+ return cm_rmw_mod_reg_bits(bits, bits, module, idx);
+}
+
+static __inline__ u32 __attribute__((unused)) cm_clear_mod_reg_bits(u32 bits,
+ s16 module, s16 idx)
+{
+ return cm_rmw_mod_reg_bits(bits, 0x0, module, idx);
+}
+
#endif
/* CM register bits shared between 24XX and 3430 */
#include <asm/arch/board.h>
#include <asm/arch/mux.h>
#include <asm/arch/gpio.h>
+#include <asm/arch/eac.h>
-#if defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE)
+#if defined(CONFIG_VIDEO_OMAP2) || defined(CONFIG_VIDEO_OMAP2_MODULE)
-#define OMAP2_I2C_BASE2 0x48072000
-#define OMAP2_I2C_INT2 57
-
-static struct resource i2c_resources2[] = {
+static struct resource cam_resources[] = {
{
- .start = OMAP2_I2C_BASE2,
- .end = OMAP2_I2C_BASE2 + 0x3f,
+ .start = OMAP24XX_CAMERA_BASE,
+ .end = OMAP24XX_CAMERA_BASE + 0xfff,
.flags = IORESOURCE_MEM,
},
{
- .start = OMAP2_I2C_INT2,
+ .start = INT_24XX_CAM_IRQ,
.flags = IORESOURCE_IRQ,
- },
+ }
};
-static struct platform_device omap_i2c_device2 = {
- .name = "i2c_omap",
- .id = 2,
- .num_resources = ARRAY_SIZE(i2c_resources2),
- .resource = i2c_resources2,
+static struct platform_device omap_cam_device = {
+ .name = "omap24xxcam",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(cam_resources),
+ .resource = cam_resources,
};
-/* See also arch/arm/plat-omap/devices.c for first I2C on 24xx */
-static void omap_init_i2c(void)
+static inline void omap_init_camera(void)
{
- /* REVISIT: Second I2C not in use on H4? */
- if (machine_is_omap_h4())
- return;
-
- if (!cpu_is_omap2430()) {
- omap_cfg_reg(J15_24XX_I2C2_SCL);
- omap_cfg_reg(H19_24XX_I2C2_SDA);
- }
- (void) platform_device_register(&omap_i2c_device2);
+ platform_device_register(&omap_cam_device);
}
-
#else
-
-static void omap_init_i2c(void) {}
-
+static inline void omap_init_camera(void)
+{
+}
#endif
#if defined(CONFIG_OMAP_DSP) || defined(CONFIG_OMAP_DSP_MODULE)
static inline void omap_init_sti(void) {}
#endif
-#if defined(CONFIG_SPI_OMAP24XX)
+#if defined(CONFIG_SPI_OMAP24XX) || defined(CONFIG_SPI_OMAP24XX_MODULE)
#include <asm/arch/mcspi.h>
#define OMAP2_MCSPI1_BASE 0x48098000
#define OMAP2_MCSPI2_BASE 0x4809a000
+#define OMAP2_MCSPI3_BASE 0x480b8000
+#define OMAP2_MCSPI4_BASE 0x480ba000
static struct omap2_mcspi_platform_config omap2_mcspi1_config = {
.num_cs = 4,
},
};
+#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3)
+static struct omap2_mcspi_platform_config omap2_mcspi3_config = {
+ .num_cs = 2,
+};
+
+static struct resource omap2_mcspi3_resources[] = {
+ {
+ .start = OMAP2_MCSPI3_BASE,
+ .end = OMAP2_MCSPI3_BASE + 0xff,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+struct platform_device omap2_mcspi3 = {
+ .name = "omap2_mcspi",
+ .id = 3,
+ .num_resources = ARRAY_SIZE(omap2_mcspi3_resources),
+ .resource = omap2_mcspi3_resources,
+ .dev = {
+ .platform_data = &omap2_mcspi3_config,
+ },
+};
+#endif
+
+#ifdef CONFIG_ARCH_OMAP3
+static struct omap2_mcspi_platform_config omap2_mcspi4_config = {
+ .num_cs = 1,
+};
+
+static struct resource omap2_mcspi4_resources[] = {
+ {
+ .start = OMAP2_MCSPI4_BASE,
+ .end = OMAP2_MCSPI4_BASE + 0xff,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+struct platform_device omap2_mcspi4 = {
+ .name = "omap2_mcspi",
+ .id = 4,
+ .num_resources = ARRAY_SIZE(omap2_mcspi4_resources),
+ .resource = omap2_mcspi4_resources,
+ .dev = {
+ .platform_data = &omap2_mcspi4_config,
+ },
+};
+#endif
+
static void omap_init_mcspi(void)
{
platform_device_register(&omap2_mcspi1);
platform_device_register(&omap2_mcspi2);
+#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3)
+ platform_device_register(&omap2_mcspi3);
+#endif
+#ifdef CONFIG_ARCH_OMAP3
+ platform_device_register(&omap2_mcspi4);
+#endif
}
#else
static inline void omap_init_mcspi(void) {}
#endif
+#ifdef CONFIG_SND_OMAP24XX_EAC
+
+#define OMAP2_EAC_BASE 0x48090000
+
+static struct resource omap2_eac_resources[] = {
+ {
+ .start = OMAP2_EAC_BASE,
+ .end = OMAP2_EAC_BASE + 0x109,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device omap2_eac_device = {
+ .name = "omap24xx-eac",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(omap2_eac_resources),
+ .resource = omap2_eac_resources,
+ .dev = {
+ .platform_data = NULL,
+ },
+};
+
+void omap_init_eac(struct eac_platform_data *pdata)
+{
+ omap2_eac_device.dev.platform_data = pdata;
+ platform_device_register(&omap2_eac_device);
+}
+
+#else
+void omap_init_eac(struct eac_platform_data *pdata) {}
+#endif
+
+#ifdef CONFIG_OMAP_SHA1_MD5
+static struct resource sha1_md5_resources[] = {
+ {
+ .start = OMAP24XX_SEC_SHA1MD5_BASE,
+ .end = OMAP24XX_SEC_SHA1MD5_BASE + 0x64,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = INT_24XX_SHA1MD5,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static struct platform_device sha1_md5_device = {
+ .name = "OMAP SHA1/MD5",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(sha1_md5_resources),
+ .resource = sha1_md5_resources,
+};
+
+static void omap_init_sha1_md5(void)
+{
+ platform_device_register(&sha1_md5_device);
+}
+#else
+static inline void omap_init_sha1_md5(void) { }
+#endif
+
+#if defined(CONFIG_HDQ_MASTER_OMAP) || defined(CONFIG_HDQ_MASTER_OMAP_MODULE)
+#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430)
+#define OMAP_HDQ_BASE 0x480B2000
+#endif
+static struct resource omap_hdq_resources[] = {
+ {
+ .start = OMAP_HDQ_BASE,
+ .end = OMAP_HDQ_BASE + 0x1C,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = INT_24XX_HDQ_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+static struct platform_device omap_hdq_dev = {
+ .name = "omap_hdq",
+ .id = 0,
+ .dev = {
+ .platform_data = NULL,
+ },
+ .num_resources = ARRAY_SIZE(omap_hdq_resources),
+ .resource = omap_hdq_resources,
+};
+static inline void omap_hdq_init(void)
+{
+ (void) platform_device_register(&omap_hdq_dev);
+}
+#else
+static inline void omap_hdq_init(void) {}
+#endif
+
/*-------------------------------------------------------------------------*/
static int __init omap2_init_devices(void)
/* please keep these calls, and their implementations above,
* in alphabetical order so they're easier to sort through.
*/
- omap_init_i2c();
+ omap_init_camera();
omap_init_mbox();
omap_init_mcspi();
+ omap_hdq_init();
omap_init_sti();
+ omap_init_sha1_md5();
return 0;
}
#include <linux/clk.h>
#include <linux/ioport.h>
#include <linux/spinlock.h>
+#include <linux/module.h>
#include <asm/io.h>
#include <asm/mach-types.h>
#undef DEBUG
-#ifdef CONFIG_ARCH_OMAP2420
+#if defined(CONFIG_ARCH_OMAP2420)
#define GPMC_BASE 0x6800a000
-#endif
-
-#ifdef CONFIG_ARCH_OMAP2430
-#define GPMC_BASE 0x6E000000
+#elif defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX)
+#define GPMC_BASE 0x6e000000
#endif
#define GPMC_REVISION 0x00
#define GPMC_STATUS 0x54
#define GPMC_PREFETCH_CONFIG1 0x1e0
#define GPMC_PREFETCH_CONFIG2 0x1e4
-#define GPMC_PREFETCH_CONTROL 0x1e8
+#define GPMC_PREFETCH_CONTROL 0x1ec
#define GPMC_PREFETCH_STATUS 0x1f0
#define GPMC_ECC_CONFIG 0x1f4
#define GPMC_ECC_CONTROL 0x1f8
#define GPMC_CS0 0x60
#define GPMC_CS_SIZE 0x30
-#define GPMC_CS_NUM 8
#define GPMC_MEM_START 0x00000000
#define GPMC_MEM_END 0x3FFFFFFF
#define BOOT_ROM_SPACE 0x100000 /* 1MB */
static void __iomem *gpmc_cs_base =
(void __iomem *) IO_ADDRESS(GPMC_BASE) + GPMC_CS0;
-static struct clk *gpmc_fck;
+static struct clk *gpmc_l3_clk;
static void gpmc_write_reg(int idx, u32 val)
{
return __raw_readl(gpmc_cs_base + (cs * GPMC_CS_SIZE) + idx);
}
+/* TODO: Add support for gpmc_fck to clock framework and use it */
unsigned long gpmc_get_fclk_period(void)
{
- /* In picoseconds */
- return 1000000000 / ((clk_get_rate(gpmc_fck)) / 1000);
+ unsigned long rate = clk_get_rate(gpmc_l3_clk);
+
+ if (rate == 0) {
+ printk(KERN_WARNING "gpmc_l3_clk no enabled\n");
+ return 0;
+ }
+
+ rate /= 1000;
+ rate = 1000000000 / rate; /* In picoseconds */
+
+ return rate;
}
unsigned int gpmc_ns_to_ticks(unsigned int time_ns)
return (time_ns * 1000 + tick_ps - 1) / tick_ps;
}
+unsigned int gpmc_ticks_to_ns(unsigned int ticks)
+{
+ return ticks * gpmc_get_fclk_period() / 1000;
+}
+
unsigned int gpmc_round_ns_to_ticks(unsigned int time_ns)
{
unsigned long ticks = gpmc_ns_to_ticks(time_ns);
spin_unlock(&gpmc_mem_lock);
return r;
}
+EXPORT_SYMBOL(gpmc_cs_request);
void gpmc_cs_free(int cs)
{
gpmc_cs_set_reserved(cs, 0);
spin_unlock(&gpmc_mem_lock);
}
+EXPORT_SYMBOL(gpmc_cs_free);
void __init gpmc_mem_init(void)
{
{
u32 l;
- gpmc_fck = clk_get(NULL, "gpmc_fck"); /* Always on ENABLE_ON_INIT */
- if (IS_ERR(gpmc_fck))
- WARN_ON(1);
- else
- clk_enable(gpmc_fck);
+ if (cpu_is_omap24xx())
+ gpmc_l3_clk = clk_get(NULL, "core_l3_ck");
+ else if (cpu_is_omap34xx())
+ gpmc_l3_clk = clk_get(NULL, "gpmc_fck");
+
+ BUG_ON(IS_ERR(gpmc_l3_clk));
l = gpmc_read_reg(GPMC_REVISION);
printk(KERN_INFO "GPMC revision %d.%d\n", (l >> 4) & 0x0f, l & 0x0f);
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap2/board-sdp-hsmmc.c
+ *
+ * Copyright (C) 2007-2008 Texas Instruments
+ * Copyright (C) 2008 Nokia Corporation
+ * Author: Texas Instruments
+ *
+ * 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/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/i2c/twl4030.h>
+#include <asm/hardware.h>
+#include <asm/arch/mmc.h>
+#include <asm/arch/board.h>
+
+#if defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)
+
+#define VMMC1_DEV_GRP 0x27
+#define P1_DEV_GRP 0x20
+#define VMMC1_DEDICATED 0x2A
+#define VSEL_3V 0x02
+#define VSEL_18V 0x00
+#define TWL_GPIO_PUPDCTR1 0x13
+#define TWL_GPIO_IMR1A 0x1C
+#define TWL_GPIO_ISR1A 0x19
+#define LDO_CLR 0x00
+#define VSEL_S2_CLR 0x40
+#define GPIO_0_BIT_POS (1 << 0)
+#define MMC1_CD_IRQ 0
+#define MMC2_CD_IRQ 1
+
+#define OMAP2_CONTROL_DEVCONF0 0x48002274
+#define OMAP2_CONTROL_DEVCONF1 0x490022E8
+
+#define OMAP2_CONTROL_DEVCONF0_LBCLK (1 << 24)
+#define OMAP2_CONTROL_DEVCONF1_ACTOV (1 << 31)
+
+#define OMAP2_CONTROL_PBIAS_VMODE (1 << 0)
+#define OMAP2_CONTROL_PBIAS_PWRDNZ (1 << 1)
+#define OMAP2_CONTROL_PBIAS_SCTRL (1 << 2)
+
+static int hsmmc_card_detect(int irq)
+{
+ return twl4030_get_gpio_datain(irq - TWL4030_GPIO_IRQ_BASE);
+}
+
+/*
+ * MMC Slot Initialization.
+ */
+static int hsmmc_late_init(struct device *dev)
+{
+ int ret = 0;
+
+ /*
+ * Configure TWL4030 GPIO parameters for MMC hotplug irq
+ */
+ ret = twl4030_request_gpio(MMC1_CD_IRQ);
+ if (ret)
+ goto err;
+
+ ret = twl4030_set_gpio_edge_ctrl(MMC1_CD_IRQ,
+ TWL4030_GPIO_EDGE_RISING | TWL4030_GPIO_EDGE_FALLING);
+ if (ret)
+ goto err;
+
+ ret = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0x02,
+ TWL_GPIO_PUPDCTR1);
+ if (ret)
+ goto err;
+
+ ret = twl4030_set_gpio_debounce(MMC1_CD_IRQ, TWL4030_GPIO_IS_ENABLE);
+ if (ret)
+ goto err;
+
+ return ret;
+
+err:
+ dev_err(dev, "Failed to configure TWL4030 GPIO IRQ\n");
+ return ret;
+}
+
+static void hsmmc_cleanup(struct device *dev)
+{
+ int ret = 0;
+
+ ret = twl4030_free_gpio(MMC1_CD_IRQ);
+ if (ret)
+ dev_err(dev, "Failed to configure TWL4030 GPIO IRQ\n");
+}
+
+#ifdef CONFIG_PM
+
+/*
+ * To mask and unmask MMC Card Detect Interrupt
+ * mask : 1
+ * unmask : 0
+ */
+static int mask_cd_interrupt(int mask)
+{
+ u8 reg = 0, ret = 0;
+
+ ret = twl4030_i2c_read_u8(TWL4030_MODULE_GPIO, ®, TWL_GPIO_IMR1A);
+ if (ret)
+ goto err;
+
+ reg = (mask == 1) ? (reg | GPIO_0_BIT_POS) : (reg & ~GPIO_0_BIT_POS);
+
+ ret = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, reg, TWL_GPIO_IMR1A);
+ if (ret)
+ goto err;
+
+ ret = twl4030_i2c_read_u8(TWL4030_MODULE_GPIO, ®, TWL_GPIO_ISR1A);
+ if (ret)
+ goto err;
+
+ reg = (mask == 1) ? (reg | GPIO_0_BIT_POS) : (reg & ~GPIO_0_BIT_POS);
+
+ ret = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, reg, TWL_GPIO_ISR1A);
+ if (ret)
+ goto err;
+
+err:
+ return ret;
+}
+
+static int hsmmc_suspend(struct device *dev, int slot)
+{
+ int ret = 0;
+
+ disable_irq(TWL4030_GPIO_IRQ_NO(MMC1_CD_IRQ));
+ ret = mask_cd_interrupt(1);
+
+ return ret;
+}
+
+static int hsmmc_resume(struct device *dev, int slot)
+{
+ int ret = 0;
+
+ enable_irq(TWL4030_GPIO_IRQ_NO(MMC1_CD_IRQ));
+ ret = mask_cd_interrupt(0);
+
+ return ret;
+}
+
+#endif
+
+static int hsmmc_set_power(struct device *dev, int slot, int power_on,
+ int vdd)
+{
+ u32 vdd_sel = 0, devconf = 0, reg = 0;
+ int ret = 0;
+
+ /* REVISIT: Using address directly till the control.h defines
+ * are settled.
+ */
+#if defined(CONFIG_ARCH_OMAP2430)
+ #define OMAP2_CONTROL_PBIAS 0x490024A0
+#else
+ #define OMAP2_CONTROL_PBIAS 0x48002520
+#endif
+
+ if (power_on) {
+ if (cpu_is_omap24xx())
+ devconf = omap_readl(OMAP2_CONTROL_DEVCONF1);
+ else
+ devconf = omap_readl(OMAP2_CONTROL_DEVCONF0);
+
+ switch (1 << vdd) {
+ case MMC_VDD_33_34:
+ case MMC_VDD_32_33:
+ vdd_sel = VSEL_3V;
+ if (cpu_is_omap24xx())
+ devconf |= OMAP2_CONTROL_DEVCONF1_ACTOV;
+ break;
+ case MMC_VDD_165_195:
+ vdd_sel = VSEL_18V;
+ if (cpu_is_omap24xx())
+ devconf &= ~OMAP2_CONTROL_DEVCONF1_ACTOV;
+ }
+
+ if (cpu_is_omap24xx())
+ omap_writel(devconf, OMAP2_CONTROL_DEVCONF1);
+ else
+ omap_writel(devconf | OMAP2_CONTROL_DEVCONF0_LBCLK,
+ OMAP2_CONTROL_DEVCONF0);
+
+ reg = omap_readl(OMAP2_CONTROL_PBIAS);
+ reg |= OMAP2_CONTROL_PBIAS_SCTRL;
+ omap_writel(reg, OMAP2_CONTROL_PBIAS);
+
+ reg = omap_readl(OMAP2_CONTROL_PBIAS);
+ reg &= ~OMAP2_CONTROL_PBIAS_PWRDNZ;
+ omap_writel(reg, OMAP2_CONTROL_PBIAS);
+
+ ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+ P1_DEV_GRP, VMMC1_DEV_GRP);
+ if (ret)
+ goto err;
+
+ ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+ vdd_sel, VMMC1_DEDICATED);
+ if (ret)
+ goto err;
+
+ msleep(100);
+ reg = omap_readl(OMAP2_CONTROL_PBIAS);
+ reg |= (OMAP2_CONTROL_PBIAS_SCTRL |
+ OMAP2_CONTROL_PBIAS_PWRDNZ);
+ if (vdd_sel == VSEL_18V)
+ reg &= ~OMAP2_CONTROL_PBIAS_VMODE;
+ else
+ reg |= OMAP2_CONTROL_PBIAS_VMODE;
+ omap_writel(reg, OMAP2_CONTROL_PBIAS);
+
+ return ret;
+
+ } else {
+ /* Power OFF */
+
+ /* For MMC1, Toggle PBIAS before every power up sequence */
+ reg = omap_readl(OMAP2_CONTROL_PBIAS);
+ reg &= ~OMAP2_CONTROL_PBIAS_PWRDNZ;
+ omap_writel(reg, OMAP2_CONTROL_PBIAS);
+
+ ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+ LDO_CLR, VMMC1_DEV_GRP);
+ if (ret)
+ goto err;
+
+ ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+ VSEL_S2_CLR, VMMC1_DEDICATED);
+ if (ret)
+ goto err;
+
+ /* 100ms delay required for PBIAS configuration */
+ msleep(100);
+ reg = omap_readl(OMAP2_CONTROL_PBIAS);
+ reg |= (OMAP2_CONTROL_PBIAS_VMODE |
+ OMAP2_CONTROL_PBIAS_PWRDNZ |
+ OMAP2_CONTROL_PBIAS_SCTRL);
+ omap_writel(reg, OMAP2_CONTROL_PBIAS);
+ }
+
+ return 0;
+
+err:
+ return 1;
+}
+
+static struct omap_mmc_platform_data hsmmc_data = {
+ .nr_slots = 1,
+ .switch_slot = NULL,
+ .init = hsmmc_late_init,
+ .cleanup = hsmmc_cleanup,
+#ifdef CONFIG_PM
+ .suspend = hsmmc_suspend,
+ .resume = hsmmc_resume,
+#endif
+ .slots[0] = {
+ .set_power = hsmmc_set_power,
+ .set_bus_mode = NULL,
+ .get_ro = NULL,
+ .get_cover_state = NULL,
+ .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34 |
+ MMC_VDD_165_195,
+ .name = "first slot",
+
+ .card_detect_irq = TWL4030_GPIO_IRQ_NO(MMC1_CD_IRQ),
+ .card_detect = hsmmc_card_detect,
+ },
+};
+
+void __init hsmmc_init(void)
+{
+ omap_set_mmc_info(1, &hsmmc_data);
+}
+
+#else
+
+void __init hsmmc_init(void)
+{
+
+}
+
+#endif
#include <asm/io.h>
-#if defined(CONFIG_ARCH_OMAP2420)
-#define OMAP24XX_TAP_BASE io_p2v(0x48014000)
-#endif
+#include <asm/arch/control.h>
+#include <asm/arch/cpu.h>
-#if defined(CONFIG_ARCH_OMAP2430)
-#define OMAP24XX_TAP_BASE io_p2v(0x4900A000)
+#if defined(CONFIG_ARCH_OMAP2420)
+#define TAP_BASE io_p2v(0x48014000)
+#elif defined(CONFIG_ARCH_OMAP2430)
+#define TAP_BASE io_p2v(0x4900A000)
+#elif defined(CONFIG_ARCH_OMAP34XX)
+#define TAP_BASE io_p2v(0x4830A000)
#endif
#define OMAP_TAP_IDCODE 0x0204
+#if defined(CONFIG_ARCH_OMAP34XX)
+#define OMAP_TAP_PROD_ID 0x0210
+#else
#define OMAP_TAP_PROD_ID 0x0208
+#endif
#define OMAP_TAP_DIE_ID_0 0x0218
#define OMAP_TAP_DIE_ID_1 0x021C
{ .hawkeye = 0xb68a, .dev = 0x0, .type = 0x24300000 },
};
+static struct omap_chip_id omap_chip;
+
+/**
+ * omap_chip_is - test whether currently running OMAP matches a chip type
+ * @oc: omap_chip_t to test against
+ *
+ * Test whether the currently-running OMAP chip matches the supplied
+ * chip type 'oc'. Returns 1 upon a match; 0 upon failure.
+ */
+int omap_chip_is(struct omap_chip_id oci)
+{
+ return (oci.oc & omap_chip.oc) ? 1 : 0;
+}
+EXPORT_SYMBOL(omap_chip_is);
+
static u32 __init read_tap_reg(int reg)
{
- return __raw_readl(OMAP24XX_TAP_BASE + reg);
+ unsigned int regval = 0;
+ u32 cpuid;
+
+ /* Reading the IDCODE register on 3430 ES1 results in a
+ * data abort as the register is not exposed on the OCP
+ * Hence reading the Cortex Rev
+ */
+ cpuid = read_cpuid(CPUID_ID);
+
+ /* If the processor type is Cortex-A8 and the revision is 0x0
+ * it means its Cortex r0p0 which is 3430 ES1
+ */
+ if ((((cpuid >> 4) & 0xFFF) == 0xC08) && ((cpuid & 0xF) == 0x0)) {
+ switch (reg) {
+ case OMAP_TAP_IDCODE : regval = 0x0B7AE02F; break;
+ /* Making DevType as 0xF in ES1 to differ from ES2 */
+ case OMAP_TAP_PROD_ID : regval = 0x000F00F0; break;
+ case OMAP_TAP_DIE_ID_0: regval = 0x01000000; break;
+ case OMAP_TAP_DIE_ID_1: regval = 0x1012d687; break;
+ case OMAP_TAP_DIE_ID_2: regval = 0x00000000; break;
+ case OMAP_TAP_DIE_ID_3: regval = 0x2d2c0000; break;
+ }
+ } else
+ regval = __raw_readl(TAP_BASE + reg);
+
+ return regval;
+
+}
+
+/*
+ * _set_system_rev - set the system_rev global based on current OMAP chip type
+ *
+ * Set the system_rev global. This is primarily used by the cpu_is_omapxxxx()
+ * macros.
+ */
+static void __init _set_system_rev(u32 type, u8 rev)
+{
+ u32 i, ctrl_status;
+
+ /*
+ * system_rev encoding is as follows
+ * system_rev & 0xff000000 -> Omap Class (24xx/34xx)
+ * system_rev & 0xfff00000 -> Omap Sub Class (242x/343x)
+ * system_rev & 0xffff0000 -> Omap type (2420/2422/2423/2430/3430)
+ * system_rev & 0x0000f000 -> Silicon revision (ES1, ES2 )
+ * system_rev & 0x00000700 -> Device Type ( EMU/HS/GP/BAD )
+ * system_rev & 0x000000c0 -> IDCODE revision[6:7]
+ * system_rev & 0x0000003f -> sys_boot[0:5]
+ */
+ /* Embedding the ES revision info in type field */
+ system_rev = type;
+ /* Also add IDCODE revision info only two lower bits */
+ system_rev |= ((rev & 0x3) << 6);
+
+ /* Add in the device type and sys_boot fields (see above) */
+ if (cpu_is_omap24xx()) {
+ i = OMAP24XX_CONTROL_STATUS;
+ } else if (cpu_is_omap343x()) {
+ i = OMAP343X_CONTROL_STATUS;
+ } else {
+ printk(KERN_ERR "id: unknown CPU type\n");
+ BUG();
+ }
+ ctrl_status = omap_ctrl_readl(i);
+ system_rev |= (ctrl_status & (OMAP2_SYSBOOT_5_MASK |
+ OMAP2_SYSBOOT_4_MASK |
+ OMAP2_SYSBOOT_3_MASK |
+ OMAP2_SYSBOOT_2_MASK |
+ OMAP2_SYSBOOT_1_MASK |
+ OMAP2_SYSBOOT_0_MASK));
+ system_rev |= (ctrl_status & OMAP2_DEVICETYPE_MASK);
+}
+
+
+/*
+ * _set_omap_chip - set the omap_chip global based on OMAP chip type
+ *
+ * Build the omap_chip bits. This variable is used by powerdomain and
+ * clockdomain code to indicate whether structures are applicable for
+ * the current OMAP chip type by ANDing it against a 'platform' bitfield
+ * in the structure.
+ */
+static void __init _set_omap_chip(void)
+{
+ if (cpu_is_omap343x()) {
+
+ omap_chip.oc = CHIP_IS_OMAP3430;
+ if (is_sil_rev_equal_to(OMAP3430_REV_ES1_0))
+ omap_chip.oc |= CHIP_IS_OMAP3430ES1;
+ else if (is_sil_rev_greater_than(OMAP3430_REV_ES1_0))
+ omap_chip.oc |= CHIP_IS_OMAP3430ES2;
+
+ } else if (cpu_is_omap243x()) {
+
+ /* Currently only supports 2430ES2.1 and 2430-all */
+ omap_chip.oc |= CHIP_IS_OMAP2430;
+
+ } else if (cpu_is_omap242x()) {
+
+ /* Currently only supports 2420ES2.1.1 and 2420-all */
+ omap_chip.oc |= CHIP_IS_OMAP2420;
+
+ } else {
+
+ /* Current CPU not supported by this code. */
+ printk(KERN_WARNING "OMAP chip type code does not yet support "
+ "this CPU type.\n");
+ WARN_ON(1);
+
+ }
+
}
void __init omap2_check_revision(void)
rev = (idcode >> 28) & 0x0f;
dev_type = (prod_id >> 16) & 0x0f;
-#ifdef DEBUG
- printk(KERN_DEBUG "OMAP_TAP_IDCODE 0x%08x REV %i HAWKEYE 0x%04x MANF %03x\n",
- idcode, rev, hawkeye, (idcode >> 1) & 0x7ff);
- printk(KERN_DEBUG "OMAP_TAP_DIE_ID_0: 0x%08x\n",
- read_tap_reg(OMAP_TAP_DIE_ID_0));
- printk(KERN_DEBUG "OMAP_TAP_DIE_ID_1: 0x%08x DEV_REV: %i\n",
- read_tap_reg(OMAP_TAP_DIE_ID_1),
- (read_tap_reg(OMAP_TAP_DIE_ID_1) >> 28) & 0xf);
- printk(KERN_DEBUG "OMAP_TAP_DIE_ID_2: 0x%08x\n",
- read_tap_reg(OMAP_TAP_DIE_ID_2));
- printk(KERN_DEBUG "OMAP_TAP_DIE_ID_3: 0x%08x\n",
- read_tap_reg(OMAP_TAP_DIE_ID_3));
- printk(KERN_DEBUG "OMAP_TAP_PROD_ID_0: 0x%08x DEV_TYPE: %i\n",
- prod_id, dev_type);
-#endif
+ pr_debug("OMAP_TAP_IDCODE 0x%08x REV %i HAWKEYE 0x%04x MANF %03x\n",
+ idcode, rev, hawkeye, (idcode >> 1) & 0x7ff);
+ pr_debug("OMAP_TAP_DIE_ID_0: 0x%08x\n",
+ read_tap_reg(OMAP_TAP_DIE_ID_0));
+ pr_debug("OMAP_TAP_DIE_ID_1: 0x%08x DEV_REV: %i\n",
+ read_tap_reg(OMAP_TAP_DIE_ID_1),
+ (read_tap_reg(OMAP_TAP_DIE_ID_1) >> 28) & 0xf);
+ pr_debug("OMAP_TAP_DIE_ID_2: 0x%08x\n",
+ read_tap_reg(OMAP_TAP_DIE_ID_2));
+ pr_debug("OMAP_TAP_DIE_ID_3: 0x%08x\n",
+ read_tap_reg(OMAP_TAP_DIE_ID_3));
+ pr_debug("OMAP_TAP_PROD_ID_0: 0x%08x DEV_TYPE: %i\n",
+ prod_id, dev_type);
+
+ /*
+ * Detection for 34xx ES2.0 and above can be done with just
+ * hawkeye and rev. See TRM 1.5.2 Device Identification.
+ * Note that rev cannot be used directly as ES1.0 uses value 0.
+ */
+ if (hawkeye == 0xb7ae) {
+ system_rev = 0x34300000 | ((1 + rev) << 12);
+ pr_info("OMAP%04x ES2.%i\n", system_rev >> 16, rev);
+ _set_omap_chip();
+ return;
+ }
/* Check hawkeye ids */
for (i = 0; i < ARRAY_SIZE(omap_ids); i++) {
omap_ids[i].type >> 16);
j = i;
}
- system_rev = omap_ids[j].type;
- system_rev |= rev << 8;
+ _set_system_rev(omap_ids[j].type, rev);
- /* Add the cpu class info (24xx) */
- system_rev |= 0x24;
+ _set_omap_chip();
pr_info("OMAP%04x", system_rev >> 16);
if ((system_rev >> 8) & 0x0f)
- printk("%x", (system_rev >> 8) & 0x0f);
- printk("\n");
+ pr_info("ES%x", (system_rev >> 12) & 0xf);
+ pr_info("\n");
+
}
* OMAP2 I/O mapping code
*
* Copyright (C) 2005 Nokia Corporation
- * Author: Juha Yrjölä <juha.yrjola@nokia.com>
- * Updated map desc to add 2430 support : <x0khasim@ti.com>
+ * Copyright (C) 2007 Texas Instruments
+ *
+ * Author:
+ * Juha Yrjola <juha.yrjola@nokia.com>
+ * Syed Khasim <x0khasim@ti.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
#include <asm/arch/mux.h>
#include <asm/arch/omapfb.h>
+#include <asm/arch/powerdomain.h>
+
+#include "powerdomains.h"
+
+#include <asm/arch/clockdomain.h>
+#include "clockdomains.h"
+
extern void omap_sram_init(void);
extern int omap2_clk_init(void);
extern void omap2_check_revision(void);
* The machine specific code may provide the extra mapping besides the
* default mapping provided here.
*/
-static struct map_desc omap2_io_desc[] __initdata = {
+
+#ifdef CONFIG_ARCH_OMAP24XX
+static struct map_desc omap24xx_io_desc[] __initdata = {
{
.virtual = L3_24XX_VIRT,
.pfn = __phys_to_pfn(L3_24XX_PHYS),
.type = MT_DEVICE
},
{
- .virtual = L4_24XX_VIRT,
- .pfn = __phys_to_pfn(L4_24XX_PHYS),
- .length = L4_24XX_SIZE,
- .type = MT_DEVICE
+ .virtual = L4_24XX_VIRT,
+ .pfn = __phys_to_pfn(L4_24XX_PHYS),
+ .length = L4_24XX_SIZE,
+ .type = MT_DEVICE
+ },
+};
+
+#ifdef CONFIG_ARCH_OMAP2420
+static struct map_desc omap242x_io_desc[] __initdata = {
+ {
+ .virtual = DSP_MEM_24XX_VIRT,
+ .pfn = __phys_to_pfn(DSP_MEM_24XX_PHYS),
+ .length = DSP_MEM_24XX_SIZE,
+ .type = MT_DEVICE
},
+ {
+ .virtual = DSP_IPI_24XX_VIRT,
+ .pfn = __phys_to_pfn(DSP_IPI_24XX_PHYS),
+ .length = DSP_IPI_24XX_SIZE,
+ .type = MT_DEVICE
+ },
+ {
+ .virtual = DSP_MMU_24XX_VIRT,
+ .pfn = __phys_to_pfn(DSP_MMU_24XX_PHYS),
+ .length = DSP_MMU_24XX_SIZE,
+ .type = MT_DEVICE
+ },
+};
+
+#endif
+
#ifdef CONFIG_ARCH_OMAP2430
+static struct map_desc omap243x_io_desc[] __initdata = {
{
.virtual = L4_WK_243X_VIRT,
.pfn = __phys_to_pfn(L4_WK_243X_PHYS),
.length = OMAP243X_GPMC_SIZE,
.type = MT_DEVICE
},
+ {
+ .virtual = OMAP243X_SDRC_VIRT,
+ .pfn = __phys_to_pfn(OMAP243X_SDRC_PHYS),
+ .length = OMAP243X_SDRC_SIZE,
+ .type = MT_DEVICE
+ },
+ {
+ .virtual = OMAP243X_SMS_VIRT,
+ .pfn = __phys_to_pfn(OMAP243X_SMS_PHYS),
+ .length = OMAP243X_SMS_SIZE,
+ .type = MT_DEVICE
+ },
+};
+#endif
#endif
+
+#ifdef CONFIG_ARCH_OMAP34XX
+static struct map_desc omap34xx_io_desc[] __initdata = {
{
- .virtual = DSP_MEM_24XX_VIRT,
- .pfn = __phys_to_pfn(DSP_MEM_24XX_PHYS),
- .length = DSP_MEM_24XX_SIZE,
+ .virtual = L3_34XX_VIRT,
+ .pfn = __phys_to_pfn(L3_34XX_PHYS),
+ .length = L3_34XX_SIZE,
.type = MT_DEVICE
},
{
- .virtual = DSP_IPI_24XX_VIRT,
- .pfn = __phys_to_pfn(DSP_IPI_24XX_PHYS),
- .length = DSP_IPI_24XX_SIZE,
+ .virtual = L4_34XX_VIRT,
+ .pfn = __phys_to_pfn(L4_34XX_PHYS),
+ .length = L4_34XX_SIZE,
.type = MT_DEVICE
},
{
- .virtual = DSP_MMU_24XX_VIRT,
- .pfn = __phys_to_pfn(DSP_MMU_24XX_PHYS),
- .length = DSP_MMU_24XX_SIZE,
+ .virtual = L4_WK_34XX_VIRT,
+ .pfn = __phys_to_pfn(L4_WK_34XX_PHYS),
+ .length = L4_WK_34XX_SIZE,
.type = MT_DEVICE
- }
+ },
+ {
+ .virtual = OMAP34XX_GPMC_VIRT,
+ .pfn = __phys_to_pfn(OMAP34XX_GPMC_PHYS),
+ .length = OMAP34XX_GPMC_SIZE,
+ .type = MT_DEVICE
+ },
+ {
+ .virtual = OMAP343X_SMS_VIRT,
+ .pfn = __phys_to_pfn(OMAP343X_SMS_PHYS),
+ .length = OMAP343X_SMS_SIZE,
+ .type = MT_DEVICE
+ },
+ {
+ .virtual = OMAP343X_SDRC_VIRT,
+ .pfn = __phys_to_pfn(OMAP343X_SDRC_PHYS),
+ .length = OMAP343X_SDRC_SIZE,
+ .type = MT_DEVICE
+ },
+ {
+ .virtual = L4_PER_34XX_VIRT,
+ .pfn = __phys_to_pfn(L4_PER_34XX_PHYS),
+ .length = L4_PER_34XX_SIZE,
+ .type = MT_DEVICE
+ },
+ {
+ .virtual = L4_EMU_34XX_VIRT,
+ .pfn = __phys_to_pfn(L4_EMU_34XX_PHYS),
+ .length = L4_EMU_34XX_SIZE,
+ .type = MT_DEVICE
+ },
};
+#endif
void __init omap2_map_common_io(void)
{
- iotable_init(omap2_io_desc, ARRAY_SIZE(omap2_io_desc));
-
+#if defined(CONFIG_ARCH_OMAP2420)
+ iotable_init(omap24xx_io_desc, ARRAY_SIZE(omap24xx_io_desc));
+ iotable_init(omap242x_io_desc, ARRAY_SIZE(omap242x_io_desc));
+#elif defined(CONFIG_ARCH_OMAP2430)
+ iotable_init(omap24xx_io_desc, ARRAY_SIZE(omap24xx_io_desc));
+ iotable_init(omap243x_io_desc, ARRAY_SIZE(omap243x_io_desc));
+#elif defined(CONFIG_ARCH_OMAP34XX)
+ iotable_init(omap34xx_io_desc, ARRAY_SIZE(omap34xx_io_desc));
+#endif
/* 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.
void __init omap2_init_common_hw(void)
{
omap2_mux_init();
+ pwrdm_init(powerdomains_omap);
+ clkdm_init(clockdomains_omap, clkdm_pwrdm_autodeps);
omap2_clk_init();
-/*
- * Need to Fix this for 2430
- */
-#ifndef CONFIG_ARCH_OMAP2430
omap2_init_memory();
-#endif
gpmc_init();
}
} __attribute__ ((aligned(4))) irq_banks[] = {
{
/* MPU INTC */
- .base_reg = IO_ADDRESS(OMAP24XX_IC_BASE),
+ .base_reg = 0,
.nr_irqs = 96,
- }, {
- /* XXX: DSP INTC */
- }
+ },
};
/* XXX: FIQ and additional INTC support (only MPU at the moment) */
for (i = 0; i < ARRAY_SIZE(irq_banks); i++) {
struct omap_irq_bank *bank = irq_banks + i;
- /* XXX */
- if (!bank->base_reg)
- continue;
-
+ if (cpu_is_omap24xx()) {
+ bank->base_reg = IO_ADDRESS(OMAP24XX_IC_BASE);
+ }
+ if (cpu_is_omap34xx()) {
+ bank->base_reg = IO_ADDRESS(OMAP34XX_IC_BASE);
+ }
omap_irq_bank_init_one(bank);
nr_irqs += bank->nr_irqs;
static struct clk *mbox_ick_handle;
+static void omap2_mbox_enable_irq(struct omap_mbox *mbox,
+ omap_mbox_type_t irq);
+
static inline unsigned int mbox_read_reg(unsigned int reg)
{
return __raw_readl(mbox_base + reg);
}
/* Mailbox H/W preparations */
-static inline int omap2_mbox_startup(struct omap_mbox *mbox)
+static int omap2_mbox_startup(struct omap_mbox *mbox)
{
unsigned int l;
l |= 0x00000011;
mbox_write_reg(l, MAILBOX_SYSCONFIG);
+ omap2_mbox_enable_irq(mbox, IRQ_RX);
+
return 0;
}
-static inline void omap2_mbox_shutdown(struct omap_mbox *mbox)
+static void omap2_mbox_shutdown(struct omap_mbox *mbox)
{
clk_disable(mbox_ick_handle);
clk_put(mbox_ick_handle);
}
/* Mailbox FIFO handle functions */
-static inline mbox_msg_t omap2_mbox_fifo_read(struct omap_mbox *mbox)
+static mbox_msg_t omap2_mbox_fifo_read(struct omap_mbox *mbox)
{
struct omap_mbox2_fifo *fifo =
&((struct omap_mbox2_priv *)mbox->priv)->rx_fifo;
return (mbox_msg_t) mbox_read_reg(fifo->msg);
}
-static inline void omap2_mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg)
+static void omap2_mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg)
{
struct omap_mbox2_fifo *fifo =
&((struct omap_mbox2_priv *)mbox->priv)->tx_fifo;
mbox_write_reg(msg, fifo->msg);
}
-static inline int omap2_mbox_fifo_empty(struct omap_mbox *mbox)
+static int omap2_mbox_fifo_empty(struct omap_mbox *mbox)
{
struct omap_mbox2_fifo *fifo =
&((struct omap_mbox2_priv *)mbox->priv)->rx_fifo;
return (mbox_read_reg(fifo->msg_stat) == 0);
}
-static inline int omap2_mbox_fifo_full(struct omap_mbox *mbox)
+static int omap2_mbox_fifo_full(struct omap_mbox *mbox)
{
struct omap_mbox2_fifo *fifo =
&((struct omap_mbox2_priv *)mbox->priv)->tx_fifo;
}
/* Mailbox IRQ handle functions */
-static inline void omap2_mbox_enable_irq(struct omap_mbox *mbox,
+static void omap2_mbox_enable_irq(struct omap_mbox *mbox,
omap_mbox_type_t irq)
{
struct omap_mbox2_priv *p = (struct omap_mbox2_priv *)mbox->priv;
mbox_write_reg(l, p->irqenable);
}
-static inline void omap2_mbox_disable_irq(struct omap_mbox *mbox,
+static void omap2_mbox_disable_irq(struct omap_mbox *mbox,
omap_mbox_type_t irq)
{
struct omap_mbox2_priv *p = (struct omap_mbox2_priv *)mbox->priv;
mbox_write_reg(l, p->irqenable);
}
-static inline void omap2_mbox_ack_irq(struct omap_mbox *mbox,
+static void omap2_mbox_ack_irq(struct omap_mbox *mbox,
omap_mbox_type_t irq)
{
struct omap_mbox2_priv *p = (struct omap_mbox2_priv *)mbox->priv;
mbox_write_reg(bit, p->irqstatus);
}
-static inline int omap2_mbox_is_irq(struct omap_mbox *mbox,
+static int omap2_mbox_is_irq(struct omap_mbox *mbox,
omap_mbox_type_t irq)
{
struct omap_mbox2_priv *p = (struct omap_mbox2_priv *)mbox->priv;
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap2/mmu.c
+ *
+ * Support for non-MPU OMAP2 MMUs.
+ *
+ * Copyright (C) 2002-2007 Nokia Corporation
+ *
+ * Written by Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ * and Paul Mundt <paul.mundt@nokia.com>
+ *
+ * TWL support: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/rwsem.h>
+#include <linux/device.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include "mmu.h"
+#include <asm/arch/mmu.h>
+#include <asm/tlbflush.h>
+#include <asm/io.h>
+#include <asm/sizes.h>
+
+static void *dspvect_page;
+#define DSP_INIT_PAGE 0xfff000
+
+static inline void
+omap2_mmu_read_tlb(struct omap_mmu *mmu, struct cam_ram_regset *cr)
+{
+ cr->cam = omap_mmu_read_reg(mmu, OMAP_MMU_READ_CAM);
+ cr->ram = omap_mmu_read_reg(mmu, OMAP_MMU_READ_RAM);
+}
+
+static inline void
+omap2_mmu_load_tlb(struct omap_mmu *mmu, struct cam_ram_regset *cr)
+{
+ /* Set the CAM and RAM entries */
+ omap_mmu_write_reg(mmu, cr->cam | OMAP_MMU_CAM_V, OMAP_MMU_CAM);
+ omap_mmu_write_reg(mmu, cr->ram, OMAP_MMU_RAM);
+}
+
+static void exmap_setup_iomap_page(struct omap_mmu *mmu, unsigned long phys,
+ unsigned long dsp_io_adr, int index)
+{
+ unsigned long dspadr;
+ void *virt;
+ struct omap_mmu_tlb_entry tlb_ent;
+
+ dspadr = (IOMAP_VAL << 18) + (dsp_io_adr << 1);
+ virt = omap_mmu_to_virt(mmu, dspadr);
+ exmap_set_armmmu(mmu, (unsigned long)virt, phys, PAGE_SIZE);
+ INIT_EXMAP_TBL_ENTRY_4KB_PRESERVED(mmu->exmap_tbl + index, NULL, virt);
+ INIT_TLB_ENTRY_4KB_ES32_PRESERVED(&tlb_ent, dspadr, phys);
+ omap_mmu_load_pte_entry(mmu, &tlb_ent);
+}
+
+static void exmap_clear_iomap_page(struct omap_mmu *mmu,
+ unsigned long dsp_io_adr)
+{
+ unsigned long dspadr;
+ void *virt;
+
+ dspadr = (IOMAP_VAL << 18) + (dsp_io_adr << 1);
+ virt = omap_mmu_to_virt(mmu, dspadr);
+ exmap_clear_armmmu(mmu, (unsigned long)virt, PAGE_SIZE);
+ /* DSP MMU is shutting down. not handled here. */
+}
+
+#define OMAP24XX_MAILBOX_BASE (L4_24XX_BASE + 0x94000)
+#define OMAP2420_GPT5_BASE (L4_24XX_BASE + 0x7c000)
+#define OMAP2420_GPT6_BASE (L4_24XX_BASE + 0x7e000)
+#define OMAP2420_GPT7_BASE (L4_24XX_BASE + 0x80000)
+#define OMAP2420_GPT8_BASE (L4_24XX_BASE + 0x82000)
+#define OMAP24XX_EAC_BASE (L4_24XX_BASE + 0x90000)
+#define OMAP24XX_STI_BASE (L4_24XX_BASE + 0x68000)
+#define OMAP24XX_STI_CH_BASE (L4_24XX_BASE + 0x0c000000)
+
+static int exmap_setup_preserved_entries(struct omap_mmu *mmu)
+{
+ int i, n = 0;
+
+ exmap_setup_preserved_mem_page(mmu, dspvect_page, DSP_INIT_PAGE, n++);
+
+ /* REVISIT: This will need to be revisited for 3430 */
+ exmap_setup_iomap_page(mmu, OMAP2_PRCM_BASE, 0x7000, n++);
+ exmap_setup_iomap_page(mmu, OMAP24XX_MAILBOX_BASE, 0x11000, n++);
+
+ if (cpu_is_omap2420()) {
+ exmap_setup_iomap_page(mmu, OMAP2420_GPT5_BASE, 0xe000, n++);
+ exmap_setup_iomap_page(mmu, OMAP2420_GPT6_BASE, 0xe800, n++);
+ exmap_setup_iomap_page(mmu, OMAP2420_GPT7_BASE, 0xf000, n++);
+ exmap_setup_iomap_page(mmu, OMAP2420_GPT8_BASE, 0xf800, n++);
+ exmap_setup_iomap_page(mmu, OMAP24XX_EAC_BASE, 0x10000, n++);
+ exmap_setup_iomap_page(mmu, OMAP24XX_STI_BASE, 0xc800, n++);
+ for (i = 0; i < 5; i++)
+ exmap_setup_preserved_mem_page(mmu,
+ __va(OMAP24XX_STI_CH_BASE + i*SZ_4K),
+ 0xfb0000 + i*SZ_4K, n++);
+ }
+
+ return n;
+}
+
+static void exmap_clear_preserved_entries(struct omap_mmu *mmu)
+{
+ int i;
+
+ exmap_clear_iomap_page(mmu, 0x7000); /* PRCM registers */
+ exmap_clear_iomap_page(mmu, 0x11000); /* MAILBOX registers */
+
+ if (cpu_is_omap2420()) {
+ exmap_clear_iomap_page(mmu, 0xe000); /* GPT5 */
+ exmap_clear_iomap_page(mmu, 0xe800); /* GPT6 */
+ exmap_clear_iomap_page(mmu, 0xf000); /* GPT7 */
+ exmap_clear_iomap_page(mmu, 0xf800); /* GPT8 */
+ exmap_clear_iomap_page(mmu, 0x10000); /* EAC */
+ exmap_clear_iomap_page(mmu, 0xc800); /* STI */
+ for (i = 0; i < 5; i++) /* STI CH */
+ exmap_clear_mem_page(mmu, 0xfb0000 + i*SZ_4K);
+ }
+
+ exmap_clear_mem_page(mmu, DSP_INIT_PAGE);
+}
+
+#define MMU_IRQ_MASK \
+ (OMAP_MMU_IRQ_MULTIHITFAULT | \
+ OMAP_MMU_IRQ_TABLEWALKFAULT | \
+ OMAP_MMU_IRQ_EMUMISS | \
+ OMAP_MMU_IRQ_TRANSLATIONFAULT)
+
+static int omap2_mmu_startup(struct omap_mmu *mmu)
+{
+ u32 rev = omap_mmu_read_reg(mmu, OMAP_MMU_REVISION);
+
+ pr_info("MMU: OMAP %s MMU initialized (HW v%d.%d)\n", mmu->name,
+ (rev >> 4) & 0xf, rev & 0xf);
+
+ dspvect_page = (void *)__get_dma_pages(GFP_KERNEL, 0);
+ if (dspvect_page == NULL) {
+ dev_err(mmu->dev, "MMU %s: failed to allocate memory "
+ "for vector table\n", mmu->name);
+ return -ENOMEM;
+ }
+
+ mmu->nr_exmap_preserved = exmap_setup_preserved_entries(mmu);
+
+ omap_mmu_write_reg(mmu, MMU_IRQ_MASK, OMAP_MMU_IRQENABLE);
+
+ return 0;
+}
+
+static void omap2_mmu_shutdown(struct omap_mmu *mmu)
+{
+ exmap_clear_preserved_entries(mmu);
+
+ if (dspvect_page != NULL) {
+ unsigned long virt;
+
+ down_read(&mmu->exmap_sem);
+
+ virt = (unsigned long)omap_mmu_to_virt(mmu, DSP_INIT_PAGE);
+ flush_tlb_kernel_range(virt, virt + PAGE_SIZE);
+ free_page((unsigned long)dspvect_page);
+ dspvect_page = NULL;
+
+ up_read(&mmu->exmap_sem);
+ }
+}
+
+static ssize_t omap2_mmu_show(struct omap_mmu *mmu, char *buf,
+ struct omap_mmu_tlb_lock *tlb_lock)
+{
+ int i, len;
+
+ len = sprintf(buf, "P: preserved, V: valid\n"
+ "B: big endian, L:little endian, "
+ "M: mixed page attribute\n"
+ "ety P V size cam_va ram_pa E ES M\n");
+ /* 00: P V 4KB 0x300000 0x10171800 B 16 M */
+
+ for (i = 0; i < mmu->nr_tlb_entries; i++) {
+ struct omap_mmu_tlb_entry ent;
+ struct cam_ram_regset cr;
+ struct omap_mmu_tlb_lock entry_lock;
+ char *pgsz_str, *elsz_str;
+
+ /* read a TLB entry */
+ entry_lock.base = tlb_lock->base;
+ entry_lock.victim = i;
+ omap_mmu_read_tlb(mmu, &entry_lock, &cr);
+
+ ent.pgsz = cr.cam & OMAP_MMU_CAM_PAGESIZE_MASK;
+ ent.prsvd = cr.cam & OMAP_MMU_CAM_P;
+ ent.valid = cr.cam & OMAP_MMU_CAM_V;
+ ent.va = cr.cam & OMAP_MMU_CAM_VATAG_MASK;
+ ent.endian = cr.ram & OMAP_MMU_RAM_ENDIANNESS;
+ ent.elsz = cr.ram & OMAP_MMU_RAM_ELEMENTSIZE_MASK;
+ ent.pa = cr.ram & OMAP_MMU_RAM_PADDR_MASK;
+ ent.mixed = cr.ram & OMAP_MMU_RAM_MIXED;
+
+ pgsz_str = (ent.pgsz == OMAP_MMU_CAM_PAGESIZE_16MB) ? "64MB":
+ (ent.pgsz == OMAP_MMU_CAM_PAGESIZE_1MB) ? " 1MB":
+ (ent.pgsz == OMAP_MMU_CAM_PAGESIZE_64KB) ? "64KB":
+ (ent.pgsz == OMAP_MMU_CAM_PAGESIZE_4KB) ? " 4KB":
+ " ???";
+ elsz_str = (ent.elsz == OMAP_MMU_RAM_ELEMENTSIZE_8) ? " 8":
+ (ent.elsz == OMAP_MMU_RAM_ELEMENTSIZE_16) ? "16":
+ (ent.elsz == OMAP_MMU_RAM_ELEMENTSIZE_32) ? "32":
+ "??";
+
+ if (i == tlb_lock->base)
+ len += sprintf(buf + len, "lock base = %d\n",
+ tlb_lock->base);
+ if (i == tlb_lock->victim)
+ len += sprintf(buf + len, "victim = %d\n",
+ tlb_lock->victim);
+
+ len += sprintf(buf + len,
+ /* 00: P V 4KB 0x300000 0x10171800 B 16 M */
+ "%02d: %c %c %s 0x%06lx 0x%08lx %c %s %c\n",
+ i,
+ ent.prsvd ? 'P' : ' ',
+ ent.valid ? 'V' : ' ',
+ pgsz_str, ent.va, ent.pa,
+ ent.endian ? 'B' : 'L',
+ elsz_str,
+ ent.mixed ? 'M' : ' ');
+ }
+
+ return len;
+}
+
+#define get_cam_va_mask(pgsz) \
+ (((pgsz) == OMAP_MMU_CAM_PAGESIZE_16MB) ? 0xff000000 : \
+ ((pgsz) == OMAP_MMU_CAM_PAGESIZE_1MB) ? 0xfff00000 : \
+ ((pgsz) == OMAP_MMU_CAM_PAGESIZE_64KB) ? 0xffff0000 : \
+ ((pgsz) == OMAP_MMU_CAM_PAGESIZE_4KB) ? 0xfffff000 : 0)
+
+static inline unsigned long omap2_mmu_cam_va(struct cam_ram_regset *cr)
+{
+ unsigned int page_size = cr->cam & OMAP_MMU_CAM_PAGESIZE_MASK;
+ unsigned int mask = get_cam_va_mask(cr->cam & page_size);
+
+ return cr->cam & mask;
+}
+
+static struct cam_ram_regset *
+omap2_mmu_cam_ram_alloc(struct omap_mmu *mmu, struct omap_mmu_tlb_entry *entry)
+{
+ struct cam_ram_regset *cr;
+
+ if (entry->va & ~(get_cam_va_mask(entry->pgsz))) {
+ dev_err(mmu->dev, "MMU %s: mapping vadr (0x%06lx) is not on"
+ " an aligned boundary\n", mmu->name, entry->va);
+ return ERR_PTR(-EINVAL);
+ }
+
+ cr = kmalloc(sizeof(struct cam_ram_regset), GFP_KERNEL);
+
+ cr->cam = (entry->va & OMAP_MMU_CAM_VATAG_MASK) |
+ entry->prsvd | entry->pgsz;
+ cr->ram = entry->pa | entry->endian | entry->elsz;
+
+ return cr;
+}
+
+static inline int omap2_mmu_cam_ram_valid(struct cam_ram_regset *cr)
+{
+ return cr->cam & OMAP_MMU_CAM_V;
+}
+
+static void omap2_mmu_interrupt(struct omap_mmu *mmu)
+{
+ unsigned long status, va;
+
+ status = MMU_IRQ_MASK & omap_mmu_read_reg(mmu, OMAP_MMU_IRQSTATUS);
+ va = omap_mmu_read_reg(mmu, OMAP_MMU_FAULT_AD);
+
+ pr_info("%s\n", (status & OMAP_MMU_IRQ_MULTIHITFAULT)?
+ "multi hit":"");
+ pr_info("%s\n", (status & OMAP_MMU_IRQ_TABLEWALKFAULT)?
+ "table walk fault":"");
+ pr_info("%s\n", (status & OMAP_MMU_IRQ_EMUMISS)?
+ "EMU miss":"");
+ pr_info("%s\n", (status & OMAP_MMU_IRQ_TRANSLATIONFAULT)?
+ "translation fault":"");
+ pr_info("%s\n", (status & OMAP_MMU_IRQ_TLBMISS)?
+ "TLB miss":"");
+ pr_info("fault address = %#08lx\n", va);
+
+ omap_mmu_disable(mmu);
+ omap_mmu_write_reg(mmu, status, OMAP_MMU_IRQSTATUS);
+
+ mmu->fault_address = va;
+ schedule_work(&mmu->irq_work);
+}
+
+static pgprot_t omap2_mmu_pte_get_attr(struct omap_mmu_tlb_entry *entry)
+{
+ u32 attr;
+
+ attr = entry->mixed << 5;
+ attr |= entry->endian;
+ attr |= entry->elsz >> 3;
+ attr <<= ((entry->pgsz & OMAP_MMU_CAM_PAGESIZE_4KB) ? 0:6);
+
+ return attr;
+}
+
+struct omap_mmu_ops omap2_mmu_ops = {
+ .startup = omap2_mmu_startup,
+ .shutdown = omap2_mmu_shutdown,
+ .read_tlb = omap2_mmu_read_tlb,
+ .load_tlb = omap2_mmu_load_tlb,
+ .show = omap2_mmu_show,
+ .cam_va = omap2_mmu_cam_va,
+ .cam_ram_alloc = omap2_mmu_cam_ram_alloc,
+ .cam_ram_valid = omap2_mmu_cam_ram_valid,
+ .interrupt = omap2_mmu_interrupt,
+ .pte_get_attr = omap2_mmu_pte_get_attr,
+};
+EXPORT_SYMBOL_GPL(omap2_mmu_ops);
+
+MODULE_LICENSE("GPL");
--- /dev/null
+#ifndef __MACH_OMAP2_MMU_H
+#define __MACH_OMAP2_MMU_H
+
+#include <asm/arch/mmu.h>
+#include <asm/io.h>
+
+#define MMU_LOCK_BASE_MASK (0x1f << 10)
+#define MMU_LOCK_VICTIM_MASK (0x1f << 4)
+
+#define OMAP_MMU_REVISION 0x00
+#define OMAP_MMU_SYSCONFIG 0x10
+#define OMAP_MMU_SYSSTATUS 0x14
+#define OMAP_MMU_IRQSTATUS 0x18
+#define OMAP_MMU_IRQENABLE 0x1c
+#define OMAP_MMU_WALKING_ST 0x40
+#define OMAP_MMU_CNTL 0x44
+#define OMAP_MMU_FAULT_AD 0x48
+#define OMAP_MMU_TTB 0x4c
+#define OMAP_MMU_LOCK 0x50
+#define OMAP_MMU_LD_TLB 0x54
+#define OMAP_MMU_CAM 0x58
+#define OMAP_MMU_RAM 0x5c
+#define OMAP_MMU_GFLUSH 0x60
+#define OMAP_MMU_FLUSH_ENTRY 0x64
+#define OMAP_MMU_READ_CAM 0x68
+#define OMAP_MMU_READ_RAM 0x6c
+#define OMAP_MMU_EMU_FAULT_AD 0x70
+
+#define OMAP_MMU_CNTL_BURST_16MNGT_EN 0x0020
+#define OMAP_MMU_CNTL_WTL_EN 0x0004
+#define OMAP_MMU_CNTL_MMU_EN 0x0002
+#define OMAP_MMU_CNTL_RESET_SW 0x0001
+
+#define OMAP_MMU_IRQ_MULTIHITFAULT 0x00000010
+#define OMAP_MMU_IRQ_TABLEWALKFAULT 0x00000008
+#define OMAP_MMU_IRQ_EMUMISS 0x00000004
+#define OMAP_MMU_IRQ_TRANSLATIONFAULT 0x00000002
+#define OMAP_MMU_IRQ_TLBMISS 0x00000001
+
+#define OMAP_MMU_CAM_VATAG_MASK 0xfffff000
+#define OMAP_MMU_CAM_P 0x00000008
+#define OMAP_MMU_CAM_V 0x00000004
+#define OMAP_MMU_CAM_PAGESIZE_MASK 0x00000003
+#define OMAP_MMU_CAM_PAGESIZE_1MB 0x00000000
+#define OMAP_MMU_CAM_PAGESIZE_64KB 0x00000001
+#define OMAP_MMU_CAM_PAGESIZE_4KB 0x00000002
+#define OMAP_MMU_CAM_PAGESIZE_16MB 0x00000003
+
+#define OMAP_MMU_RAM_PADDR_MASK 0xfffff000
+#define OMAP_MMU_RAM_ENDIANNESS 0x00000200
+#define OMAP_MMU_RAM_ENDIANNESS_BIG 0x00000200
+#define OMAP_MMU_RAM_ENDIANNESS_LITTLE 0x00000000
+#define OMAP_MMU_RAM_ELEMENTSIZE_MASK 0x00000180
+#define OMAP_MMU_RAM_ELEMENTSIZE_8 0x00000000
+#define OMAP_MMU_RAM_ELEMENTSIZE_16 0x00000080
+#define OMAP_MMU_RAM_ELEMENTSIZE_32 0x00000100
+#define OMAP_MMU_RAM_ELEMENTSIZE_NONE 0x00000180
+#define OMAP_MMU_RAM_MIXED 0x00000040
+
+#define IOMAP_VAL 0x3f
+
+#define INIT_TLB_ENTRY(ent, v, p, ps) \
+do { \
+ (ent)->va = (v); \
+ (ent)->pa = (p); \
+ (ent)->pgsz = (ps); \
+ (ent)->prsvd = 0; \
+ (ent)->endian = OMAP_MMU_RAM_ENDIANNESS_LITTLE; \
+ (ent)->elsz = OMAP_MMU_RAM_ELEMENTSIZE_16; \
+ (ent)->mixed = 0; \
+ (ent)->tlb = 1; \
+} while (0)
+
+#define INIT_TLB_ENTRY_4KB_PRESERVED(ent, v, p) \
+do { \
+ (ent)->va = (v); \
+ (ent)->pa = (p); \
+ (ent)->pgsz = OMAP_MMU_CAM_PAGESIZE_4KB; \
+ (ent)->prsvd = OMAP_MMU_CAM_P; \
+ (ent)->endian = OMAP_MMU_RAM_ENDIANNESS_LITTLE; \
+ (ent)->elsz = OMAP_MMU_RAM_ELEMENTSIZE_16; \
+ (ent)->mixed = 0; \
+} while (0)
+
+#define INIT_TLB_ENTRY_4KB_ES32_PRESERVED(ent, v, p) \
+do { \
+ (ent)->va = (v); \
+ (ent)->pa = (p); \
+ (ent)->pgsz = OMAP_MMU_CAM_PAGESIZE_4KB; \
+ (ent)->prsvd = OMAP_MMU_CAM_P; \
+ (ent)->endian = OMAP_MMU_RAM_ENDIANNESS_LITTLE; \
+ (ent)->elsz = OMAP_MMU_RAM_ELEMENTSIZE_32; \
+ (ent)->mixed = 0; \
+} while (0)
+
+struct omap_mmu_tlb_entry {
+ unsigned long va;
+ unsigned long pa;
+ unsigned int pgsz, prsvd, valid;
+
+ u32 endian, elsz, mixed;
+ unsigned int tlb;
+};
+
+static inline unsigned long
+omap_mmu_read_reg(struct omap_mmu *mmu, unsigned long reg)
+{
+ return __raw_readl(mmu->base + reg);
+}
+
+static inline void omap_mmu_write_reg(struct omap_mmu *mmu,
+ unsigned long val, unsigned long reg)
+{
+ __raw_writel(val, mmu->base + reg);
+}
+
+#endif /* __MACH_OMAP2_MMU_H */
/*
* linux/arch/arm/mach-omap2/mux.c
*
- * OMAP2 pin multiplexing configurations
+ * OMAP2 and OMAP3 pin multiplexing configurations
*
* Copyright (C) 2004 - 2008 Texas Instruments Inc.
* Copyright (C) 2003 - 2008 Nokia Corporation
#define OMAP24XX_PINS_SZ 0
#endif /* CONFIG_ARCH_OMAP24XX */
-#define OMAP24XX_PULL_ENA (1 << 3)
-#define OMAP24XX_PULL_UP (1 << 4)
+#ifdef CONFIG_ARCH_OMAP34XX
+static struct pin_config __initdata_or_module omap34xx_pins[] = {
+/*
+ * Name, reg-offset,
+ * mux-mode | [active-mode | off-mode]
+ */
+
+/* PHY - HSUSB: 12-pin ULPI PHY: Port 1*/
+MUX_CFG_34XX("Y8_3430_USB1HS_PHY_CLK", 0x5da,
+ OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("Y9_3430_USB1HS_PHY_STP", 0x5d8,
+ OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("AA14_3430_USB1HS_PHY_DIR", 0x5ec,
+ OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AA11_3430_USB1HS_PHY_NXT", 0x5ee,
+ OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W13_3430_USB1HS_PHY_D0", 0x5dc,
+ OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W12_3430_USB1HS_PHY_D1", 0x5de,
+ OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W11_3430_USB1HS_PHY_D2", 0x5e0,
+ OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("Y11_3430_USB1HS_PHY_D3", 0x5ea,
+ OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W9_3430_USB1HS_PHY_D4", 0x5e4,
+ OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("Y12_3430_USB1HS_PHY_D5", 0x5e6,
+ OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W8_3430_USB1HS_PHY_D6", 0x5e8,
+ OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("Y13_3430_USB1HS_PHY_D7", 0x5e2,
+ OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+
+/* PHY - HSUSB: 12-pin ULPI PHY: Port 2*/
+MUX_CFG_34XX("AA8_3430_USB2HS_PHY_CLK", 0x5f0,
+ OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("AA10_3430_USB2HS_PHY_STP", 0x5f2,
+ OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("AA9_3430_USB2HS_PHY_DIR", 0x5f4,
+ OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AB11_3430_USB2HS_PHY_NXT", 0x5f6,
+ OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AB10_3430_USB2HS_PHY_D0", 0x5f8,
+ OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AB9_3430_USB2HS_PHY_D1", 0x5fa,
+ OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W3_3430_USB2HS_PHY_D2", 0x1d4,
+ OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("T4_3430_USB2HS_PHY_D3", 0x1de,
+ OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("T3_3430_USB2HS_PHY_D4", 0x1d8,
+ OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("R3_3430_USB2HS_PHY_D5", 0x1da,
+ OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("R4_3430_USB2HS_PHY_D6", 0x1dc,
+ OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("T2_3430_USB2HS_PHY_D7", 0x1d6,
+ OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+
+/* TLL - HSUSB: 12-pin TLL Port 1*/
+MUX_CFG_34XX("Y8_3430_USB1HS_TLL_CLK", 0x5da,
+ OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("Y9_3430_USB1HS_TLL_STP", 0x5d8,
+ OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AA14_3430_USB1HS_TLL_DIR", 0x5ec,
+ OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("AA11_3430_USB1HS_TLL_NXT", 0x5ee,
+ OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("W13_3430_USB1HS_TLL_D0", 0x5dc,
+ OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W12_3430_USB1HS_TLL_D1", 0x5de,
+ OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W11_3430_USB1HS_TLL_D2", 0x5e0,
+ OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("Y11_3430_USB1HS_TLL_D3", 0x5ea,
+ OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W9_3430_USB1HS_TLL_D4", 0x5e4,
+ OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("Y12_3430_USB1HS_TLL_D5", 0x5e6,
+ OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W8_3430_USB1HS_TLL_D6", 0x5e8,
+ OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("Y13_3430_USB1HS_TLL_D7", 0x5e2,
+ OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+
+/* TLL - HSUSB: 12-pin TLL Port 2*/
+MUX_CFG_34XX("AA8_3430_USB2HS_TLL_CLK", 0x5f0,
+ OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("AA10_3430_USB2HS_TLL_STP", 0x5f2,
+ OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AA9_3430_USB2HS_TLL_DIR", 0x5f4,
+ OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("AB11_3430_USB2HS_TLL_NXT", 0x5f6,
+ OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("AB10_3430_USB2HS_TLL_D0", 0x5f8,
+ OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AB9_3430_USB2HS_TLL_D1", 0x5fa,
+ OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W3_3430_USB2HS_TLL_D2", 0x1d4,
+ OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("T4_3430_USB2HS_TLL_D3", 0x1de,
+ OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("T3_3430_USB2HS_TLL_D4", 0x1d8,
+ OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("R3_3430_USB2HS_TLL_D5", 0x1da,
+ OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("R4_3430_USB2HS_TLL_D6", 0x1dc,
+ OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("T2_3430_USB2HS_TLL_D7", 0x1d6,
+ OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_INPUT_PULLDOWN)
+
+/* TLL - HSUSB: 12-pin TLL Port 3*/
+MUX_CFG_34XX("AA6_3430_USB3HS_TLL_CLK", 0x180,
+ OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("AB3_3430_USB3HS_TLL_STP", 0x166,
+ OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AA3_3430_USB3HS_TLL_DIR", 0x168,
+ OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("Y3_3430_USB3HS_TLL_NXT", 0x16a,
+ OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("AA5_3430_USB3HS_TLL_D0", 0x186,
+ OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("Y4_3430_USB3HS_TLL_D1", 0x184,
+ OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("Y5_3430_USB3HS_TLL_D2", 0x188,
+ OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W5_3430_USB3HS_TLL_D3", 0x18a,
+ OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AB12_3430_USB3HS_TLL_D4", 0x16c,
+ OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AB13_3430_USB3HS_TLL_D5", 0x16e,
+ OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AA13_3430_USB3HS_TLL_D6", 0x170,
+ OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AA12_3430_USB3HS_TLL_D7", 0x172,
+ OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+};
+
+#define OMAP34XX_PINS_SZ ARRAY_SIZE(omap34xx_pins)
+
+#else
+#define omap34xx_pins NULL
+#define OMAP34XX_PINS_SZ 0
+#endif /* CONFIG_ARCH_OMAP34XX */
#if defined(CONFIG_OMAP_MUX_DEBUG) || defined(CONFIG_OMAP_MUX_WARNINGS)
-void __init_or_module omap2_cfg_debug(const struct pin_config *cfg, u8 reg)
+void __init_or_module omap2_cfg_debug(const struct pin_config *cfg, u16 reg)
{
u16 orig;
u8 warn = 0, debug = 0;
- orig = omap_ctrl_readb(cfg->mux_reg);
+ if (cpu_is_omap24xx())
+ orig = omap_ctrl_readb(cfg->mux_reg);
+ else
+ orig = omap_ctrl_readw(cfg->mux_reg);
#ifdef CONFIG_OMAP_MUX_DEBUG
debug = cfg->debug;
warn = (orig != reg);
if (debug || warn)
printk(KERN_WARNING
- "MUX: setup %s (0x%08x): 0x%02x -> 0x%02x\n",
+ "MUX: setup %s (0x%08x): 0x%04x -> 0x%04x\n",
cfg->name, omap_ctrl_base_get() + cfg->mux_reg,
orig, reg);
}
spin_lock_irqsave(&mux_spin_lock, flags);
reg |= cfg->mask & 0x7;
if (cfg->pull_val)
- reg |= OMAP24XX_PULL_ENA;
+ reg |= OMAP2_PULL_ENA;
if (cfg->pu_pd_val)
- reg |= OMAP24XX_PULL_UP;
+ reg |= OMAP2_PULL_UP;
omap2_cfg_debug(cfg, reg);
omap_ctrl_writeb(reg, cfg->mux_reg);
spin_unlock_irqrestore(&mux_spin_lock, flags);
#define omap24xx_cfg_reg 0
#endif
+#ifdef CONFIG_ARCH_OMAP34XX
+int __init_or_module omap34xx_cfg_reg(const struct pin_config *cfg)
+{
+ static DEFINE_SPINLOCK(mux_spin_lock);
+ unsigned long flags;
+ u16 reg = 0;
+
+ spin_lock_irqsave(&mux_spin_lock, flags);
+ reg |= cfg->mux_val;
+ omap2_cfg_debug(cfg, reg);
+ omap_ctrl_writew(reg, cfg->mux_reg);
+ spin_unlock_irqrestore(&mux_spin_lock, flags);
+
+ return 0;
+}
+#else
+#define omap34xx_cfg_reg 0
+#endif
+
int __init omap2_mux_init(void)
{
if (cpu_is_omap24xx()) {
arch_mux_cfg.cfg_reg = omap24xx_cfg_reg;
}
+ if (cpu_is_omap34xx()) {
+ arch_mux_cfg.pins = omap34xx_pins;
+ arch_mux_cfg.size = OMAP34XX_PINS_SZ;
+ arch_mux_cfg.cfg_reg = omap34xx_cfg_reg;
+ }
+
return omap_mux_register(&arch_mux_cfg);
}
*
* OMAP2 Power Management Routines
*
- * Copyright (C) 2006 Nokia Corporation
- * Tony Lindgren <tony@atomide.com>
- *
* Copyright (C) 2005 Texas Instruments, Inc.
+ * Copyright (C) 2006-2008 Nokia Corporation
+ *
+ * Written by:
* Richard Woodruff <r-woodruff2@ti.com>
+ * Tony Lindgren
+ * Juha Yrjola
+ * Amit Kucheria <amit.kucheria@nokia.com>
+ * Igor Stoppa <igor.stoppa@nokia.com>
*
* Based on pm.c for omap1
*
#include <asm/arch/irqs.h>
#include <asm/arch/clock.h>
#include <asm/arch/sram.h>
+#include <asm/arch/control.h>
+#include <asm/arch/gpio.h>
#include <asm/arch/pm.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/dma.h>
+#include <asm/arch/board.h>
+
+#include "prm.h"
+#include "prm-regbits-24xx.h"
+#include "cm.h"
+#include "cm-regbits-24xx.h"
+#include "sdrc.h"
+
+/* These addrs are in assembly language code to be patched at runtime */
+extern void *omap2_ocs_sdrc_power;
+extern void *omap2_ocs_sdrc_dlla_ctrl;
-static struct clk *vclk;
static void (*omap2_sram_idle)(void);
-static void (*omap2_sram_suspend)(int dllctrl, int cpu_rev);
+static void (*omap2_sram_suspend)(void __iomem *dllctrl);
static void (*saved_idle)(void);
-extern void __init pmdomain_init(void);
-extern void pmdomain_set_autoidle(void);
+static u32 omap2_read_32k_sync_counter(void)
+{
+ return omap_readl(OMAP2_32KSYNCT_BASE + 0x0010);
+}
+
+#ifdef CONFIG_PM_DEBUG
+int omap2_pm_debug = 0;
+
+static int serial_console_clock_disabled;
+static int serial_console_uart;
+static unsigned int serial_console_next_disable;
+
+static struct clk *console_iclk, *console_fclk;
+
+static void serial_console_kick(void)
+{
+ serial_console_next_disable = omap2_read_32k_sync_counter();
+ /* Keep the clocks on for 4 secs */
+ serial_console_next_disable += 4 * 32768;
+}
+
+static void serial_wait_tx(void)
+{
+ static const unsigned long uart_bases[3] = {
+ 0x4806a000, 0x4806c000, 0x4806e000
+ };
+ unsigned long lsr_reg;
+ int looped = 0;
+
+ /* Wait for TX FIFO and THR to get empty */
+ lsr_reg = IO_ADDRESS(uart_bases[serial_console_uart - 1] + (5 << 2));
+ while ((__raw_readb(lsr_reg) & 0x60) != 0x60)
+ looped = 1;
+ if (looped)
+ serial_console_kick();
+}
-static unsigned int omap24xx_sleep_save[OMAP24XX_SLEEP_SAVE_SIZE];
+static void serial_console_fclk_mask(u32 *f1, u32 *f2)
+{
+ switch (serial_console_uart) {
+ case 1:
+ *f1 &= ~(1 << 21);
+ break;
+ case 2:
+ *f1 &= ~(1 << 22);
+ break;
+ case 3:
+ *f2 &= ~(1 << 2);
+ break;
+ }
+}
-void omap2_pm_idle(void)
+static void serial_console_sleep(int enable)
+{
+ if (console_iclk == NULL || console_fclk == NULL)
+ return;
+
+ if (enable) {
+ BUG_ON(serial_console_clock_disabled);
+ if (clk_get_usecount(console_fclk) == 0)
+ return;
+ if ((int) serial_console_next_disable - (int) omap2_read_32k_sync_counter() >= 0)
+ return;
+ serial_wait_tx();
+ clk_disable(console_iclk);
+ clk_disable(console_fclk);
+ serial_console_clock_disabled = 1;
+ } else {
+ int serial_wakeup = 0;
+ u32 l;
+
+ switch (serial_console_uart) {
+ case 1:
+ l = prm_read_mod_reg(CORE_MOD, PM_WKST1);
+ if (l & OMAP24XX_ST_UART1)
+ serial_wakeup = 1;
+ break;
+ case 2:
+ l = prm_read_mod_reg(CORE_MOD, PM_WKST1);
+ if (l & OMAP24XX_ST_UART2)
+ serial_wakeup = 1;
+ break;
+ case 3:
+ l = prm_read_mod_reg(CORE_MOD, OMAP24XX_PM_WKST2);
+ if (l & OMAP24XX_ST_UART3)
+ serial_wakeup = 1;
+ break;
+ }
+ if (serial_wakeup)
+ serial_console_kick();
+ if (!serial_console_clock_disabled)
+ return;
+ clk_enable(console_iclk);
+ clk_enable(console_fclk);
+ serial_console_clock_disabled = 0;
+ }
+}
+
+static void pm_init_serial_console(void)
+{
+ const struct omap_serial_console_config *conf;
+ char name[16];
+
+ conf = omap_get_config(OMAP_TAG_SERIAL_CONSOLE,
+ struct omap_serial_console_config);
+ if (conf == NULL)
+ return;
+ if (conf->console_uart > 3 || conf->console_uart < 1)
+ return;
+ serial_console_uart = conf->console_uart;
+ sprintf(name, "uart%d_fck", conf->console_uart);
+ console_fclk = clk_get(NULL, name);
+ if (IS_ERR(console_fclk))
+ console_fclk = NULL;
+ name[6] = 'i';
+ console_iclk = clk_get(NULL, name);
+ if (IS_ERR(console_fclk))
+ console_iclk = NULL;
+ if (console_fclk == NULL || console_iclk == NULL) {
+ serial_console_uart = 0;
+ return;
+ }
+ switch (serial_console_uart) {
+ case 1:
+ prm_set_mod_reg_bits(OMAP24XX_ST_UART1, CORE_MOD, PM_WKEN1);
+ break;
+ case 2:
+ prm_set_mod_reg_bits(OMAP24XX_ST_UART2, CORE_MOD, PM_WKEN1);
+ break;
+ case 3:
+ prm_set_mod_reg_bits(OMAP24XX_ST_UART3, CORE_MOD, OMAP24XX_PM_WKEN2);
+ break;
+ }
+}
+
+#define DUMP_PRM_MOD_REG(mod, reg) \
+ regs[reg_count].name = #mod "." #reg; \
+ regs[reg_count++].val = prm_read_mod_reg(mod, reg)
+#define DUMP_CM_MOD_REG(mod, reg) \
+ regs[reg_count].name = #mod "." #reg; \
+ regs[reg_count++].val = cm_read_mod_reg(mod, reg)
+#define DUMP_PRM_REG(reg) \
+ regs[reg_count].name = #reg; \
+ regs[reg_count++].val = __raw_readl(reg)
+#define DUMP_CM_REG(reg) \
+ regs[reg_count].name = #reg; \
+ regs[reg_count++].val = __raw_readl(reg)
+#define DUMP_INTC_REG(reg, off) \
+ regs[reg_count].name = #reg; \
+ regs[reg_count++].val = __raw_readl(IO_ADDRESS(0x480fe000 + (off)))
+
+static void omap2_pm_dump(int mode, int resume, unsigned int us)
+{
+ struct reg {
+ const char *name;
+ u32 val;
+ } regs[32];
+ int reg_count = 0, i;
+ const char *s1 = NULL, *s2 = NULL;
+
+ if (!resume) {
+#if 0
+ /* MPU */
+ DUMP_PRM_REG(OMAP24XX_PRCM_IRQENABLE_MPU);
+ DUMP_CM_MOD_REG(MPU_MOD, CM_CLKSTCTRL);
+ DUMP_PRM_MOD_REG(MPU_MOD, PM_PWSTCTRL);
+ DUMP_PRM_MOD_REG(MPU_MOD, PM_PWSTST);
+ DUMP_PRM_MOD_REG(MPU_MOD, PM_WKDEP);
+#endif
+#if 0
+ /* INTC */
+ DUMP_INTC_REG(INTC_MIR0, 0x0084);
+ DUMP_INTC_REG(INTC_MIR1, 0x00a4);
+ DUMP_INTC_REG(INTC_MIR2, 0x00c4);
+#endif
+#if 0
+ DUMP_CM_MOD_REG(CORE_MOD, CM_FCLKEN1);
+ DUMP_CM_MOD_REG(CORE_MOD, OMAP24XX_CM_FCLKEN2);
+ DUMP_CM_MOD_REG(WKUP_MOD, CM_FCLKEN);
+ DUMP_CM_MOD_REG(CORE_MOD, CM_ICLKEN1);
+ DUMP_CM_MOD_REG(CORE_MOD, CM_ICLKEN2);
+ DUMP_CM_MOD_REG(WKUP_MOD, CM_ICLKEN);
+ DUMP_CM_MOD_REG(PLL_MOD, CM_CLKEN);
+ DUMP_PRM_REG(OMAP24XX_PRCM_CLKEMUL_CTRL);
+ DUMP_CM_MOD_REG(PLL_MOD, CM_AUTOIDLE);
+ DUMP_PRM_MOD_REG(CORE_MOD, PM_PWSTST);
+ DUMP_PRM_REG(OMAP24XX_PRCM_CLKSRC_CTRL);
+#endif
+#if 0
+ /* DSP */
+ DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_FCLKEN);
+ DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_ICLKEN);
+ DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_IDLEST);
+ DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_AUTOIDLE);
+ DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_CLKSEL);
+ DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_CLKSTCTRL);
+ DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, RM_RSTCTRL);
+ DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, RM_RSTST);
+ DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, PM_PWSTCTRL);
+ DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, PM_PWSTST);
+#endif
+ } else {
+ DUMP_PRM_MOD_REG(CORE_MOD, PM_WKST1);
+ DUMP_PRM_MOD_REG(CORE_MOD, OMAP24XX_PM_WKST2);
+ DUMP_PRM_MOD_REG(WKUP_MOD, PM_WKST);
+ DUMP_PRM_REG(OMAP24XX_PRCM_IRQSTATUS_MPU);
+#if 1
+ DUMP_INTC_REG(INTC_PENDING_IRQ0, 0x0098);
+ DUMP_INTC_REG(INTC_PENDING_IRQ1, 0x00b8);
+ DUMP_INTC_REG(INTC_PENDING_IRQ2, 0x00d8);
+#endif
+ }
+
+ switch (mode) {
+ case 0:
+ s1 = "full";
+ s2 = "retention";
+ break;
+ case 1:
+ s1 = "MPU";
+ s2 = "retention";
+ break;
+ case 2:
+ s1 = "MPU";
+ s2 = "idle";
+ break;
+ }
+
+ if (!resume)
+#if defined(CONFIG_NO_IDLE_HZ) || defined(CONFIG_NO_HZ)
+ printk("--- Going to %s %s (next timer after %u ms)\n", s1, s2,
+ jiffies_to_msecs(get_next_timer_interrupt(jiffies) -
+ jiffies));
+#else
+ printk("--- Going to %s %s\n", s1, s2);
+#endif
+ else
+ printk("--- Woke up (slept for %u.%03u ms)\n", us / 1000, us % 1000);
+ for (i = 0; i < reg_count; i++)
+ printk("%-20s: 0x%08x\n", regs[i].name, regs[i].val);
+}
+
+#else
+static inline void serial_console_sleep(int enable) {}
+static inline void pm_init_serial_console(void) {}
+static inline void omap2_pm_dump(int mode, int resume, unsigned int us) {}
+static inline void serial_console_fclk_mask(u32 *f1, u32 *f2) {}
+
+#define omap2_pm_debug 0
+
+#endif
+
+static unsigned short enable_dyn_sleep = 0; /* disabled till drivers are fixed */
+
+static ssize_t idle_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%hu\n", enable_dyn_sleep);
+}
+
+static ssize_t idle_store(struct kobject *kobj, struct kobj_attribute *attr,
+ 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 kobj_attribute sleep_while_idle_attr =
+ __ATTR(sleep_while_idle, 0644, idle_show, idle_store);
+
+static struct clk *osc_ck, *emul_ck;
+
+static int omap2_fclks_active(void)
+{
+ u32 f1, f2;
+
+ f1 = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
+ f2 = cm_read_mod_reg(CORE_MOD, OMAP24XX_CM_FCLKEN2);
+ serial_console_fclk_mask(&f1, &f2);
+ if (f1 | f2)
+ return 1;
+ return 0;
+}
+
+static int omap2_irq_pending(void)
+{
+ u32 pending_reg = IO_ADDRESS(0x480fe098);
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ if (__raw_readl(pending_reg))
+ return 1;
+ pending_reg += 0x20;
+ }
+ return 0;
+}
+
+static atomic_t sleep_block = ATOMIC_INIT(0);
+
+void omap2_block_sleep(void)
+{
+ atomic_inc(&sleep_block);
+}
+
+void omap2_allow_sleep(void)
+{
+ int i;
+
+ i = atomic_dec_return(&sleep_block);
+ BUG_ON(i < 0);
+}
+
+static void omap2_enter_full_retention(void)
+{
+ u32 l, sleep_time = 0;
+
+ /* There is 1 reference hold for all children of the oscillator
+ * clock, the following will remove it. If no one else uses the
+ * oscillator itself it will be disabled if/when we enter retention
+ * mode.
+ */
+ clk_disable(osc_ck);
+
+ /* Clear old wake-up events */
+ /* REVISIT: These write to reserved bits? */
+ prm_write_mod_reg(0xffffffff, CORE_MOD, PM_WKST1);
+ prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2);
+ prm_write_mod_reg(0xffffffff, WKUP_MOD, PM_WKST);
+
+ /* Try to enter retention */
+ prm_write_mod_reg((0x01 << OMAP_POWERSTATE_SHIFT) | OMAP_LOGICRETSTATE,
+ MPU_MOD, PM_PWSTCTRL);
+
+ /* Workaround to kill USB */
+ l = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0) | OMAP24XX_USBSTANDBYCTRL;
+ omap_ctrl_writel(l, OMAP2_CONTROL_DEVCONF0);
+
+ omap2_gpio_prepare_for_retention();
+
+ if (omap2_pm_debug) {
+ omap2_pm_dump(0, 0, 0);
+ sleep_time = omap2_read_32k_sync_counter();
+ }
+
+ /* One last check for pending IRQs to avoid extra latency due
+ * to sleeping unnecessarily. */
+ if (omap2_irq_pending())
+ goto no_sleep;
+
+ serial_console_sleep(1);
+ /* Jump to SRAM suspend code */
+ omap2_sram_suspend(OMAP_SDRC_REGADDR(SDRC_DLLA_CTRL));
+no_sleep:
+ serial_console_sleep(0);
+
+ if (omap2_pm_debug) {
+ unsigned long long tmp;
+ u32 resume_time;
+
+ resume_time = omap2_read_32k_sync_counter();
+ tmp = resume_time - sleep_time;
+ tmp *= 1000000;
+ omap2_pm_dump(0, 1, tmp / 32768);
+ }
+ omap2_gpio_resume_after_retention();
+
+ clk_enable(osc_ck);
+
+ /* clear CORE wake-up events */
+ prm_write_mod_reg(0xffffffff, CORE_MOD, PM_WKST1);
+ prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2);
+
+ /* wakeup domain events - bit 1: GPT1, bit5 GPIO */
+ prm_clear_mod_reg_bits(0x4 | 0x1, WKUP_MOD, PM_WKST);
+
+ /* MPU domain wake events */
+ l = __raw_readl(OMAP24XX_PRCM_IRQSTATUS_MPU);
+ if (l & 0x01)
+ __raw_writel(0x01, OMAP24XX_PRCM_IRQSTATUS_MPU);
+ if (l & 0x20)
+ __raw_writel(0x20, OMAP24XX_PRCM_IRQSTATUS_MPU);
+
+ /* Mask future PRCM-to-MPU interrupts */
+ __raw_writel(0x0, OMAP24XX_PRCM_IRQSTATUS_MPU);
+}
+
+static int omap2_i2c_active(void)
+{
+ u32 l;
+
+ l = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
+ return l & (OMAP2420_EN_I2C2 | OMAP2420_EN_I2C1);
+}
+
+static int sti_console_enabled;
+
+static int omap2_allow_mpu_retention(void)
+{
+ u32 l;
+
+ if (atomic_read(&sleep_block))
+ return 0;
+
+ /* Check for MMC, UART2, UART1, McSPI2, McSPI1 and DSS1. */
+ l = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
+ if (l & (OMAP2420_EN_MMC | OMAP24XX_EN_UART2 |
+ OMAP24XX_EN_UART1 | OMAP24XX_EN_MCSPI2 |
+ OMAP24XX_EN_MCSPI1 | OMAP24XX_EN_DSS1))
+ return 0;
+ /* Check for UART3. */
+ l = cm_read_mod_reg(CORE_MOD, OMAP24XX_CM_FCLKEN2);
+ if (l & OMAP24XX_EN_UART3)
+ return 0;
+ if (sti_console_enabled)
+ return 0;
+
+ return 1;
+}
+
+static void omap2_enter_mpu_retention(void)
+{
+ u32 sleep_time = 0;
+ int only_idle = 0;
+
+ /* Putting MPU into the WFI state while a transfer is active
+ * seems to cause the I2C block to timeout. Why? Good question. */
+ if (omap2_i2c_active())
+ return;
+
+ /* The peripherals seem not to be able to wake up the MPU when
+ * it is in retention mode. */
+ if (omap2_allow_mpu_retention()) {
+ /* REVISIT: These write to reserved bits? */
+ prm_write_mod_reg(0xffffffff, CORE_MOD, PM_WKST1);
+ prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2);
+ prm_write_mod_reg(0xffffffff, WKUP_MOD, PM_WKST);
+
+ /* Try to enter MPU retention */
+ prm_write_mod_reg((0x01 << OMAP_POWERSTATE_SHIFT) |
+ OMAP_LOGICRETSTATE,
+ MPU_MOD, PM_PWSTCTRL);
+ } else {
+ /* Block MPU retention */
+
+ prm_write_mod_reg(OMAP_LOGICRETSTATE, MPU_MOD, PM_PWSTCTRL);
+ only_idle = 1;
+ }
+
+ if (omap2_pm_debug) {
+ omap2_pm_dump(only_idle ? 2 : 1, 0, 0);
+ sleep_time = omap2_read_32k_sync_counter();
+ }
+
+ omap2_sram_idle();
+
+ if (omap2_pm_debug) {
+ unsigned long long tmp;
+ u32 resume_time;
+
+ resume_time = omap2_read_32k_sync_counter();
+ tmp = resume_time - sleep_time;
+ tmp *= 1000000;
+ omap2_pm_dump(only_idle ? 2 : 1, 1, tmp / 32768);
+ }
+}
+
+static int omap2_can_sleep(void)
+{
+ if (!enable_dyn_sleep)
+ return 0;
+ if (omap2_fclks_active())
+ return 0;
+ if (atomic_read(&sleep_block) > 0)
+ return 0;
+ if (clk_get_usecount(osc_ck) > 1)
+ return 0;
+ if (omap_dma_running())
+ return 0;
+
+ return 1;
+}
+
+static void omap2_pm_idle(void)
{
local_irq_disable();
local_fiq_disable();
- if (need_resched()) {
- local_fiq_enable();
- local_irq_enable();
- return;
+
+ if (!omap2_can_sleep()) {
+ /* timer_dyn_reprogram() takes about 100-200 us to complete.
+ * In some contexts (e.g. when waiting for a GPMC-SDRAM DMA
+ * transfer to complete), the increased latency is too much.
+ *
+ * omap2_block_sleep() and omap2_allow_sleep() can be used
+ * to indicate this.
+ */
+ if (atomic_read(&sleep_block) == 0) {
+ timer_dyn_reprogram();
+ if (omap2_irq_pending())
+ goto out;
+ }
+ omap2_enter_mpu_retention();
+ goto out;
}
/*
*/
timer_dyn_reprogram();
- omap2_sram_idle();
+ if (omap2_irq_pending())
+ goto out;
+
+ omap2_enter_full_retention();
+
+out:
local_fiq_enable();
local_irq_enable();
}
/* We cannot sleep in idle until we have resumed */
saved_idle = pm_idle;
pm_idle = NULL;
+
return 0;
}
static int omap2_pm_suspend(void)
{
+ u32 wken_wkup, mir1;
+
+ wken_wkup = prm_read_mod_reg(WKUP_MOD, PM_WKEN);
+ prm_write_mod_reg(wken_wkup & ~OMAP24XX_EN_GPT1, WKUP_MOD, PM_WKEN);
+
+ /* Mask GPT1 */
+ mir1 = omap_readl(0x480fe0a4);
+ omap_writel(1 << 5, 0x480fe0ac);
+
+ omap2_enter_full_retention();
+
+ omap_writel(mir1, 0x480fe0a4);
+ prm_write_mod_reg(wken_wkup, WKUP_MOD, PM_WKEN);
+
return 0;
}
{
int ret = 0;
- switch (state)
- {
+ switch (state) {
case PM_SUSPEND_STANDBY:
case PM_SUSPEND_MEM:
ret = omap2_pm_suspend();
.valid = suspend_valid_only_mem,
};
+static void __init prcm_setup_regs(void)
+{
+ u32 l;
+
+ /* Enable autoidle */
+ __raw_writel(OMAP24XX_AUTOIDLE, OMAP24XX_PRCM_SYSCONFIG);
+
+ /* Set all domain wakeup dependencies */
+ prm_write_mod_reg(OMAP_EN_WKUP_MASK, MPU_MOD, PM_WKDEP);
+ prm_write_mod_reg(0, OMAP24XX_DSP_MOD, PM_WKDEP);
+ prm_write_mod_reg(0, GFX_MOD, PM_WKDEP);
+ prm_write_mod_reg(0, CORE_MOD, PM_WKDEP);
+ if (cpu_is_omap2430())
+ prm_write_mod_reg(0, OMAP2430_MDM_MOD, PM_WKDEP);
+
+ l = prm_read_mod_reg(CORE_MOD, PM_PWSTCTRL);
+ /* Enable retention for all memory blocks */
+ l |= OMAP24XX_MEM3RETSTATE | OMAP24XX_MEM2RETSTATE |
+ OMAP24XX_MEM1RETSTATE;
+
+ /* Set power state to RETENTION */
+ l &= ~OMAP_POWERSTATE_MASK;
+ l |= 0x01 << OMAP_POWERSTATE_SHIFT;
+ prm_write_mod_reg(l, CORE_MOD, PM_PWSTCTRL);
+
+ prm_write_mod_reg((0x01 << OMAP_POWERSTATE_SHIFT) |
+ OMAP_LOGICRETSTATE,
+ MPU_MOD, PM_PWSTCTRL);
+
+ /* Power down DSP and GFX */
+ prm_write_mod_reg(OMAP24XX_FORCESTATE | (0x3 << OMAP_POWERSTATE_SHIFT),
+ OMAP24XX_DSP_MOD, PM_PWSTCTRL);
+ prm_write_mod_reg(OMAP24XX_FORCESTATE | (0x3 << OMAP_POWERSTATE_SHIFT),
+ GFX_MOD, PM_PWSTCTRL);
+
+ /* Enable clock auto control for all domains */
+ cm_write_mod_reg(OMAP24XX_AUTOSTATE_MPU_MASK, MPU_MOD, CM_CLKSTCTRL);
+ cm_write_mod_reg(OMAP24XX_AUTOSTATE_DSS_MASK |
+ OMAP24XX_AUTOSTATE_L4_MASK |
+ OMAP24XX_AUTOSTATE_L3_MASK,
+ CORE_MOD, CM_CLKSTCTRL);
+ cm_write_mod_reg(OMAP24XX_AUTOSTATE_GFX_MASK, GFX_MOD, CM_CLKSTCTRL);
+ cm_write_mod_reg(OMAP2420_AUTOSTATE_IVA_MASK |
+ OMAP24XX_AUTOSTATE_DSP_MASK,
+ OMAP24XX_DSP_MOD, CM_CLKSTCTRL);
+
+ /* Enable clock autoidle for all domains */
+ cm_write_mod_reg(OMAP24XX_AUTO_CAM |
+ OMAP24XX_AUTO_MAILBOXES |
+ OMAP24XX_AUTO_WDT4 |
+ OMAP2420_AUTO_WDT3 |
+ OMAP24XX_AUTO_MSPRO |
+ OMAP2420_AUTO_MMC |
+ OMAP24XX_AUTO_FAC |
+ OMAP2420_AUTO_EAC |
+ OMAP24XX_AUTO_HDQ |
+ OMAP24XX_AUTO_UART2 |
+ OMAP24XX_AUTO_UART1 |
+ OMAP24XX_AUTO_I2C2 |
+ OMAP24XX_AUTO_I2C1 |
+ OMAP24XX_AUTO_MCSPI2 |
+ OMAP24XX_AUTO_MCSPI1 |
+ OMAP24XX_AUTO_MCBSP2 |
+ OMAP24XX_AUTO_MCBSP1 |
+ OMAP24XX_AUTO_GPT12 |
+ OMAP24XX_AUTO_GPT11 |
+ OMAP24XX_AUTO_GPT10 |
+ OMAP24XX_AUTO_GPT9 |
+ OMAP24XX_AUTO_GPT8 |
+ OMAP24XX_AUTO_GPT7 |
+ OMAP24XX_AUTO_GPT6 |
+ OMAP24XX_AUTO_GPT5 |
+ OMAP24XX_AUTO_GPT4 |
+ OMAP24XX_AUTO_GPT3 |
+ OMAP24XX_AUTO_GPT2 |
+ OMAP2420_AUTO_VLYNQ |
+ OMAP24XX_AUTO_DSS,
+ CORE_MOD, CM_AUTOIDLE1);
+ cm_write_mod_reg(OMAP24XX_AUTO_UART3 |
+ OMAP24XX_AUTO_SSI |
+ OMAP24XX_AUTO_USB,
+ CORE_MOD, CM_AUTOIDLE2);
+ cm_write_mod_reg(OMAP24XX_AUTO_SDRC |
+ OMAP24XX_AUTO_GPMC |
+ OMAP24XX_AUTO_SDMA,
+ CORE_MOD, CM_AUTOIDLE3);
+ cm_write_mod_reg(OMAP24XX_AUTO_PKA |
+ OMAP24XX_AUTO_AES |
+ OMAP24XX_AUTO_RNG |
+ OMAP24XX_AUTO_SHA |
+ OMAP24XX_AUTO_DES,
+ CORE_MOD, OMAP24XX_CM_AUTOIDLE4);
+
+ cm_write_mod_reg(OMAP2420_AUTO_DSP_IPI, OMAP24XX_DSP_MOD, CM_AUTOIDLE);
+
+ /* Put DPLL and both APLLs into autoidle mode */
+ cm_write_mod_reg((0x03 << OMAP24XX_AUTO_DPLL_SHIFT) |
+ (0x03 << OMAP24XX_AUTO_96M_SHIFT) |
+ (0x03 << OMAP24XX_AUTO_54M_SHIFT),
+ PLL_MOD, CM_AUTOIDLE);
+
+ cm_write_mod_reg(OMAP24XX_AUTO_OMAPCTRL |
+ OMAP24XX_AUTO_WDT1 |
+ OMAP24XX_AUTO_MPU_WDT |
+ OMAP24XX_AUTO_GPIOS |
+ OMAP24XX_AUTO_32KSYNC |
+ OMAP24XX_AUTO_GPT1,
+ WKUP_MOD, CM_AUTOIDLE);
+
+ /* REVISIT: Configure number of 32 kHz clock cycles for sys_clk
+ * stabilisation */
+ __raw_writel(15 << OMAP_SETUP_TIME_SHIFT, OMAP24XX_PRCM_CLKSSETUP);
+
+ /* Configure automatic voltage transition */
+ __raw_writel(2 << OMAP_SETUP_TIME_SHIFT, OMAP24XX_PRCM_VOLTSETUP);
+ __raw_writel(OMAP24XX_AUTO_EXTVOLT |
+ (0x1 << OMAP24XX_SETOFF_LEVEL_SHIFT) |
+ OMAP24XX_MEMRETCTRL |
+ (0x1 << OMAP24XX_SETRET_LEVEL_SHIFT) |
+ (0x0 << OMAP24XX_VOLT_LEVEL_SHIFT),
+ OMAP24XX_PRCM_VOLTCTRL);
+
+ /* Enable wake-up events */
+ prm_write_mod_reg(OMAP24XX_EN_GPIOS | OMAP24XX_EN_GPT1,
+ WKUP_MOD, PM_WKEN);
+}
+
int __init omap2_pm_init(void)
{
+ u32 l;
+ int error;
+
+ printk(KERN_INFO "Power Management for OMAP2 initializing\n");
+ l = __raw_readl(OMAP24XX_PRCM_REVISION);
+ printk(KERN_INFO "PRCM revision %d.%d\n", (l >> 4) & 0x0f, l & 0x0f);
+
+ osc_ck = clk_get(NULL, "osc_ck");
+ if (IS_ERR(osc_ck)) {
+ printk(KERN_ERR "could not get osc_ck\n");
+ return -ENODEV;
+ }
+
+ if (cpu_is_omap242x()) {
+ emul_ck = clk_get(NULL, "emul_ck");
+ if (IS_ERR(emul_ck)) {
+ printk(KERN_ERR "could not get emul_ck\n");
+ clk_put(osc_ck);
+ return -ENODEV;
+ }
+ }
+
+ prcm_setup_regs();
+
+ pm_init_serial_console();
+
+ /* Hack to prevent MPU retention when STI console is enabled. */
+ {
+ const struct omap_sti_console_config *sti;
+
+ sti = omap_get_config(OMAP_TAG_STI_CONSOLE,
+ struct omap_sti_console_config);
+ if (sti != NULL && sti->enable)
+ sti_console_enabled = 1;
+ }
+
+ /*
+ * 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);
+
+ /* Patch in the correct register addresses for multiboot */
+ omap_sram_patch_va(omap24xx_cpu_suspend, &omap2_ocs_sdrc_power,
+ omap2_sram_suspend,
+ OMAP_SDRC_REGADDR(SDRC_POWER));
+ omap_sram_patch_va(omap24xx_cpu_suspend, &omap2_ocs_sdrc_dlla_ctrl,
+ omap2_sram_suspend,
+ OMAP_SDRC_REGADDR(SDRC_DLLA_CTRL));
+
+ suspend_set_ops(&omap_pm_ops);
+ pm_idle = omap2_pm_idle;
+
+ error = sysfs_create_file(power_kobj, &sleep_while_idle_attr.attr);
+ if (error)
+ printk(KERN_ERR "sysfs_create_file failed: %d\n", error);
+
return 0;
}
-__initcall(omap2_pm_init);
+late_initcall(omap2_pm_init);
--- /dev/null
+/*
+ * OMAP powerdomain control
+ *
+ * Copyright (C) 2007-2008 Texas Instruments, Inc.
+ * Copyright (C) 2007-2008 Nokia Corporation
+ *
+ * Written by Paul Walmsley
+ *
+ * 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.
+ */
+#ifdef CONFIG_OMAP_DEBUG_POWERDOMAIN
+# define DEBUG
+#endif
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+
+#include <asm/atomic.h>
+
+#include "cm.h"
+#include "cm-regbits-34xx.h"
+#include "prm.h"
+#include "prm-regbits-34xx.h"
+
+#include <asm/arch/cpu.h>
+#include <asm/arch/powerdomain.h>
+#include <asm/arch/clockdomain.h>
+
+/* pwrdm_list contains all registered struct powerdomains */
+static LIST_HEAD(pwrdm_list);
+
+/* pwrdm_mutex protects pwrdm_list add and del ops */
+static DEFINE_MUTEX(pwrdm_mutex);
+
+/* Private functions */
+
+static u32 prm_read_mod_bits_shift(s16 domain, s16 idx, u32 mask)
+{
+ u32 v;
+
+ v = prm_read_mod_reg(domain, idx);
+ v &= mask;
+ v >>= __ffs(mask);
+
+ return v;
+}
+
+struct powerdomain *_pwrdm_lookup(const char *name)
+{
+ struct powerdomain *pwrdm, *temp_pwrdm;
+
+ pwrdm = NULL;
+
+ list_for_each_entry(temp_pwrdm, &pwrdm_list, node) {
+ if (!strcmp(name, temp_pwrdm->name)) {
+ pwrdm = temp_pwrdm;
+ break;
+ }
+ }
+
+ return pwrdm;
+}
+
+/* _pwrdm_deps_lookup - look up the specified powerdomain in a pwrdm list */
+static struct powerdomain *_pwrdm_deps_lookup(struct powerdomain *pwrdm,
+ struct pwrdm_dep *deps)
+{
+ struct pwrdm_dep *pd;
+
+ if (!pwrdm || !deps || !omap_chip_is(pwrdm->omap_chip))
+ return ERR_PTR(-EINVAL);
+
+ for (pd = deps; pd; pd++) {
+
+ if (!omap_chip_is(pd->omap_chip))
+ continue;
+
+ if (!pd->pwrdm && pd->pwrdm_name)
+ pd->pwrdm = pwrdm_lookup(pd->pwrdm_name);
+
+ if (pd->pwrdm == pwrdm)
+ break;
+
+ }
+
+ if (!pd)
+ return ERR_PTR(-ENOENT);
+
+ return pd->pwrdm;
+}
+
+
+/* Public functions */
+
+/**
+ * pwrdm_init - set up the powerdomain layer
+ *
+ * Loop through the list of powerdomains, registering all that are
+ * available on the current CPU. If pwrdm_list is supplied and not
+ * null, all of the referenced powerdomains will be registered. No
+ * return value.
+ */
+void pwrdm_init(struct powerdomain **pwrdm_list)
+{
+ struct powerdomain **p = NULL;
+
+ if (pwrdm_list)
+ for (p = pwrdm_list; *p; p++)
+ pwrdm_register(*p);
+}
+
+/**
+ * pwrdm_register - register a powerdomain
+ * @pwrdm: struct powerdomain * to register
+ *
+ * Adds a powerdomain to the internal powerdomain list. Returns
+ * -EINVAL if given a null pointer, -EEXIST if a powerdomain is
+ * already registered by the provided name, or 0 upon success.
+ */
+int pwrdm_register(struct powerdomain *pwrdm)
+{
+ int ret = -EINVAL;
+
+ if (!pwrdm)
+ return -EINVAL;
+
+ if (!omap_chip_is(pwrdm->omap_chip))
+ return -EINVAL;
+
+ mutex_lock(&pwrdm_mutex);
+ if (_pwrdm_lookup(pwrdm->name)) {
+ ret = -EEXIST;
+ goto pr_unlock;
+ }
+
+ list_add(&pwrdm->node, &pwrdm_list);
+
+ pr_debug("powerdomain: registered %s\n", pwrdm->name);
+ ret = 0;
+
+pr_unlock:
+ mutex_unlock(&pwrdm_mutex);
+
+ return ret;
+}
+
+/**
+ * pwrdm_unregister - unregister a powerdomain
+ * @pwrdm: struct powerdomain * to unregister
+ *
+ * Removes a powerdomain from the internal powerdomain list. Returns
+ * -EINVAL if pwrdm argument is NULL.
+ */
+int pwrdm_unregister(struct powerdomain *pwrdm)
+{
+ if (!pwrdm)
+ return -EINVAL;
+
+ mutex_lock(&pwrdm_mutex);
+ list_del(&pwrdm->node);
+ mutex_unlock(&pwrdm_mutex);
+
+ pr_debug("powerdomain: unregistered %s\n", pwrdm->name);
+
+ return 0;
+}
+
+/**
+ * pwrdm_lookup - look up a powerdomain by name, return a pointer
+ * @name: name of powerdomain
+ *
+ * Find a registered powerdomain by its name. Returns a pointer to the
+ * struct powerdomain if found, or NULL otherwise.
+ */
+struct powerdomain *pwrdm_lookup(const char *name)
+{
+ struct powerdomain *pwrdm;
+
+ if (!name)
+ return NULL;
+
+ mutex_lock(&pwrdm_mutex);
+ pwrdm = _pwrdm_lookup(name);
+ mutex_unlock(&pwrdm_mutex);
+
+ return pwrdm;
+}
+
+/**
+ * pwrdm_for_each - call function on each registered clockdomain
+ * @fn: callback function *
+ *
+ * Call the supplied function for each registered powerdomain.
+ * The callback function can return anything but 0 to bail
+ * out early from the iterator. The callback function is called with
+ * the pwrdm_mutex held, so no powerdomain structure manipulation
+ * functions should be called from the callback, although hardware
+ * powerdomain control functions are fine. Returns the last return
+ * value of the callback function, which should be 0 for success or
+ * anything else to indicate failure; or -EINVAL if the function pointer
+ * is null.
+ */
+int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm))
+{
+ struct powerdomain *temp_pwrdm;
+ int ret = 0;
+
+ if (!fn)
+ return -EINVAL;
+
+ mutex_lock(&pwrdm_mutex);
+ list_for_each_entry(temp_pwrdm, &pwrdm_list, node) {
+ ret = (*fn)(temp_pwrdm);
+ if (ret)
+ break;
+ }
+ mutex_unlock(&pwrdm_mutex);
+
+ return ret;
+}
+
+/**
+ * pwrdm_add_clkdm - add a clockdomain to a powerdomain
+ * @pwrdm: struct powerdomain * to add the clockdomain to
+ * @clkdm: struct clockdomain * to associate with a powerdomain
+ *
+ * Associate the clockdomain 'clkdm' with a powerdomain 'pwrdm'. This
+ * enables the use of pwrdm_for_each_clkdm(). Returns -EINVAL if
+ * presented with invalid pointers; -ENOMEM if memory could not be allocated;
+ * or 0 upon success.
+ */
+int pwrdm_add_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm)
+{
+ int i;
+ int ret = -EINVAL;
+
+ if (!pwrdm || !clkdm)
+ return -EINVAL;
+
+ pr_debug("powerdomain: associating clockdomain %s with powerdomain "
+ "%s\n", clkdm->name, pwrdm->name);
+ mutex_lock(&pwrdm_mutex);
+
+ for (i = 0; i < PWRDM_MAX_CLKDMS; i++) {
+ if (!pwrdm->pwrdm_clkdms[i])
+ break;
+#ifdef DEBUG
+ if (pwrdm->pwrdm_clkdms[i] == clkdm) {
+ ret = -EINVAL;
+ goto pac_exit;
+ }
+#endif
+ }
+
+ if (i == PWRDM_MAX_CLKDMS) {
+ pr_debug("powerdomain: increase PWRDM_MAX_CLKDMS for "
+ "pwrdm %s clkdm %s\n", pwrdm->name, clkdm->name);
+ WARN_ON(1);
+ ret = -ENOMEM;
+ goto pac_exit;
+ }
+
+ pwrdm->pwrdm_clkdms[i] = clkdm;
+
+ ret = 0;
+
+pac_exit:
+ mutex_unlock(&pwrdm_mutex);
+
+ return ret;
+}
+
+/**
+ * pwrdm_del_clkdm - remove a clockdomain to a powerdomain
+ * @pwrdm: struct powerdomain * to add the clockdomain to
+ * @clkdm: struct clockdomain * to associate with a powerdomain
+ *
+ * Dissociate the clockdomain 'clkdm' from the powerdomain
+ * 'pwrdm'. Returns -EINVAL if presented with invalid pointers;
+ * -ENOENT if the clkdm was not associated with the powerdomain, or 0
+ * upon success.
+ */
+int pwrdm_del_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm)
+{
+ int ret = -EINVAL;
+ int i;
+
+ if (!pwrdm || !clkdm)
+ return -EINVAL;
+
+ pr_debug("powerdomain: dissociating clockdomain %s from powerdomain "
+ "%s\n", clkdm->name, pwrdm->name);
+
+ mutex_lock(&pwrdm_mutex);
+
+ for (i = 0; i < PWRDM_MAX_CLKDMS; i++)
+ if (pwrdm->pwrdm_clkdms[i] == clkdm)
+ break;
+
+ if (i == PWRDM_MAX_CLKDMS) {
+ pr_debug("powerdomain: clkdm %s not associated with pwrdm "
+ "%s ?!\n", clkdm->name, pwrdm->name);
+ ret = -ENOENT;
+ goto pdc_exit;
+ }
+
+ pwrdm->pwrdm_clkdms[i] = NULL;
+
+ ret = 0;
+
+pdc_exit:
+ mutex_unlock(&pwrdm_mutex);
+
+ return ret;
+}
+
+/**
+ * pwrdm_for_each_clkdm - call function on each clkdm in a pwrdm
+ * @pwrdm: struct powerdomain * to iterate over
+ * @fn: callback function *
+ *
+ * Call the supplied function for each clockdomain in the powerdomain
+ * 'pwrdm'. The callback function can return anything but 0 to bail
+ * out early from the iterator. The callback function is called with
+ * the pwrdm_mutex held, so no powerdomain structure manipulation
+ * functions should be called from the callback, although hardware
+ * powerdomain control functions are fine. Returns -EINVAL if
+ * presented with invalid pointers; or passes along the last return
+ * value of the callback function, which should be 0 for success or
+ * anything else to indicate failure.
+ */
+int pwrdm_for_each_clkdm(struct powerdomain *pwrdm,
+ int (*fn)(struct powerdomain *pwrdm,
+ struct clockdomain *clkdm))
+{
+ int ret = 0;
+ int i;
+
+ if (!fn)
+ return -EINVAL;
+
+ mutex_lock(&pwrdm_mutex);
+
+ for (i = 0; i < PWRDM_MAX_CLKDMS && !ret; i++)
+ ret = (*fn)(pwrdm, pwrdm->pwrdm_clkdms[i]);
+
+ mutex_unlock(&pwrdm_mutex);
+
+ return ret;
+}
+
+
+/**
+ * pwrdm_add_wkdep - add a wakeup dependency from pwrdm2 to pwrdm1
+ * @pwrdm1: wake this struct powerdomain * up (dependent)
+ * @pwrdm2: when this struct powerdomain * wakes up (source)
+ *
+ * When the powerdomain represented by pwrdm2 wakes up (due to an
+ * interrupt), wake up pwrdm1. Implemented in hardware on the OMAP,
+ * this feature is designed to reduce wakeup latency of the dependent
+ * powerdomain. Returns -EINVAL if presented with invalid powerdomain
+ * pointers, -ENOENT if pwrdm2 cannot wake up pwrdm1 in hardware, or
+ * 0 upon success.
+ */
+int pwrdm_add_wkdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2)
+{
+ struct powerdomain *p;
+
+ if (!pwrdm1)
+ return -EINVAL;
+
+ p = _pwrdm_deps_lookup(pwrdm2, pwrdm1->wkdep_srcs);
+ if (IS_ERR(p)) {
+ pr_debug("powerdomain: hardware cannot set/clear wake up of "
+ "%s when %s wakes up\n", pwrdm1->name, pwrdm2->name);
+ return IS_ERR(p);
+ }
+
+ pr_debug("powerdomain: hardware will wake up %s when %s wakes up\n",
+ pwrdm1->name, pwrdm2->name);
+
+ prm_set_mod_reg_bits((1 << pwrdm2->dep_bit),
+ pwrdm1->prcm_offs, PM_WKDEP);
+
+ return 0;
+}
+
+/**
+ * pwrdm_del_wkdep - remove a wakeup dependency from pwrdm2 to pwrdm1
+ * @pwrdm1: wake this struct powerdomain * up (dependent)
+ * @pwrdm2: when this struct powerdomain * wakes up (source)
+ *
+ * Remove a wakeup dependency that causes pwrdm1 to wake up when pwrdm2
+ * wakes up. Returns -EINVAL if presented with invalid powerdomain
+ * pointers, -ENOENT if pwrdm2 cannot wake up pwrdm1 in hardware, or
+ * 0 upon success.
+ */
+int pwrdm_del_wkdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2)
+{
+ struct powerdomain *p;
+
+ if (!pwrdm1)
+ return -EINVAL;
+
+ p = _pwrdm_deps_lookup(pwrdm2, pwrdm1->wkdep_srcs);
+ if (IS_ERR(p)) {
+ pr_debug("powerdomain: hardware cannot set/clear wake up of "
+ "%s when %s wakes up\n", pwrdm1->name, pwrdm2->name);
+ return IS_ERR(p);
+ }
+
+ pr_debug("powerdomain: hardware will no longer wake up %s after %s "
+ "wakes up\n", pwrdm1->name, pwrdm2->name);
+
+ prm_clear_mod_reg_bits((1 << pwrdm2->dep_bit),
+ pwrdm1->prcm_offs, PM_WKDEP);
+
+ return 0;
+}
+
+/**
+ * pwrdm_read_wkdep - read wakeup dependency state from pwrdm2 to pwrdm1
+ * @pwrdm1: wake this struct powerdomain * up (dependent)
+ * @pwrdm2: when this struct powerdomain * wakes up (source)
+ *
+ * Return 1 if a hardware wakeup dependency exists wherein pwrdm1 will be
+ * awoken when pwrdm2 wakes up; 0 if dependency is not set; -EINVAL
+ * if either powerdomain pointer is invalid; or -ENOENT if the hardware
+ * is incapable.
+ *
+ * REVISIT: Currently this function only represents software-controllable
+ * wakeup dependencies. Wakeup dependencies fixed in hardware are not
+ * yet handled here.
+ */
+int pwrdm_read_wkdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2)
+{
+ struct powerdomain *p;
+
+ if (!pwrdm1)
+ return -EINVAL;
+
+ p = _pwrdm_deps_lookup(pwrdm2, pwrdm1->wkdep_srcs);
+ if (IS_ERR(p)) {
+ pr_debug("powerdomain: hardware cannot set/clear wake up of "
+ "%s when %s wakes up\n", pwrdm1->name, pwrdm2->name);
+ return IS_ERR(p);
+ }
+
+ return prm_read_mod_bits_shift(pwrdm1->prcm_offs, PM_WKDEP,
+ (1 << pwrdm2->dep_bit));
+}
+
+/**
+ * pwrdm_add_sleepdep - add a sleep dependency from pwrdm2 to pwrdm1
+ * @pwrdm1: prevent this struct powerdomain * from sleeping (dependent)
+ * @pwrdm2: when this struct powerdomain * is active (source)
+ *
+ * Prevent pwrdm1 from automatically going inactive (and then to
+ * retention or off) if pwrdm2 is still active. Returns -EINVAL if
+ * presented with invalid powerdomain pointers or called on a machine
+ * that does not support software-configurable hardware sleep dependencies,
+ * -ENOENT if the specified dependency cannot be set in hardware, or
+ * 0 upon success.
+ */
+int pwrdm_add_sleepdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2)
+{
+ struct powerdomain *p;
+
+ if (!pwrdm1)
+ return -EINVAL;
+
+ if (!cpu_is_omap34xx())
+ return -EINVAL;
+
+ p = _pwrdm_deps_lookup(pwrdm2, pwrdm1->sleepdep_srcs);
+ if (IS_ERR(p)) {
+ pr_debug("powerdomain: hardware cannot set/clear sleep "
+ "dependency affecting %s from %s\n", pwrdm1->name,
+ pwrdm2->name);
+ return IS_ERR(p);
+ }
+
+ pr_debug("powerdomain: will prevent %s from sleeping if %s is active\n",
+ pwrdm1->name, pwrdm2->name);
+
+ cm_set_mod_reg_bits((1 << pwrdm2->dep_bit),
+ pwrdm1->prcm_offs, OMAP3430_CM_SLEEPDEP);
+
+ return 0;
+}
+
+/**
+ * pwrdm_del_sleepdep - remove a sleep dependency from pwrdm2 to pwrdm1
+ * @pwrdm1: prevent this struct powerdomain * from sleeping (dependent)
+ * @pwrdm2: when this struct powerdomain * is active (source)
+ *
+ * Allow pwrdm1 to automatically go inactive (and then to retention or
+ * off), independent of the activity state of pwrdm2. Returns -EINVAL
+ * if presented with invalid powerdomain pointers or called on a machine
+ * that does not support software-configurable hardware sleep dependencies,
+ * -ENOENT if the specified dependency cannot be cleared in hardware, or
+ * 0 upon success.
+ */
+int pwrdm_del_sleepdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2)
+{
+ struct powerdomain *p;
+
+ if (!pwrdm1)
+ return -EINVAL;
+
+ if (!cpu_is_omap34xx())
+ return -EINVAL;
+
+ p = _pwrdm_deps_lookup(pwrdm2, pwrdm1->sleepdep_srcs);
+ if (IS_ERR(p)) {
+ pr_debug("powerdomain: hardware cannot set/clear sleep "
+ "dependency affecting %s from %s\n", pwrdm1->name,
+ pwrdm2->name);
+ return IS_ERR(p);
+ }
+
+ pr_debug("powerdomain: will no longer prevent %s from sleeping if "
+ "%s is active\n", pwrdm1->name, pwrdm2->name);
+
+ cm_clear_mod_reg_bits((1 << pwrdm2->dep_bit),
+ pwrdm1->prcm_offs, OMAP3430_CM_SLEEPDEP);
+
+ return 0;
+}
+
+/**
+ * pwrdm_read_sleepdep - read sleep dependency state from pwrdm2 to pwrdm1
+ * @pwrdm1: prevent this struct powerdomain * from sleeping (dependent)
+ * @pwrdm2: when this struct powerdomain * is active (source)
+ *
+ * Return 1 if a hardware sleep dependency exists wherein pwrdm1 will
+ * not be allowed to automatically go inactive if pwrdm2 is active;
+ * 0 if pwrdm1's automatic power state inactivity transition is independent
+ * of pwrdm2's; -EINVAL if either powerdomain pointer is invalid or called
+ * on a machine that does not support software-configurable hardware sleep
+ * dependencies; or -ENOENT if the hardware is incapable.
+ *
+ * REVISIT: Currently this function only represents software-controllable
+ * sleep dependencies. Sleep dependencies fixed in hardware are not
+ * yet handled here.
+ */
+int pwrdm_read_sleepdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2)
+{
+ struct powerdomain *p;
+
+ if (!pwrdm1)
+ return -EINVAL;
+
+ if (!cpu_is_omap34xx())
+ return -EINVAL;
+
+ p = _pwrdm_deps_lookup(pwrdm2, pwrdm1->sleepdep_srcs);
+ if (IS_ERR(p)) {
+ pr_debug("powerdomain: hardware cannot set/clear sleep "
+ "dependency affecting %s from %s\n", pwrdm1->name,
+ pwrdm2->name);
+ return IS_ERR(p);
+ }
+
+ return prm_read_mod_bits_shift(pwrdm1->prcm_offs, OMAP3430_CM_SLEEPDEP,
+ (1 << pwrdm2->dep_bit));
+}
+
+
+/**
+ * pwrdm_set_next_pwrst - set next powerdomain power state
+ * @pwrdm: struct powerdomain * to set
+ * @pwrst: one of the PWRDM_POWER_* macros
+ *
+ * Set the powerdomain pwrdm's next power state to pwrst. The powerdomain
+ * may not enter this state immediately if the preconditions for this state
+ * have not been satisfied. Returns -EINVAL if the powerdomain pointer is
+ * null or if the power state is invalid for the powerdomin, or returns 0
+ * upon success.
+ */
+int pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)
+{
+ if (!pwrdm)
+ return -EINVAL;
+
+ if (!(pwrdm->pwrsts & (1 << pwrst)))
+ return -EINVAL;
+
+ pr_debug("powerdomain: setting next powerstate for %s to %0x\n",
+ pwrdm->name, pwrst);
+
+ prm_rmw_mod_reg_bits(OMAP_POWERSTATE_MASK,
+ (pwrst << OMAP_POWERSTATE_SHIFT),
+ pwrdm->prcm_offs, PM_PWSTCTRL);
+
+ return 0;
+}
+
+/**
+ * pwrdm_read_next_pwrst - get next powerdomain power state
+ * @pwrdm: struct powerdomain * to get power state
+ *
+ * Return the powerdomain pwrdm's next power state. Returns -EINVAL
+ * if the powerdomain pointer is null or returns the next power state
+ * upon success.
+ */
+int pwrdm_read_next_pwrst(struct powerdomain *pwrdm)
+{
+ if (!pwrdm)
+ return -EINVAL;
+
+ return prm_read_mod_bits_shift(pwrdm->prcm_offs, PM_PWSTCTRL,
+ OMAP_POWERSTATE_MASK);
+}
+
+/**
+ * pwrdm_read_pwrst - get current powerdomain power state
+ * @pwrdm: struct powerdomain * to get power state
+ *
+ * Return the powerdomain pwrdm's current power state. Returns -EINVAL
+ * if the powerdomain pointer is null or returns the current power state
+ * upon success.
+ */
+int pwrdm_read_pwrst(struct powerdomain *pwrdm)
+{
+ if (!pwrdm)
+ return -EINVAL;
+
+ return prm_read_mod_bits_shift(pwrdm->prcm_offs, PM_PWSTST,
+ OMAP_POWERSTATEST_MASK);
+}
+
+/**
+ * pwrdm_read_prev_pwrst - get previous powerdomain power state
+ * @pwrdm: struct powerdomain * to get previous power state
+ *
+ * Return the powerdomain pwrdm's previous power state. Returns -EINVAL
+ * if the powerdomain pointer is null or returns the previous power state
+ * upon success.
+ */
+int pwrdm_read_prev_pwrst(struct powerdomain *pwrdm)
+{
+ if (!pwrdm)
+ return -EINVAL;
+
+ return prm_read_mod_bits_shift(pwrdm->prcm_offs, OMAP3430_PM_PREPWSTST,
+ OMAP3430_LASTPOWERSTATEENTERED_MASK);
+}
+
+/**
+ * pwrdm_set_logic_retst - set powerdomain logic power state upon retention
+ * @pwrdm: struct powerdomain * to set
+ * @pwrst: one of the PWRDM_POWER_* macros
+ *
+ * Set the next power state that the logic portion of the powerdomain
+ * pwrdm will enter when the powerdomain enters retention. This will
+ * be either RETENTION or OFF, if supported. Returns -EINVAL if the
+ * powerdomain pointer is null or the target power state is not not
+ * supported, or returns 0 upon success.
+ */
+int pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst)
+{
+ if (!pwrdm)
+ return -EINVAL;
+
+ if (!(pwrdm->pwrsts_logic_ret & (1 << pwrst)))
+ return -EINVAL;
+
+ pr_debug("powerdomain: setting next logic powerstate for %s to %0x\n",
+ pwrdm->name, pwrst);
+
+ /*
+ * The register bit names below may not correspond to the
+ * actual names of the bits in each powerdomain's register,
+ * but the type of value returned is the same for each
+ * powerdomain.
+ */
+ prm_rmw_mod_reg_bits(OMAP3430_LOGICL1CACHERETSTATE,
+ (pwrst << __ffs(OMAP3430_LOGICL1CACHERETSTATE)),
+ pwrdm->prcm_offs, PM_PWSTCTRL);
+
+ return 0;
+}
+
+/**
+ * pwrdm_set_mem_onst - set memory power state while powerdomain ON
+ * @pwrdm: struct powerdomain * to set
+ * @bank: memory bank number to set (0-3)
+ * @pwrst: one of the PWRDM_POWER_* macros
+ *
+ * Set the next power state that memory bank x of the powerdomain
+ * pwrdm will enter when the powerdomain enters the ON state. Bank
+ * will be a number from 0 to 3, and represents different types of
+ * memory, depending on the powerdomain. Returns -EINVAL if the
+ * powerdomain pointer is null or the target power state is not not
+ * supported for this memory bank, -EEXIST if the target memory bank
+ * does not exist or is not controllable, or returns 0 upon success.
+ */
+int pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)
+{
+ u32 m;
+
+ if (!pwrdm)
+ return -EINVAL;
+
+ if (pwrdm->banks < (bank + 1))
+ return -EEXIST;
+
+ if (!(pwrdm->pwrsts_mem_on[bank] & (1 << pwrst)))
+ return -EINVAL;
+
+ pr_debug("powerdomain: setting next memory powerstate for domain %s "
+ "bank %0x while pwrdm-ON to %0x\n", pwrdm->name, bank, pwrst);
+
+ /*
+ * The register bit names below may not correspond to the
+ * actual names of the bits in each powerdomain's register,
+ * but the type of value returned is the same for each
+ * powerdomain.
+ */
+ switch (bank) {
+ case 0:
+ m = OMAP3430_SHAREDL1CACHEFLATONSTATE_MASK;
+ break;
+ case 1:
+ m = OMAP3430_L1FLATMEMONSTATE_MASK;
+ break;
+ case 2:
+ m = OMAP3430_SHAREDL2CACHEFLATONSTATE_MASK;
+ break;
+ case 3:
+ m = OMAP3430_L2FLATMEMONSTATE_MASK;
+ break;
+ default:
+ WARN_ON(1); /* should never happen */
+ return -EEXIST;
+ }
+
+ prm_rmw_mod_reg_bits(m, (pwrst << __ffs(m)),
+ pwrdm->prcm_offs, PM_PWSTCTRL);
+
+ return 0;
+}
+
+/**
+ * pwrdm_set_mem_retst - set memory power state while powerdomain in RET
+ * @pwrdm: struct powerdomain * to set
+ * @bank: memory bank number to set (0-3)
+ * @pwrst: one of the PWRDM_POWER_* macros
+ *
+ * Set the next power state that memory bank x of the powerdomain
+ * pwrdm will enter when the powerdomain enters the RETENTION state.
+ * Bank will be a number from 0 to 3, and represents different types
+ * of memory, depending on the powerdomain. pwrst will be either
+ * RETENTION or OFF, if supported. Returns -EINVAL if the powerdomain
+ * pointer is null or the target power state is not not supported for
+ * this memory bank, -EEXIST if the target memory bank does not exist
+ * or is not controllable, or returns 0 upon success.
+ */
+int pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)
+{
+ u32 m;
+
+ if (!pwrdm)
+ return -EINVAL;
+
+ if (pwrdm->banks < (bank + 1))
+ return -EEXIST;
+
+ if (!(pwrdm->pwrsts_mem_ret[bank] & (1 << pwrst)))
+ return -EINVAL;
+
+ pr_debug("powerdomain: setting next memory powerstate for domain %s "
+ "bank %0x while pwrdm-RET to %0x\n", pwrdm->name, bank, pwrst);
+
+ /*
+ * The register bit names below may not correspond to the
+ * actual names of the bits in each powerdomain's register,
+ * but the type of value returned is the same for each
+ * powerdomain.
+ */
+ switch (bank) {
+ case 0:
+ m = OMAP3430_SHAREDL1CACHEFLATRETSTATE;
+ break;
+ case 1:
+ m = OMAP3430_L1FLATMEMRETSTATE;
+ break;
+ case 2:
+ m = OMAP3430_SHAREDL2CACHEFLATRETSTATE;
+ break;
+ case 3:
+ m = OMAP3430_L2FLATMEMRETSTATE;
+ break;
+ default:
+ WARN_ON(1); /* should never happen */
+ return -EEXIST;
+ }
+
+ prm_rmw_mod_reg_bits(m, (pwrst << __ffs(m)), pwrdm->prcm_offs,
+ PM_PWSTCTRL);
+
+ return 0;
+}
+
+/**
+ * pwrdm_read_logic_pwrst - get current powerdomain logic retention power state
+ * @pwrdm: struct powerdomain * to get current logic retention power state
+ *
+ * Return the current power state that the logic portion of
+ * powerdomain pwrdm will enter
+ * Returns -EINVAL if the powerdomain pointer is null or returns the
+ * current logic retention power state upon success.
+ */
+int pwrdm_read_logic_pwrst(struct powerdomain *pwrdm)
+{
+ if (!pwrdm)
+ return -EINVAL;
+
+ return prm_read_mod_bits_shift(pwrdm->prcm_offs, PM_PWSTST,
+ OMAP3430_LOGICSTATEST);
+}
+
+/**
+ * pwrdm_read_prev_logic_pwrst - get previous powerdomain logic power state
+ * @pwrdm: struct powerdomain * to get previous logic power state
+ *
+ * Return the powerdomain pwrdm's logic power state. Returns -EINVAL
+ * if the powerdomain pointer is null or returns the previous logic
+ * power state upon success.
+ */
+int pwrdm_read_prev_logic_pwrst(struct powerdomain *pwrdm)
+{
+ if (!pwrdm)
+ return -EINVAL;
+
+ /*
+ * The register bit names below may not correspond to the
+ * actual names of the bits in each powerdomain's register,
+ * but the type of value returned is the same for each
+ * powerdomain.
+ */
+ return prm_read_mod_bits_shift(pwrdm->prcm_offs, OMAP3430_PM_PREPWSTST,
+ OMAP3430_LASTLOGICSTATEENTERED);
+}
+
+/**
+ * pwrdm_read_mem_pwrst - get current memory bank power state
+ * @pwrdm: struct powerdomain * to get current memory bank power state
+ * @bank: memory bank number (0-3)
+ *
+ * Return the powerdomain pwrdm's current memory power state for bank
+ * x. Returns -EINVAL if the powerdomain pointer is null, -EEXIST if
+ * the target memory bank does not exist or is not controllable, or
+ * returns the current memory power state upon success.
+ */
+int pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
+{
+ u32 m;
+
+ if (!pwrdm)
+ return -EINVAL;
+
+ if (pwrdm->banks < (bank + 1))
+ return -EEXIST;
+
+ /*
+ * The register bit names below may not correspond to the
+ * actual names of the bits in each powerdomain's register,
+ * but the type of value returned is the same for each
+ * powerdomain.
+ */
+ switch (bank) {
+ case 0:
+ m = OMAP3430_SHAREDL1CACHEFLATSTATEST_MASK;
+ break;
+ case 1:
+ m = OMAP3430_L1FLATMEMSTATEST_MASK;
+ break;
+ case 2:
+ m = OMAP3430_SHAREDL2CACHEFLATSTATEST_MASK;
+ break;
+ case 3:
+ m = OMAP3430_L2FLATMEMSTATEST_MASK;
+ break;
+ default:
+ WARN_ON(1); /* should never happen */
+ return -EEXIST;
+ }
+
+ return prm_read_mod_bits_shift(pwrdm->prcm_offs, PM_PWSTST, m);
+}
+
+/**
+ * pwrdm_read_prev_mem_pwrst - get previous memory bank power state
+ * @pwrdm: struct powerdomain * to get previous memory bank power state
+ * @bank: memory bank number (0-3)
+ *
+ * Return the powerdomain pwrdm's previous memory power state for bank
+ * x. Returns -EINVAL if the powerdomain pointer is null, -EEXIST if
+ * the target memory bank does not exist or is not controllable, or
+ * returns the previous memory power state upon success.
+ */
+int pwrdm_read_prev_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
+{
+ u32 m;
+
+ if (!pwrdm)
+ return -EINVAL;
+
+ if (pwrdm->banks < (bank + 1))
+ return -EEXIST;
+
+ /*
+ * The register bit names below may not correspond to the
+ * actual names of the bits in each powerdomain's register,
+ * but the type of value returned is the same for each
+ * powerdomain.
+ */
+ switch (bank) {
+ case 0:
+ m = OMAP3430_LASTMEM1STATEENTERED_MASK;
+ break;
+ case 1:
+ m = OMAP3430_LASTMEM2STATEENTERED_MASK;
+ break;
+ case 2:
+ m = OMAP3430_LASTSHAREDL2CACHEFLATSTATEENTERED_MASK;
+ break;
+ case 3:
+ m = OMAP3430_LASTL2FLATMEMSTATEENTERED_MASK;
+ break;
+ default:
+ WARN_ON(1); /* should never happen */
+ return -EEXIST;
+ }
+
+ return prm_read_mod_bits_shift(pwrdm->prcm_offs,
+ OMAP3430_PM_PREPWSTST, m);
+}
+
+/**
+ * pwrdm_clear_all_prev_pwrst - clear previous powerstate register for a pwrdm
+ * @pwrdm: struct powerdomain * to clear
+ *
+ * Clear the powerdomain's previous power state register. Clears the
+ * entire register, including logic and memory bank previous power states.
+ * Returns -EINVAL if the powerdomain pointer is null, or returns 0 upon
+ * success.
+ */
+int pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm)
+{
+ if (!pwrdm)
+ return -EINVAL;
+
+ /*
+ * XXX should get the powerdomain's current state here;
+ * warn & fail if it is not ON.
+ */
+
+ pr_debug("powerdomain: clearing previous power state reg for %s\n",
+ pwrdm->name);
+
+ prm_write_mod_reg(0, pwrdm->prcm_offs, OMAP3430_PM_PREPWSTST);
+
+ return 0;
+}
+
+/**
+ * pwrdm_wait_transition - wait for powerdomain power transition to finish
+ * @pwrdm: struct powerdomain * to wait for
+ *
+ * If the powerdomain pwrdm is in the process of a state transition,
+ * spin until it completes the power transition, or until an iteration
+ * bailout value is reached. Returns -EINVAL if the powerdomain
+ * pointer is null, -EAGAIN if the bailout value was reached, or
+ * returns 0 upon success.
+ */
+int pwrdm_wait_transition(struct powerdomain *pwrdm)
+{
+ u32 c = 0;
+
+ if (!pwrdm)
+ return -EINVAL;
+
+ /*
+ * REVISIT: pwrdm_wait_transition() may be better implemented
+ * via a callback and a periodic timer check -- how long do we expect
+ * powerdomain transitions to take?
+ */
+
+ /* XXX Is this udelay() value meaningful? */
+ while ((prm_read_mod_reg(pwrdm->prcm_offs, PM_PWSTST) &
+ OMAP_INTRANSITION) &&
+ (c++ < PWRDM_TRANSITION_BAILOUT))
+ udelay(1);
+
+ if (c >= PWRDM_TRANSITION_BAILOUT) {
+ printk(KERN_ERR "powerdomain: waited too long for "
+ "powerdomain %s to complete transition\n", pwrdm->name);
+ return -EAGAIN;
+ }
+
+ pr_debug("powerdomain: completed transition in %d loops\n", c);
+
+ return 0;
+}
+
+
--- /dev/null
+/*
+ * OMAP2/3 common powerdomain definitions
+ *
+ * Copyright (C) 2007-8 Texas Instruments, Inc.
+ * Copyright (C) 2007-8 Nokia Corporation
+ *
+ * Written by Paul Walmsley
+ * Debugging and integration fixes by Jouni Högander
+ *
+ * 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 ARCH_ARM_MACH_OMAP2_POWERDOMAINS
+#define ARCH_ARM_MACH_OMAP2_POWERDOMAINS
+
+/*
+ * This file contains all of the powerdomains that have some element
+ * of software control for the OMAP24xx and OMAP34XX chips.
+ *
+ * A few notes:
+ *
+ * This is not an exhaustive listing of powerdomains on the chips; only
+ * powerdomains that can be controlled in software.
+ *
+ * A useful validation rule for struct powerdomain:
+ * Any powerdomain referenced by a wkdep_srcs or sleepdep_srcs array
+ * must have a dep_bit assigned. So wkdep_srcs/sleepdep_srcs are really
+ * just software-controllable dependencies. Non-software-controllable
+ * dependencies do exist, but they are not encoded below (yet).
+ *
+ * 24xx does not support programmable sleep dependencies (SLEEPDEP)
+ *
+ */
+
+/*
+ * The names for the DSP/IVA2 powerdomains are confusing.
+ *
+ * Most OMAP chips have an on-board DSP.
+ *
+ * On the 2420, this is a 'C55 DSP called, simply, the DSP. Its
+ * powerdomain is called the "DSP power domain." On the 2430, the
+ * on-board DSP is a 'C64 DSP, now called the IVA2 or IVA2.1. Its
+ * powerdomain is still called the "DSP power domain." On the 3430,
+ * the DSP is a 'C64 DSP like the 2430, also known as the IVA2; but
+ * its powerdomain is now called the "IVA2 power domain."
+ *
+ * The 2420 also has something called the IVA, which is a separate ARM
+ * core, and has nothing to do with the DSP/IVA2.
+ *
+ * Ideally the DSP/IVA2 could just be the same powerdomain, but the PRCM
+ * address offset is different between the C55 and C64 DSPs.
+ *
+ * The overly-specific dep_bit names are due to a bit name collision
+ * with CM_FCLKEN_{DSP,IVA2}. The DSP/IVA2 PM_WKDEP and CM_SLEEPDEP shift
+ * value are the same for all powerdomains: 2
+ */
+
+/*
+ * XXX should dep_bit be a mask, so we can test to see if it is 0 as a
+ * sanity check?
+ * XXX encode hardware fixed wakeup dependencies -- esp. for 3430 CORE
+ */
+
+#include <asm/arch/powerdomain.h>
+
+#include "prcm-common.h"
+#include "prm.h"
+#include "cm.h"
+
+/* OMAP2/3-common powerdomains and wakeup dependencies */
+
+/*
+ * 2420/2430 PM_WKDEP_GFX: CORE, MPU, WKUP
+ * 3430ES1 PM_WKDEP_GFX: adds IVA2, removes CORE
+ * 3430ES2 PM_WKDEP_SGX: adds IVA2, removes CORE
+ */
+static struct pwrdm_dep gfx_sgx_wkdeps[] = {
+ {
+ .pwrdm_name = "core_pwrdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX)
+ },
+ {
+ .pwrdm_name = "iva2_pwrdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+ },
+ {
+ .pwrdm_name = "mpu_pwrdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX |
+ CHIP_IS_OMAP3430)
+ },
+ {
+ .pwrdm_name = "wkup_pwrdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX |
+ CHIP_IS_OMAP3430)
+ },
+ { NULL },
+};
+
+/*
+ * 3430: CM_SLEEPDEP_CAM: MPU
+ * 3430ES1: CM_SLEEPDEP_GFX: MPU
+ * 3430ES2: CM_SLEEPDEP_SGX: MPU
+ */
+static struct pwrdm_dep cam_gfx_sleepdeps[] = {
+ {
+ .pwrdm_name = "mpu_pwrdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+ },
+ { NULL },
+};
+
+
+#include "powerdomains24xx.h"
+#include "powerdomains34xx.h"
+
+
+/*
+ * OMAP2/3 common powerdomains
+ */
+
+/*
+ * The GFX powerdomain is not present on 3430ES2, but currently we do not
+ * have a macro to filter it out at compile-time.
+ */
+static struct powerdomain gfx_pwrdm = {
+ .name = "gfx_pwrdm",
+ .prcm_offs = GFX_MOD,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX |
+ CHIP_IS_OMAP3430ES1),
+ .wkdep_srcs = gfx_sgx_wkdeps,
+ .sleepdep_srcs = cam_gfx_sleepdeps,
+ .pwrsts = PWRSTS_OFF_RET_ON,
+ .pwrsts_logic_ret = PWRDM_POWER_RET,
+ .banks = 1,
+ .pwrsts_mem_ret = {
+ [0] = PWRDM_POWER_RET, /* MEMRETSTATE */
+ },
+ .pwrsts_mem_on = {
+ [0] = PWRDM_POWER_ON, /* MEMONSTATE */
+ },
+};
+
+static struct powerdomain wkup_pwrdm = {
+ .name = "wkup_pwrdm",
+ .prcm_offs = WKUP_MOD,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX | CHIP_IS_OMAP3430),
+ .dep_bit = OMAP_EN_WKUP_SHIFT,
+};
+
+
+
+/* As powerdomains are added or removed above, this list must also be changed */
+static struct powerdomain *powerdomains_omap[] __initdata = {
+
+ &gfx_pwrdm,
+ &wkup_pwrdm,
+
+#ifdef CONFIG_ARCH_OMAP24XX
+ &dsp_pwrdm,
+ &mpu_24xx_pwrdm,
+ &core_24xx_pwrdm,
+#endif
+
+#ifdef CONFIG_ARCH_OMAP2430
+ &mdm_pwrdm,
+#endif
+
+#ifdef CONFIG_ARCH_OMAP34XX
+ &iva2_pwrdm,
+ &mpu_34xx_pwrdm,
+ &neon_pwrdm,
+ &core_34xx_pwrdm,
+ &cam_pwrdm,
+ &dss_pwrdm,
+ &per_pwrdm,
+ &emu_pwrdm,
+ &sgx_pwrdm,
+ &usbhost_pwrdm,
+#endif
+
+ NULL
+};
+
+
+#endif
--- /dev/null
+/*
+ * OMAP24XX powerdomain definitions
+ *
+ * Copyright (C) 2007-2008 Texas Instruments, Inc.
+ * Copyright (C) 2007-2008 Nokia Corporation
+ *
+ * Written by Paul Walmsley
+ * Debugging and integration fixes by Jouni Högander
+ *
+ * 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 ARCH_ARM_MACH_OMAP2_POWERDOMAINS24XX
+#define ARCH_ARM_MACH_OMAP2_POWERDOMAINS24XX
+
+/*
+ * N.B. If powerdomains are added or removed from this file, update
+ * the array in mach-omap2/powerdomains.h.
+ */
+
+#include <asm/arch/powerdomain.h>
+
+#include "prcm-common.h"
+#include "prm.h"
+#include "prm-regbits-24xx.h"
+#include "cm.h"
+#include "cm-regbits-24xx.h"
+
+/* 24XX powerdomains and dependencies */
+
+#ifdef CONFIG_ARCH_OMAP24XX
+
+
+/* Wakeup dependency source arrays */
+
+/*
+ * 2420/2430 PM_WKDEP_DSP: CORE, MPU, WKUP
+ * 2430 PM_WKDEP_MDM: same as above
+ */
+static struct pwrdm_dep dsp_mdm_24xx_wkdeps[] = {
+ {
+ .pwrdm_name = "core_pwrdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX)
+ },
+ {
+ .pwrdm_name = "mpu_pwrdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX)
+ },
+ {
+ .pwrdm_name = "wkup_pwrdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX)
+ },
+ { NULL },
+};
+
+/*
+ * 2420 PM_WKDEP_MPU: CORE, DSP, WKUP
+ * 2430 adds MDM
+ */
+static struct pwrdm_dep mpu_24xx_wkdeps[] = {
+ {
+ .pwrdm_name = "core_pwrdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX)
+ },
+ {
+ .pwrdm_name = "dsp_pwrdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX)
+ },
+ {
+ .pwrdm_name = "wkup_pwrdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX)
+ },
+ {
+ .pwrdm_name = "mdm_pwrdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430)
+ },
+ { NULL },
+};
+
+/*
+ * 2420 PM_WKDEP_CORE: DSP, GFX, MPU, WKUP
+ * 2430 adds MDM
+ */
+static struct pwrdm_dep core_24xx_wkdeps[] = {
+ {
+ .pwrdm_name = "dsp_pwrdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX)
+ },
+ {
+ .pwrdm_name = "gfx_pwrdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX)
+ },
+ {
+ .pwrdm_name = "mpu_pwrdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX)
+ },
+ {
+ .pwrdm_name = "wkup_pwrdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX)
+ },
+ {
+ .pwrdm_name = "mdm_pwrdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430)
+ },
+ { NULL },
+};
+
+
+/* Powerdomains */
+
+static struct powerdomain dsp_pwrdm = {
+ .name = "dsp_pwrdm",
+ .prcm_offs = OMAP24XX_DSP_MOD,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX),
+ .dep_bit = OMAP24XX_PM_WKDEP_MPU_EN_DSP_SHIFT,
+ .wkdep_srcs = dsp_mdm_24xx_wkdeps,
+ .pwrsts = PWRSTS_OFF_RET_ON,
+ .pwrsts_logic_ret = PWRDM_POWER_RET,
+ .banks = 1,
+ .pwrsts_mem_ret = {
+ [0] = PWRDM_POWER_RET,
+ },
+ .pwrsts_mem_on = {
+ [0] = PWRDM_POWER_ON,
+ },
+};
+
+static struct powerdomain mpu_24xx_pwrdm = {
+ .name = "mpu_pwrdm",
+ .prcm_offs = MPU_MOD,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX),
+ .dep_bit = OMAP24XX_EN_MPU_SHIFT,
+ .wkdep_srcs = mpu_24xx_wkdeps,
+ .pwrsts = PWRSTS_OFF_RET_ON,
+ .pwrsts_logic_ret = PWRSTS_OFF_RET,
+ .banks = 1,
+ .pwrsts_mem_ret = {
+ [0] = PWRDM_POWER_RET,
+ },
+ .pwrsts_mem_on = {
+ [0] = PWRDM_POWER_ON,
+ },
+};
+
+static struct powerdomain core_24xx_pwrdm = {
+ .name = "core_pwrdm",
+ .prcm_offs = CORE_MOD,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX),
+ .wkdep_srcs = core_24xx_wkdeps,
+ .pwrsts = PWRSTS_OFF_RET_ON,
+ .dep_bit = OMAP24XX_EN_CORE_SHIFT,
+ .banks = 3,
+ .pwrsts_mem_ret = {
+ [0] = PWRSTS_OFF_RET, /* MEM1RETSTATE */
+ [1] = PWRSTS_OFF_RET, /* MEM2RETSTATE */
+ [2] = PWRSTS_OFF_RET, /* MEM3RETSTATE */
+ },
+ .pwrsts_mem_on = {
+ [0] = PWRSTS_OFF_RET_ON, /* MEM1ONSTATE */
+ [1] = PWRSTS_OFF_RET_ON, /* MEM2ONSTATE */
+ [2] = PWRSTS_OFF_RET_ON, /* MEM3ONSTATE */
+ },
+};
+
+#endif /* CONFIG_ARCH_OMAP24XX */
+
+
+
+/*
+ * 2430-specific powerdomains
+ */
+
+#ifdef CONFIG_ARCH_OMAP2430
+
+/* XXX 2430 KILLDOMAINWKUP bit? No current users apparently */
+
+/* Another case of bit name collisions between several registers: EN_MDM */
+static struct powerdomain mdm_pwrdm = {
+ .name = "mdm_pwrdm",
+ .prcm_offs = OMAP2430_MDM_MOD,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430),
+ .dep_bit = OMAP2430_PM_WKDEP_MPU_EN_MDM_SHIFT,
+ .wkdep_srcs = dsp_mdm_24xx_wkdeps,
+ .pwrsts = PWRSTS_OFF_RET_ON,
+ .pwrsts_logic_ret = PWRDM_POWER_RET,
+ .banks = 1,
+ .pwrsts_mem_ret = {
+ [0] = PWRDM_POWER_RET, /* MEMRETSTATE */
+ },
+ .pwrsts_mem_on = {
+ [0] = PWRDM_POWER_ON, /* MEMONSTATE */
+ },
+};
+
+#endif /* CONFIG_ARCH_OMAP2430 */
+
+
+#endif
--- /dev/null
+/*
+ * OMAP34XX powerdomain definitions
+ *
+ * Copyright (C) 2007-2008 Texas Instruments, Inc.
+ * Copyright (C) 2007-2008 Nokia Corporation
+ *
+ * Written by Paul Walmsley
+ * Debugging and integration fixes by Jouni Högander
+ *
+ * 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 ARCH_ARM_MACH_OMAP2_POWERDOMAINS34XX
+#define ARCH_ARM_MACH_OMAP2_POWERDOMAINS34XX
+
+/*
+ * N.B. If powerdomains are added or removed from this file, update
+ * the array in mach-omap2/powerdomains.h.
+ */
+
+#include <asm/arch/powerdomain.h>
+
+#include "prcm-common.h"
+#include "prm.h"
+#include "prm-regbits-34xx.h"
+#include "cm.h"
+#include "cm-regbits-34xx.h"
+
+/*
+ * 34XX-specific powerdomains, dependencies
+ */
+
+#ifdef CONFIG_ARCH_OMAP34XX
+
+/*
+ * 3430: PM_WKDEP_{PER,USBHOST}: CORE, IVA2, MPU, WKUP
+ * (USBHOST is ES2 only)
+ */
+static struct pwrdm_dep per_usbhost_wkdeps[] = {
+ {
+ .pwrdm_name = "core_pwrdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+ },
+ {
+ .pwrdm_name = "iva2_pwrdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+ },
+ {
+ .pwrdm_name = "mpu_pwrdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+ },
+ {
+ .pwrdm_name = "wkup_pwrdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+ },
+ { NULL },
+};
+
+/*
+ * 3430 PM_WKDEP_MPU: CORE, IVA2, DSS, PER
+ */
+static struct pwrdm_dep mpu_34xx_wkdeps[] = {
+ {
+ .pwrdm_name = "core_pwrdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+ },
+ {
+ .pwrdm_name = "iva2_pwrdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+ },
+ {
+ .pwrdm_name = "dss_pwrdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+ },
+ {
+ .pwrdm_name = "per_pwrdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+ },
+ { NULL },
+};
+
+/*
+ * 3430 PM_WKDEP_IVA2: CORE, MPU, WKUP, DSS, PER
+ */
+static struct pwrdm_dep iva2_wkdeps[] = {
+ {
+ .pwrdm_name = "core_pwrdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+ },
+ {
+ .pwrdm_name = "mpu_pwrdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+ },
+ {
+ .pwrdm_name = "wkup_pwrdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+ },
+ {
+ .pwrdm_name = "dss_pwrdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+ },
+ {
+ .pwrdm_name = "per_pwrdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+ },
+ { NULL },
+};
+
+
+/* 3430 PM_WKDEP_{CAM,DSS}: IVA2, MPU, WKUP */
+static struct pwrdm_dep cam_dss_wkdeps[] = {
+ {
+ .pwrdm_name = "iva2_pwrdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+ },
+ {
+ .pwrdm_name = "mpu_pwrdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+ },
+ {
+ .pwrdm_name = "wkup_pwrdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+ },
+ { NULL },
+};
+
+/* 3430: PM_WKDEP_NEON: MPU */
+static struct pwrdm_dep neon_wkdeps[] = {
+ {
+ .pwrdm_name = "mpu_pwrdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+ },
+ { NULL },
+};
+
+
+/* Sleep dependency source arrays for 34xx-specific pwrdms - 34XX only */
+
+/*
+ * 3430: CM_SLEEPDEP_{DSS,PER}: MPU, IVA
+ * 3430ES2: CM_SLEEPDEP_USBHOST: MPU, IVA
+ */
+static struct pwrdm_dep dss_per_usbhost_sleepdeps[] = {
+ {
+ .pwrdm_name = "mpu_pwrdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+ },
+ {
+ .pwrdm_name = "iva2_pwrdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+ },
+ { NULL },
+};
+
+
+/*
+ * Powerdomains
+ */
+
+static struct powerdomain iva2_pwrdm = {
+ .name = "iva2_pwrdm",
+ .prcm_offs = OMAP3430_IVA2_MOD,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+ .dep_bit = OMAP3430_PM_WKDEP_MPU_EN_IVA2_SHIFT,
+ .wkdep_srcs = iva2_wkdeps,
+ .pwrsts = PWRSTS_OFF_RET_ON,
+ .pwrsts_logic_ret = PWRSTS_OFF_RET,
+ .banks = 4,
+ .pwrsts_mem_ret = {
+ [0] = PWRSTS_OFF_RET,
+ [1] = PWRSTS_OFF_RET,
+ [2] = PWRSTS_OFF_RET,
+ [3] = PWRSTS_OFF_RET,
+ },
+ .pwrsts_mem_on = {
+ [0] = PWRDM_POWER_ON,
+ [1] = PWRDM_POWER_ON,
+ [2] = PWRSTS_OFF_ON,
+ [3] = PWRDM_POWER_ON,
+ },
+};
+
+static struct powerdomain mpu_34xx_pwrdm = {
+ .name = "mpu_pwrdm",
+ .prcm_offs = MPU_MOD,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+ .dep_bit = OMAP3430_EN_MPU_SHIFT,
+ .wkdep_srcs = mpu_34xx_wkdeps,
+ .pwrsts = PWRSTS_OFF_RET_ON,
+ .pwrsts_logic_ret = PWRSTS_OFF_RET,
+ .banks = 1,
+ .pwrsts_mem_ret = {
+ [0] = PWRSTS_OFF_RET,
+ },
+ .pwrsts_mem_on = {
+ [0] = PWRSTS_OFF_ON,
+ },
+};
+
+/* No wkdeps or sleepdeps for 34xx core apparently */
+static struct powerdomain core_34xx_pwrdm = {
+ .name = "core_pwrdm",
+ .prcm_offs = CORE_MOD,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+ .pwrsts = PWRSTS_OFF_RET_ON,
+ .dep_bit = OMAP3430_EN_CORE_SHIFT,
+ .banks = 2,
+ .pwrsts_mem_ret = {
+ [0] = PWRSTS_OFF_RET, /* MEM1RETSTATE */
+ [1] = PWRSTS_OFF_RET, /* MEM2RETSTATE */
+ },
+ .pwrsts_mem_on = {
+ [0] = PWRSTS_OFF_RET_ON, /* MEM1ONSTATE */
+ [1] = PWRSTS_OFF_RET_ON, /* MEM2ONSTATE */
+ },
+};
+
+/* Another case of bit name collisions between several registers: EN_DSS */
+static struct powerdomain dss_pwrdm = {
+ .name = "dss_pwrdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+ .prcm_offs = OMAP3430_DSS_MOD,
+ .dep_bit = OMAP3430_PM_WKDEP_MPU_EN_DSS_SHIFT,
+ .wkdep_srcs = cam_dss_wkdeps,
+ .sleepdep_srcs = dss_per_usbhost_sleepdeps,
+ .pwrsts = PWRSTS_OFF_RET_ON,
+ .pwrsts_logic_ret = PWRDM_POWER_RET,
+ .banks = 1,
+ .pwrsts_mem_ret = {
+ [0] = PWRDM_POWER_RET, /* MEMRETSTATE */
+ },
+ .pwrsts_mem_on = {
+ [0] = PWRDM_POWER_ON, /* MEMONSTATE */
+ },
+};
+
+static struct powerdomain sgx_pwrdm = {
+ .name = "sgx_pwrdm",
+ .prcm_offs = OMAP3430ES2_SGX_MOD,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES2),
+ .wkdep_srcs = gfx_sgx_wkdeps,
+ .sleepdep_srcs = cam_gfx_sleepdeps,
+ /* XXX This is accurate for 3430 SGX, but what about GFX? */
+ .pwrsts = PWRSTS_OFF_RET_ON,
+ .pwrsts_logic_ret = PWRDM_POWER_RET,
+ .banks = 1,
+ .pwrsts_mem_ret = {
+ [0] = PWRDM_POWER_RET, /* MEMRETSTATE */
+ },
+ .pwrsts_mem_on = {
+ [0] = PWRDM_POWER_ON, /* MEMONSTATE */
+ },
+};
+
+static struct powerdomain cam_pwrdm = {
+ .name = "cam_pwrdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+ .prcm_offs = OMAP3430_CAM_MOD,
+ .wkdep_srcs = cam_dss_wkdeps,
+ .sleepdep_srcs = cam_gfx_sleepdeps,
+ .pwrsts = PWRSTS_OFF_RET_ON,
+ .pwrsts_logic_ret = PWRDM_POWER_RET,
+ .banks = 1,
+ .pwrsts_mem_ret = {
+ [0] = PWRDM_POWER_RET, /* MEMRETSTATE */
+ },
+ .pwrsts_mem_on = {
+ [0] = PWRDM_POWER_ON, /* MEMONSTATE */
+ },
+};
+
+static struct powerdomain per_pwrdm = {
+ .name = "per_pwrdm",
+ .prcm_offs = OMAP3430_PER_MOD,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+ .dep_bit = OMAP3430_EN_PER_SHIFT,
+ .wkdep_srcs = per_usbhost_wkdeps,
+ .sleepdep_srcs = dss_per_usbhost_sleepdeps,
+ .pwrsts = PWRSTS_OFF_RET_ON,
+ .pwrsts_logic_ret = PWRSTS_OFF_RET,
+ .banks = 1,
+ .pwrsts_mem_ret = {
+ [0] = PWRDM_POWER_RET, /* MEMRETSTATE */
+ },
+ .pwrsts_mem_on = {
+ [0] = PWRDM_POWER_ON, /* MEMONSTATE */
+ },
+};
+
+static struct powerdomain emu_pwrdm = {
+ .name = "emu_pwrdm",
+ .prcm_offs = OMAP3430_EMU_MOD,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct powerdomain neon_pwrdm = {
+ .name = "neon_pwrdm",
+ .prcm_offs = OMAP3430_NEON_MOD,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+ .wkdep_srcs = neon_wkdeps,
+ .pwrsts = PWRSTS_OFF_RET_ON,
+ .pwrsts_logic_ret = PWRDM_POWER_RET,
+};
+
+static struct powerdomain usbhost_pwrdm = {
+ .name = "usbhost_pwrdm",
+ .prcm_offs = OMAP3430ES2_USBHOST_MOD,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES2),
+ .wkdep_srcs = per_usbhost_wkdeps,
+ .sleepdep_srcs = dss_per_usbhost_sleepdeps,
+ .pwrsts = PWRSTS_OFF_RET_ON,
+ .pwrsts_logic_ret = PWRDM_POWER_RET,
+ .banks = 1,
+ .pwrsts_mem_ret = {
+ [0] = PWRDM_POWER_RET, /* MEMRETSTATE */
+ },
+ .pwrsts_mem_on = {
+ [0] = PWRDM_POWER_ON, /* MEMONSTATE */
+ },
+};
+
+#endif /* CONFIG_ARCH_OMAP34XX */
+
+
+#endif
#define OMAP3430_ST_GPT2 (1 << 3)
/* CM_SLEEPDEP_PER, PM_WKDEP_IVA2, PM_WKDEP_MPU, PM_WKDEP_PER shared bits */
-#define OMAP3430_EN_CORE (1 << 0)
+#define OMAP3430_EN_CORE_SHIFT 0
+#define OMAP3430_EN_CORE_MASK (1 << 0)
#endif
#include <linux/module.h>
#include <linux/init.h>
#include <linux/clk.h>
-
-#include <asm/io.h>
+#include <linux/io.h>
#include "prm.h"
#include "prm-regbits-24xx.h"
u32 omap_prcm_get_reset_sources(void)
{
+ /* XXX This presumably needs modification for 34XX */
return prm_read_mod_reg(WKUP_MOD, RM_RSTST) & 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 wkup;
+ s16 prcm_offs;
omap2_clk_prepare_for_reboot();
if (cpu_is_omap24xx()) {
- wkup = prm_read_mod_reg(WKUP_MOD, RM_RSTCTRL) | OMAP_RST_DPLL3;
- prm_write_mod_reg(wkup, WKUP_MOD, RM_RSTCTRL);
+ prcm_offs = WKUP_MOD;
+ } else if (cpu_is_omap34xx()) {
+ prcm_offs = OMAP3430_GR_MOD;
+ } else {
+ WARN_ON(1);
}
+
+ prm_set_mod_reg_bits(OMAP_RST_DPLL3, prcm_offs, RM_RSTCTRL);
}
#define OMAP24XX_WKUP1_EN (1 << 0)
/* PM_WKDEP_GFX, PM_WKDEP_MPU, PM_WKDEP_DSP, PM_WKDEP_MDM shared bits */
-#define OMAP24XX_EN_MPU (1 << 1)
-#define OMAP24XX_EN_CORE (1 << 0)
+#define OMAP24XX_EN_MPU_SHIFT 1
+#define OMAP24XX_EN_MPU_MASK (1 << 1)
+#define OMAP24XX_EN_CORE_SHIFT 0
+#define OMAP24XX_EN_CORE_MASK (1 << 0)
/*
* PM_PWSTCTRL_MPU, PM_PWSTCTRL_GFX, PM_PWSTCTRL_DSP, PM_PWSTCTRL_MDM
/* 2430 calls GLOBALWMPU_RST "GLOBALWARM_RST" instead */
/* PM_WKDEP_MPU specific bits */
-#define OMAP2430_PM_WKDEP_MPU_EN_MDM (1 << 5)
-#define OMAP24XX_PM_WKDEP_MPU_EN_DSP (1 << 2)
+#define OMAP2430_PM_WKDEP_MPU_EN_MDM_SHIFT 5
+#define OMAP2430_PM_WKDEP_MPU_EN_MDM_MASK (1 << 5)
+#define OMAP24XX_PM_WKDEP_MPU_EN_DSP_SHIFT 2
+#define OMAP24XX_PM_WKDEP_MPU_EN_DSP_MASK (1 << 2)
/* PM_EVGENCTRL_MPU specific bits */
#define OMAP3430_VPINIDLE (1 << 0)
/* PM_WKDEP_IVA2, PM_WKDEP_MPU shared bits */
-#define OMAP3430_EN_PER (1 << 7)
+#define OMAP3430_EN_PER_SHIFT 7
+#define OMAP3430_EN_PER_MASK (1 << 7)
/* PM_PWSTCTRL_IVA2, PM_PWSTCTRL_MPU, PM_PWSTCTRL_CORE shared bits */
#define OMAP3430_MEMORYCHANGE (1 << 3)
#define OMAP3430_LOGICSTATEST (1 << 2)
/* PM_PREPWSTST_IVA2, PM_PREPWSTST_CORE shared bits */
-#define OMAP3430_LASTLOGICSTATEENTERED (1 << 2)
+#define OMAP3430_LASTLOGICSTATEENTERED (1 << 2)
/*
* PM_PREPWSTST_IVA2, PM_PREPWSTST_MPU, PM_PREPWSTST_CORE,
#define OMAP3430_EMULATION_MPU_RST (1 << 11)
/* PM_WKDEP_MPU specific bits */
-#define OMAP3430_PM_WKDEP_MPU_EN_DSS (1 << 5)
-#define OMAP3430_PM_WKDEP_MPU_EN_IVA2 (1 << 2)
+#define OMAP3430_PM_WKDEP_MPU_EN_DSS_SHIFT 5
+#define OMAP3430_PM_WKDEP_MPU_EN_DSS_MASK (1 << 5)
+#define OMAP3430_PM_WKDEP_MPU_EN_IVA2_SHIFT 2
+#define OMAP3430_PM_WKDEP_MPU_EN_IVA2_MASK (1 << 2)
/* PM_EVGENCTRL_MPU */
#define OMAP3430_OFFLOADMODE_SHIFT 3
/*
* OMAP2/3 Power/Reset Management (PRM) register definitions
*
- * Copyright (C) 2007 Texas Instruments, Inc.
- * Copyright (C) 2007 Nokia Corporation
+ * Copyright (C) 2007-2008 Texas Instruments, Inc.
+ * Copyright (C) 2007-2008 Nokia Corporation
*
* Written by Paul Walmsley
*
* published by the Free Software Foundation.
*/
+#include <asm/io.h>
+#include <asm/bitops.h>
+
#include "prcm-common.h"
#ifndef __ASSEMBLER__
/*
* Architecture-specific global PRM registers
- * Use prm_{read,write}_reg() with these registers.
+ * Use __raw_{read,write}l() with these registers.
*
* With a few exceptions, these are the register names beginning with
* PRCM_* on 24xx, and PRM_* on 34xx. (The exceptions are the
#define OMAP3430_PRM_IRQSTATUS_MPU OMAP_PRM_REGADDR(OCP_MOD, 0x0018)
#define OMAP3430_PRM_IRQENABLE_MPU OMAP_PRM_REGADDR(OCP_MOD, 0x001c)
-
#define OMAP3430_PRM_VC_SMPS_SA OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0020)
#define OMAP3430_PRM_VC_SMPS_VOL_RA OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0024)
#define OMAP3430_PRM_VC_SMPS_CMD_RA OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0028)
#define OMAP3430_PRM_CLKSEL OMAP_PRM_REGADDR(OMAP3430_CCR_MOD, 0x0040)
#define OMAP3430_PRM_CLKOUT_CTRL OMAP_PRM_REGADDR(OMAP3430_CCR_MOD, 0x0070)
+#ifndef __ASSEMBLER__
+
+/* Read-modify-write bits in a PRM register */
+static __inline__ u32 __attribute__((unused)) prm_rmw_reg_bits(u32 mask,
+ u32 bits, void __iomem *va)
+{
+ u32 v;
+
+ v = __raw_readl(va);
+ v &= ~mask;
+ v |= bits;
+ __raw_writel(v, va);
+
+ return v;
+}
+
+#endif
+
/*
* Module specific PRM registers from PRM_BASE + domain offset
*
#define OMAP3430_PRM_IRQSTATUS_IVA2 0x00f8
#define OMAP3430_PRM_IRQENABLE_IVA2 0x00fc
+/* Read-modify-write bits in a PRM register (by domain) */
+static u32 __attribute__((unused)) prm_rmw_mod_reg_bits(u32 mask, u32 bits,
+ s16 module, s16 idx)
+{
+ return prm_rmw_reg_bits(mask, bits, OMAP_PRM_REGADDR(module, idx));
+}
+
+static u32 __attribute__((unused)) prm_set_mod_reg_bits(u32 bits, s16 module, s16 idx)
+{
+ return prm_rmw_mod_reg_bits(bits, bits, module, idx);
+}
+
+static u32 __attribute__((unused)) prm_clear_mod_reg_bits(u32 bits, s16 module, s16 idx)
+{
+ return prm_rmw_mod_reg_bits(bits, 0x0, module, idx);
+}
/* Architecture-specific registers */
/* Power/reset management domain register get/set */
-static inline void prm_write_mod_reg(u32 val, s16 module, s16 idx)
+static __inline__ void __attribute__((unused)) prm_write_mod_reg(u32 val,
+ s16 module, s16 idx)
{
__raw_writel(val, OMAP_PRM_REGADDR(module, idx));
}
-static inline u32 prm_read_mod_reg(s16 module, s16 idx)
+static __inline__ u32 __attribute__((unused)) prm_read_mod_reg(s16 module,
+ s16 idx)
{
return __raw_readl(OMAP_PRM_REGADDR(module, idx));
}
* 3430: PM_WKDEP_IVA2, PM_WKDEP_GFX, PM_WKDEP_DSS, PM_WKDEP_CAM,
* PM_WKDEP_PER
*/
-#define OMAP_EN_WKUP (1 << 4)
+#define OMAP_EN_WKUP_SHIFT 4
+#define OMAP_EN_WKUP_MASK (1 << 4)
/*
* 24XX: PM_PWSTCTRL_MPU, PM_PWSTCTRL_CORE, PM_PWSTCTRL_GFX,
/* SDRC global register get/set */
-static inline void sdrc_write_reg(u32 val, u16 reg)
+static void __attribute__((unused)) sdrc_write_reg(u32 val, u16 reg)
{
+ pr_debug("sdrc_write_reg: writing 0x%0x to 0x%0x\n", val,
+ (u32)OMAP_SDRC_REGADDR(reg));
+
__raw_writel(val, OMAP_SDRC_REGADDR(reg));
}
-static inline u32 sdrc_read_reg(u16 reg)
+static u32 __attribute__((unused)) sdrc_read_reg(u16 reg)
{
return __raw_readl(OMAP_SDRC_REGADDR(reg));
}
/* SMS global register get/set */
-static inline void sms_write_reg(u32 val, u16 reg)
+static void __attribute__((unused)) sms_write_reg(u32 val, u16 reg)
{
+ pr_debug("sms_write_reg: writing 0x%0x to 0x%0x\n", val,
+ (u32)OMAP_SMS_REGADDR(reg));
+
__raw_writel(val, OMAP_SMS_REGADDR(reg));
}
-static inline u32 sms_read_reg(u16 reg)
+static u32 __attribute__((unused)) sms_read_reg(u16 reg)
{
return __raw_readl(OMAP_SMS_REGADDR(reg));
}
*
* OMAP2 serial support.
*
- * Copyright (C) 2005 Nokia Corporation
+ * Copyright (C) 2005-2008 Nokia Corporation
* Author: Paul Mundt <paul.mundt@nokia.com>
*
* Based off of arch/arm/mach-omap/omap1/serial.c
#include <linux/serial_reg.h>
#include <linux/clk.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/arch/common.h>
#include <asm/arch/board.h>
-static struct clk * uart1_ick = NULL;
-static struct clk * uart1_fck = NULL;
-static struct clk * uart2_ick = NULL;
-static struct clk * uart2_fck = NULL;
-static struct clk * uart3_ick = NULL;
-static struct clk * uart3_fck = NULL;
+static struct clk *uart_ick[OMAP_MAX_NR_PORTS];
+static struct clk *uart_fck[OMAP_MAX_NR_PORTS];
static struct plat_serial8250_port serial_platform_data[] = {
{
.flags = UPF_BOOT_AUTOCONF,
.iotype = UPIO_MEM,
.regshift = 2,
- .uartclk = OMAP16XX_BASE_BAUD * 16,
+ .uartclk = OMAP24XX_BASE_BAUD * 16,
}, {
.membase = (char *)IO_ADDRESS(OMAP_UART2_BASE),
.mapbase = (unsigned long)OMAP_UART2_BASE,
.flags = UPF_BOOT_AUTOCONF,
.iotype = UPIO_MEM,
.regshift = 2,
- .uartclk = OMAP16XX_BASE_BAUD * 16,
+ .uartclk = OMAP24XX_BASE_BAUD * 16,
}, {
.membase = (char *)IO_ADDRESS(OMAP_UART3_BASE),
.mapbase = (unsigned long)OMAP_UART3_BASE,
.flags = UPF_BOOT_AUTOCONF,
.iotype = UPIO_MEM,
.regshift = 2,
- .uartclk = OMAP16XX_BASE_BAUD * 16,
+ .uartclk = OMAP24XX_BASE_BAUD * 16,
}, {
.flags = 0
}
serial_write_reg(p, UART_OMAP_SYSC, (0x02 << 3) | (1 << 2) | (1 << 0));
}
-void __init omap_serial_init()
+void omap_serial_enable_clocks(int enable)
+{
+ int i;
+ for (i = 0; i < OMAP_MAX_NR_PORTS; i++) {
+ if (uart_ick[i])
+ enable ? clk_enable(uart_ick[i]) :
+ clk_disable(uart_ick[i]);
+ if (uart_fck[i])
+ enable ? clk_enable(uart_fck[i]) :
+ clk_disable(uart_fck[i]);
+ }
+}
+
+void __init omap_serial_init(void)
{
int i;
const struct omap_uart_config *info;
+ char name[16];
/*
* Make sure the serial ports are muxed on at this point.
* if not needed.
*/
- info = omap_get_config(OMAP_TAG_UART,
- struct omap_uart_config);
+ info = omap_get_config(OMAP_TAG_UART, struct omap_uart_config);
if (info == NULL)
return;
continue;
}
- switch (i) {
- case 0:
- uart1_ick = clk_get(NULL, "uart1_ick");
- if (IS_ERR(uart1_ick))
- printk("Could not get uart1_ick\n");
- else {
- clk_enable(uart1_ick);
- }
-
- uart1_fck = clk_get(NULL, "uart1_fck");
- if (IS_ERR(uart1_fck))
- printk("Could not get uart1_fck\n");
- else {
- clk_enable(uart1_fck);
- }
- break;
- case 1:
- uart2_ick = clk_get(NULL, "uart2_ick");
- if (IS_ERR(uart2_ick))
- printk("Could not get uart2_ick\n");
- else {
- clk_enable(uart2_ick);
- }
-
- uart2_fck = clk_get(NULL, "uart2_fck");
- if (IS_ERR(uart2_fck))
- printk("Could not get uart2_fck\n");
- else {
- clk_enable(uart2_fck);
- }
- break;
- case 2:
- uart3_ick = clk_get(NULL, "uart3_ick");
- if (IS_ERR(uart3_ick))
- printk("Could not get uart3_ick\n");
- else {
- clk_enable(uart3_ick);
- }
-
- uart3_fck = clk_get(NULL, "uart3_fck");
- if (IS_ERR(uart3_fck))
- printk("Could not get uart3_fck\n");
- else {
- clk_enable(uart3_fck);
- }
- break;
- }
+ sprintf(name, "uart%d_ick", i+1);
+ uart_ick[i] = clk_get(NULL, name);
+ if (IS_ERR(uart_ick[i])) {
+ printk(KERN_ERR "Could not get uart%d_ick\n", i+1);
+ uart_ick[i] = NULL;
+ } else
+ clk_enable(uart_ick[i]);
+
+ sprintf(name, "uart%d_fck", i+1);
+ uart_fck[i] = clk_get(NULL, name);
+ if (IS_ERR(uart_fck[i])) {
+ printk(KERN_ERR "Could not get uart%d_fck\n", i+1);
+ uart_fck[i] = NULL;
+ } else
+ clk_enable(uart_fck[i]);
omap_serial_reset(p);
}
* Texas Instruments, <www.ti.com>
* Richard Woodruff <r-woodruff2@ti.com>
*
+ * (C) Copyright 2006 Nokia Corporation
+ * Fixed idle loop sleep
+ * Igor Stoppa <igor.stoppa@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
*/
#include <linux/linkage.h>
+#include <linux/poison.h> /* for SRAM_VA_MAGIC */
#include <asm/assembler.h>
#include <asm/arch/io.h>
#include <asm/arch/pm.h>
-#include "sdrc.h"
+#include <asm/arch/omap24xx.h>
/* First address of reserved address space? apparently valid for OMAP2 & 3 */
#define A_SDRC0_V (0xC0000000)
*/
ENTRY(omap24xx_idle_loop_suspend)
stmfd sp!, {r0, lr} @ save registers on stack
- mov r0, #0 @ clear for mcr setup
+ mov r0, #0x0 @ clear for mrc call
mcr p15, 0, r0, c7, c0, 4 @ wait for interrupt
ldmfd sp!, {r0, pc} @ restore regs and return
*
* 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
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 r3, omap2_ocs_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)
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
+ ldrne r1, omap2_ocs_sdrc_dlla_ctrl @ 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
/* resume*/
ldmfd sp!, {r0 - r12, pc} @ restore regs and return
-A_SDRC_POWER:
- .word OMAP242X_SDRC_REGADDR(SDRC_POWER)
+ .globl omap2_ocs_sdrc_power
+ .globl omap2_ocs_sdrc_dlla_ctrl
+
+omap2_ocs_sdrc_power:
+ .word SRAM_VA_MAGIC
A_SDRC0:
.word A_SDRC0_V
-A_SDRC_DLLA_CTRL_S:
- .word OMAP242X_SDRC_REGADDR(SDRC_DLLA_CTRL)
+omap2_ocs_sdrc_dlla_ctrl:
+ .word SRAM_VA_MAGIC
ENTRY(omap24xx_cpu_suspend_sz)
.word . - omap24xx_cpu_suspend
#include <asm/assembler.h>
#include <asm/arch/io.h>
#include <asm/hardware.h>
-
-#include "sdrc.h"
-#include "prm.h"
-#include "cm.h"
-
-#define TIMER_32KSYNCT_CR_V IO_ADDRESS(OMAP2420_32KSYNCT_BASE + 0x010)
+#include <linux/poison.h>
.text
-ENTRY(sram_ddr_init)
+ENTRY(omap24xx_sram_ddr_init)
stmfd sp!, {r0 - r12, lr} @ save registers on stack
mov r12, r2 @ capture CS1 vs CS0
mov r8, r3 @ capture force parameter
/* frequency shift down */
- ldr r2, cm_clksel2_pll @ get address of dpllout reg
+ ldr r2, omap24xx_sdi_cm_clksel2_pll @ get address of dpllout reg
mov r3, #0x1 @ value for 1x operation
str r3, [r2] @ go to L1-freq operation
bl voltage_shift @ go drop voltage
/* dll lock mode */
- ldr r11, sdrc_dlla_ctrl @ addr of dlla ctrl
+ ldr r11, omap24xx_sdi_sdrc_dlla_ctrl @ addr of dlla ctrl
ldr r10, [r11] @ get current val
cmp r12, #0x1 @ cs1 base (2422 es2.05/1)
addeq r11, r11, #0x8 @ if cs1 base, move to DLLB
* wait for it to finish, use 32k sync counter, 1tick=31uS.
*/
voltage_shift:
- ldr r4, prcm_voltctrl @ get addr of volt ctrl.
+ ldr r4, omap24xx_sdi_prcm_voltctrl @ get addr of volt ctrl.
ldr r5, [r4] @ get value.
ldr r6, prcm_mask_val @ get value of mask
and r5, r5, r6 @ apply mask to clear bits
orr r5, r5, r3 @ build value for force
str r5, [r4] @ Force transition to L1
- ldr r3, timer_32ksynct_cr @ get addr of counter
+ ldr r3, omap24xx_sdi_timer_32ksynct_cr @ get addr of counter
ldr r5, [r3] @ get value
add r5, r5, #0x3 @ give it at most 93uS
volt_delay:
mov pc, lr @ back to caller.
/* relative load constants */
-cm_clksel2_pll:
- .word OMAP2420_CM_REGADDR(PLL_MOD, CM_CLKSEL2)
-sdrc_dlla_ctrl:
- .word OMAP242X_SDRC_REGADDR(SDRC_DLLA_CTRL)
-prcm_voltctrl:
- .word OMAP2420_PRM_REGADDR(OCP_MOD, 0x50)
+ .globl omap24xx_sdi_cm_clksel2_pll
+ .globl omap24xx_sdi_sdrc_dlla_ctrl
+ .globl omap24xx_sdi_prcm_voltctrl
+ .globl omap24xx_sdi_timer_32ksynct_cr
+
+omap24xx_sdi_cm_clksel2_pll:
+ .word SRAM_VA_MAGIC
+omap24xx_sdi_sdrc_dlla_ctrl:
+ .word SRAM_VA_MAGIC
+omap24xx_sdi_prcm_voltctrl:
+ .word SRAM_VA_MAGIC
prcm_mask_val:
.word 0xFFFF3FFC
-timer_32ksynct_cr:
- .word TIMER_32KSYNCT_CR_V
-ENTRY(sram_ddr_init_sz)
- .word . - sram_ddr_init
+omap24xx_sdi_timer_32ksynct_cr:
+ .word SRAM_VA_MAGIC
+ENTRY(omap24xx_sram_ddr_init_sz)
+ .word . - omap24xx_sram_ddr_init
/*
* Reprograms memory timings.
* r0 = [PRCM_FULL | PRCM_HALF] r1 = SDRC_DLLA_CTRL value r2 = [DDR | SDR]
* PRCM_FULL = 2, PRCM_HALF = 1, DDR = 1, SDR = 0
*/
-ENTRY(sram_reprogram_sdrc)
+ENTRY(omap24xx_sram_reprogram_sdrc)
stmfd sp!, {r0 - r10, lr} @ save registers on stack
mov r3, #0x0 @ clear for mrc call
mcr p15, 0, r3, c7, c10, 4 @ memory barrier, finish ARM SDR/DDR
nop
nop
- ldr r6, ddr_sdrc_rfr_ctrl @ get addr of refresh reg
+ ldr r6, omap24xx_srs_sdrc_rfr_ctrl @ get addr of refresh reg
ldr r5, [r6] @ get value
mov r5, r5, lsr #8 @ isolate rfr field and drop burst
movne r5, r5, lsl #1 @ mult by 2 if to full
mov r5, r5, lsl #8 @ put rfr field back into place
add r5, r5, #0x1 @ turn on burst of 1
- ldr r4, ddr_cm_clksel2_pll @ get address of out reg
+ ldr r4, omap24xx_srs_cm_clksel2_pll @ get address of out reg
ldr r3, [r4] @ get curr value
orr r3, r3, #0x3
bic r3, r3, #0x3 @ clear lower bits
bne freq_out @ leave if SDR, no DLL function
/* With DDR, we need to take care of the DLL for the frequency change */
- ldr r2, ddr_sdrc_dlla_ctrl @ addr of dlla ctrl
+ ldr r2, omap24xx_srs_sdrc_dlla_ctrl @ addr of dlla ctrl
str r1, [r2] @ write out new SDRC_DLLA_CTRL
add r2, r2, #0x8 @ addr to SDRC_DLLB_CTRL
str r1, [r2] @ commit to SDRC_DLLB_CTRL
* wait for it to finish, use 32k sync counter, 1tick=31uS.
*/
voltage_shift_c:
- ldr r10, ddr_prcm_voltctrl @ get addr of volt ctrl
+ ldr r10, omap24xx_srs_prcm_voltctrl @ get addr of volt ctrl
ldr r8, [r10] @ get value
ldr r7, ddr_prcm_mask_val @ get value of mask
and r8, r8, r7 @ apply mask to clear bits
orr r8, r8, r7 @ build value for force
str r8, [r10] @ Force transition to L1
- ldr r10, ddr_timer_32ksynct @ get addr of counter
+ ldr r10, omap24xx_srs_timer_32ksynct @ get addr of counter
ldr r8, [r10] @ get value
add r8, r8, #0x2 @ give it at most 62uS (min 31+)
volt_delay_c:
bhi volt_delay_c @ not yet->branch
mov pc, lr @ back to caller
-ddr_cm_clksel2_pll:
- .word OMAP2420_CM_REGADDR(PLL_MOD, CM_CLKSEL2)
-ddr_sdrc_dlla_ctrl:
- .word OMAP242X_SDRC_REGADDR(SDRC_DLLA_CTRL)
-ddr_sdrc_rfr_ctrl:
- .word OMAP242X_SDRC_REGADDR(SDRC_RFR_CTRL_0)
-ddr_prcm_voltctrl:
- .word OMAP2420_PRM_REGADDR(OCP_MOD, 0x50)
+ .globl omap24xx_srs_cm_clksel2_pll
+ .globl omap24xx_srs_sdrc_dlla_ctrl
+ .globl omap24xx_srs_sdrc_rfr_ctrl
+ .globl omap24xx_srs_prcm_voltctrl
+ .globl omap24xx_srs_timer_32ksynct
+
+omap24xx_srs_cm_clksel2_pll:
+ .word SRAM_VA_MAGIC
+omap24xx_srs_sdrc_dlla_ctrl:
+ .word SRAM_VA_MAGIC
+omap24xx_srs_sdrc_rfr_ctrl:
+ .word SRAM_VA_MAGIC
+omap24xx_srs_prcm_voltctrl:
+ .word SRAM_VA_MAGIC
ddr_prcm_mask_val:
.word 0xFFFF3FFC
-ddr_timer_32ksynct:
- .word TIMER_32KSYNCT_CR_V
+omap24xx_srs_timer_32ksynct:
+ .word SRAM_VA_MAGIC
-ENTRY(sram_reprogram_sdrc_sz)
- .word . - sram_reprogram_sdrc
+ENTRY(omap24xx_sram_reprogram_sdrc_sz)
+ .word . - omap24xx_sram_reprogram_sdrc
/*
* Set dividers and pll. Also recalculate DLL value for DDR and unlock mode.
*/
-ENTRY(sram_set_prcm)
+ENTRY(omap24xx_sram_set_prcm)
stmfd sp!, {r0-r12, lr} @ regs to stack
adr r4, pbegin @ addr of preload start
adr r8, pend @ addr of preload end
mcrr p15, 1, r8, r4, c12 @ preload into icache
pbegin:
/* move into fast relock bypass */
- ldr r8, pll_ctl @ get addr
+ ldr r8, omap24xx_ssp_pll_ctl @ get addr
ldr r5, [r8] @ get val
mvn r6, #0x3 @ clear mask
and r5, r5, r6 @ clear field
orr r7, r5, #0x2 @ fast relock val
str r7, [r8] @ go to fast relock
- ldr r4, pll_stat @ addr of stat
+ ldr r4, omap24xx_ssp_pll_stat @ addr of stat
block:
/* wait for bypass */
ldr r8, [r4] @ stat value
bne block @ loop if not
/* set new dpll dividers _after_ in bypass */
- ldr r4, pll_div @ get addr
+ ldr r4, omap24xx_ssp_pll_div @ get addr
str r0, [r4] @ set dpll ctrl val
- ldr r4, set_config @ get addr
+ ldr r4, omap24xx_ssp_set_config @ get addr
mov r8, #1 @ valid cfg msk
str r8, [r4] @ make dividers take
beq pend @ jump over dpll relock
/* relock DPLL with new vals */
- ldr r5, pll_stat @ get addr
- ldr r4, pll_ctl @ get addr
+ ldr r5, omap24xx_ssp_pll_stat @ get addr
+ ldr r4, omap24xx_ssp_pll_ctl @ get addr
orr r8, r7, #0x3 @ val for lock dpll
str r8, [r4] @ set val
mov r0, #1000 @ dead spin a bit
bne wait_lock @ wait if not
pend:
/* update memory timings & briefly lock dll */
- ldr r4, sdrc_rfr @ get addr
+ ldr r4, omap24xx_ssp_sdrc_rfr @ get addr
str r1, [r4] @ update refresh timing
- ldr r11, dlla_ctrl @ get addr of DLLA ctrl
+ ldr r11, omap24xx_ssp_dlla_ctrl @ get addr of DLLA ctrl
ldr r10, [r11] @ get current val
mvn r9, #0x4 @ mask to get clear bit2
and r10, r10, r9 @ clear bit2 for lock mode
nop
ldmfd sp!, {r0-r12, pc} @ restore regs and return
-set_config:
- .word OMAP2420_PRM_REGADDR(OCP_MOD, 0x80)
-pll_ctl:
- .word OMAP2420_CM_REGADDR(PLL_MOD, CM_FCLKEN1)
-pll_stat:
- .word OMAP2420_CM_REGADDR(PLL_MOD, CM_IDLEST1)
-pll_div:
- .word OMAP2420_CM_REGADDR(PLL_MOD, CM_CLKSEL)
-sdrc_rfr:
- .word OMAP242X_SDRC_REGADDR(SDRC_RFR_CTRL_0)
-dlla_ctrl:
- .word OMAP242X_SDRC_REGADDR(SDRC_DLLA_CTRL)
-
-ENTRY(sram_set_prcm_sz)
- .word . - sram_set_prcm
+ .globl omap24xx_ssp_set_config
+ .globl omap24xx_ssp_pll_ctl
+ .globl omap24xx_ssp_pll_stat
+ .globl omap24xx_ssp_pll_div
+ .globl omap24xx_ssp_sdrc_rfr
+ .globl omap24xx_ssp_dlla_ctrl
+
+omap24xx_ssp_set_config:
+ .word SRAM_VA_MAGIC
+omap24xx_ssp_pll_ctl:
+ .word SRAM_VA_MAGIC
+omap24xx_ssp_pll_stat:
+ .word SRAM_VA_MAGIC
+omap24xx_ssp_pll_div:
+ .word SRAM_VA_MAGIC
+omap24xx_ssp_sdrc_rfr:
+ .word SRAM_VA_MAGIC
+omap24xx_ssp_dlla_ctrl:
+ .word SRAM_VA_MAGIC
+
+ENTRY(omap24xx_sram_set_prcm_sz)
+ .word . - omap24xx_sram_set_prcm
static int omap2_gp_timer_set_next_event(unsigned long cycles,
struct clock_event_device *evt)
{
- omap_dm_timer_set_load(gptimer, 0, 0xffffffff - cycles);
- omap_dm_timer_start(gptimer);
+ omap_dm_timer_set_load_start(gptimer, 0, 0xffffffff - cycles);
return 0;
}
period = clk_get_rate(omap_dm_timer_get_fclk(gptimer)) / HZ;
period -= 1;
- omap_dm_timer_set_load(gptimer, 1, 0xffffffff - period);
- omap_dm_timer_start(gptimer);
+ omap_dm_timer_set_load_start(gptimer, 1, 0xffffffff - period);
break;
case CLOCK_EVT_MODE_ONESHOT:
break;
tick_rate = clk_get_rate(omap_dm_timer_get_fclk(gpt));
tick_period = (tick_rate / HZ) - 1;
- omap_dm_timer_set_load(gpt, 1, 0);
- omap_dm_timer_start(gpt);
+ omap_dm_timer_set_load_start(gpt, 1, 0);
clocksource_gpt.mult =
clocksource_khz2mult(tick_rate/1000, clocksource_gpt.shift);
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap2/usb-ehci.c
+ *
+ * This file will contain the board specific details for the
+ * Synopsys EHCI host controller on OMAP3430
+ *
+ * Copyright (C) 2007 Texas Instruments
+ * Author: Vikram Pandita <vikram.pandita@ti.com>
+ *
+ * Generalization by:
+ * Felipe Balbi <felipe.balbi@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/types.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <asm/io.h>
+#include <asm/arch/mux.h>
+#include <linux/usb/musb.h>
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/pm.h>
+#include <asm/arch/usb.h>
+
+#if defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_EHCI_HCD_MODULE)
+static struct resource ehci_resources[] = {
+ [0] = {
+ .start = OMAP34XX_HSUSB_HOST_BASE + 0x800,
+ .end = OMAP34XX_HSUSB_HOST_BASE + 0x800 + SZ_1K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = { /* general IRQ */
+ .start = INT_34XX_EHCI_IRQ,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static u64 ehci_dmamask = ~(u32)0;
+static struct platform_device ehci_device = {
+ .name = "ehci-omap",
+ .id = 0,
+ .dev = {
+ .dma_mask = &ehci_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ .platform_data = 0x0,
+ },
+ .num_resources = ARRAY_SIZE(ehci_resources),
+ .resource = ehci_resources,
+};
+
+
+/* MUX settings for EHCI pins */
+/*
+ * setup_ehci_io_mux - initialize IO pad mux for USBHOST
+ */
+static void setup_ehci_io_mux(void)
+{
+#ifdef CONFIG_OMAP_EHCI_PHY_MODE
+ /* PHY mode of operation for board: 750-2083-001
+ * ISP1504 connected to Port1 and Port2
+ * Do Func Mux setting for 12-pin ULPI PHY mode
+ */
+
+ /* Port1 */
+ omap_cfg_reg(Y9_3430_USB1HS_PHY_STP);
+ omap_cfg_reg(Y8_3430_USB1HS_PHY_CLK);
+ omap_cfg_reg(AA14_3430_USB1HS_PHY_DIR);
+ omap_cfg_reg(AA11_3430_USB1HS_PHY_NXT);
+ omap_cfg_reg(W13_3430_USB1HS_PHY_DATA0);
+ omap_cfg_reg(W12_3430_USB1HS_PHY_DATA1);
+ omap_cfg_reg(W11_3430_USB1HS_PHY_DATA2);
+ omap_cfg_reg(Y11_3430_USB1HS_PHY_DATA3);
+ omap_cfg_reg(W9_3430_USB1HS_PHY_DATA4);
+ omap_cfg_reg(Y12_3430_USB1HS_PHY_DATA5);
+ omap_cfg_reg(W8_3430_USB1HS_PHY_DATA6);
+ omap_cfg_reg(Y13_3430_USB1HS_PHY_DATA7);
+
+ /* Port2 */
+ omap_cfg_reg(AA10_3430_USB2HS_PHY_STP);
+ omap_cfg_reg(AA8_3430_USB2HS_PHY_CLK);
+ omap_cfg_reg(AA9_3430_USB2HS_PHY_DIR);
+ omap_cfg_reg(AB11_3430_USB2HS_PHY_NXT);
+ omap_cfg_reg(AB10_3430_USB2HS_PHY_DATA0);
+ omap_cfg_reg(AB9_3430_USB2HS_PHY_DATA1);
+ omap_cfg_reg(W3_3430_USB2HS_PHY_DATA2);
+ omap_cfg_reg(T4_3430_USB2HS_PHY_DATA3);
+ omap_cfg_reg(T3_3430_USB2HS_PHY_DATA4);
+ omap_cfg_reg(R3_3430_USB2HS_PHY_DATA5);
+ omap_cfg_reg(R4_3430_USB2HS_PHY_DATA6);
+ omap_cfg_reg(T2_3430_USB2HS_PHY_DATA7);
+
+#else
+ /* Set Func mux for :
+ * TLL mode of operation
+ * 12-pin ULPI SDR TLL mode for Port1/2/3
+ */
+
+ /* Port1 */
+ omap_cfg_reg(Y9_3430_USB1HS_TLL_STP);
+ omap_cfg_reg(Y8_3430_USB1HS_TLL_CLK);
+ omap_cfg_reg(AA14_3430_USB1HS_TLL_DIR);
+ omap_cfg_reg(AA11_3430_USB1HS_TLL_NXT);
+ omap_cfg_reg(W13_3430_USB1HS_TLL_DATA0);
+ omap_cfg_reg(W12_3430_USB1HS_TLL_DATA1);
+ omap_cfg_reg(W11_3430_USB1HS_TLL_DATA2);
+ omap_cfg_reg(Y11_3430_USB1HS_TLL_DATA3);
+ omap_cfg_reg(W9_3430_USB1HS_TLL_DATA4);
+ omap_cfg_reg(Y12_3430_USB1HS_TLL_DATA5);
+ omap_cfg_reg(W8_3430_USB1HS_TLL_DATA6);
+ omap_cfg_reg(Y13_3430_USB1HS_TLL_DATA7);
+
+ /* Port2 */
+ omap_cfg_reg(AA10_3430_USB2HS_TLL_STP);
+ omap_cfg_reg(AA8_3430_USB2HS_TLL_CLK);
+ omap_cfg_reg(AA9_3430_USB2HS_TLL_DIR);
+ omap_cfg_reg(AB11_3430_USB2HS_TLL_NXT);
+ omap_cfg_reg(AB10_3430_USB2HS_TLL_DATA0);
+ omap_cfg_reg(AB9_3430_USB2HS_TLL_DATA1);
+ omap_cfg_reg(W3_3430_USB2HS_TLL_DATA2);
+ omap_cfg_reg(T4_3430_USB2HS_TLL_DATA3);
+ omap_cfg_reg(T3_3430_USB2HS_TLL_DATA4);
+ omap_cfg_reg(R3_3430_USB2HS_TLL_DATA5);
+ omap_cfg_reg(R4_3430_USB2HS_TLL_DATA6);
+ omap_cfg_reg(T2_3430_USB2HS_TLL_DATA7);
+
+ /* Port3 */
+ omap_cfg_reg(AB3_3430_USB3HS_TLL_STP);
+ omap_cfg_reg(AA6_3430_USB3HS_TLL_CLK);
+ omap_cfg_reg(AA3_3430_USB3HS_TLL_DIR);
+ omap_cfg_reg(Y3_3430_USB3HS_TLL_NXT);
+ omap_cfg_reg(AA5_3430_USB3HS_TLL_DATA0);
+ omap_cfg_reg(Y4_3430_USB3HS_TLL_DATA1);
+ omap_cfg_reg(Y5_3430_USB3HS_TLL_DATA2);
+ omap_cfg_reg(W5_3430_USB3HS_TLL_DATA3);
+ omap_cfg_reg(AB12_3430_USB3HS_TLL_DATA4);
+ omap_cfg_reg(AB13_3430_USB3HS_TLL_DATA5);
+ omap_cfg_reg(AA13_3430_USB3HS_TLL_DATA6);
+ omap_cfg_reg(AA12_3430_USB3HS_TLL_DATA7);
+#endif /* CONFIG_OMAP_EHCI_PHY_MODE */
+
+ return;
+}
+
+#endif /* EHCI specific data */
+
+void __init usb_ehci_init(void)
+{
+#if defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_EHCI_HCD_MODULE)
+ /* Setup Pin IO MUX for EHCI */
+ if (cpu_is_omap34xx())
+ setup_ehci_io_mux();
+
+ if (platform_device_register(&ehci_device) < 0) {
+ printk(KERN_ERR "Unable to register HS-USB (EHCI) device\n");
+ return;
+ }
+#endif
+}
+
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap2/usb-musb.c
+ *
+ * This file will contain the board specific details for the
+ * MENTOR USB OTG controller on OMAP3430
+ *
+ * Copyright (C) 2007-2008 Texas Instruments
+ * Copyright (C) 2008 Nokia Corporation
+ * Author: Vikram Pandita
+ *
+ * Generalization by:
+ * Felipe Balbi <felipe.balbi@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/types.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <asm/io.h>
+#include <asm/arch/mux.h>
+#include <linux/usb/musb.h>
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/pm.h>
+#include <asm/arch/usb.h>
+
+#ifdef CONFIG_USB_MUSB_SOC
+static struct resource musb_resources[] = {
+ [0] = {
+ .start = cpu_is_omap34xx()
+ ? OMAP34XX_HSUSB_OTG_BASE
+ : OMAP243X_HS_BASE,
+ .end = cpu_is_omap34xx()
+ ? OMAP34XX_HSUSB_OTG_BASE + SZ_8K - 1
+ : OMAP243X_HS_BASE + SZ_8K -1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = { /* general IRQ */
+ .start = INT_243X_HS_USB_MC,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = { /* DMA IRQ */
+ .start = INT_243X_HS_USB_DMA,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static int clk_on;
+
+static int musb_set_clock(struct clk *clk, int state)
+{
+ if (state) {
+ if (clk_on > 0)
+ return -ENODEV;
+
+ omap2_block_sleep();
+ clk_enable(clk);
+ clk_on = 1;
+ } else {
+ if (clk_on == 0)
+ return -ENODEV;
+
+ clk_disable(clk);
+ clk_on = 0;
+ omap2_allow_sleep();
+ }
+
+ return 0;
+}
+
+static struct musb_hdrc_platform_data musb_plat = {
+#ifdef CONFIG_USB_MUSB_OTG
+ .mode = MUSB_OTG,
+#elif defined(CONFIG_USB_MUSB_HDRC_HCD)
+ .mode = MUSB_HOST,
+#elif defined(CONFIG_USB_GADGET_MUSB_HDRC)
+ .mode = MUSB_PERIPHERAL,
+#endif
+ .multipoint = 1,
+ .clock = cpu_is_omap34xx()
+ ? "hsotgusb_ick"
+ : "usbhs_ick",
+ .set_clock = musb_set_clock,
+};
+
+static u64 musb_dmamask = ~(u32)0;
+
+static struct platform_device musb_device = {
+ .name = "musb_hdrc",
+ .id = 0,
+ .dev = {
+ .dma_mask = &musb_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ .platform_data = &musb_plat,
+ },
+ .num_resources = ARRAY_SIZE(musb_resources),
+ .resource = musb_resources,
+};
+#endif
+
+
+void __init usb_musb_init(void)
+{
+#ifdef CONFIG_USB_MUSB_SOC
+ if (platform_device_register(&musb_device) < 0) {
+ printk(KERN_ERR "Unable to register HS-USB (MUSB) device\n");
+ return;
+ }
+#endif
+}
+
return gpmc_cs_set_timings(sync_cs, &t);
}
-extern unsigned long gpmc_get_fclk_period(void);
-
/* tusb driver calls this when it changes the chip's clocking */
int tusb6010_platform_retime(unsigned is_refclk)
{
# ARMv7
config CPU_V7
bool "Support ARM V7 processor"
- depends on ARCH_INTEGRATOR || MACH_REALVIEW_EB
+ depends on ARCH_INTEGRATOR || MACH_REALVIEW_EB || ARCH_OMAP3
select CPU_32v6K
select CPU_32v7
select CPU_ABRT_EV7
config ARCH_OMAP2
bool "TI OMAP2"
+config ARCH_OMAP3
+ bool "TI OMAP3"
+
endchoice
comment "OMAP Feature Selections"
depends on OMAP_DEBUG_DEVICES
default y if LEDS || LEDS_OMAP_DEBUG
+config OMAP_DEBUG_SRAM_PATCH
+ bool "Extra sanity checking for SRAM patch code"
+ depends on ARCH_OMAP
+ default y
+ help
+ Say Y here if you want the kernel to use extra caution
+ in patching SRAM virtual addresses. If you are
+ confident in your SRAM code, disabling this will save
+ about 600 bytes.
+
+config OMAP_DEBUG_POWERDOMAIN
+ bool "Emit debug messages from powerdomain layer"
+ depends on ARCH_OMAP2 || ARCH_OMAP3
+ default n
+ help
+ Say Y here if you want to compile in powerdomain layer
+ debugging messages for OMAP2/3. These messages can
+ provide more detail as to why some powerdomain calls
+ may be failing, and will also emit a descriptive message
+ for every powerdomain register write. However, the
+ extra detail costs some memory.
+
+config OMAP_DEBUG_CLOCKDOMAIN
+ bool "Emit debug messages from clockdomain layer"
+ depends on ARCH_OMAP2 || ARCH_OMAP3
+ default n
+ help
+ Say Y here if you want to compile in clockdomain layer
+ debugging messages for OMAP2/3. These messages can
+ provide more detail as to why some clockdomain calls
+ may be failing, and will also emit a descriptive message
+ for every clockdomain register write. However, the
+ extra detail costs some memory.
+
config OMAP_RESET_CLOCKS
bool "Reset unused clocks during boot"
depends on ARCH_OMAP
probably do not want this option enabled until your
device drivers work properly.
+config OMAP_BOOT_TAG
+ bool "OMAP bootloader information passing"
+ depends on ARCH_OMAP
+ default n
+ help
+ Say Y, if you have a bootloader which passes information
+ about your board and its peripheral configuration.
+
+config OMAP_BOOT_REASON
+ bool "Support for boot reason"
+ depends on OMAP_BOOT_TAG
+ default n
+ help
+ Say Y, if you want to have a procfs entry for reading the boot
+ reason in user-space.
+
+config OMAP_COMPONENT_VERSION
+ bool "Support for component version display"
+ depends on OMAP_BOOT_TAG && PROC_FS
+ default n
+ help
+ Say Y, if you want to have a procfs entry for reading component
+ versions (supplied by the bootloader) in user-space.
+
+config OMAP_GPIO_SWITCH
+ bool "GPIO switch support"
+ default n
+ help
+ Say Y, if you want to have support for reporting of GPIO
+ switches (e.g. cover switches) via sysfs. Your bootloader has
+ to provide information about the switches to the kernel via the
+ ATAG_BOARD mechanism if they're not defined by the board config.
+
config OMAP_MUX
bool "OMAP multiplexing support"
depends on ARCH_OMAP
Say Y here if you want support for the OMAP Multichannel
Buffered Serial Port.
+config OMAP_MMU_FWK
+ bool "MMU framework support"
+ depends on ARCH_OMAP
+ default n
+ help
+ Say Y here if you want to use OMAP MMU framework support for
+ DSP, IVA1.0 and Camera in OMAP1/2.
+
+config OMAP_MBOX_FWK
+ tristate "Mailbox framework support"
+ depends on ARCH_OMAP
+ default n
+ help
+ Say Y here if you want to use OMAP Mailbox framework support for
+ DSP and IVA1.0 in OMAP1/2.
+
choice
prompt "System timer"
default OMAP_MPU_TIMER
config OMAP_32K_TIMER
bool "Use 32KHz timer"
- depends on ARCH_OMAP16XX || ARCH_OMAP24XX
+ depends on ARCH_OMAP16XX || ARCH_OMAP24XX || ARCH_OMAP34XX
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 OMAP16XX and 24XX.
+ currently only available for OMAP16XX, 24XX and 34XX.
endchoice
config OMAP_DM_TIMER
bool "Use dual-mode timer"
- depends on ARCH_OMAP16XX || ARCH_OMAP24XX
+ depends on ARCH_OMAP16XX || ARCH_OMAP24XX || ARCH_OMAP34XX
help
Select this option if you want to use OMAP Dual-Mode timers.
obj-$(CONFIG_CPU_FREQ) += cpu-omap.o
obj-$(CONFIG_OMAP_DM_TIMER) += dmtimer.o
+obj-$(CONFIG_OMAP_BOOT_REASON) += bootreason.o
+obj-$(CONFIG_OMAP_COMPONENT_VERSION) += component-version.o
+obj-$(CONFIG_OMAP_GPIO_SWITCH) += gpio-switch.o
obj-$(CONFIG_OMAP_DEBUG_DEVICES) += debug-devices.o
obj-$(CONFIG_OMAP_DEBUG_LEDS) += debug-leds.o
obj-$(CONFIG_I2C_OMAP) += i2c.o
+# OMAP MMU framework
+obj-$(CONFIG_OMAP_MMU_FWK) += mmu.o
+
# OMAP mailbox framework
obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox.o
--- /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/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);
/*
* linux/arch/arm/plat-omap/clock.c
*
- * Copyright (C) 2004 - 2005 Nokia corporation
+ * Copyright (C) 2004 - 2008 Nokia corporation
* Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
*
* Modified for omap shared clock framework by Tony Lindgren <tony@atomide.com>
#include <linux/clk.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
+#include <linux/debugfs.h>
#include <asm/io.h>
+#include <asm/semaphore.h>
#include <asm/arch/clock.h>
static struct clk_functions *arch_clock;
-#ifdef CONFIG_PM_DEBUG
-
-static void print_parents(struct clk *clk)
-{
- struct clk *p;
- int printed = 0;
-
- list_for_each_entry(p, &clocks, node) {
- if (p->parent == clk && p->usecount) {
- if (!clk->usecount && !printed) {
- printk("MISMATCH: %s\n", clk->name);
- printed = 1;
- }
- printk("\t%-15s\n", p->name);
- }
- }
-}
-
-void clk_print_usecounts(void)
-{
- unsigned long flags;
- struct clk *p;
-
- spin_lock_irqsave(&clockfw_lock, flags);
- list_for_each_entry(p, &clocks, node) {
- if (p->usecount)
- printk("%-15s: %d\n", p->name, p->usecount);
- print_parents(p);
-
- }
- spin_unlock_irqrestore(&clockfw_lock, flags);
-}
-
-#endif
-
/*-------------------------------------------------------------------------
* Standard clock functions defined in include/linux/clk.h
*-------------------------------------------------------------------------*/
return;
spin_lock_irqsave(&clockfw_lock, flags);
- BUG_ON(clk->usecount == 0);
+ if (clk->usecount == 0) {
+ printk(KERN_ERR "Trying disable clock %s with 0 usecount\n",
+ clk->name);
+ WARN_ON(1);
+ goto out;
+ }
+
if (arch_clock->clk_disable)
arch_clock->clk_disable(clk);
+
+out:
spin_unlock_irqrestore(&clockfw_lock, flags);
}
EXPORT_SYMBOL(clk_disable);
return 0;
}
+#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS)
+/*
+ * debugfs support to trace clock tree hierarchy and attributes
+ */
+static struct dentry *clk_debugfs_root;
+
+static int clk_debugfs_register_one(struct clk *c)
+{
+ int err;
+ struct dentry *d, *child;
+ struct clk *pa = c->parent;
+ char s[255];
+ char *p = s;
+
+ p += sprintf(p, "%s", c->name);
+ if (c->id != 0)
+ sprintf(p, ":%d", c->id);
+ d = debugfs_create_dir(s, pa ? pa->dent : clk_debugfs_root);
+ if (IS_ERR(d))
+ return PTR_ERR(d);
+ c->dent = d;
+
+ d = debugfs_create_u8("usecount", S_IRUGO, c->dent, (u8 *)&c->usecount);
+ if (IS_ERR(d)) {
+ err = PTR_ERR(d);
+ goto err_out;
+ }
+ d = debugfs_create_u32("rate", S_IRUGO, c->dent, (u32 *)&c->rate);
+ if (IS_ERR(d)) {
+ err = PTR_ERR(d);
+ goto err_out;
+ }
+ d = debugfs_create_x32("flags", S_IRUGO, c->dent, (u32 *)&c->flags);
+ if (IS_ERR(d)) {
+ err = PTR_ERR(d);
+ goto err_out;
+ }
+ return 0;
+
+err_out:
+ d = c->dent;
+ list_for_each_entry(child, &d->d_subdirs, d_u.d_child)
+ debugfs_remove(child);
+ debugfs_remove(c->dent);
+ return err;
+}
+
+static int clk_debugfs_register(struct clk *c)
+{
+ int err;
+ struct clk *pa = c->parent;
+
+ if (pa && !pa->dent) {
+ err = clk_debugfs_register(pa);
+ if (err)
+ return err;
+ }
+
+ if (!c->dent) {
+ err = clk_debugfs_register_one(c);
+ if (err)
+ return err;
+ }
+ return 0;
+}
+
+static int __init clk_debugfs_init(void)
+{
+ struct clk *c;
+ struct dentry *d;
+ int err;
+
+ d = debugfs_create_dir("clock", NULL);
+ if (IS_ERR(d))
+ return PTR_ERR(d);
+ clk_debugfs_root = d;
+
+ list_for_each_entry(c, &clocks, node) {
+ err = clk_debugfs_register(c);
+ if (err)
+ goto err_out;
+ }
+ return 0;
+err_out:
+ debugfs_remove(clk_debugfs_root); /* REVISIT: Cleanup correctly */
+ return err;
+}
+late_initcall(clk_debugfs_init);
+
+#endif /* defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS) */
#define NO_LENGTH_CHECK 0xffffffff
-unsigned char omap_bootloader_tag[512];
+unsigned char omap_bootloader_tag[1024];
int omap_bootloader_tag_len;
struct omap_board_config_kernel *omap_board_config;
int omap_board_config_size;
+#ifdef CONFIG_OMAP_BOOT_TAG
+
+static int __init parse_tag_omap(const struct tag *tag)
+{
+ u32 size = tag->hdr.size - (sizeof(tag->hdr) >> 2);
+
+ size <<= 2;
+ if (size > sizeof(omap_bootloader_tag))
+ return -1;
+
+ memcpy(omap_bootloader_tag, tag->u.omap.data, size);
+ omap_bootloader_tag_len = size;
+
+ return 0;
+}
+
+__tagtable(ATAG_BOARD, parse_tag_omap);
+
+#endif
+
static const void *get_config(u16 tag, size_t len, int skip, size_t *len_out)
{
struct omap_board_config_kernel *kinfo = NULL;
--- /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/hardware.h>
#include <asm/io.h>
#include <asm/system.h>
+#include <asm/arch/clock.h>
#define VERY_HI_RATE 900000000
+static struct cpufreq_frequency_table *freq_table;
+
#ifdef CONFIG_ARCH_OMAP1
#define MPU_CLK "mpu"
#else
int omap_verify_speed(struct cpufreq_policy *policy)
{
+ if (freq_table)
+ return cpufreq_frequency_table_verify(policy, freq_table);
+
if (policy->cpu)
return -EINVAL;
struct cpufreq_freqs freqs;
int ret = 0;
+ /* Ensure desired rate is within allowed range. Some govenors
+ * (ondemand) will just pass target_freq=0 to get the minimum. */
+ if (target_freq < policy->cpuinfo.min_freq)
+ target_freq = policy->cpuinfo.min_freq;
+ if (target_freq > policy->cpuinfo.max_freq)
+ target_freq = policy->cpuinfo.max_freq;
+
freqs.old = omap_getspeed(0);
freqs.new = clk_round_rate(mpu_clk, target_freq * 1000) / 1000;
freqs.cpu = 0;
+ if (freqs.old == freqs.new)
+ return ret;
+
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
- ret = clk_set_rate(mpu_clk, target_freq * 1000);
+#ifdef CONFIG_CPU_FREQ_DEBUG
+ printk(KERN_DEBUG "cpufreq-omap: transition: %u --> %u\n",
+ freqs.old, freqs.new);
+#endif
+ ret = clk_set_rate(mpu_clk, freqs.new * 1000);
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
return ret;
static int __init omap_cpu_init(struct cpufreq_policy *policy)
{
+ int result = 0;
+
mpu_clk = clk_get(NULL, MPU_CLK);
if (IS_ERR(mpu_clk))
return PTR_ERR(mpu_clk);
if (policy->cpu != 0)
return -EINVAL;
+
policy->cur = policy->min = policy->max = omap_getspeed(0);
- policy->cpuinfo.min_freq = clk_round_rate(mpu_clk, 0) / 1000;
- policy->cpuinfo.max_freq = clk_round_rate(mpu_clk, VERY_HI_RATE) / 1000;
- policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
+
+ clk_init_cpufreq_table(&freq_table);
+ if (freq_table) {
+ result = cpufreq_frequency_table_cpuinfo(policy, freq_table);
+ if (!result)
+ cpufreq_frequency_table_get_attr(freq_table,
+ policy->cpu);
+ } else {
+ policy->cpuinfo.min_freq = clk_round_rate(mpu_clk, 0) / 1000;
+ policy->cpuinfo.max_freq = clk_round_rate(mpu_clk,
+ VERY_HI_RATE) / 1000;
+ }
+
+ /* FIXME: what's the actual transition time? */
+ policy->cpuinfo.transition_latency = 10 * 1000 * 1000;
return 0;
}
return 0;
}
+static struct freq_attr *omap_cpufreq_attr[] = {
+ &cpufreq_freq_attr_scaling_available_freqs,
+ NULL,
+};
+
static struct cpufreq_driver omap_driver = {
.flags = CPUFREQ_STICKY,
.verify = omap_verify_speed,
.init = omap_cpu_init,
.exit = omap_cpu_exit,
.name = "omap",
+ .attr = omap_cpufreq_attr,
};
static int __init omap_cpufreq_init(void)
}
arch_initcall(omap_cpufreq_init);
+
+/*
+ * if ever we want to remove this, upon cleanup call:
+ *
+ * cpufreq_unregister_driver()
+ * cpufreq_frequency_table_put_attr()
+ */
+
#include <asm/mach/map.h>
#include <asm/arch/tc.h>
+#include <asm/arch/control.h>
#include <asm/arch/board.h>
+#include <asm/arch/mmc.h>
#include <asm/arch/mux.h>
#include <asm/arch/gpio.h>
#include <asm/arch/menelaus.h>
+#include <asm/arch/dsp_common.h>
#if defined(CONFIG_OMAP_DSP) || defined(CONFIG_OMAP_DSP_MODULE)
-#include "../plat-omap/dsp/dsp_common.h"
-
static struct dsp_platform_data dsp_pdata = {
.kdev_list = LIST_HEAD_INIT(dsp_pdata.kdev_list),
};
{
static DEFINE_MUTEX(dsp_pdata_lock);
- mutex_init(&kdev->lock);
+ spin_lock_init(&kdev->lock);
mutex_lock(&dsp_pdata_lock);
list_add_tail(&kdev->entry, &dsp_pdata.kdev_list);
static void omap_init_kp(void)
{
+ /* REVISIT: 2430 keypad is on TWL4030 */
+ if (cpu_is_omap2430() || cpu_is_omap34xx())
+ return;
+
if (machine_is_omap_h2() || machine_is_omap_h3()) {
omap_cfg_reg(F18_1610_KBC0);
omap_cfg_reg(D20_1610_KBC1);
/*-------------------------------------------------------------------------*/
-#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
+#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) \
+ || defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)
-#ifdef CONFIG_ARCH_OMAP24XX
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
#define OMAP_MMC1_BASE 0x4809c000
-#define OMAP_MMC1_INT INT_24XX_MMC_IRQ
+#define OMAP_MMC1_END OMAP_MMC1_BASE + 0x1fc
+#define OMAP_MMC1_INT INT_24XX_MMC_IRQ
+
+#define OMAP_MMC2_BASE 0x480b4000
+#define OMAP_MMC2_END OMAP_MMC2_BASE + 0x1fc
+#define OMAP_MMC2_INT INT_24XX_MMC2_IRQ
+
#else
+
#define OMAP_MMC1_BASE 0xfffb7800
+#define OMAP_MMC1_END OMAP_MMC1_BASE + 0x7f
#define OMAP_MMC1_INT INT_MMC
-#endif
+
#define OMAP_MMC2_BASE 0xfffb7c00 /* omap16xx only */
+#define OMAP_MMC2_END OMAP_MMC2_BASE + 0x7f
+#define OMAP_MMC2_INT INT_1610_MMC2
-static struct omap_mmc_conf mmc1_conf;
+#endif
+
+static struct omap_mmc_platform_data mmc1_data;
static u64 mmc1_dmamask = 0xffffffff;
static struct resource mmc1_resources[] = {
{
.start = OMAP_MMC1_BASE,
- .end = OMAP_MMC1_BASE + 0x7f,
+ .end = OMAP_MMC1_END,
.flags = IORESOURCE_MEM,
},
{
.id = 1,
.dev = {
.dma_mask = &mmc1_dmamask,
- .platform_data = &mmc1_conf,
+ .platform_data = &mmc1_data,
},
.num_resources = ARRAY_SIZE(mmc1_resources),
.resource = mmc1_resources,
};
-#ifdef CONFIG_ARCH_OMAP16XX
+#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2430) || \
+ defined(CONFIG_ARCH_OMAP34XX)
-static struct omap_mmc_conf mmc2_conf;
+static struct omap_mmc_platform_data mmc2_data;
static u64 mmc2_dmamask = 0xffffffff;
+
static struct resource mmc2_resources[] = {
{
.start = OMAP_MMC2_BASE,
- .end = OMAP_MMC2_BASE + 0x7f,
+ .end = OMAP_MMC2_END,
.flags = IORESOURCE_MEM,
},
{
- .start = INT_1610_MMC2,
+ .start = OMAP_MMC2_INT,
.flags = IORESOURCE_IRQ,
},
};
.id = 2,
.dev = {
.dma_mask = &mmc2_dmamask,
- .platform_data = &mmc2_conf,
+ .platform_data = &mmc2_data,
},
.num_resources = ARRAY_SIZE(mmc2_resources),
.resource = mmc2_resources,
/* block 1 is always available and has just one pinout option */
mmc = &mmc_conf->mmc[0];
+
+ if (cpu_is_omap2430() || cpu_is_omap34xx()) {
+ if (mmc->enabled)
+ (void) platform_device_register(&mmc_omap_device1);
+
+#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX)
+ mmc = &mmc_conf->mmc[1];
+ if (mmc->enabled)
+ (void) platform_device_register(&mmc_omap_device2);
+#endif
+
+ return;
+ }
+
if (mmc->enabled) {
if (cpu_is_omap24xx()) {
omap_cfg_reg(H18_24XX_MMC_CMD);
omap_cfg_reg(MMC_DAT3);
}
}
- mmc1_conf = *mmc;
+#if defined(CONFIG_ARCH_OMAP2420)
+ if (mmc->internal_clock) {
+ /*
+ * Use internal loop-back in MMC/SDIO
+ * Module Input Clock selection
+ */
+ if (cpu_is_omap24xx()) {
+ u32 v = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0);
+ v |= (1 << 24); /* not used in 243x */
+ omap_ctrl_writel(v, OMAP2_CONTROL_DEVCONF0);
+ }
+ }
+#endif
+ mmc1_data.conf = *mmc;
(void) platform_device_register(&mmc_omap_device1);
}
if (cpu_is_omap1710())
omap_writel(omap_readl(MOD_CONF_CTRL_1) | (1 << 24),
MOD_CONF_CTRL_1);
- mmc2_conf = *mmc;
+ mmc2_data.conf = *mmc;
(void) platform_device_register(&mmc_omap_device2);
}
#endif
return;
}
+
+void omap_set_mmc_info(int host, const struct omap_mmc_platform_data *info)
+{
+ switch (host) {
+ case 1:
+ mmc1_data = *info;
+ break;
+#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2430) || \
+ defined(CONFIG_ARCH_OMAP34XX)
+ case 2:
+ mmc2_data = *info;
+ break;
+#endif
+ default:
+ BUG();
+ }
+}
+
#else
+void omap_set_mmc_info(int host, const struct omap_mmc_platform_data *info) {}
static inline void omap_init_mmc(void) {}
#endif
#if defined(CONFIG_OMAP_WATCHDOG) || defined(CONFIG_OMAP_WATCHDOG_MODULE)
-#ifdef CONFIG_ARCH_OMAP24XX
+#if defined(CONFIG_ARCH_OMAP34XX)
+#define OMAP_WDT_BASE 0x48314000
+#elif defined(CONFIG_ARCH_OMAP24XX)
+
+#ifdef CONFIG_ARCH_OMAP2430
+/* WDT2 */
+#define OMAP_WDT_BASE 0x49016000
+#else
#define OMAP_WDT_BASE 0x48022000
+#endif
+
#else
#define OMAP_WDT_BASE 0xfffeb000
#endif
*/
static int __init omap_init_devices(void)
{
-/*
- * Need to enable relevant once for 2430 SDP
- */
-#ifndef CONFIG_MACH_OMAP_2430SDP
/* please keep these calls, and their implementations above,
* in alphabetical order so they're easier to sort through.
*/
omap_init_uwire();
omap_init_wdt();
omap_init_rng();
-#endif
return 0;
}
arch_initcall(omap_init_devices);
chan->data = data;
#ifndef CONFIG_ARCH_OMAP1
chan->chain_id = -1;
+ chan->next_linked_ch = -1;
#endif
chan->enabled_irqs = OMAP_DMA_DROP_IRQ | OMAP_DMA_BLOCK_IRQ;
printk(KERN_ERR "omap_dma: Request failed %d\n", err);
return err;
}
- dma_chan[channels[i]].next_linked_ch = -1;
dma_chan[channels[i]].prev_linked_ch = -1;
dma_chan[channels[i]].state = DMA_CH_NOTSTARTED;
#include <asm/arch/irqs.h>
/* register offsets */
-#define OMAP_TIMER_ID_REG 0x00
-#define OMAP_TIMER_OCP_CFG_REG 0x10
-#define OMAP_TIMER_SYS_STAT_REG 0x14
-#define OMAP_TIMER_STAT_REG 0x18
-#define OMAP_TIMER_INT_EN_REG 0x1c
-#define OMAP_TIMER_WAKEUP_EN_REG 0x20
-#define OMAP_TIMER_CTRL_REG 0x24
-#define OMAP_TIMER_COUNTER_REG 0x28
-#define OMAP_TIMER_LOAD_REG 0x2c
-#define OMAP_TIMER_TRIGGER_REG 0x30
-#define OMAP_TIMER_WRITE_PEND_REG 0x34
-#define OMAP_TIMER_MATCH_REG 0x38
-#define OMAP_TIMER_CAPTURE_REG 0x3c
-#define OMAP_TIMER_IF_CTRL_REG 0x40
-
-/* timer control reg bits */
-#define OMAP_TIMER_CTRL_GPOCFG (1 << 14)
-#define OMAP_TIMER_CTRL_CAPTMODE (1 << 13)
-#define OMAP_TIMER_CTRL_PT (1 << 12)
-#define OMAP_TIMER_CTRL_TCM_LOWTOHIGH (0x1 << 8)
-#define OMAP_TIMER_CTRL_TCM_HIGHTOLOW (0x2 << 8)
-#define OMAP_TIMER_CTRL_TCM_BOTHEDGES (0x3 << 8)
-#define OMAP_TIMER_CTRL_SCPWM (1 << 7)
-#define OMAP_TIMER_CTRL_CE (1 << 6) /* compare enable */
-#define OMAP_TIMER_CTRL_PRE (1 << 5) /* prescaler enable */
-#define OMAP_TIMER_CTRL_PTV_SHIFT 2 /* how much to shift the prescaler value */
-#define OMAP_TIMER_CTRL_AR (1 << 1) /* auto-reload enable */
-#define OMAP_TIMER_CTRL_ST (1 << 0) /* start timer */
+#define _OMAP_TIMER_ID_OFFSET 0x00
+#define _OMAP_TIMER_OCP_CFG_OFFSET 0x10
+#define _OMAP_TIMER_SYS_STAT_OFFSET 0x14
+#define _OMAP_TIMER_STAT_OFFSET 0x18
+#define _OMAP_TIMER_INT_EN_OFFSET 0x1c
+#define _OMAP_TIMER_WAKEUP_EN_OFFSET 0x20
+#define _OMAP_TIMER_CTRL_OFFSET 0x24
+#define OMAP_TIMER_CTRL_GPOCFG (1 << 14)
+#define OMAP_TIMER_CTRL_CAPTMODE (1 << 13)
+#define OMAP_TIMER_CTRL_PT (1 << 12)
+#define OMAP_TIMER_CTRL_TCM_LOWTOHIGH (0x1 << 8)
+#define OMAP_TIMER_CTRL_TCM_HIGHTOLOW (0x2 << 8)
+#define OMAP_TIMER_CTRL_TCM_BOTHEDGES (0x3 << 8)
+#define OMAP_TIMER_CTRL_SCPWM (1 << 7)
+#define OMAP_TIMER_CTRL_CE (1 << 6) /* compare enable */
+#define OMAP_TIMER_CTRL_PRE (1 << 5) /* prescaler enable */
+#define OMAP_TIMER_CTRL_PTV_SHIFT 2 /* prescaler value shift */
+#define OMAP_TIMER_CTRL_POSTED (1 << 2)
+#define OMAP_TIMER_CTRL_AR (1 << 1) /* auto-reload enable */
+#define OMAP_TIMER_CTRL_ST (1 << 0) /* start timer */
+#define _OMAP_TIMER_COUNTER_OFFSET 0x28
+#define _OMAP_TIMER_LOAD_OFFSET 0x2c
+#define _OMAP_TIMER_TRIGGER_OFFSET 0x30
+#define _OMAP_TIMER_WRITE_PEND_OFFSET 0x34
+#define WP_NONE 0 /* no write pending bit */
+#define WP_TCLR (1 << 0)
+#define WP_TCRR (1 << 1)
+#define WP_TLDR (1 << 2)
+#define WP_TTGR (1 << 3)
+#define WP_TMAR (1 << 4)
+#define WP_TPIR (1 << 5)
+#define WP_TNIR (1 << 6)
+#define WP_TCVR (1 << 7)
+#define WP_TOCR (1 << 8)
+#define WP_TOWR (1 << 9)
+#define _OMAP_TIMER_MATCH_OFFSET 0x38
+#define _OMAP_TIMER_CAPTURE_OFFSET 0x3c
+#define _OMAP_TIMER_IF_CTRL_OFFSET 0x40
+#define _OMAP_TIMER_CAPTURE2_OFFSET 0x44 /* TCAR2, 34xx only */
+#define _OMAP_TIMER_TICK_POS_OFFSET 0x48 /* TPIR, 34xx only */
+#define _OMAP_TIMER_TICK_NEG_OFFSET 0x4c /* TNIR, 34xx only */
+#define _OMAP_TIMER_TICK_COUNT_OFFSET 0x50 /* TCVR, 34xx only */
+#define _OMAP_TIMER_TICK_INT_MASK_SET_OFFSET 0x54 /* TOCR, 34xx only */
+#define _OMAP_TIMER_TICK_INT_MASK_COUNT_OFFSET 0x58 /* TOWR, 34xx only */
+
+/* register offsets with the write pending bit encoded */
+#define WPSHIFT 16
+
+#define OMAP_TIMER_ID_REG (_OMAP_TIMER_ID_OFFSET \
+ | (WP_NONE << WPSHIFT))
+
+#define OMAP_TIMER_OCP_CFG_REG (_OMAP_TIMER_OCP_CFG_OFFSET \
+ | (WP_NONE << WPSHIFT))
+
+#define OMAP_TIMER_SYS_STAT_REG (_OMAP_TIMER_SYS_STAT_OFFSET \
+ | (WP_NONE << WPSHIFT))
+
+#define OMAP_TIMER_STAT_REG (_OMAP_TIMER_STAT_OFFSET \
+ | (WP_NONE << WPSHIFT))
+
+#define OMAP_TIMER_INT_EN_REG (_OMAP_TIMER_INT_EN_OFFSET \
+ | (WP_NONE << WPSHIFT))
+
+#define OMAP_TIMER_WAKEUP_EN_REG (_OMAP_TIMER_WAKEUP_EN_OFFSET \
+ | (WP_NONE << WPSHIFT))
+
+#define OMAP_TIMER_CTRL_REG (_OMAP_TIMER_CTRL_OFFSET \
+ | (WP_TCLR << WPSHIFT))
+
+#define OMAP_TIMER_COUNTER_REG (_OMAP_TIMER_COUNTER_OFFSET \
+ | (WP_TCRR << WPSHIFT))
+
+#define OMAP_TIMER_LOAD_REG (_OMAP_TIMER_LOAD_OFFSET \
+ | (WP_TLDR << WPSHIFT))
+
+#define OMAP_TIMER_TRIGGER_REG (_OMAP_TIMER_TRIGGER_OFFSET \
+ | (WP_TTGR << WPSHIFT))
+
+#define OMAP_TIMER_WRITE_PEND_REG (_OMAP_TIMER_WRITE_PEND_OFFSET \
+ | (WP_NONE << WPSHIFT))
+
+#define OMAP_TIMER_MATCH_REG (_OMAP_TIMER_MATCH_OFFSET \
+ | (WP_TMAR << WPSHIFT))
+
+#define OMAP_TIMER_CAPTURE_REG (_OMAP_TIMER_CAPTURE_OFFSET \
+ | (WP_NONE << WPSHIFT))
+
+#define OMAP_TIMER_IF_CTRL_REG (_OMAP_TIMER_IF_CTRL_OFFSET \
+ | (WP_NONE << WPSHIFT))
+
+#define OMAP_TIMER_CAPTURE2_REG (_OMAP_TIMER_CAPTURE2_OFFSET \
+ | (WP_NONE << WPSHIFT))
+
+#define OMAP_TIMER_TICK_POS_REG (_OMAP_TIMER_TICK_POS_OFFSET \
+ | (WP_TPIR << WPSHIFT))
+
+#define OMAP_TIMER_TICK_NEG_REG (_OMAP_TIMER_TICK_NEG_OFFSET \
+ | (WP_TNIR << WPSHIFT))
+
+#define OMAP_TIMER_TICK_COUNT_REG (_OMAP_TIMER_TICK_COUNT_OFFSET \
+ | (WP_TCVR << WPSHIFT))
+
+#define OMAP_TIMER_TICK_INT_MASK_SET_REG \
+ (_OMAP_TIMER_TICK_INT_MASK_SET_OFFSET | (WP_TOCR << WPSHIFT))
+
+#define OMAP_TIMER_TICK_INT_MASK_COUNT_REG \
+ (_OMAP_TIMER_TICK_INT_MASK_COUNT_OFFSET | (WP_TOWR << WPSHIFT))
struct omap_dm_timer {
unsigned long phys_base;
void __iomem *io_base;
unsigned reserved:1;
unsigned enabled:1;
+ unsigned posted:1;
};
#ifdef CONFIG_ARCH_OMAP1
static spinlock_t dm_timer_lock;
-static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, int reg)
+/*
+ * Reads timer registers in posted and non-posted mode. The posted mode bit
+ * is encoded in reg. Note that in posted mode write pending bit must be
+ * checked. Otherwise a read of a non completed write will produce an error.
+ */
+static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
{
- return readl(timer->io_base + reg);
+ if (timer->posted)
+ while (readl(timer->io_base + (OMAP_TIMER_WRITE_PEND_REG & 0xff))
+ & (reg >> WPSHIFT))
+ cpu_relax();
+ return readl(timer->io_base + (reg & 0xff));
}
-static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, int reg, u32 value)
+/*
+ * Writes timer registers in posted and non-posted mode. The posted mode bit
+ * is encoded in reg. Note that in posted mode the write pending bit must be
+ * checked. Otherwise a write on a register which has a pending write will be
+ * lost.
+ */
+static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
+ u32 value)
{
- writel(value, timer->io_base + reg);
- while (omap_dm_timer_read_reg(timer, OMAP_TIMER_WRITE_PEND_REG))
- ;
+ if (timer->posted)
+ while (readl(timer->io_base + (OMAP_TIMER_WRITE_PEND_REG & 0xff))
+ & (reg >> WPSHIFT))
+ cpu_relax();
+ writel(value, timer->io_base + (reg & 0xff));
}
static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
}
omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
- /* Set to smart-idle mode */
l = omap_dm_timer_read_reg(timer, OMAP_TIMER_OCP_CFG_REG);
- l |= 0x02 << 3;
-
- if (cpu_class_is_omap2() && timer == &dm_timers[0]) {
- /* Enable wake-up only for GPT1 on OMAP2 CPUs*/
+ l |= 0x02 << 3; /* Set to smart-idle mode */
+ l |= 0x2 << 8; /* Set clock activity to perserve f-clock on idle */
+
+ /*
+ * Enable wake-up only for GPT1 on OMAP2 CPUs.
+ * FIXME: All timers should have wake-up enabled and clear
+ * PRCM status.
+ */
+ if (cpu_class_is_omap2() && (timer == &dm_timers[0]))
l |= 1 << 2;
- /* Non-posted mode */
- omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0);
- }
omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_REG, l);
+
+ /* Match hardware reset default of posted mode */
+ omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG,
+ OMAP_TIMER_CTRL_POSTED);
+ timer->posted = 1;
}
static void omap_dm_timer_prepare(struct omap_dm_timer *timer)
l &= ~OMAP_TIMER_CTRL_AR;
omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
+
+ /* REVISIT: hw feature, ttgr overtaking tldr? */
+ while (readl(timer->io_base + (OMAP_TIMER_WRITE_PEND_REG & 0xff)))
+ cpu_relax();
+
omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
}
+/* Optimized set_load which removes costly spin wait in timer_start */
+void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
+ unsigned int load)
+{
+ u32 l;
+
+ l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
+ if (autoreload)
+ l |= OMAP_TIMER_CTRL_AR;
+ else
+ l &= ~OMAP_TIMER_CTRL_AR;
+ l |= OMAP_TIMER_CTRL_ST;
+
+ omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, load);
+ omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
+ omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
+}
+
void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
unsigned int match)
{
omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
}
-
void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
int toggle, int trigger)
{
--- /dev/null
+/*
+ * linux/arch/arm/plat-omap/gpio-switch.c
+ *
+ * Copyright (C) 2004-2006 Nokia Corporation
+ * Written by Juha Yrjölä <juha.yrjola@nokia.com>
+ * and Paul Mundt <paul.mundt@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/timer.h>
+#include <linux/err.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/irqs.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/board.h>
+#include <asm/arch/gpio-switch.h>
+
+struct gpio_switch {
+ char name[14];
+ u16 gpio;
+ unsigned flags:4;
+ unsigned type:4;
+ unsigned state:1;
+ unsigned both_edges:1;
+
+ u16 debounce_rising;
+ u16 debounce_falling;
+
+ void (* notify)(void *data, int state);
+ void *notify_data;
+
+ struct work_struct work;
+ struct timer_list timer;
+ struct platform_device pdev;
+
+ struct list_head node;
+};
+
+static LIST_HEAD(gpio_switches);
+static struct platform_device *gpio_sw_platform_dev;
+static struct platform_driver gpio_sw_driver;
+
+static const struct omap_gpio_switch *board_gpio_sw_table;
+static int board_gpio_sw_count;
+
+static const char *cover_str[2] = { "open", "closed" };
+static const char *connection_str[2] = { "disconnected", "connected" };
+static const char *activity_str[2] = { "inactive", "active" };
+
+/*
+ * GPIO switch state default debounce delay in ms
+ */
+#define OMAP_GPIO_SW_DEFAULT_DEBOUNCE 10
+
+static const char **get_sw_str(struct gpio_switch *sw)
+{
+ switch (sw->type) {
+ case OMAP_GPIO_SWITCH_TYPE_COVER:
+ return cover_str;
+ case OMAP_GPIO_SWITCH_TYPE_CONNECTION:
+ return connection_str;
+ case OMAP_GPIO_SWITCH_TYPE_ACTIVITY:
+ return activity_str;
+ default:
+ BUG();
+ return NULL;
+ }
+}
+
+static const char *get_sw_type(struct gpio_switch *sw)
+{
+ switch (sw->type) {
+ case OMAP_GPIO_SWITCH_TYPE_COVER:
+ return "cover";
+ case OMAP_GPIO_SWITCH_TYPE_CONNECTION:
+ return "connection";
+ case OMAP_GPIO_SWITCH_TYPE_ACTIVITY:
+ return "activity";
+ default:
+ BUG();
+ return NULL;
+ }
+}
+
+static void print_sw_state(struct gpio_switch *sw, int state)
+{
+ const char **str;
+
+ str = get_sw_str(sw);
+ if (str != NULL)
+ printk(KERN_INFO "%s (GPIO %d) is now %s\n", sw->name, sw->gpio, str[state]);
+}
+
+static int gpio_sw_get_state(struct gpio_switch *sw)
+{
+ int state;
+
+ state = omap_get_gpio_datain(sw->gpio);
+ if (sw->flags & OMAP_GPIO_SWITCH_FLAG_INVERTED)
+ state = !state;
+
+ return state;
+}
+
+static ssize_t gpio_sw_state_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct gpio_switch *sw = dev_get_drvdata(dev);
+ const char **str;
+ char state[16];
+ int enable;
+
+ if (!(sw->flags & OMAP_GPIO_SWITCH_FLAG_OUTPUT))
+ return -EPERM;
+
+ if (sscanf(buf, "%15s", state) != 1)
+ return -EINVAL;
+
+ str = get_sw_str(sw);
+ if (strcmp(state, str[0]) == 0)
+ enable = 0;
+ else if (strcmp(state, str[1]) == 0)
+ enable = 1;
+ else
+ return -EINVAL;
+ if (sw->flags & OMAP_GPIO_SWITCH_FLAG_INVERTED)
+ enable = !enable;
+ omap_set_gpio_dataout(sw->gpio, enable);
+
+ return count;
+}
+
+static ssize_t gpio_sw_state_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct gpio_switch *sw = dev_get_drvdata(dev);
+ const char **str;
+
+ str = get_sw_str(sw);
+ return sprintf(buf, "%s\n", str[sw->state]);
+}
+
+static DEVICE_ATTR(state, S_IRUGO | S_IWUSR, gpio_sw_state_show,
+ gpio_sw_state_store);
+
+static ssize_t gpio_sw_type_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct gpio_switch *sw = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%s\n", get_sw_type(sw));
+}
+
+static DEVICE_ATTR(type, S_IRUGO, gpio_sw_type_show, NULL);
+
+static ssize_t gpio_sw_direction_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct gpio_switch *sw = dev_get_drvdata(dev);
+ int is_output;
+
+ is_output = sw->flags & OMAP_GPIO_SWITCH_FLAG_OUTPUT;
+ return sprintf(buf, "%s\n", is_output ? "output" : "input");
+}
+
+static DEVICE_ATTR(direction, S_IRUGO, gpio_sw_direction_show, NULL);
+
+
+static irqreturn_t gpio_sw_irq_handler(int irq, void *arg)
+{
+ struct gpio_switch *sw = arg;
+ unsigned long timeout;
+ int state;
+
+ if (!sw->both_edges) {
+ if (omap_get_gpio_datain(sw->gpio))
+ set_irq_type(OMAP_GPIO_IRQ(sw->gpio), IRQT_FALLING);
+ else
+ set_irq_type(OMAP_GPIO_IRQ(sw->gpio), IRQT_RISING);
+ }
+
+ state = gpio_sw_get_state(sw);
+ if (sw->state == state)
+ return IRQ_HANDLED;
+
+ if (state)
+ timeout = sw->debounce_rising;
+ else
+ timeout = sw->debounce_falling;
+ if (!timeout)
+ schedule_work(&sw->work);
+ else
+ mod_timer(&sw->timer, jiffies + msecs_to_jiffies(timeout));
+
+ return IRQ_HANDLED;
+}
+
+static void gpio_sw_timer(unsigned long arg)
+{
+ struct gpio_switch *sw = (struct gpio_switch *) arg;
+
+ schedule_work(&sw->work);
+}
+
+static void gpio_sw_handler(struct work_struct *work)
+{
+ struct gpio_switch *sw = container_of(work, struct gpio_switch, work);
+ int state;
+
+ state = gpio_sw_get_state(sw);
+ if (sw->state == state)
+ return;
+
+ sw->state = state;
+ if (sw->notify != NULL)
+ sw->notify(sw->notify_data, state);
+ sysfs_notify(&sw->pdev.dev.kobj, NULL, "state");
+ print_sw_state(sw, state);
+}
+
+static int __init can_do_both_edges(struct gpio_switch *sw)
+{
+ if (!cpu_class_is_omap1())
+ return 1;
+ if (OMAP_GPIO_IS_MPUIO(sw->gpio))
+ return 0;
+ else
+ return 1;
+}
+
+static void gpio_sw_release(struct device *dev)
+{
+}
+
+static int __init new_switch(struct gpio_switch *sw)
+{
+ int r, direction, trigger;
+
+ switch (sw->type) {
+ case OMAP_GPIO_SWITCH_TYPE_COVER:
+ case OMAP_GPIO_SWITCH_TYPE_CONNECTION:
+ case OMAP_GPIO_SWITCH_TYPE_ACTIVITY:
+ break;
+ default:
+ printk(KERN_ERR "invalid GPIO switch type: %d\n", sw->type);
+ return -EINVAL;
+ }
+
+ sw->pdev.name = sw->name;
+ sw->pdev.id = -1;
+
+ sw->pdev.dev.parent = &gpio_sw_platform_dev->dev;
+ sw->pdev.dev.driver = &gpio_sw_driver.driver;
+ sw->pdev.dev.release = gpio_sw_release;
+
+ r = platform_device_register(&sw->pdev);
+ if (r) {
+ printk(KERN_ERR "gpio-switch: platform device registration "
+ "failed for %s", sw->name);
+ return r;
+ }
+ dev_set_drvdata(&sw->pdev.dev, sw);
+
+ r = omap_request_gpio(sw->gpio);
+ if (r < 0) {
+ platform_device_unregister(&sw->pdev);
+ return r;
+ }
+
+ /* input: 1, output: 0 */
+ direction = !(sw->flags & OMAP_GPIO_SWITCH_FLAG_OUTPUT);
+ omap_set_gpio_direction(sw->gpio, direction);
+
+ sw->state = gpio_sw_get_state(sw);
+
+ r = 0;
+ r |= device_create_file(&sw->pdev.dev, &dev_attr_state);
+ r |= device_create_file(&sw->pdev.dev, &dev_attr_type);
+ r |= device_create_file(&sw->pdev.dev, &dev_attr_direction);
+ if (r)
+ printk(KERN_ERR "gpio-switch: attribute file creation "
+ "failed for %s\n", sw->name);
+
+ if (!direction)
+ return 0;
+
+ if (can_do_both_edges(sw)) {
+ trigger = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING;
+ sw->both_edges = 1;
+ } else {
+ if (omap_get_gpio_datain(sw->gpio))
+ trigger = IRQF_TRIGGER_FALLING;
+ else
+ trigger = IRQF_TRIGGER_RISING;
+ }
+ r = request_irq(OMAP_GPIO_IRQ(sw->gpio), gpio_sw_irq_handler,
+ IRQF_SHARED | trigger, sw->name, sw);
+ if (r < 0) {
+ printk(KERN_ERR "gpio-switch: request_irq() failed "
+ "for GPIO %d\n", sw->gpio);
+ platform_device_unregister(&sw->pdev);
+ omap_free_gpio(sw->gpio);
+ return r;
+ }
+
+ INIT_WORK(&sw->work, gpio_sw_handler);
+ init_timer(&sw->timer);
+
+ sw->timer.function = gpio_sw_timer;
+ sw->timer.data = (unsigned long)sw;
+
+ list_add(&sw->node, &gpio_switches);
+
+ return 0;
+}
+
+static int __init add_atag_switches(void)
+{
+ const struct omap_gpio_switch_config *cfg;
+ struct gpio_switch *sw;
+ int i, r;
+
+ for (i = 0; ; i++) {
+ cfg = omap_get_nr_config(OMAP_TAG_GPIO_SWITCH,
+ struct omap_gpio_switch_config, i);
+ if (cfg == NULL)
+ break;
+ sw = kzalloc(sizeof(*sw), GFP_KERNEL);
+ if (sw == NULL) {
+ printk(KERN_ERR "gpio-switch: kmalloc failed\n");
+ return -ENOMEM;
+ }
+ strncpy(sw->name, cfg->name, sizeof(cfg->name));
+ sw->gpio = cfg->gpio;
+ sw->flags = cfg->flags;
+ sw->type = cfg->type;
+ sw->debounce_rising = OMAP_GPIO_SW_DEFAULT_DEBOUNCE;
+ sw->debounce_falling = OMAP_GPIO_SW_DEFAULT_DEBOUNCE;
+ if ((r = new_switch(sw)) < 0) {
+ kfree(sw);
+ return r;
+ }
+ }
+ return 0;
+}
+
+static struct gpio_switch * __init find_switch(int gpio, const char *name)
+{
+ struct gpio_switch *sw;
+
+ list_for_each_entry(sw, &gpio_switches, node) {
+ if ((gpio < 0 || sw->gpio != gpio) &&
+ (name == NULL || strcmp(sw->name, name) != 0))
+ continue;
+
+ if (gpio < 0 || name == NULL)
+ goto no_check;
+
+ if (strcmp(sw->name, name) != 0)
+ printk("gpio-switch: name mismatch for %d (%s, %s)\n",
+ gpio, name, sw->name);
+ else if (sw->gpio != gpio)
+ printk("gpio-switch: GPIO mismatch for %s (%d, %d)\n",
+ name, gpio, sw->gpio);
+no_check:
+ return sw;
+ }
+ return NULL;
+}
+
+static int __init add_board_switches(void)
+{
+ int i;
+
+ for (i = 0; i < board_gpio_sw_count; i++) {
+ const struct omap_gpio_switch *cfg;
+ struct gpio_switch *sw;
+ int r;
+
+ cfg = board_gpio_sw_table + i;
+ if (strlen(cfg->name) > sizeof(sw->name) - 1)
+ return -EINVAL;
+ /* Check whether we only update an existing switch
+ * or add a new switch. */
+ sw = find_switch(cfg->gpio, cfg->name);
+ if (sw != NULL) {
+ sw->debounce_rising = cfg->debounce_rising;
+ sw->debounce_falling = cfg->debounce_falling;
+ sw->notify = cfg->notify;
+ sw->notify_data = cfg->notify_data;
+ continue;
+ } else {
+ if (cfg->gpio < 0 || cfg->name == NULL) {
+ printk("gpio-switch: required switch not "
+ "found (%d, %s)\n", cfg->gpio,
+ cfg->name);
+ continue;
+ }
+ }
+ sw = kzalloc(sizeof(*sw), GFP_KERNEL);
+ if (sw == NULL) {
+ printk(KERN_ERR "gpio-switch: kmalloc failed\n");
+ return -ENOMEM;
+ }
+ strlcpy(sw->name, cfg->name, sizeof(sw->name));
+ sw->gpio = cfg->gpio;
+ sw->flags = cfg->flags;
+ sw->type = cfg->type;
+ sw->debounce_rising = cfg->debounce_rising;
+ sw->debounce_falling = cfg->debounce_falling;
+ sw->notify = cfg->notify;
+ sw->notify_data = cfg->notify_data;
+ if ((r = new_switch(sw)) < 0) {
+ kfree(sw);
+ return r;
+ }
+ }
+ return 0;
+}
+
+static void gpio_sw_cleanup(void)
+{
+ struct gpio_switch *sw = NULL, *old = NULL;
+
+ list_for_each_entry(sw, &gpio_switches, node) {
+ if (old != NULL)
+ kfree(old);
+ flush_scheduled_work();
+ del_timer_sync(&sw->timer);
+
+ free_irq(OMAP_GPIO_IRQ(sw->gpio), sw);
+
+ device_remove_file(&sw->pdev.dev, &dev_attr_state);
+ device_remove_file(&sw->pdev.dev, &dev_attr_type);
+ device_remove_file(&sw->pdev.dev, &dev_attr_direction);
+
+ platform_device_unregister(&sw->pdev);
+ omap_free_gpio(sw->gpio);
+ old = sw;
+ }
+ kfree(old);
+}
+
+static void __init report_initial_state(void)
+{
+ struct gpio_switch *sw;
+
+ list_for_each_entry(sw, &gpio_switches, node) {
+ int state;
+
+ state = omap_get_gpio_datain(sw->gpio);
+ if (sw->flags & OMAP_GPIO_SWITCH_FLAG_INVERTED)
+ state = !state;
+ if (sw->notify != NULL)
+ sw->notify(sw->notify_data, state);
+ print_sw_state(sw, state);
+ }
+}
+
+static int gpio_sw_remove(struct platform_device *dev)
+{
+ return 0;
+}
+
+static struct platform_driver gpio_sw_driver = {
+ .remove = gpio_sw_remove,
+ .driver = {
+ .name = "gpio-switch",
+ },
+};
+
+void __init omap_register_gpio_switches(const struct omap_gpio_switch *tbl,
+ int count)
+{
+ BUG_ON(board_gpio_sw_table != NULL);
+
+ board_gpio_sw_table = tbl;
+ board_gpio_sw_count = count;
+}
+
+static int __init gpio_sw_init(void)
+{
+ int r;
+
+ printk(KERN_INFO "OMAP GPIO switch handler initializing\n");
+
+ r = platform_driver_register(&gpio_sw_driver);
+ if (r)
+ return r;
+
+ gpio_sw_platform_dev = platform_device_register_simple("gpio-switch",
+ -1, NULL, 0);
+ if (IS_ERR(gpio_sw_platform_dev)) {
+ r = PTR_ERR(gpio_sw_platform_dev);
+ goto err1;
+ }
+
+ r = add_atag_switches();
+ if (r < 0)
+ goto err2;
+
+ r = add_board_switches();
+ if (r < 0)
+ goto err2;
+
+ report_initial_state();
+
+ return 0;
+err2:
+ gpio_sw_cleanup();
+ platform_device_unregister(gpio_sw_platform_dev);
+err1:
+ platform_driver_unregister(&gpio_sw_driver);
+ return r;
+}
+
+static void __exit gpio_sw_exit(void)
+{
+ gpio_sw_cleanup();
+ platform_device_unregister(gpio_sw_platform_dev);
+ platform_driver_unregister(&gpio_sw_driver);
+}
+
+#ifndef MODULE
+late_initcall(gpio_sw_init);
+#else
+module_init(gpio_sw_init);
+#endif
+module_exit(gpio_sw_exit);
+
+MODULE_AUTHOR("Juha Yrjölä <juha.yrjola@nokia.com>, Paul Mundt <paul.mundt@nokia.com");
+MODULE_DESCRIPTION("GPIO switch driver");
+MODULE_LICENSE("GPL");
"failed to register mailbox interrupt:%d\n", ret);
goto fail_request_irq;
}
- enable_mbox_irq(mbox, IRQ_RX);
mq = mbox_queue_alloc(mbox, mbox_txq_fn, mbox_tx_work);
if (!mq) {
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/delay.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
+#include <linux/io.h>
+#include <linux/irq.h>
#include <asm/arch/dma.h>
#include <asm/arch/mux.h>
struct completion tx_dma_completion;
struct completion rx_dma_completion;
+ /* Protect the field .free, while checking if the mcbsp is in use */
spinlock_t lock;
};
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;
+static struct clk *mcbsp_dsp_ck;
+static struct clk *mcbsp_api_ck;
+static struct clk *mcbsp_dspxor_ck;
#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 *mcbsp1_ick;
+static struct clk *mcbsp1_fck;
+static struct clk *mcbsp2_ick;
+static struct clk *mcbsp2_fck;
#endif
static void omap_mcbsp_dump_reg(u8 id)
OMAP_MCBSP_READ(mcbsp_tx->io_base, SPCR2));
complete(&mcbsp_tx->tx_irq_completion);
+
return IRQ_HANDLED;
}
OMAP_MCBSP_READ(mcbsp_rx->io_base, SPCR2));
complete(&mcbsp_rx->rx_irq_completion);
+
return IRQ_HANDLED;
}
complete(&mcbsp_dma_rx->rx_dma_completion);
}
-
/*
* omap_mcbsp_config simply write a config to the
* appropriate McBSP.
* You either call this function or set the McBSP registers
* by yourself before calling omap_mcbsp_start().
*/
-
-void omap_mcbsp_config(unsigned int id, const struct omap_mcbsp_reg_cfg * config)
+void omap_mcbsp_config(unsigned int id, const struct omap_mcbsp_reg_cfg *config)
{
u32 io_base = mcbsp[id].io_base;
- DBG("OMAP-McBSP: McBSP%d io_base: 0x%8x\n", id+1, io_base);
+ DBG("OMAP-McBSP: McBSP%d io_base: 0x%8x\n", id + 1, io_base);
/* We write the given config */
OMAP_MCBSP_WRITE(io_base, SPCR2, config->spcr2);
OMAP_MCBSP_WRITE(io_base, MCR1, config->mcr1);
OMAP_MCBSP_WRITE(io_base, PCR0, config->pcr0);
}
-
-
+EXPORT_SYMBOL(omap_mcbsp_config);
static int omap_mcbsp_check(unsigned int id)
{
if (cpu_is_omap730()) {
if (id > OMAP_MAX_MCBSP_COUNT - 1) {
- printk(KERN_ERR "OMAP-McBSP: McBSP%d doesn't exist\n", id + 1);
+ printk(KERN_ERR "OMAP-McBSP: McBSP%d doesn't exist\n",
+ id + 1);
return -1;
}
return 0;
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);
+ printk(KERN_ERR "OMAP-McBSP: McBSP%d doesn't exist\n",
+ id + 1);
return -1;
}
return 0;
spin_lock(&mcbsp[id].lock);
if (!mcbsp[id].free) {
- printk (KERN_ERR "OMAP-McBSP: McBSP%d is currently in use\n", id + 1);
+ printk(KERN_ERR "OMAP-McBSP: McBSP%d is currently in use\n",
+ id + 1);
spin_unlock(&mcbsp[id].lock);
return -EINVAL;
}
return 0;
}
+EXPORT_SYMBOL(omap_mcbsp_set_io_type);
int omap_mcbsp_request(unsigned int id)
{
spin_lock(&mcbsp[id].lock);
if (!mcbsp[id].free) {
- printk (KERN_ERR "OMAP-McBSP: McBSP%d is currently in use\n", id + 1);
+ printk(KERN_ERR "OMAP-McBSP: McBSP%d is currently in use\n",
+ id + 1);
spin_unlock(&mcbsp[id].lock);
return -1;
}
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]));
+ 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);
+ 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]));
+ 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);
+ 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;
}
}
return 0;
-
}
+EXPORT_SYMBOL(omap_mcbsp_request);
void omap_mcbsp_free(unsigned int id)
{
spin_lock(&mcbsp[id].lock);
if (mcbsp[id].free) {
- printk (KERN_ERR "OMAP-McBSP: McBSP%d was not reserved\n", id + 1);
+ printk(KERN_ERR "OMAP-McBSP: McBSP%d was not reserved\n",
+ id + 1);
spin_unlock(&mcbsp[id].lock);
return;
}
free_irq(mcbsp[id].tx_irq, (void *) (&mcbsp[id]));
}
}
+EXPORT_SYMBOL(omap_mcbsp_free);
/*
* Here we start the McBSP, by enabling the sample
io_base = mcbsp[id].io_base;
- mcbsp[id].rx_word_length = ((OMAP_MCBSP_READ(io_base, RCR1) >> 5) & 0x7);
- mcbsp[id].tx_word_length = ((OMAP_MCBSP_READ(io_base, XCR1) >> 5) & 0x7);
+ mcbsp[id].rx_word_length = (OMAP_MCBSP_READ(io_base, RCR1) >> 5) & 0x7;
+ mcbsp[id].tx_word_length = (OMAP_MCBSP_READ(io_base, XCR1) >> 5) & 0x7;
/* Start the sample generator */
w = OMAP_MCBSP_READ(io_base, SPCR2);
/* Dump McBSP Regs */
omap_mcbsp_dump_reg(id);
-
}
+EXPORT_SYMBOL(omap_mcbsp_start);
void omap_mcbsp_stop(unsigned int id)
{
io_base = mcbsp[id].io_base;
- /* Reset transmitter */
+ /* Reset transmitter */
w = OMAP_MCBSP_READ(io_base, SPCR2);
OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1));
w = OMAP_MCBSP_READ(io_base, SPCR2);
OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1 << 6));
}
-
+EXPORT_SYMBOL(omap_mcbsp_stop);
/* polled mcbsp i/o operations */
int omap_mcbsp_pollwrite(unsigned int id, u16 buf)
}
}
}
+
return 0;
}
+EXPORT_SYMBOL(omap_mcbsp_pollwrite);
-int omap_mcbsp_pollread(unsigned int id, u16 * buf)
+int omap_mcbsp_pollread(unsigned int id, u16 *buf)
{
u32 base = mcbsp[id].io_base;
/* if frame sync error - clear the error */
}
}
*buf = readw(base + OMAP_MCBSP_REG_DRR1);
+
return 0;
}
+EXPORT_SYMBOL(omap_mcbsp_pollread);
/*
* IRQ based word transmission.
OMAP_MCBSP_WRITE(io_base, DXR2, word >> 16);
OMAP_MCBSP_WRITE(io_base, DXR1, word & 0xffff);
}
+EXPORT_SYMBOL(omap_mcbsp_xmit_word);
u32 omap_mcbsp_recv_word(unsigned int id)
{
return (word_lsb | (word_msb << 16));
}
-
+EXPORT_SYMBOL(omap_mcbsp_recv_word);
int omap_mcbsp_spi_master_xmit_word_poll(unsigned int id, u32 word)
{
udelay(10);
OMAP_MCBSP_WRITE(io_base, SPCR2, spcr2 | XRST);
udelay(10);
- printk("McBSP transmitter not ready\n");
+ printk(KERN_ERR "McBSP transmitter not ready\n");
return -EAGAIN;
}
}
udelay(10);
OMAP_MCBSP_WRITE(io_base, SPCR1, spcr1 | RRST);
udelay(10);
- printk("McBSP receiver not ready\n");
+ printk(KERN_ERR "McBSP receiver not ready\n");
return -EAGAIN;
}
}
return 0;
}
+EXPORT_SYMBOL(omap_mcbsp_spi_master_xmit_word_poll);
-int omap_mcbsp_spi_master_recv_word_poll(unsigned int id, u32 * word)
+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;
udelay(10);
OMAP_MCBSP_WRITE(io_base, SPCR2, spcr2 | XRST);
udelay(10);
- printk("McBSP transmitter not ready\n");
+ printk(KERN_ERR "McBSP transmitter not ready\n");
return -EAGAIN;
}
}
udelay(10);
OMAP_MCBSP_WRITE(io_base, SPCR1, spcr1 | RRST);
udelay(10);
- printk("McBSP receiver not ready\n");
+ printk(KERN_ERR "McBSP receiver not ready\n");
return -EAGAIN;
}
}
return 0;
}
-
+EXPORT_SYMBOL(omap_mcbsp_spi_master_recv_word_poll);
/*
* Simple DMA based buffer rx/tx routines.
* For anything fancier, you should use your own customized DMA
* routines and callbacks.
*/
-int omap_mcbsp_xmit_buffer(unsigned int id, dma_addr_t buffer, unsigned int length)
+int omap_mcbsp_xmit_buffer(unsigned int id, dma_addr_t buffer,
+ unsigned int length)
{
int dma_tx_ch;
int src_port = 0;
if (omap_mcbsp_check(id) < 0)
return -EINVAL;
- if (omap_request_dma(mcbsp[id].dma_tx_sync, "McBSP TX", omap_mcbsp_tx_dma_callback,
- &mcbsp[id],
- &dma_tx_ch)) {
- printk("OMAP-McBSP: Unable to request DMA channel for McBSP%d TX. Trying IRQ based TX\n", id+1);
+ if (omap_request_dma(mcbsp[id].dma_tx_sync, "McBSP TX",
+ omap_mcbsp_tx_dma_callback,
+ &mcbsp[id],
+ &dma_tx_ch)) {
+ printk(KERN_ERR "OMAP-McBSP: Unable to request DMA channel for"
+ " McBSP%d TX. Trying IRQ based TX\n", id + 1);
return -EAGAIN;
}
mcbsp[id].dma_tx_lch = dma_tx_ch;
omap_start_dma(mcbsp[id].dma_tx_lch);
wait_for_completion(&(mcbsp[id].tx_dma_completion));
+
return 0;
}
+EXPORT_SYMBOL(omap_mcbsp_xmit_buffer);
-
-int omap_mcbsp_recv_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 dma_rx_ch;
int src_port = 0;
if (omap_mcbsp_check(id) < 0)
return -EINVAL;
- if (omap_request_dma(mcbsp[id].dma_rx_sync, "McBSP RX", omap_mcbsp_rx_dma_callback,
- &mcbsp[id],
- &dma_rx_ch)) {
- printk("Unable to request DMA channel for McBSP%d RX. Trying IRQ based RX\n", id+1);
+ if (omap_request_dma(mcbsp[id].dma_rx_sync, "McBSP RX",
+ omap_mcbsp_rx_dma_callback,
+ &mcbsp[id],
+ &dma_rx_ch)) {
+ printk(KERN_ERR "Unable to request DMA channel for McBSP%d RX."
+ " Trying IRQ based RX\n", id + 1);
return -EAGAIN;
}
mcbsp[id].dma_rx_lch = dma_rx_ch;
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,
- sync_dev, 0);
+ OMAP_DMA_DATA_TYPE_S16,
+ length >> 1, 1,
+ OMAP_DMA_SYNC_ELEMENT,
+ sync_dev, 0);
omap_set_dma_src_params(mcbsp[id].dma_rx_lch,
src_port,
0, 0);
omap_set_dma_dest_params(mcbsp[id].dma_rx_lch,
- dest_port,
- OMAP_DMA_AMODE_POST_INC,
- buffer,
- 0, 0);
+ dest_port,
+ OMAP_DMA_AMODE_POST_INC,
+ buffer,
+ 0, 0);
omap_start_dma(mcbsp[id].dma_rx_lch);
wait_for_completion(&(mcbsp[id].rx_dma_completion));
+
return 0;
}
-
+EXPORT_SYMBOL(omap_mcbsp_recv_buffer);
/*
* SPI wrapper.
* this wrapper just need an omap_mcbsp_spi_cfg structure as an input.
* Once this is done, you can call omap_mcbsp_start().
*/
-void omap_mcbsp_set_spi_mode(unsigned int id, const struct omap_mcbsp_spi_cfg * spi_cfg)
+void omap_mcbsp_set_spi_mode(unsigned int id,
+ const struct omap_mcbsp_spi_cfg *spi_cfg)
{
struct omap_mcbsp_reg_cfg mcbsp_cfg;
mcbsp_cfg.rcr1 |= (RWDLEN1(spi_cfg->word_length) | RFRLEN1(0));
mcbsp_cfg.xcr1 |= (XWDLEN1(spi_cfg->word_length) | XFRLEN1(0));
- /* Clock stop mode */
+ /* Clock stop mode */
if (spi_cfg->clk_stp_mode == OMAP_MCBSP_CLK_STP_MODE_NO_DELAY)
mcbsp_cfg.spcr1 |= (1 << 12);
else
if (spi_cfg->spi_mode == OMAP_MCBSP_SPI_MASTER) {
mcbsp_cfg.pcr0 |= CLKXM;
- mcbsp_cfg.srgr1 |= CLKGDV(spi_cfg->clk_div -1);
+ mcbsp_cfg.srgr1 |= CLKGDV(spi_cfg->clk_div - 1);
mcbsp_cfg.pcr0 |= FSXM;
mcbsp_cfg.srgr2 &= ~FSGM;
mcbsp_cfg.xcr2 |= XDATDLY(1);
mcbsp_cfg.rcr2 |= RDATDLY(1);
- }
- else {
+ } else {
mcbsp_cfg.pcr0 &= ~CLKXM;
mcbsp_cfg.srgr1 |= CLKGDV(1);
mcbsp_cfg.pcr0 &= ~FSXM;
omap_mcbsp_config(id, &mcbsp_cfg);
}
-
+EXPORT_SYMBOL(omap_mcbsp_set_spi_mode);
/*
* McBSP1 and McBSP3 are directly mapped on 1610 and 1510.
int mcbsp_count = 0, i;
static const struct omap_mcbsp_info *mcbsp_info;
- printk("Initializing OMAP McBSP system\n");
+ printk(KERN_INFO "Initializing OMAP McBSP system\n");
#ifdef CONFIG_ARCH_OMAP1
mcbsp_dsp_ck = clk_get(0, "dsp_ck");
#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");
+ 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");
+ 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");
+ 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");
+ printk(KERN_ERR "mcbsp: could not acquire "
+ "mcbsp2_fck handle.\n");
return PTR_ERR(mcbsp2_fck);
}
#endif
if (i >= mcbsp_count) {
mcbsp[i].io_base = 0;
mcbsp[i].free = 0;
- continue;
+ continue;
}
mcbsp[i].id = i + 1;
mcbsp[i].free = 1;
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 */
+ /* Default I/O is IRQ based */
+ mcbsp[i].io_type = OMAP_MCBSP_IRQ_IO;
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;
}
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_pollread);
-EXPORT_SYMBOL(omap_mcbsp_pollwrite);
-EXPORT_SYMBOL(omap_mcbsp_xmit_word);
-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);
--- /dev/null
+/*
+ * linux/arch/arm/plat-omap/mmu.c
+ *
+ * OMAP MMU management framework
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation
+ *
+ * Written by Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ * and Paul Mundt <lethal@linux-sh.org>
+ *
+ * TWL support: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/mempool.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+#include <asm/arch/mmu.h>
+#include <asm/sizes.h>
+#include <asm/arch/dsp_common.h>
+
+#if defined(CONFIG_ARCH_OMAP1)
+#include "../mach-omap1/mmu.h"
+#elif defined(CONFIG_ARCH_OMAP2)
+#include "../mach-omap2/mmu.h"
+#endif
+
+/*
+ * On OMAP2 MMU_LOCK_xxx_MASK only applies to the IVA and DSP, the camera
+ * MMU has base and victim implemented in different bits in the LOCK
+ * register (shifts are still the same), all of the other registers are
+ * the same on all of the MMUs..
+ */
+#define MMU_LOCK_BASE_SHIFT 10
+#define MMU_LOCK_VICTIM_SHIFT 4
+
+#define CAMERA_MMU_LOCK_BASE_MASK (0x7 << MMU_LOCK_BASE_SHIFT)
+#define CAMERA_MMU_LOCK_VICTIM_MASK (0x7 << MMU_LOCK_VICTIM_SHIFT)
+
+#define is_aligned(adr, align) (!((adr)&((align)-1)))
+#define ORDER_1MB (20 - PAGE_SHIFT)
+#define ORDER_64KB (16 - PAGE_SHIFT)
+#define ORDER_4KB (12 - PAGE_SHIFT)
+
+#define MMU_CNTL_EMUTLBUPDATE (1<<3)
+#define MMU_CNTL_TWLENABLE (1<<2)
+#define MMU_CNTL_MMUENABLE (1<<1)
+
+static mempool_t *mempool_1M;
+static mempool_t *mempool_64K;
+
+#define omap_mmu_for_each_tlb_entry(mmu, entry) \
+ for (entry = mmu->exmap_tbl; prefetch(entry + 1), \
+ entry < (mmu->exmap_tbl + mmu->nr_tlb_entries); \
+ entry++)
+
+#define to_dev(obj) container_of(obj, struct device, kobj)
+
+static void *mempool_alloc_from_pool(mempool_t *pool,
+ unsigned int __nocast gfp_mask)
+{
+ spin_lock_irq(&pool->lock);
+ if (likely(pool->curr_nr)) {
+ void *element = pool->elements[--pool->curr_nr];
+ spin_unlock_irq(&pool->lock);
+ return element;
+ }
+
+ spin_unlock_irq(&pool->lock);
+ return mempool_alloc(pool, gfp_mask);
+}
+
+/*
+ * kmem_reserve(), kmem_release():
+ * reserve or release kernel memory for exmap().
+ *
+ * exmap() might request consecutive 1MB or 64kB,
+ * but it will be difficult after memory pages are fragmented.
+ * So, user can reserve such memory blocks in the early phase
+ * through kmem_reserve().
+ */
+static void *omap_mmu_pool_alloc(unsigned int __nocast gfp, void *order)
+{
+ return (void *)__get_dma_pages(gfp, (unsigned int)order);
+}
+
+static void omap_mmu_pool_free(void *buf, void *order)
+{
+ free_pages((unsigned long)buf, (unsigned int)order);
+}
+
+int omap_mmu_kmem_reserve(struct omap_mmu *mmu, unsigned long size)
+{
+ unsigned long len = size;
+
+ /* alignment check */
+ if (!is_aligned(size, SZ_64K)) {
+ dev_err(mmu->dev,
+ "MMU %s: size(0x%lx) is not multiple of 64KB.\n",
+ mmu->name, size);
+ return -EINVAL;
+ }
+
+ if (size > (1 << mmu->addrspace)) {
+ dev_err(mmu->dev,
+ "MMU %s: size(0x%lx) is larger than external device "
+ " memory space size (0x%x.\n", mmu->name, size,
+ (1 << mmu->addrspace));
+ return -EINVAL;
+ }
+
+ if (size >= SZ_1M) {
+ int nr = size >> 20;
+
+ if (likely(!mempool_1M))
+ mempool_1M = mempool_create(nr, omap_mmu_pool_alloc,
+ omap_mmu_pool_free,
+ (void *)ORDER_1MB);
+ else
+ mempool_resize(mempool_1M, mempool_1M->min_nr + nr,
+ GFP_KERNEL);
+
+ size &= ~(0xf << 20);
+ }
+
+ if (size >= SZ_64K) {
+ int nr = size >> 16;
+
+ if (likely(!mempool_64K))
+ mempool_64K = mempool_create(nr, omap_mmu_pool_alloc,
+ omap_mmu_pool_free,
+ (void *)ORDER_64KB);
+ else
+ mempool_resize(mempool_64K, mempool_64K->min_nr + nr,
+ GFP_KERNEL);
+
+ size &= ~(0xf << 16);
+ }
+
+ if (size)
+ len -= size;
+
+ return len;
+}
+EXPORT_SYMBOL_GPL(omap_mmu_kmem_reserve);
+
+void omap_mmu_kmem_release(void)
+{
+ if (mempool_64K) {
+ mempool_destroy(mempool_64K);
+ mempool_64K = NULL;
+ }
+
+ if (mempool_1M) {
+ mempool_destroy(mempool_1M);
+ mempool_1M = NULL;
+ }
+}
+EXPORT_SYMBOL_GPL(omap_mmu_kmem_release);
+
+static void omap_mmu_free_pages(unsigned long buf, unsigned int order)
+{
+ struct page *page, *ps, *pe;
+
+ ps = virt_to_page(buf);
+ pe = virt_to_page(buf + (1 << (PAGE_SHIFT + order)));
+
+ for (page = ps; page < pe; page++)
+ ClearPageReserved(page);
+
+ if ((order == ORDER_64KB) && likely(mempool_64K))
+ mempool_free((void *)buf, mempool_64K);
+ else if ((order == ORDER_1MB) && likely(mempool_1M))
+ mempool_free((void *)buf, mempool_1M);
+ else
+ free_pages(buf, order);
+}
+
+/*
+ * ARM MMU operations
+ */
+int exmap_set_armmmu(struct omap_mmu *mmu, unsigned long virt,
+ unsigned long phys, unsigned long size)
+{
+ long off;
+ unsigned long sz_left;
+ pmd_t *pmdp;
+ pte_t *ptep;
+ int prot_pmd, prot_pte;
+
+ dev_dbg(mmu->dev,
+ "MMU %s: mapping in ARM MMU, v=0x%08lx, p=0x%08lx, sz=0x%lx\n",
+ mmu->name, virt, phys, size);
+
+ prot_pmd = PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_IO);
+ prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_WRITE;
+
+ pmdp = pmd_offset(pgd_offset_k(virt), virt);
+ if (pmd_none(*pmdp)) {
+ ptep = pte_alloc_one_kernel(&init_mm, 0);
+ if (ptep == NULL)
+ return -ENOMEM;
+ /* note: two PMDs will be set */
+ pmd_populate_kernel(&init_mm, pmdp, ptep);
+ }
+
+ off = phys - virt;
+ for (sz_left = size;
+ sz_left >= PAGE_SIZE;
+ sz_left -= PAGE_SIZE, virt += PAGE_SIZE) {
+ ptep = pte_offset_kernel(pmdp, virt);
+ set_pte_ext(ptep, __pte((virt + off) | prot_pte), 0);
+ }
+ if (sz_left)
+ BUG();
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(exmap_set_armmmu);
+
+void exmap_clear_armmmu(struct omap_mmu *mmu, unsigned long virt,
+ unsigned long size)
+{
+ unsigned long sz_left;
+ pmd_t *pmdp;
+ pte_t *ptep;
+
+ dev_dbg(mmu->dev,
+ "MMU %s: unmapping in ARM MMU, v=0x%08lx, sz=0x%lx\n",
+ mmu->name, virt, size);
+
+ for (sz_left = size;
+ sz_left >= PAGE_SIZE;
+ sz_left -= PAGE_SIZE, virt += PAGE_SIZE) {
+ pmdp = pmd_offset(pgd_offset_k(virt), virt);
+ ptep = pte_offset_kernel(pmdp, virt);
+ pte_clear(&init_mm, virt, ptep);
+ }
+ if (sz_left)
+ BUG();
+}
+EXPORT_SYMBOL_GPL(exmap_clear_armmmu);
+
+int exmap_valid(struct omap_mmu *mmu, void *vadr, size_t len)
+{
+ /* exmap_sem should be held before calling this function */
+ struct exmap_tbl *ent;
+
+start:
+ omap_mmu_for_each_tlb_entry(mmu, ent) {
+ void *mapadr;
+ unsigned long mapsize;
+
+ if (!ent->valid)
+ continue;
+ mapadr = (void *)ent->vadr;
+ mapsize = 1 << (ent->order + PAGE_SHIFT);
+ if ((vadr >= mapadr) && (vadr < mapadr + mapsize)) {
+ if (vadr + len <= mapadr + mapsize) {
+ /* this map covers whole address. */
+ return 1;
+ } else {
+ /*
+ * this map covers partially.
+ * check rest portion.
+ */
+ len -= mapadr + mapsize - vadr;
+ vadr = mapadr + mapsize;
+ goto start;
+ }
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(exmap_valid);
+
+/*
+ * omap_mmu_exmap_use(), unuse():
+ * when the mapped area is exported to user space with mmap,
+ * the usecount is incremented.
+ * while the usecount > 0, that area can't be released.
+ */
+void omap_mmu_exmap_use(struct omap_mmu *mmu, void *vadr, size_t len)
+{
+ struct exmap_tbl *ent;
+
+ down_write(&mmu->exmap_sem);
+ omap_mmu_for_each_tlb_entry(mmu, ent) {
+ void *mapadr;
+ unsigned long mapsize;
+
+ if (!ent->valid)
+ continue;
+ mapadr = (void *)ent->vadr;
+ mapsize = 1 << (ent->order + PAGE_SHIFT);
+ if ((vadr + len > mapadr) && (vadr < mapadr + mapsize))
+ ent->usecount++;
+ }
+ up_write(&mmu->exmap_sem);
+}
+EXPORT_SYMBOL_GPL(omap_mmu_exmap_use);
+
+void omap_mmu_exmap_unuse(struct omap_mmu *mmu, void *vadr, size_t len)
+{
+ struct exmap_tbl *ent;
+
+ down_write(&mmu->exmap_sem);
+ omap_mmu_for_each_tlb_entry(mmu, ent) {
+ void *mapadr;
+ unsigned long mapsize;
+
+ if (!ent->valid)
+ continue;
+ mapadr = (void *)ent->vadr;
+ mapsize = 1 << (ent->order + PAGE_SHIFT);
+ if ((vadr + len > mapadr) && (vadr < mapadr + mapsize))
+ ent->usecount--;
+ }
+ up_write(&mmu->exmap_sem);
+}
+EXPORT_SYMBOL_GPL(omap_mmu_exmap_unuse);
+
+/*
+ * omap_mmu_virt_to_phys()
+ * returns physical address, and sets len to valid length
+ */
+unsigned long
+omap_mmu_virt_to_phys(struct omap_mmu *mmu, void *vadr, size_t *len)
+{
+ struct exmap_tbl *ent;
+
+ if (omap_mmu_internal_memory(mmu, vadr)) {
+ unsigned long addr = (unsigned long)vadr;
+ *len = mmu->membase + mmu->memsize - addr;
+ return addr;
+ }
+
+ /* EXRAM */
+ omap_mmu_for_each_tlb_entry(mmu, ent) {
+ void *mapadr;
+ unsigned long mapsize;
+
+ if (!ent->valid)
+ continue;
+ mapadr = (void *)ent->vadr;
+ mapsize = 1 << (ent->order + PAGE_SHIFT);
+ if ((vadr >= mapadr) && (vadr < mapadr + mapsize)) {
+ *len = mapadr + mapsize - vadr;
+ return __pa(ent->buf) + vadr - mapadr;
+ }
+ }
+
+ /* valid mapping not found */
+ return 0;
+}
+EXPORT_SYMBOL_GPL(omap_mmu_virt_to_phys);
+
+/*
+ * PTE operations
+ */
+static inline void
+omap_mmu_alloc_section(struct mm_struct *mm, unsigned long virt,
+ unsigned long phys, int prot)
+{
+ pmd_t *pmdp = pmd_offset(pgd_offset(mm, virt), virt);
+ if (virt & (1 << SECTION_SHIFT))
+ pmdp++;
+ *pmdp = __pmd((phys & SECTION_MASK) | prot | PMD_TYPE_SECT);
+ flush_pmd_entry(pmdp);
+}
+
+static inline void
+omap_mmu_alloc_supersection(struct mm_struct *mm, unsigned long virt,
+ unsigned long phys, int prot)
+{
+ int i;
+ for (i = 0; i < 16; i += 1) {
+ omap_mmu_alloc_section(mm, virt, phys, prot | PMD_SECT_SUPER);
+ virt += (PGDIR_SIZE / 2);
+ }
+}
+
+static inline int
+omap_mmu_alloc_page(struct mm_struct *mm, unsigned long virt,
+ unsigned long phys, pgprot_t prot)
+{
+ pte_t *ptep;
+ pmd_t *pmdp = pmd_offset(pgd_offset(mm, virt), virt);
+
+ if (!(prot & PTE_TYPE_MASK))
+ prot |= PTE_TYPE_SMALL;
+
+ if (pmd_none(*pmdp)) {
+ ptep = pte_alloc_one_kernel(mm, virt);
+ if (ptep == NULL)
+ return -ENOMEM;
+ pmd_populate_kernel(mm, pmdp, ptep);
+ }
+ ptep = pte_offset_kernel(pmdp, virt);
+ ptep -= PTRS_PER_PTE;
+ *ptep = pfn_pte(phys >> PAGE_SHIFT, prot);
+ flush_pmd_entry((pmd_t *)ptep);
+ return 0;
+}
+
+static inline int
+omap_mmu_alloc_largepage(struct mm_struct *mm, unsigned long virt,
+ unsigned long phys, pgprot_t prot)
+{
+ int i, ret;
+ for (i = 0; i < 16; i += 1) {
+ ret = omap_mmu_alloc_page(mm, virt, phys,
+ prot | PTE_TYPE_LARGE);
+ if (ret)
+ return -ENOMEM; /* only 1st time */
+ virt += PAGE_SIZE;
+ }
+ return 0;
+}
+
+static int omap_mmu_load_pte(struct omap_mmu *mmu,
+ struct omap_mmu_tlb_entry *e)
+{
+ int ret = 0;
+ struct mm_struct *mm = mmu->twl_mm;
+ const unsigned long va = e->va;
+ const unsigned long pa = e->pa;
+ const pgprot_t prot = mmu->ops->pte_get_attr(e);
+
+ spin_lock(&mm->page_table_lock);
+
+ switch (e->pgsz) {
+ case OMAP_MMU_CAM_PAGESIZE_16MB:
+ omap_mmu_alloc_supersection(mm, va, pa, prot);
+ break;
+ case OMAP_MMU_CAM_PAGESIZE_1MB:
+ omap_mmu_alloc_section(mm, va, pa, prot);
+ break;
+ case OMAP_MMU_CAM_PAGESIZE_64KB:
+ ret = omap_mmu_alloc_largepage(mm, va, pa, prot);
+ break;
+ case OMAP_MMU_CAM_PAGESIZE_4KB:
+ ret = omap_mmu_alloc_page(mm, va, pa, prot);
+ break;
+ default:
+ BUG();
+ break;
+ }
+
+ spin_unlock(&mm->page_table_lock);
+
+ return ret;
+}
+
+static void omap_mmu_clear_pte(struct omap_mmu *mmu, unsigned long virt)
+{
+ pte_t *ptep, *end;
+ pmd_t *pmdp;
+ struct mm_struct *mm = mmu->twl_mm;
+
+ spin_lock(&mm->page_table_lock);
+
+ pmdp = pmd_offset(pgd_offset(mm, virt), virt);
+
+ if (pmd_none(*pmdp))
+ goto out;
+
+ if (!pmd_table(*pmdp))
+ goto invalidate_pmd;
+
+ ptep = pte_offset_kernel(pmdp, virt);
+ pte_clear(mm, virt, ptep);
+ flush_pmd_entry((pmd_t *)ptep);
+
+ /* zap pte */
+ end = pmd_page_vaddr(*pmdp);
+ ptep = end - PTRS_PER_PTE;
+ while (ptep < end) {
+ if (!pte_none(*ptep))
+ goto out;
+ ptep++;
+ }
+ pte_free_kernel(mm, pmd_page_vaddr(*pmdp));
+
+ invalidate_pmd:
+ pmd_clear(pmdp);
+ flush_pmd_entry(pmdp);
+ out:
+ spin_unlock(&mm->page_table_lock);
+}
+
+/*
+ * TLB operations
+ */
+static struct cam_ram_regset *
+omap_mmu_cam_ram_alloc(struct omap_mmu *mmu, struct omap_mmu_tlb_entry *entry)
+{
+ return mmu->ops->cam_ram_alloc(mmu, entry);
+}
+
+static int omap_mmu_cam_ram_valid(struct omap_mmu *mmu,
+ struct cam_ram_regset *cr)
+{
+ return mmu->ops->cam_ram_valid(cr);
+}
+
+static inline void
+omap_mmu_get_tlb_lock(struct omap_mmu *mmu, struct omap_mmu_tlb_lock *tlb_lock)
+{
+ unsigned long lock = omap_mmu_read_reg(mmu, OMAP_MMU_LOCK);
+ int mask;
+
+ mask = (mmu->type == OMAP_MMU_CAMERA) ?
+ CAMERA_MMU_LOCK_BASE_MASK : MMU_LOCK_BASE_MASK;
+ tlb_lock->base = (lock & mask) >> MMU_LOCK_BASE_SHIFT;
+
+ mask = (mmu->type == OMAP_MMU_CAMERA) ?
+ CAMERA_MMU_LOCK_VICTIM_MASK : MMU_LOCK_VICTIM_MASK;
+ tlb_lock->victim = (lock & mask) >> MMU_LOCK_VICTIM_SHIFT;
+}
+
+static inline void
+omap_mmu_set_tlb_lock(struct omap_mmu *mmu, struct omap_mmu_tlb_lock *lock)
+{
+ omap_mmu_write_reg(mmu,
+ (lock->base << MMU_LOCK_BASE_SHIFT) |
+ (lock->victim << MMU_LOCK_VICTIM_SHIFT),
+ OMAP_MMU_LOCK);
+}
+
+static inline void omap_mmu_flush(struct omap_mmu *mmu)
+{
+ omap_mmu_write_reg(mmu, 0x1, OMAP_MMU_FLUSH_ENTRY);
+}
+
+static inline void omap_mmu_ldtlb(struct omap_mmu *mmu)
+{
+ omap_mmu_write_reg(mmu, 0x1, OMAP_MMU_LD_TLB);
+}
+
+void omap_mmu_read_tlb(struct omap_mmu *mmu, struct omap_mmu_tlb_lock *lock,
+ struct cam_ram_regset *cr)
+{
+ /* set victim */
+ omap_mmu_set_tlb_lock(mmu, lock);
+
+ if (likely(mmu->ops->read_tlb))
+ mmu->ops->read_tlb(mmu, cr);
+}
+EXPORT_SYMBOL_GPL(omap_mmu_read_tlb);
+
+void omap_mmu_load_tlb(struct omap_mmu *mmu, struct cam_ram_regset *cr)
+{
+ if (likely(mmu->ops->load_tlb))
+ mmu->ops->load_tlb(mmu, cr);
+
+ /* flush the entry */
+ omap_mmu_flush(mmu);
+
+ /* load a TLB entry */
+ omap_mmu_ldtlb(mmu);
+}
+
+int omap_mmu_load_tlb_entry(struct omap_mmu *mmu,
+ struct omap_mmu_tlb_entry *entry)
+{
+ struct omap_mmu_tlb_lock lock;
+ struct cam_ram_regset *cr;
+ int ret;
+
+ clk_enable(mmu->clk);
+ ret = omap_dsp_request_mem();
+ if (ret < 0)
+ goto out;
+
+ omap_mmu_get_tlb_lock(mmu, &lock);
+ for (lock.victim = 0; lock.victim < lock.base; lock.victim++) {
+ struct cam_ram_regset tmp;
+
+ /* read a TLB entry */
+ omap_mmu_read_tlb(mmu, &lock, &tmp);
+ if (!omap_mmu_cam_ram_valid(mmu, &tmp))
+ goto found_victim;
+ }
+ omap_mmu_set_tlb_lock(mmu, &lock);
+
+found_victim:
+ /* The last entry cannot be locked? */
+ if (lock.victim == (mmu->nr_tlb_entries - 1)) {
+ dev_err(mmu->dev, "MMU %s: TLB is full.\n", mmu->name);
+ return -EBUSY;
+ }
+
+ cr = omap_mmu_cam_ram_alloc(mmu, entry);
+ if (IS_ERR(cr))
+ return PTR_ERR(cr);
+
+ omap_mmu_load_tlb(mmu, cr);
+ kfree(cr);
+
+ /* update lock base */
+ if (lock.victim == lock.base)
+ lock.base++;
+
+ omap_mmu_set_tlb_lock(mmu, &lock);
+
+ omap_dsp_release_mem();
+out:
+ clk_disable(mmu->clk);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(omap_mmu_load_tlb_entry);
+
+static inline unsigned long
+omap_mmu_cam_va(struct omap_mmu *mmu, struct cam_ram_regset *cr)
+{
+ return mmu->ops->cam_va(cr);
+}
+
+int omap_mmu_clear_tlb_entry(struct omap_mmu *mmu, unsigned long vadr)
+{
+ struct omap_mmu_tlb_lock lock;
+ int i, ret = 0;
+ int max_valid = 0;
+
+ clk_enable(mmu->clk);
+ ret = omap_dsp_request_mem();
+ if (ret < 0)
+ goto out;
+
+ omap_mmu_get_tlb_lock(mmu, &lock);
+ for (i = 0; i < lock.base; i++) {
+ struct cam_ram_regset cr;
+
+ /* read a TLB entry */
+ lock.victim = i;
+ omap_mmu_read_tlb(mmu, &lock, &cr);
+ if (!omap_mmu_cam_ram_valid(mmu, &cr))
+ continue;
+
+ if (omap_mmu_cam_va(mmu, &cr) == vadr)
+ /* flush the entry */
+ omap_mmu_flush(mmu);
+ else
+ max_valid = i;
+ }
+
+ /* set new lock base */
+ lock.base = lock.victim = max_valid + 1;
+ omap_mmu_set_tlb_lock(mmu, &lock);
+
+ omap_dsp_release_mem();
+out:
+ clk_disable(mmu->clk);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(omap_mmu_clear_tlb_entry);
+
+static void omap_mmu_gflush(struct omap_mmu *mmu)
+{
+ struct omap_mmu_tlb_lock lock;
+ int ret;
+
+ clk_enable(mmu->clk);
+ ret = omap_dsp_request_mem();
+ if (ret < 0)
+ goto out;
+
+ omap_mmu_write_reg(mmu, 0x1, OMAP_MMU_GFLUSH);
+ lock.base = lock.victim = mmu->nr_exmap_preserved;
+ omap_mmu_set_tlb_lock(mmu, &lock);
+
+ omap_dsp_release_mem();
+out:
+ clk_disable(mmu->clk);
+}
+
+int omap_mmu_load_pte_entry(struct omap_mmu *mmu,
+ struct omap_mmu_tlb_entry *entry)
+{
+ int ret = -1;
+ /*XXX use PG_flag for prsvd */
+ ret = omap_mmu_load_pte(mmu, entry);
+ if (ret)
+ return ret;
+ if (entry->tlb)
+ ret = omap_mmu_load_tlb_entry(mmu, entry);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(omap_mmu_load_pte_entry);
+
+int omap_mmu_clear_pte_entry(struct omap_mmu *mmu, unsigned long vadr)
+{
+ int ret = omap_mmu_clear_tlb_entry(mmu, vadr);
+ if (ret)
+ return ret;
+ omap_mmu_clear_pte(mmu, vadr);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(omap_mmu_clear_pte_entry);
+
+/*
+ * omap_mmu_exmap()
+ *
+ * MEM_IOCTL_EXMAP ioctl calls this function with padr=0.
+ * In this case, the buffer for external device 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 external device.
+ */
+int omap_mmu_exmap(struct omap_mmu *mmu, unsigned long devadr,
+ unsigned long padr, unsigned long size,
+ enum exmap_type type)
+{
+ unsigned long pgsz;
+ void *buf;
+ unsigned int order = 0;
+ unsigned long unit;
+ int prev = -1;
+ unsigned long _devadr = devadr;
+ unsigned long _padr = padr;
+ void *_vadr = omap_mmu_to_virt(mmu, devadr);
+ unsigned long _size = size;
+ struct omap_mmu_tlb_entry tlb_ent;
+ struct exmap_tbl *exmap_ent, *tmp_ent;
+ int status;
+ int idx;
+
+#define MINIMUM_PAGESZ SZ_4K
+ /*
+ * alignment check
+ */
+ if (!is_aligned(size, MINIMUM_PAGESZ)) {
+ dev_err(mmu->dev,
+ "MMU %s: size(0x%lx) is not multiple of 4KB.\n",
+ mmu->name, size);
+ return -EINVAL;
+ }
+ if (!is_aligned(devadr, MINIMUM_PAGESZ)) {
+ dev_err(mmu->dev,
+ "MMU %s: external device address(0x%lx) is not"
+ " aligned.\n", mmu->name, devadr);
+ return -EINVAL;
+ }
+ if (!is_aligned(padr, MINIMUM_PAGESZ)) {
+ dev_err(mmu->dev,
+ "MMU %s: physical address(0x%lx) is not aligned.\n",
+ mmu->name, padr);
+ return -EINVAL;
+ }
+
+ /* address validity check */
+ if ((devadr < mmu->memsize) ||
+ (devadr >= (1 << mmu->addrspace))) {
+ dev_err(mmu->dev,
+ "MMU %s: illegal address/size for %s().\n",
+ mmu->name, __FUNCTION__);
+ return -EINVAL;
+ }
+
+ down_write(&mmu->exmap_sem);
+
+ /* overlap check */
+ omap_mmu_for_each_tlb_entry(mmu, tmp_ent) {
+ unsigned long mapsize;
+
+ if (!tmp_ent->valid)
+ continue;
+ mapsize = 1 << (tmp_ent->order + PAGE_SHIFT);
+ if ((_vadr + size > tmp_ent->vadr) &&
+ (_vadr < tmp_ent->vadr + mapsize)) {
+ dev_err(mmu->dev, "MMU %s: exmap page overlap!\n",
+ mmu->name);
+ up_write(&mmu->exmap_sem);
+ return -EINVAL;
+ }
+ }
+
+start:
+ buf = NULL;
+ /* Are there any free TLB lines? */
+ for (idx = 0; idx < mmu->nr_tlb_entries; idx++)
+ if (!mmu->exmap_tbl[idx].valid)
+ goto found_free;
+
+ dev_err(mmu->dev, "MMU %s: TLB is full.\n", mmu->name);
+ status = -EBUSY;
+ goto fail;
+
+found_free:
+ exmap_ent = mmu->exmap_tbl + idx;
+
+ if ((_size >= SZ_1M) &&
+ (is_aligned(_padr, SZ_1M) || (padr == 0)) &&
+ is_aligned(_devadr, SZ_1M)) {
+ unit = SZ_1M;
+ pgsz = OMAP_MMU_CAM_PAGESIZE_1MB;
+ } else if ((_size >= SZ_64K) &&
+ (is_aligned(_padr, SZ_64K) || (padr == 0)) &&
+ is_aligned(_devadr, SZ_64K)) {
+ unit = SZ_64K;
+ pgsz = OMAP_MMU_CAM_PAGESIZE_64KB;
+ } else {
+ unit = SZ_4K;
+ pgsz = OMAP_MMU_CAM_PAGESIZE_4KB;
+ }
+
+ order = get_order(unit);
+
+ /* buffer allocation */
+ if (type == EXMAP_TYPE_MEM) {
+ struct page *page, *ps, *pe;
+
+ if ((order == ORDER_1MB) && likely(mempool_1M))
+ buf = mempool_alloc_from_pool(mempool_1M, GFP_KERNEL);
+ else if ((order == ORDER_64KB) && likely(mempool_64K))
+ buf = mempool_alloc_from_pool(mempool_64K, GFP_KERNEL);
+ else {
+ buf = (void *)__get_dma_pages(GFP_KERNEL, order);
+ if (buf == NULL) {
+ status = -ENOMEM;
+ goto fail;
+ }
+ }
+
+ /* mark the pages as reserved; this is needed for mmap */
+ ps = virt_to_page(buf);
+ pe = virt_to_page(buf + unit);
+
+ for (page = ps; page < pe; page++)
+ SetPageReserved(page);
+
+ _padr = __pa(buf);
+ }
+
+ /*
+ * mapping for ARM MMU:
+ * we should not access to the allocated memory through 'buf'
+ * since this area should not be cached.
+ */
+ status = exmap_set_armmmu(mmu, (unsigned long)_vadr, _padr, unit);
+ if (status < 0)
+ goto fail;
+
+ /* loading external device PTE entry */
+ INIT_TLB_ENTRY(&tlb_ent, _devadr, _padr, pgsz);
+ status = omap_mmu_load_pte_entry(mmu, &tlb_ent);
+ if (status < 0) {
+ exmap_clear_armmmu(mmu, (unsigned long)_vadr, unit);
+ goto fail;
+ }
+
+ INIT_EXMAP_TBL_ENTRY(exmap_ent, buf, _vadr, type, order);
+ exmap_ent->link.prev = prev;
+ if (prev >= 0)
+ mmu->exmap_tbl[prev].link.next = idx;
+
+ if ((_size -= unit) == 0) { /* normal completion */
+ up_write(&mmu->exmap_sem);
+ return size;
+ }
+
+ _devadr += unit;
+ _vadr += unit;
+ _padr = padr ? _padr + unit : 0;
+ prev = idx;
+ goto start;
+
+fail:
+ up_write(&mmu->exmap_sem);
+ if (buf)
+ omap_mmu_free_pages((unsigned long)buf, order);
+ omap_mmu_exunmap(mmu, devadr);
+ return status;
+}
+EXPORT_SYMBOL_GPL(omap_mmu_exmap);
+
+static unsigned long unmap_free_arm(struct omap_mmu *mmu,
+ struct exmap_tbl *ent)
+{
+ unsigned long size;
+
+ /* clearing ARM MMU */
+ size = 1 << (ent->order + PAGE_SHIFT);
+ exmap_clear_armmmu(mmu, (unsigned long)ent->vadr, size);
+
+ /* freeing allocated memory */
+ if (ent->type == EXMAP_TYPE_MEM) {
+ omap_mmu_free_pages((unsigned long)ent->buf, ent->order);
+ dev_dbg(mmu->dev, "MMU %s: freeing 0x%lx bytes @ adr 0x%8p\n",
+ mmu->name, size, ent->buf);
+ }
+
+ ent->valid = 0;
+ return size;
+}
+
+int omap_mmu_exunmap(struct omap_mmu *mmu, unsigned long devadr)
+{
+ void *vadr;
+ unsigned long size;
+ int total = 0;
+ struct exmap_tbl *ent;
+ int idx;
+
+ vadr = omap_mmu_to_virt(mmu, devadr);
+ down_write(&mmu->exmap_sem);
+ for (idx = 0; idx < mmu->nr_tlb_entries; idx++) {
+ ent = mmu->exmap_tbl + idx;
+ if (!ent->valid || ent->prsvd)
+ continue;
+ if (ent->vadr == vadr)
+ goto found_map;
+ }
+ up_write(&mmu->exmap_sem);
+ dev_warn(mmu->dev, "MMU %s: address %06lx not found in exmap_tbl.\n",
+ mmu->name, devadr);
+ return -EINVAL;
+
+found_map:
+ if (ent->usecount > 0) {
+ dev_err(mmu->dev, "MMU %s: exmap reference count is not 0.\n"
+ " idx=%d, vadr=%p, order=%d, usecount=%d\n",
+ mmu->name, idx, ent->vadr, ent->order, ent->usecount);
+ up_write(&mmu->exmap_sem);
+ return -EINVAL;
+ }
+ /* clearing external device PTE entry */
+ omap_mmu_clear_pte_entry(mmu, devadr);
+
+ /* clear ARM MMU and free buffer */
+ size = unmap_free_arm(mmu, ent);
+ total += size;
+
+ /* we don't free PTEs */
+
+ /* flush TLB */
+ flush_tlb_kernel_range((unsigned long)vadr, (unsigned long)vadr + size);
+
+ /* check if next mapping is in same group */
+ idx = ent->link.next;
+ if (idx < 0)
+ goto up_out; /* normal completion */
+ ent = mmu->exmap_tbl + idx;
+ devadr += size;
+ vadr += size;
+ if (ent->vadr == vadr)
+ goto found_map; /* continue */
+
+ dev_err(mmu->dev, "MMU %s: illegal exmap_tbl grouping!\n"
+ "expected vadr = %p, exmap_tbl[%d].vadr = %p\n",
+ mmu->name, vadr, idx, ent->vadr);
+ up_write(&mmu->exmap_sem);
+ return -EINVAL;
+
+up_out:
+ up_write(&mmu->exmap_sem);
+ return total;
+}
+EXPORT_SYMBOL_GPL(omap_mmu_exunmap);
+
+void omap_mmu_exmap_flush(struct omap_mmu *mmu)
+{
+ struct exmap_tbl *ent;
+
+ down_write(&mmu->exmap_sem);
+
+ /* clearing TLB entry */
+ omap_mmu_gflush(mmu);
+
+ omap_mmu_for_each_tlb_entry(mmu, ent)
+ if (ent->valid && !ent->prsvd)
+ unmap_free_arm(mmu, ent);
+
+ /* flush TLB */
+ if (likely(mmu->membase))
+ flush_tlb_kernel_range(mmu->membase + mmu->memsize,
+ mmu->membase + (1 << mmu->addrspace));
+
+ up_write(&mmu->exmap_sem);
+}
+EXPORT_SYMBOL_GPL(omap_mmu_exmap_flush);
+
+void exmap_setup_preserved_mem_page(struct omap_mmu *mmu, void *buf,
+ unsigned long devadr, int index)
+{
+ unsigned long phys;
+ void *virt;
+ struct omap_mmu_tlb_entry tlb_ent;
+
+ phys = __pa(buf);
+ virt = omap_mmu_to_virt(mmu, devadr);
+ exmap_set_armmmu(mmu, (unsigned long)virt, phys, PAGE_SIZE);
+ INIT_EXMAP_TBL_ENTRY_4KB_PRESERVED(mmu->exmap_tbl + index, buf, virt);
+ INIT_TLB_ENTRY_4KB_PRESERVED(&tlb_ent, devadr, phys);
+ omap_mmu_load_pte_entry(mmu, &tlb_ent);
+}
+EXPORT_SYMBOL_GPL(exmap_setup_preserved_mem_page);
+
+void exmap_clear_mem_page(struct omap_mmu *mmu, unsigned long devadr)
+{
+ void *virt = omap_mmu_to_virt(mmu, devadr);
+
+ exmap_clear_armmmu(mmu, (unsigned long)virt, PAGE_SIZE);
+ /* DSP MMU is shutting down. not handled here. */
+}
+EXPORT_SYMBOL_GPL(exmap_clear_mem_page);
+
+static void omap_mmu_reset(struct omap_mmu *mmu)
+{
+#if defined(CONFIG_ARCH_OMAP2) /* FIXME */
+ int i;
+
+ omap_mmu_write_reg(mmu, 0x2, OMAP_MMU_SYSCONFIG);
+
+ for (i = 0; i < 10000; i++)
+ if (likely(omap_mmu_read_reg(mmu, OMAP_MMU_SYSSTATUS) & 0x1))
+ break;
+#endif
+}
+
+void omap_mmu_disable(struct omap_mmu *mmu)
+{
+ omap_mmu_write_reg(mmu, 0x00, OMAP_MMU_CNTL);
+}
+EXPORT_SYMBOL_GPL(omap_mmu_disable);
+
+void omap_mmu_enable(struct omap_mmu *mmu, int reset)
+{
+ u32 val = OMAP_MMU_CNTL_MMU_EN | MMU_CNTL_TWLENABLE;
+
+ if (likely(reset))
+ omap_mmu_reset(mmu);
+#if defined(CONFIG_ARCH_OMAP2) /* FIXME */
+ omap_mmu_write_reg(mmu, (u32)virt_to_phys(mmu->twl_mm->pgd),
+ OMAP_MMU_TTB);
+#else
+ omap_mmu_write_reg(mmu, (u32)virt_to_phys(mmu->twl_mm->pgd) & 0xffff,
+ OMAP_MMU_TTB_L);
+ omap_mmu_write_reg(mmu, (u32)virt_to_phys(mmu->twl_mm->pgd) >> 16,
+ OMAP_MMU_TTB_H);
+ val |= OMAP_MMU_CNTL_RESET_SW;
+#endif
+ omap_mmu_write_reg(mmu, val, OMAP_MMU_CNTL);
+}
+EXPORT_SYMBOL_GPL(omap_mmu_enable);
+
+static irqreturn_t omap_mmu_interrupt(int irq, void *dev_id)
+{
+ struct omap_mmu *mmu = dev_id;
+
+ if (likely(mmu->ops->interrupt))
+ mmu->ops->interrupt(mmu);
+
+ return IRQ_HANDLED;
+}
+
+static int omap_mmu_init(struct omap_mmu *mmu)
+{
+ struct omap_mmu_tlb_lock tlb_lock;
+ int ret = 0;
+
+ clk_enable(mmu->clk);
+ ret = omap_dsp_request_mem();
+ if (ret < 0)
+ goto out;
+
+ down_write(&mmu->exmap_sem);
+
+ ret = request_irq(mmu->irq, omap_mmu_interrupt, IRQF_DISABLED,
+ mmu->name, mmu);
+ if (ret < 0) {
+ dev_err(mmu->dev, "MMU %s: failed to register MMU interrupt:"
+ " %d\n", mmu->name, ret);
+ goto fail;
+ }
+
+ omap_mmu_disable(mmu); /* clear all */
+ udelay(100);
+ omap_mmu_enable(mmu, 1);
+
+ memset(&tlb_lock, 0, sizeof(struct omap_mmu_tlb_lock));
+ omap_mmu_set_tlb_lock(mmu, &tlb_lock);
+
+ if (unlikely(mmu->ops->startup))
+ ret = mmu->ops->startup(mmu);
+fail:
+ up_write(&mmu->exmap_sem);
+ omap_dsp_release_mem();
+out:
+ clk_disable(mmu->clk);
+
+ return ret;
+}
+
+static void omap_mmu_shutdown(struct omap_mmu *mmu)
+{
+ free_irq(mmu->irq, mmu);
+
+ if (unlikely(mmu->ops->shutdown))
+ mmu->ops->shutdown(mmu);
+
+ omap_mmu_exmap_flush(mmu);
+ omap_mmu_disable(mmu); /* clear all */
+}
+
+/*
+ * omap_mmu_mem_enable() / disable()
+ */
+int omap_mmu_mem_enable(struct omap_mmu *mmu, void *addr)
+{
+ if (unlikely(mmu->ops->mem_enable))
+ return mmu->ops->mem_enable(mmu, addr);
+
+ down_read(&mmu->exmap_sem);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(omap_mmu_mem_enable);
+
+void omap_mmu_mem_disable(struct omap_mmu *mmu, void *addr)
+{
+ if (unlikely(mmu->ops->mem_disable)) {
+ mmu->ops->mem_disable(mmu, addr);
+ return;
+ }
+
+ up_read(&mmu->exmap_sem);
+}
+EXPORT_SYMBOL_GPL(omap_mmu_mem_disable);
+
+/*
+ * dsp_mem file operations
+ */
+static ssize_t intmem_read(struct omap_mmu *mmu, char *buf, size_t count,
+ loff_t *ppos)
+{
+ unsigned long p = *ppos;
+ void *vadr = omap_mmu_to_virt(mmu, p);
+ ssize_t size = mmu->memsize;
+ ssize_t read;
+
+ if (p >= size)
+ return 0;
+ clk_enable(mmu->memclk);
+ read = count;
+ if (count > size - p)
+ read = size - p;
+ if (copy_to_user(buf, vadr, read)) {
+ read = -EFAULT;
+ goto out;
+ }
+ *ppos += read;
+out:
+ clk_disable(mmu->memclk);
+ return read;
+}
+
+static ssize_t exmem_read(struct omap_mmu *mmu, char *buf, size_t count,
+ loff_t *ppos)
+{
+ unsigned long p = *ppos;
+ void *vadr = omap_mmu_to_virt(mmu, p);
+
+ if (!exmap_valid(mmu, vadr, count)) {
+ dev_err(mmu->dev, "MMU %s: external device address %08lx / "
+ "size %08x is not valid!\n", mmu->name, p, count);
+ return -EFAULT;
+ }
+ if (count > (1 << mmu->addrspace) - p)
+ count = (1 << mmu->addrspace) - p;
+ if (copy_to_user(buf, vadr, count))
+ return -EFAULT;
+ *ppos += count;
+
+ return count;
+}
+
+static ssize_t omap_mmu_mem_read(struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t offset, size_t count)
+{
+ struct device *dev = to_dev(kobj);
+ struct omap_mmu *mmu = dev_get_drvdata(dev);
+ unsigned long p = (unsigned long)offset;
+ void *vadr = omap_mmu_to_virt(mmu, p);
+ int ret;
+
+ if (omap_mmu_mem_enable(mmu, vadr) < 0)
+ return -EBUSY;
+
+ if (p < mmu->memsize)
+ ret = intmem_read(mmu, buf, count, &offset);
+ else
+ ret = exmem_read(mmu, buf, count, &offset);
+
+ omap_mmu_mem_disable(mmu, vadr);
+
+ return ret;
+}
+
+static ssize_t intmem_write(struct omap_mmu *mmu, const char *buf, size_t count,
+ loff_t *ppos)
+{
+ unsigned long p = *ppos;
+ void *vadr = omap_mmu_to_virt(mmu, p);
+ ssize_t size = mmu->memsize;
+ ssize_t written;
+
+ if (p >= size)
+ return 0;
+ clk_enable(mmu->memclk);
+ written = count;
+ if (count > size - p)
+ written = size - p;
+ if (copy_from_user(vadr, buf, written)) {
+ written = -EFAULT;
+ goto out;
+ }
+ *ppos += written;
+out:
+ clk_disable(mmu->memclk);
+ return written;
+}
+
+static ssize_t exmem_write(struct omap_mmu *mmu, char *buf, size_t count,
+ loff_t *ppos)
+{
+ unsigned long p = *ppos;
+ void *vadr = omap_mmu_to_virt(mmu, p);
+
+ if (!exmap_valid(mmu, vadr, count)) {
+ dev_err(mmu->dev, "MMU %s: external device address %08lx "
+ "/ size %08x is not valid!\n", mmu->name, p, count);
+ return -EFAULT;
+ }
+ if (count > (1 << mmu->addrspace) - p)
+ count = (1 << mmu->addrspace) - p;
+ if (copy_from_user(vadr, buf, count))
+ return -EFAULT;
+ *ppos += count;
+
+ return count;
+}
+
+static ssize_t omap_mmu_mem_write(struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t offset, size_t count)
+{
+ struct device *dev = to_dev(kobj);
+ struct omap_mmu *mmu = dev_get_drvdata(dev);
+ unsigned long p = (unsigned long)offset;
+ void *vadr = omap_mmu_to_virt(mmu, p);
+ int ret;
+
+ if (omap_mmu_mem_enable(mmu, vadr) < 0)
+ return -EBUSY;
+
+ if (p < mmu->memsize)
+ ret = intmem_write(mmu, buf, count, &offset);
+ else
+ ret = exmem_write(mmu, buf, count, &offset);
+
+ omap_mmu_mem_disable(mmu, vadr);
+
+ return ret;
+}
+
+static struct bin_attribute dev_attr_mem = {
+ .attr = {
+ .name = "mem",
+ .owner = THIS_MODULE,
+ .mode = S_IRUSR | S_IWUSR | S_IRGRP,
+ },
+
+ .read = omap_mmu_mem_read,
+ .write = omap_mmu_mem_write,
+};
+
+/* To be obsolete for backward compatibility */
+ssize_t __omap_mmu_mem_read(struct omap_mmu *mmu,
+ struct bin_attribute *attr,
+ char *buf, loff_t offset, size_t count)
+{
+ return omap_mmu_mem_read(&mmu->dev->kobj, attr, buf, offset, count);
+}
+EXPORT_SYMBOL_GPL(__omap_mmu_mem_read);
+
+ssize_t __omap_mmu_mem_write(struct omap_mmu *mmu,
+ struct bin_attribute *attr,
+ char *buf, loff_t offset, size_t count)
+{
+ return omap_mmu_mem_write(&mmu->dev->kobj, attr, buf, offset, count);
+}
+EXPORT_SYMBOL_GPL(__omap_mmu_mem_write);
+
+/*
+ * sysfs files
+ */
+static ssize_t omap_mmu_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct omap_mmu *mmu = dev_get_drvdata(dev);
+ struct omap_mmu_tlb_lock tlb_lock;
+ int ret;
+
+ clk_enable(mmu->clk);
+ ret = omap_dsp_request_mem();
+ if (ret < 0)
+ goto out;
+
+ down_read(&mmu->exmap_sem);
+
+ omap_mmu_get_tlb_lock(mmu, &tlb_lock);
+
+ ret = -EIO;
+ if (likely(mmu->ops->show))
+ ret = mmu->ops->show(mmu, buf, &tlb_lock);
+
+ /* restore victim entry */
+ omap_mmu_set_tlb_lock(mmu, &tlb_lock);
+
+ up_read(&mmu->exmap_sem);
+ omap_dsp_release_mem();
+out:
+ clk_disable(mmu->clk);
+
+ return ret;
+}
+
+static DEVICE_ATTR(mmu, S_IRUGO, omap_mmu_show, NULL);
+
+static ssize_t exmap_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct omap_mmu *mmu = dev_get_drvdata(dev);
+ struct exmap_tbl *ent;
+ int len;
+ int i = 0;
+
+ down_read(&mmu->exmap_sem);
+ len = sprintf(buf, " devadr size buf size uc\n");
+ /* 0x300000 0x123000 0xc0171000 0x100000 0*/
+
+ omap_mmu_for_each_tlb_entry(mmu, ent) {
+ void *vadr;
+ unsigned long size;
+ enum exmap_type type;
+ int idx;
+
+ /* find a top of link */
+ if (!ent->valid || (ent->link.prev >= 0))
+ continue;
+
+ vadr = ent->vadr;
+ type = ent->type;
+ size = 0;
+ idx = i;
+ do {
+ ent = mmu->exmap_tbl + idx;
+ size += PAGE_SIZE << ent->order;
+ } while ((idx = ent->link.next) >= 0);
+
+ len += sprintf(buf + len, "0x%06lx %#8lx",
+ virt_to_omap_mmu(mmu, vadr), size);
+
+ if (type == EXMAP_TYPE_FB) {
+ len += sprintf(buf + len, " framebuf\n");
+ } else {
+ len += sprintf(buf + len, "\n");
+ idx = i;
+ do {
+ ent = mmu->exmap_tbl + idx;
+ len += sprintf(buf + len,
+ /* 0xc0171000 0x100000 0*/
+ "%19s0x%8p %#8lx %2d\n",
+ "", ent->buf,
+ PAGE_SIZE << ent->order,
+ ent->usecount);
+ } while ((idx = ent->link.next) >= 0);
+ }
+
+ i++;
+ }
+
+ up_read(&mmu->exmap_sem);
+ return len;
+}
+
+static ssize_t exmap_store(struct device *dev, struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct omap_mmu *mmu = dev_get_drvdata(dev);
+ unsigned long base = 0, len = 0;
+ int ret;
+
+ sscanf(buf, "%lx %lx", &base, &len);
+
+ if (!base)
+ return -EINVAL;
+
+ if (len) {
+ /* Add the mapping */
+ ret = omap_mmu_exmap(mmu, base, 0, len, EXMAP_TYPE_MEM);
+ if (ret < 0)
+ return ret;
+ } else {
+ /* Remove the mapping */
+ ret = omap_mmu_exunmap(mmu, base);
+ if (ret < 0)
+ return ret;
+ }
+
+ return count;
+}
+
+static DEVICE_ATTR(exmap, S_IRUGO | S_IWUSR, exmap_show, exmap_store);
+
+static ssize_t mempool_show(struct class *class, char *buf)
+{
+ int min_nr_1M = 0, curr_nr_1M = 0;
+ int min_nr_64K = 0, curr_nr_64K = 0;
+ int total = 0;
+
+ if (likely(mempool_1M)) {
+ min_nr_1M = mempool_1M->min_nr;
+ curr_nr_1M = mempool_1M->curr_nr;
+ total += min_nr_1M * SZ_1M;
+ }
+ if (likely(mempool_64K)) {
+ min_nr_64K = mempool_64K->min_nr;
+ curr_nr_64K = mempool_64K->curr_nr;
+ total += min_nr_64K * SZ_64K;
+ }
+
+ return sprintf(buf,
+ "0x%x\n"
+ "1M buffer: %d (%d free)\n"
+ "64K buffer: %d (%d free)\n",
+ total, min_nr_1M, curr_nr_1M, min_nr_64K, curr_nr_64K);
+}
+
+
+static CLASS_ATTR(mempool, S_IRUGO, mempool_show, NULL);
+
+static struct class omap_mmu_class = {
+ .name = "mmu",
+};
+
+int omap_mmu_register(struct omap_mmu *mmu)
+{
+ int ret;
+
+ mmu->dev = device_create(&omap_mmu_class, NULL, 0, "%s", mmu->name);
+ if (unlikely(IS_ERR(mmu->dev)))
+ return PTR_ERR(mmu->dev);
+ dev_set_drvdata(mmu->dev, mmu);
+
+ mmu->exmap_tbl = kcalloc(mmu->nr_tlb_entries, sizeof(struct exmap_tbl),
+ GFP_KERNEL);
+ if (!mmu->exmap_tbl)
+ return -ENOMEM;
+
+ mmu->twl_mm = mm_alloc();
+ if (!mmu->twl_mm) {
+ ret = -ENOMEM;
+ goto err_mm_alloc;
+ }
+
+ init_rwsem(&mmu->exmap_sem);
+
+ ret = omap_mmu_init(mmu);
+ if (unlikely(ret))
+ goto err_mmu_init;
+
+ ret = device_create_file(mmu->dev, &dev_attr_mmu);
+ if (unlikely(ret))
+ goto err_dev_create_mmu;
+ ret = device_create_file(mmu->dev, &dev_attr_exmap);
+ if (unlikely(ret))
+ goto err_dev_create_exmap;
+
+ if (likely(mmu->membase)) {
+ dev_attr_mem.size = mmu->memsize;
+ ret = device_create_bin_file(mmu->dev,
+ &dev_attr_mem);
+ if (unlikely(ret))
+ goto err_bin_create_mem;
+ }
+ return 0;
+
+err_bin_create_mem:
+ device_remove_file(mmu->dev, &dev_attr_exmap);
+err_dev_create_exmap:
+ device_remove_file(mmu->dev, &dev_attr_mmu);
+err_dev_create_mmu:
+ omap_mmu_shutdown(mmu);
+err_mmu_init:
+ kfree(mmu->twl_mm);
+ mmu->twl_mm = NULL;
+err_mm_alloc:
+ kfree(mmu->exmap_tbl);
+ mmu->exmap_tbl = NULL;
+ device_unregister(mmu->dev);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(omap_mmu_register);
+
+void omap_mmu_unregister(struct omap_mmu *mmu)
+{
+ omap_mmu_shutdown(mmu);
+ omap_mmu_kmem_release();
+
+ device_remove_file(mmu->dev, &dev_attr_mmu);
+ device_remove_file(mmu->dev, &dev_attr_exmap);
+
+ if (likely(mmu->membase))
+ device_remove_bin_file(mmu->dev, &dev_attr_mem);
+
+ device_unregister(mmu->dev);
+
+ kfree(mmu->exmap_tbl);
+ mmu->exmap_tbl = NULL;
+
+ if (mmu->twl_mm) {
+ __mmdrop(mmu->twl_mm);
+ mmu->twl_mm = NULL;
+ }
+}
+EXPORT_SYMBOL_GPL(omap_mmu_unregister);
+
+static int __init omap_mmu_class_init(void)
+{
+ int ret = class_register(&omap_mmu_class);
+ if (!ret)
+ ret = class_create_file(&omap_mmu_class, &class_attr_mempool);
+
+ return ret;
+}
+
+static void __exit omap_mmu_class_exit(void)
+{
+ class_remove_file(&omap_mmu_class, &class_attr_mempool);
+ class_unregister(&omap_mmu_class);
+}
+
+subsys_initcall(omap_mmu_class_init);
+module_exit(omap_mmu_class_exit);
+
+MODULE_LICENSE("GPL");
/*
* Reprograms ULPD and CKCTL.
*/
-ENTRY(sram_reprogram_clock)
+ENTRY(omap1_sram_reprogram_clock)
stmfd sp!, {r0 - r12, lr} @ save registers on stack
mov r2, #IO_ADDRESS(DPLL_CTL) & 0xff000000
out:
ldmfd sp!, {r0 - r12, pc} @ restore regs and return
-ENTRY(sram_reprogram_clock_sz)
- .word . - sram_reprogram_clock
+ENTRY(omap1_sram_reprogram_clock_sz)
+ .word . - omap1_sram_reprogram_clock
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+#undef DEBUG
#include <linux/module.h>
#include <linux/kernel.h>
#include <asm/arch/sram.h>
#include <asm/arch/board.h>
+#include <asm/arch/control.h>
+
+#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
+# include "../mach-omap2/prm.h"
+# include "../mach-omap2/cm.h"
+# include "../mach-omap2/sdrc.h"
+#endif
+
#define OMAP1_SRAM_PA 0x20000000
-#define OMAP1_SRAM_VA 0xd0000000
+#define OMAP1_SRAM_VA VMALLOC_END
#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 OMAP2_SRAM_VA VMALLOC_END
+#define OMAP2_SRAM_PUB_VA (VMALLOC_END + 0x800)
+#define OMAP3_SRAM_PA 0x40200000
+#define OMAP3_SRAM_VA 0xd7000000
+#define OMAP3_SRAM_PUB_PA 0x40208000
+#define OMAP3_SRAM_PUB_VA 0xd7008000
+
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
#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 OMAP24XX_VA_REQINFOPERM0 IO_ADDRESS(0x68005048)
+#define OMAP24XX_VA_READPERM0 IO_ADDRESS(0x68005050)
+#define OMAP24XX_VA_WRITEPERM0 IO_ADDRESS(0x68005058)
+
+#define OMAP34XX_VA_REQINFOPERM0 IO_ADDRESS(0x68012848)
+#define OMAP34XX_VA_READPERM0 IO_ADDRESS(0x68012850)
+#define OMAP34XX_VA_WRITEPERM0 IO_ADDRESS(0x68012858)
+#define OMAP34XX_VA_ADDR_MATCH2 IO_ADDRESS(0x68012880)
+#define OMAP34XX_VA_SMS_RG_ATT0 IO_ADDRESS(0x6C000048)
+#define OMAP34XX_VA_CONTROL_STAT IO_ADDRESS(0x480022F0)
+
#define GP_DEVICE 0x300
-#define TYPE_MASK 0x700
#define ROUND_DOWN(value,boundary) ((value) & (~((boundary)-1)))
unsigned long pstart_avail,
unsigned long size_avail);
+/* Global symbols in sram-fn.S to be patched with omap_sram_patch_va() */
+extern void *omap24xx_sdi_cm_clksel2_pll;
+extern void *omap24xx_sdi_sdrc_dlla_ctrl;
+extern void *omap24xx_sdi_prcm_voltctrl;
+extern void *omap24xx_sdi_timer_32ksynct_cr;
+extern void *omap24xx_srs_cm_clksel2_pll;
+extern void *omap24xx_srs_sdrc_dlla_ctrl;
+extern void *omap24xx_srs_sdrc_rfr_ctrl;
+extern void *omap24xx_srs_prcm_voltctrl;
+extern void *omap24xx_srs_timer_32ksynct;
+extern void *omap24xx_ssp_set_config;
+extern void *omap24xx_ssp_pll_ctl;
+extern void *omap24xx_ssp_pll_stat;
+extern void *omap24xx_ssp_pll_div;
+extern void *omap24xx_ssp_sdrc_rfr;
+extern void *omap24xx_ssp_dlla_ctrl;
+
+
/*
* Depending on the target RAMFS firewall setup, the public usable amount of
* SRAM varies. The default accessible size for all device types is 2k. A GP
int type = 0;
if (cpu_is_omap242x())
- type = __raw_readl(VA_CONTROL_STAT) & TYPE_MASK;
+ type = system_rev & OMAP2_DEVICETYPE_MASK;
if (type == GP_DEVICE) {
/* RAMFW: R/W access to all initiators 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 */
+ __raw_writel(0xFF, OMAP24XX_VA_REQINFOPERM0); /* all q-vects */
+ __raw_writel(0xCFDE, OMAP24XX_VA_READPERM0); /* all i-read */
+ __raw_writel(0xCFDE, OMAP24XX_VA_WRITEPERM0); /* all i-write */
+ }
+ if (cpu_is_omap34xx()) {
+ __raw_writel(0xFFFF, OMAP34XX_VA_REQINFOPERM0); /* all q-vects */
+ __raw_writel(0xFFFF, OMAP34XX_VA_READPERM0); /* all i-read */
+ __raw_writel(0xFFFF, OMAP34XX_VA_WRITEPERM0); /* all i-write */
+ __raw_writel(0x0, OMAP34XX_VA_ADDR_MATCH2);
+ __raw_writel(0xFFFFFFFF, OMAP34XX_VA_SMS_RG_ATT0);
}
return 0;
} else
{
unsigned long reserved;
- if (cpu_is_omap24xx()) {
+ if (cpu_class_is_omap2()) {
if (is_sram_locked()) {
- omap_sram_base = OMAP2_SRAM_PUB_VA;
- omap_sram_start = OMAP2_SRAM_PUB_PA;
- omap_sram_size = 0x800; /* 2K */
+ if (cpu_is_omap34xx()) {
+ omap_sram_base = OMAP3_SRAM_PUB_VA;
+ omap_sram_start = OMAP3_SRAM_PUB_PA;
+ omap_sram_size = 0x8000; /* 32K */
+ } else {
+ omap_sram_base = OMAP2_SRAM_PUB_VA;
+ omap_sram_start = OMAP2_SRAM_PUB_PA;
+ omap_sram_size = 0x800; /* 2K */
+ }
} else {
- omap_sram_base = OMAP2_SRAM_VA;
- omap_sram_start = OMAP2_SRAM_PA;
- if (cpu_is_omap242x())
- omap_sram_size = 0xa0000; /* 640K */
- else if (cpu_is_omap243x())
+ if (cpu_is_omap34xx()) {
+ omap_sram_base = OMAP3_SRAM_VA;
+ omap_sram_start = OMAP3_SRAM_PA;
omap_sram_size = 0x10000; /* 64K */
+ } else {
+ omap_sram_base = OMAP2_SRAM_VA;
+ omap_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;
omap_sram_io_desc[0].pfn = __phys_to_pfn(base);
}
+ if (cpu_is_omap34xx()) {
+ omap_sram_io_desc[0].virtual = OMAP3_SRAM_VA;
+ base = OMAP3_SRAM_PA;
+ base = ROUND_DOWN(base, PAGE_SIZE);
+ omap_sram_io_desc[0].pfn = __phys_to_pfn(base);
+ }
+
omap_sram_io_desc[0].length = 1024 * 1024; /* Use section desc */
iotable_init(omap_sram_io_desc, ARRAY_SIZE(omap_sram_io_desc));
omap_sram_ceil -= size;
omap_sram_ceil = ROUND_DOWN(omap_sram_ceil, sizeof(void *));
memcpy((void *)omap_sram_ceil, start, size);
+ flush_icache_range((unsigned long)start, (unsigned long)(start + size));
return (void *)omap_sram_ceil;
}
+/**
+ * omap_sram_patch_va - patch a virtual address into SRAM code
+ * @srcfn: original start address (in DRAM) of function to patch
+ * @srcd: original address (in DRAM) of location to patch
+ * @sramfn: start address (in SRAM) of function to patch
+ * @d: virtual address to insert
+ *
+ * Replace a location in SRAM containing a magic number
+ * (SRAM_VA_MAGIC) with a caller-specified virtual address. Used to
+ * dynamically patch SRAM code at runtime for multiboot, since some
+ * register addresses change depending on the OMAP chip in use.
+ * Returns 1 upon success, 0 upon failure.
+ */
+int omap_sram_patch_va(void *srcfn, void *srcd, void *sramfn, void __iomem *d)
+{
+ unsigned long sram_addr;
+ long offs;
+
+ offs = (unsigned long)srcd - (unsigned long)srcfn;
+ sram_addr = (unsigned long)sramfn + offs;
+
+#ifdef CONFIG_OMAP_DEBUG_SRAM_PATCH
+ if (offs < 0) {
+ printk(KERN_ERR "sram: patch address 0x%0lx < function start "
+ "address 0x%0lx\n", (unsigned long)srcd,
+ (unsigned long)srcfn);
+ WARN_ON(1);
+ return 0;
+ }
+
+ /*
+ * REVISIT: We should probably pass in the function's size also,
+ * so we can verify that the address to patch exists within
+ * the function
+ */
+ if (sram_addr > omap_sram_base + omap_sram_size ||
+ sram_addr < omap_sram_base + SRAM_BOOTLOADER_SZ) {
+ printk(KERN_ERR "sram: invalid patch address 0x%0lx\n",
+ sram_addr);
+ WARN_ON(1);
+ return 0;
+ }
+
+ if (*(typeof(SRAM_VA_MAGIC) *)sram_addr != SRAM_VA_MAGIC) {
+ printk(KERN_ERR "sram: will not patch address 0x%0lx: "
+ "no magic\n", sram_addr);
+ WARN_ON(1);
+ return 0;
+ }
+#endif /* CONFIG_OMAP_DEBUG_SRAM_PATCH */
+
+ pr_debug("sram: patching 0x%0lx with 0x%0lx\n", sram_addr,
+ (unsigned long)d);
+
+ *(unsigned long *)sram_addr = (unsigned long)d;
+
+ return 1;
+}
+
+
static void omap_sram_error(void)
{
panic("Uninitialized SRAM function\n");
int __init omap1_sram_init(void)
{
- _omap_sram_reprogram_clock = omap_sram_push(sram_reprogram_clock,
- sram_reprogram_clock_sz);
+ _omap_sram_reprogram_clock =
+ omap_sram_push(omap1_sram_reprogram_clock,
+ omap1_sram_reprogram_clock_sz);
return 0;
}
#define omap1_sram_init() do {} while (0)
#endif
-#ifdef CONFIG_ARCH_OMAP2
+#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
static void (*_omap2_sram_ddr_init)(u32 *slow_dll_ctrl, u32 fast_dll_ctrl,
u32 base_cs, u32 force_unlock);
return _omap2_set_prcm(dpll_ctrl_val, sdrc_rfr_val, bypass);
}
+#endif
-int __init omap2_sram_init(void)
+#ifdef CONFIG_ARCH_OMAP2
+int __init omap24xx_sram_init(void)
{
- _omap2_sram_ddr_init = omap_sram_push(sram_ddr_init, sram_ddr_init_sz);
-
- _omap2_sram_reprogram_sdrc = omap_sram_push(sram_reprogram_sdrc,
- sram_reprogram_sdrc_sz);
- _omap2_set_prcm = omap_sram_push(sram_set_prcm, sram_set_prcm_sz);
+ _omap2_sram_ddr_init = omap_sram_push(omap24xx_sram_ddr_init,
+ omap24xx_sram_ddr_init_sz);
+
+ /* Patch in the correct register addresses for multiboot */
+ omap_sram_patch_va(omap24xx_sram_ddr_init, &omap24xx_sdi_cm_clksel2_pll,
+ _omap2_sram_ddr_init,
+ OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL2));
+ omap_sram_patch_va(omap24xx_sram_ddr_init, &omap24xx_sdi_sdrc_dlla_ctrl,
+ _omap2_sram_ddr_init,
+ OMAP_SDRC_REGADDR(SDRC_DLLA_CTRL));
+ omap_sram_patch_va(omap24xx_sram_ddr_init, &omap24xx_sdi_prcm_voltctrl,
+ _omap2_sram_ddr_init, OMAP24XX_PRCM_VOLTCTRL);
+ omap_sram_patch_va(omap24xx_sram_ddr_init,
+ &omap24xx_sdi_timer_32ksynct_cr,
+ _omap2_sram_ddr_init,
+ (void __iomem *)IO_ADDRESS(OMAP2_32KSYNCT_BASE + 0x010));
+
+ _omap2_sram_reprogram_sdrc = omap_sram_push(omap24xx_sram_reprogram_sdrc,
+ omap24xx_sram_reprogram_sdrc_sz);
+
+ omap_sram_patch_va(omap24xx_sram_reprogram_sdrc,
+ &omap24xx_srs_cm_clksel2_pll,
+ _omap2_sram_reprogram_sdrc,
+ OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL2));
+ omap_sram_patch_va(omap24xx_sram_reprogram_sdrc,
+ &omap24xx_srs_sdrc_dlla_ctrl,
+ _omap2_sram_reprogram_sdrc,
+ OMAP_SDRC_REGADDR(SDRC_DLLA_CTRL));
+ omap_sram_patch_va(omap24xx_sram_reprogram_sdrc,
+ &omap24xx_srs_sdrc_rfr_ctrl,
+ _omap2_sram_reprogram_sdrc,
+ OMAP_SDRC_REGADDR(SDRC_RFR_CTRL_0));
+ omap_sram_patch_va(omap24xx_sram_reprogram_sdrc,
+ &omap24xx_srs_prcm_voltctrl,
+ _omap2_sram_reprogram_sdrc,
+ OMAP24XX_PRCM_VOLTCTRL);
+ omap_sram_patch_va(omap24xx_sram_reprogram_sdrc,
+ &omap24xx_srs_timer_32ksynct,
+ _omap2_sram_reprogram_sdrc,
+ (void __iomem *)IO_ADDRESS(OMAP2_32KSYNCT_BASE + 0x010));
+
+ _omap2_set_prcm = omap_sram_push(omap24xx_sram_set_prcm,
+ omap24xx_sram_set_prcm_sz);
+
+ omap_sram_patch_va(omap24xx_sram_set_prcm, &omap24xx_ssp_set_config,
+ _omap2_set_prcm,
+ OMAP24XX_PRCM_CLKCFG_CTRL);
+ omap_sram_patch_va(omap24xx_sram_set_prcm, &omap24xx_ssp_pll_ctl,
+ _omap2_set_prcm,
+ OMAP_CM_REGADDR(PLL_MOD, CM_CLKEN));
+ omap_sram_patch_va(omap24xx_sram_set_prcm, &omap24xx_ssp_pll_stat,
+ _omap2_set_prcm,
+ OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST));
+ omap_sram_patch_va(omap24xx_sram_set_prcm, &omap24xx_ssp_pll_div,
+ _omap2_set_prcm,
+ OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1));
+ omap_sram_patch_va(omap24xx_sram_set_prcm, &omap24xx_ssp_sdrc_rfr,
+ _omap2_set_prcm,
+ OMAP_SDRC_REGADDR(SDRC_RFR_CTRL_0));
+ omap_sram_patch_va(omap24xx_sram_set_prcm, &omap24xx_ssp_dlla_ctrl,
+ _omap2_set_prcm,
+ OMAP_SDRC_REGADDR(SDRC_DLLA_CTRL));
return 0;
}
#else
-#define omap2_sram_init() do {} while (0)
+static inline int omap24xx_sram_init(void)
+{
+ return 0;
+}
#endif
int __init omap_sram_init(void)
omap_detect_sram();
omap_map_sram();
- if (!cpu_is_omap24xx())
+ if (!(cpu_class_is_omap2()))
omap1_sram_init();
- else
- omap2_sram_init();
+ else if (cpu_is_omap24xx())
+ omap24xx_sram_init();
return 0;
}
obj-$(CONFIG_FB_I810) += video/i810/
obj-$(CONFIG_FB_INTEL) += video/intelfb/
+# we also need input/serio early so serio bus is initialized by the time
+# serial drivers start registering their serio ports
+obj-$(CONFIG_SERIO) += input/serio/
obj-y += serial/
obj-$(CONFIG_PARPORT) += parport/
-obj-y += base/ block/ misc/ mfd/ net/ media/
+obj-y += base/ block/ misc/ mfd/ net/ media/ cbus/
+obj-y += i2c/
+obj-y += cbus/
+obj-$(CONFIG_ARCH_OMAP) += dsp/dspgateway/
obj-$(CONFIG_NUBUS) += nubus/
obj-$(CONFIG_ATM) += atm/
obj-y += macintosh/
obj-$(CONFIG_PARIDE) += block/paride/
obj-$(CONFIG_TC) += tc/
obj-$(CONFIG_USB) += usb/
+obj-$(CONFIG_USB_MUSB_HDRC) += usb/musb/
obj-$(CONFIG_PCI) += usb/
obj-$(CONFIG_USB_GADGET) += usb/gadget/
-obj-$(CONFIG_SERIO) += input/serio/
obj-$(CONFIG_GAMEPORT) += input/gameport/
obj-$(CONFIG_INPUT) += input/
obj-$(CONFIG_I2O) += message/
obj-$(CONFIG_RTC_LIB) += rtc/
-obj-y += i2c/
obj-$(CONFIG_W1) += w1/
obj-$(CONFIG_POWER_SUPPLY) += power/
obj-$(CONFIG_HWMON) += hwmon/
Say Y here to compile support for HCI UART devices into the
kernel or say M to compile it as module (btuart_cs).
+config BT_HCIBRF6150
+ tristate "HCI TI BRF6150 driver with H4 extensions"
+ depends on BT && ARCH_OMAP
+ help
+ Bluetooth HCI driver for TI BRF6150 with H4 extensions.
+ This driver provides support for BRF6150 Bluetooth chip
+ with vendor-specific H4 extensions.
+
+ Say Y here to compile support for TI BRF6150 devices into the
+ kernel or say M to compile it as module (brf6150).
+
+config BT_HCIH4P
+ tristate "HCI driver with H4 Nokia extensions"
+ depends on BT && ARCH_OMAP
+ help
+ Bluetooth HCI driver with H4 extensions. This driver provides
+ support for H4+ Bluetooth chip with vendor-specific H4 extensions.
+
+ Say Y here to compile support for h4 extended devices into the kernel
+ or say M to compile it as module (hci_h4p).
+
config BT_HCIVHCI
tristate "HCI VHCI (Virtual HCI device) driver"
help
obj-$(CONFIG_BT_HCIBT3C) += bt3c_cs.o
obj-$(CONFIG_BT_HCIBLUECARD) += bluecard_cs.o
obj-$(CONFIG_BT_HCIBTUART) += btuart_cs.o
+obj-$(CONFIG_BT_HCIBRF6150) += brf6150.o
+obj-$(CONFIG_BT_HCIH4P) += hci_h4p/
obj-$(CONFIG_BT_HCIBTUSB) += btusb.o
obj-$(CONFIG_BT_HCIBTSDIO) += btsdio.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/module.h>
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/serial_reg.h>
+#include <linux/skbuff.h>
+#include <linux/firmware.h>
+#include <linux/irq.h>
+#include <linux/timer.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/board.h>
+#include <asm/arch/irqs.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/hci.h>
+
+#include "brf6150.h"
+
+#if 0
+#define NBT_DBG(fmt, arg...) printk("%s: " fmt "" , __FUNCTION__ , ## arg)
+#else
+#define NBT_DBG(...)
+#endif
+
+#if 0
+#define NBT_DBG_FW(fmt, arg...) printk("%s: " fmt "" , __FUNCTION__ , ## arg)
+#else
+#define NBT_DBG_FW(...)
+#endif
+
+#if 0
+#define NBT_DBG_POWER(fmt, arg...) printk("%s: " fmt "" , __FUNCTION__ , ## arg)
+#else
+#define NBT_DBG_POWER(...)
+#endif
+
+#if 0
+#define NBT_DBG_TRANSFER(fmt, arg...) printk("%s: " fmt "" , __FUNCTION__ , ## arg)
+#else
+#define NBT_DBG_TRANSFER(...)
+#endif
+
+#if 0
+#define NBT_DBG_TRANSFER_NF(fmt, arg...) printk(fmt "" , ## arg)
+#else
+#define NBT_DBG_TRANSFER_NF(...)
+#endif
+
+#define PM_TIMEOUT (2000)
+
+static void brf6150_device_release(struct device *dev);
+static struct brf6150_info *exit_info;
+
+static struct platform_device brf6150_device = {
+ .name = BT_DEVICE,
+ .id = -1,
+ .num_resources = 0,
+ .dev = {
+ .release = brf6150_device_release,
+ }
+};
+
+static struct device_driver brf6150_driver = {
+ .name = BT_DRIVER,
+ .bus = &platform_bus_type,
+};
+
+static inline void brf6150_outb(struct brf6150_info *info, unsigned int offset, u8 val)
+{
+ outb(val, info->uart_base + (offset << 2));
+}
+
+static inline u8 brf6150_inb(struct brf6150_info *info, unsigned int offset)
+{
+ return inb(info->uart_base + (offset << 2));
+}
+
+static void brf6150_set_rts(struct brf6150_info *info, int active)
+{
+ u8 b;
+
+ b = brf6150_inb(info, UART_MCR);
+ if (active)
+ b |= UART_MCR_RTS;
+ else
+ b &= ~UART_MCR_RTS;
+ brf6150_outb(info, UART_MCR, b);
+}
+
+static void brf6150_wait_for_cts(struct brf6150_info *info, int active,
+ int timeout_ms)
+{
+ int okay;
+ unsigned long timeout;
+
+ okay = 0;
+ timeout = jiffies + msecs_to_jiffies(timeout_ms);
+ for (;;) {
+ int state;
+
+ state = brf6150_inb(info, UART_MSR) & UART_MSR_CTS;
+ if (active) {
+ if (state)
+ break;
+ } else {
+ if (!state)
+ break;
+ }
+ if (jiffies > timeout)
+ break;
+ }
+}
+
+static inline void brf6150_set_auto_ctsrts(struct brf6150_info *info, int on)
+{
+ u8 lcr, b;
+
+ lcr = brf6150_inb(info, UART_LCR);
+ brf6150_outb(info, UART_LCR, 0xbf);
+ b = brf6150_inb(info, UART_EFR);
+ if (on)
+ b |= UART_EFR_CTS | UART_EFR_RTS;
+ else
+ b &= ~(UART_EFR_CTS | UART_EFR_RTS);
+ brf6150_outb(info, UART_EFR, b);
+ brf6150_outb(info, UART_LCR, lcr);
+}
+
+static inline void brf6150_enable_pm_rx(struct brf6150_info *info)
+{
+ if (info->pm_enabled) {
+ info->rx_pm_enabled = 1;
+ }
+}
+
+static inline void brf6150_disable_pm_rx(struct brf6150_info *info)
+{
+ if (info->pm_enabled) {
+ info->rx_pm_enabled = 0;
+ }
+}
+
+static void brf6150_enable_pm_tx(struct brf6150_info *info)
+{
+ if (info->pm_enabled) {
+ mod_timer(&info->pm_timer, jiffies + msecs_to_jiffies(PM_TIMEOUT));
+ info->tx_pm_enabled = 1;
+ }
+}
+
+static void brf6150_disable_pm_tx(struct brf6150_info *info)
+{
+ if (info->pm_enabled) {
+ info->tx_pm_enabled = 0;
+ omap_set_gpio_dataout(info->btinfo->bt_wakeup_gpio, 1);
+ }
+ if (omap_get_gpio_datain(info->btinfo->host_wakeup_gpio))
+ tasklet_schedule(&info->tx_task);
+}
+
+static void brf6150_pm_timer(unsigned long data)
+{
+ struct brf6150_info *info;
+
+ info = (struct brf6150_info *)data;
+ if (info->tx_pm_enabled && info->rx_pm_enabled && !test_bit(HCI_INQUIRY, &info->hdev->flags))
+ omap_set_gpio_dataout(info->btinfo->bt_wakeup_gpio, 0);
+ else
+ mod_timer(&info->pm_timer, jiffies + msecs_to_jiffies(PM_TIMEOUT));
+}
+
+static int brf6150_change_speed(struct brf6150_info *info, unsigned long speed)
+{
+ unsigned int divisor;
+ u8 lcr, mdr1;
+
+ NBT_DBG("Setting speed %lu\n", speed);
+
+ if (speed >= 460800) {
+ divisor = UART_CLOCK / 13 / speed;
+ mdr1 = 3;
+ } else {
+ divisor = UART_CLOCK / 16 / speed;
+ mdr1 = 0;
+ }
+
+ brf6150_outb(info, UART_OMAP_MDR1, 7); /* Make sure UART mode is disabled */
+ lcr = brf6150_inb(info, UART_LCR);
+ brf6150_outb(info, UART_LCR, UART_LCR_DLAB); /* Set DLAB */
+ brf6150_outb(info, UART_DLL, divisor & 0xff); /* Set speed */
+ brf6150_outb(info, UART_DLM, divisor >> 8);
+ brf6150_outb(info, UART_LCR, lcr);
+ brf6150_outb(info, UART_OMAP_MDR1, mdr1); /* Make sure UART mode is enabled */
+
+ return 0;
+}
+
+/* Firmware handling */
+static int brf6150_open_firmware(struct brf6150_info *info)
+{
+ int err;
+
+ info->fw_pos = 0;
+ err = request_firmware(&info->fw_entry, "brf6150fw.bin", &brf6150_device.dev);
+
+ return err;
+}
+
+static struct sk_buff *brf6150_read_fw_cmd(struct brf6150_info *info, int how)
+{
+ struct sk_buff *skb;
+ unsigned int cmd_len;
+
+ if (info->fw_pos >= info->fw_entry->size) {
+ return NULL;
+ }
+
+ cmd_len = info->fw_entry->data[info->fw_pos++];
+ if (!cmd_len)
+ return NULL;
+
+ if (info->fw_pos + cmd_len > info->fw_entry->size) {
+ printk(KERN_WARNING "Corrupted firmware image\n");
+ return NULL;
+ }
+
+ skb = bt_skb_alloc(cmd_len, how);
+ if (!skb) {
+ printk(KERN_WARNING "Cannot reserve memory for buffer\n");
+ return NULL;
+ }
+ memcpy(skb_put(skb, cmd_len), &info->fw_entry->data[info->fw_pos], cmd_len);
+
+ info->fw_pos += cmd_len;
+
+ return skb;
+}
+
+static int brf6150_close_firmware(struct brf6150_info *info)
+{
+ release_firmware(info->fw_entry);
+ return 0;
+}
+
+static int brf6150_send_alive_packet(struct brf6150_info *info)
+{
+ struct sk_buff *skb;
+
+ NBT_DBG("Sending alive packet\n");
+ skb = brf6150_read_fw_cmd(info, GFP_ATOMIC);
+ if (!skb) {
+ printk(KERN_WARNING "Cannot read alive command");
+ return -1;
+ }
+
+ clk_enable(info->uart_ck);
+ skb_queue_tail(&info->txq, skb);
+ tasklet_schedule(&info->tx_task);
+
+ NBT_DBG("Alive packet sent\n");
+ return 0;
+}
+
+static void brf6150_alive_packet(struct brf6150_info *info, struct sk_buff *skb)
+{
+ NBT_DBG("Received alive packet\n");
+ if (skb->data[1] == 0xCC) {
+ complete(&info->init_completion);
+ }
+
+ kfree_skb(skb);
+}
+
+static int brf6150_send_negotiation(struct brf6150_info *info)
+{
+ struct sk_buff *skb;
+ NBT_DBG("Sending negotiation..\n");
+
+ brf6150_change_speed(info, INIT_SPEED);
+
+ skb = brf6150_read_fw_cmd(info, GFP_KERNEL);
+
+ if (!skb) {
+ printk(KERN_WARNING "Cannot read negoatiation message");
+ return -1;
+ }
+
+ clk_enable(info->uart_ck);
+ skb_queue_tail(&info->txq, skb);
+ tasklet_schedule(&info->tx_task);
+
+
+ NBT_DBG("Negotiation sent\n");
+ return 0;
+}
+
+static void brf6150_negotiation_packet(struct brf6150_info *info,
+ struct sk_buff *skb)
+{
+ if (skb->data[1] == 0x20) {
+ /* Change to operational settings */
+ brf6150_set_rts(info, 0);
+ brf6150_wait_for_cts(info, 0, 100);
+ brf6150_change_speed(info, MAX_BAUD_RATE);
+ brf6150_set_rts(info, 1);
+ brf6150_wait_for_cts(info, 1, 100);
+ brf6150_set_auto_ctsrts(info, 1);
+ brf6150_send_alive_packet(info);
+ } else {
+ printk(KERN_WARNING "Could not negotiate brf6150 settings\n");
+ }
+ kfree_skb(skb);
+}
+
+static int brf6150_get_hdr_len(u8 pkt_type)
+{
+ long retval;
+
+ switch (pkt_type) {
+ case H4_EVT_PKT:
+ retval = HCI_EVENT_HDR_SIZE;
+ break;
+ case H4_ACL_PKT:
+ retval = HCI_ACL_HDR_SIZE;
+ break;
+ case H4_SCO_PKT:
+ retval = HCI_SCO_HDR_SIZE;
+ break;
+ case H4_NEG_PKT:
+ retval = 9;
+ break;
+ case H4_ALIVE_PKT:
+ retval = 3;
+ break;
+ default:
+ printk(KERN_ERR "brf6150: Unknown H4 packet");
+ retval = -1;
+ break;
+ }
+
+ return retval;
+}
+
+static unsigned int brf6150_get_data_len(struct brf6150_info *info,
+ struct sk_buff *skb)
+{
+ long retval = -1;
+ struct hci_event_hdr *evt_hdr;
+ struct hci_acl_hdr *acl_hdr;
+ struct hci_sco_hdr *sco_hdr;
+
+ switch (bt_cb(skb)->pkt_type) {
+ case H4_EVT_PKT:
+ evt_hdr = (struct hci_event_hdr *)skb->data;
+ retval = evt_hdr->plen;
+ break;
+ case H4_ACL_PKT:
+ acl_hdr = (struct hci_acl_hdr *)skb->data;
+ retval = le16_to_cpu(acl_hdr->dlen);
+ break;
+ case H4_SCO_PKT:
+ sco_hdr = (struct hci_sco_hdr *)skb->data;
+ retval = sco_hdr->dlen;
+ break;
+ case H4_NEG_PKT:
+ retval = 0;
+ break;
+ case H4_ALIVE_PKT:
+ retval = 0;
+ break;
+ }
+
+ return retval;
+}
+
+static void brf6150_parse_fw_event(struct brf6150_info *info)
+{
+ struct hci_fw_event *ev;
+
+ if (bt_cb(info->rx_skb)->pkt_type != H4_EVT_PKT) {
+ printk(KERN_WARNING "Got non event fw packet.\n");
+ info->fw_error = 1;
+ return;
+ }
+
+ ev = (struct hci_fw_event *)info->rx_skb->data;
+ if (ev->hev.evt != HCI_EV_CMD_COMPLETE) {
+ printk(KERN_WARNING "Got non cmd complete fw event\n");
+ info->fw_error = 1;
+ return;
+ }
+
+ if (ev->status != 0) {
+ printk(KERN_WARNING "Got error status from fw command\n");
+ info->fw_error = 1;
+ return;
+ }
+
+ complete(&info->fw_completion);
+}
+
+static inline void brf6150_recv_frame(struct brf6150_info *info,
+ struct sk_buff *skb)
+{
+ if (unlikely(!test_bit(HCI_RUNNING, &info->hdev->flags))) {
+ NBT_DBG("fw_event\n");
+ brf6150_parse_fw_event(info);
+ kfree_skb(skb);
+ } else {
+ hci_recv_frame(skb);
+ if (!(brf6150_inb(info, UART_LSR) & UART_LSR_DR))
+ brf6150_enable_pm_rx(info);
+ NBT_DBG("Frame sent to upper layer\n");
+ }
+
+}
+
+static inline void brf6150_rx(struct brf6150_info *info)
+{
+ u8 byte;
+
+ NBT_DBG_TRANSFER("rx_tasklet woke up\ndata ");
+
+ while (brf6150_inb(info, UART_LSR) & UART_LSR_DR) {
+ if (info->rx_skb == NULL) {
+ info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
+ if (!info->rx_skb) {
+ printk(KERN_WARNING "brf6150: Can't allocate memory for new packet\n");
+ return;
+ }
+ info->rx_state = WAIT_FOR_PKT_TYPE;
+ info->rx_skb->dev = (void *)info->hdev;
+ brf6150_disable_pm_rx(info);
+ clk_enable(info->uart_ck);
+ }
+
+ byte = brf6150_inb(info, UART_RX);
+ if (info->garbage_bytes) {
+ info->garbage_bytes--;
+ info->hdev->stat.err_rx++;
+ continue;
+ }
+ info->hdev->stat.byte_rx++;
+ NBT_DBG_TRANSFER_NF("0x%.2x ", byte);
+ switch (info->rx_state) {
+ case WAIT_FOR_PKT_TYPE:
+ bt_cb(info->rx_skb)->pkt_type = byte;
+ info->rx_count = brf6150_get_hdr_len(byte);
+ if (info->rx_count >= 0) {
+ info->rx_state = WAIT_FOR_HEADER;
+ } else {
+ info->hdev->stat.err_rx++;
+ kfree_skb(info->rx_skb);
+ info->rx_skb = NULL;
+ clk_disable(info->uart_ck);
+ }
+ break;
+ case WAIT_FOR_HEADER:
+ info->rx_count--;
+ *skb_put(info->rx_skb, 1) = byte;
+ if (info->rx_count == 0) {
+ info->rx_count = brf6150_get_data_len(info, info->rx_skb);
+ if (info->rx_count > skb_tailroom(info->rx_skb)) {
+ printk(KERN_WARNING "brf6150: Frame is %ld bytes too long.\n",
+ info->rx_count - skb_tailroom(info->rx_skb));
+ info->rx_skb = NULL;
+ info->garbage_bytes = info->rx_count - skb_tailroom(info->rx_skb);
+ clk_disable(info->uart_ck);
+ break;
+ }
+ info->rx_state = WAIT_FOR_DATA;
+ if (bt_cb(info->rx_skb)->pkt_type == H4_NEG_PKT) {
+ brf6150_negotiation_packet(info, info->rx_skb);
+ info->rx_skb = NULL;
+ clk_disable(info->uart_ck);
+ return;
+ }
+ if (bt_cb(info->rx_skb)->pkt_type == H4_ALIVE_PKT) {
+ brf6150_alive_packet(info, info->rx_skb);
+ info->rx_skb = NULL;
+ clk_disable(info->uart_ck);
+ return;
+ }
+ }
+ break;
+ case WAIT_FOR_DATA:
+ info->rx_count--;
+ *skb_put(info->rx_skb, 1) = byte;
+ if (info->rx_count == 0) {
+ brf6150_recv_frame(info, info->rx_skb);
+ info->rx_skb = NULL;
+ clk_disable(info->uart_ck);
+ }
+ break;
+ default:
+ WARN_ON(1);
+ break;
+ }
+ }
+
+ NBT_DBG_TRANSFER_NF("\n");
+}
+
+static void brf6150_tx_tasklet(unsigned long data)
+{
+ unsigned int sent = 0;
+ unsigned long flags;
+ struct sk_buff *skb;
+ struct brf6150_info *info = (struct brf6150_info *)data;
+
+ NBT_DBG_TRANSFER("tx_tasklet woke up\n data ");
+
+ skb = skb_dequeue(&info->txq);
+ if (!skb) {
+ /* No data in buffer */
+ brf6150_enable_pm_tx(info);
+ return;
+ }
+
+ /* Copy data to tx fifo */
+ while (!(brf6150_inb(info, UART_OMAP_SSR) & UART_OMAP_SSR_TXFULL) &&
+ (sent < skb->len)) {
+ NBT_DBG_TRANSFER_NF("0x%.2x ", skb->data[sent]);
+ brf6150_outb(info, UART_TX, skb->data[sent]);
+ sent++;
+ }
+
+ info->hdev->stat.byte_tx += sent;
+ NBT_DBG_TRANSFER_NF("\n");
+ if (skb->len == sent) {
+ kfree_skb(skb);
+ clk_disable(info->uart_ck);
+ } else {
+ skb_pull(skb, sent);
+ skb_queue_head(&info->txq, skb);
+ }
+
+ spin_lock_irqsave(&info->lock, flags);
+ brf6150_outb(info, UART_IER, brf6150_inb(info, UART_IER) | UART_IER_THRI);
+ spin_unlock_irqrestore(&info->lock, flags);
+}
+
+static irqreturn_t brf6150_interrupt(int irq, void *data)
+{
+ struct brf6150_info *info = (struct brf6150_info *)data;
+ u8 iir, msr;
+ int ret;
+ unsigned long flags;
+
+ ret = IRQ_NONE;
+
+ clk_enable(info->uart_ck);
+ iir = brf6150_inb(info, UART_IIR);
+ if (iir & UART_IIR_NO_INT) {
+ printk("Interrupt but no reason irq 0x%.2x\n", iir);
+ clk_disable(info->uart_ck);
+ return IRQ_HANDLED;
+ }
+
+ NBT_DBG("In interrupt handler iir 0x%.2x\n", iir);
+
+ iir &= UART_IIR_ID;
+
+ if (iir == UART_IIR_MSI) {
+ msr = brf6150_inb(info, UART_MSR);
+ ret = IRQ_HANDLED;
+ }
+ if (iir == UART_IIR_RLSI) {
+ brf6150_inb(info, UART_RX);
+ brf6150_inb(info, UART_LSR);
+ ret = IRQ_HANDLED;
+ }
+
+ if (iir == UART_IIR_RDI) {
+ brf6150_rx(info);
+ ret = IRQ_HANDLED;
+ }
+
+ if (iir == UART_IIR_THRI) {
+ spin_lock_irqsave(&info->lock, flags);
+ brf6150_outb(info, UART_IER, brf6150_inb(info, UART_IER) & ~UART_IER_THRI);
+ spin_unlock_irqrestore(&info->lock, flags);
+ tasklet_schedule(&info->tx_task);
+ ret = IRQ_HANDLED;
+ }
+
+ clk_disable(info->uart_ck);
+ return ret;
+}
+
+static irqreturn_t brf6150_wakeup_interrupt(int irq, void *dev_inst)
+{
+ struct brf6150_info *info = dev_inst;
+ int should_wakeup;
+ unsigned long flags;
+
+ spin_lock_irqsave(&info->lock, flags);
+ should_wakeup = omap_get_gpio_datain(info->btinfo->host_wakeup_gpio);
+ NBT_DBG_POWER("gpio interrupt %d\n", should_wakeup);
+ if (should_wakeup) {
+ clk_enable(info->uart_ck);
+ brf6150_set_auto_ctsrts(info, 1);
+ brf6150_rx(info);
+ tasklet_schedule(&info->tx_task);
+ } else {
+ brf6150_set_auto_ctsrts(info, 0);
+ brf6150_set_rts(info, 0);
+ clk_disable(info->uart_ck);
+ }
+
+ spin_unlock_irqrestore(&info->lock, flags);
+ return IRQ_HANDLED;
+}
+
+static int brf6150_init_uart(struct brf6150_info *info)
+{
+ int count = 0;
+
+ /* Reset the UART */
+ brf6150_outb(info, UART_OMAP_SYSC, UART_SYSC_OMAP_RESET);
+ while (!(brf6150_inb(info, UART_OMAP_SYSS) & UART_SYSS_RESETDONE)) {
+ if (count++ > 100) {
+ printk(KERN_ERR "brf6150: UART reset timeout\n");
+ return -1;
+ }
+ udelay(1);
+ }
+
+ /* Enable and setup FIFO */
+ brf6150_outb(info, UART_LCR, UART_LCR_WLEN8);
+ brf6150_outb(info, UART_OMAP_MDR1, 0x00); /* Make sure UART mode is enabled */
+ brf6150_outb(info, UART_OMAP_SCR, 0x00);
+ brf6150_outb(info, UART_EFR, brf6150_inb(info, UART_EFR) | UART_EFR_ECB);
+ brf6150_outb(info, UART_MCR, brf6150_inb(info, UART_MCR) | UART_MCR_TCRTLR);
+ brf6150_outb(info, UART_TI752_TLR, 0xff);
+ brf6150_outb(info, UART_TI752_TCR, 0x1f);
+ brf6150_outb(info, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
+ brf6150_outb(info, UART_IER, UART_IER_RDI);
+
+ return 0;
+}
+
+static int brf6150_reset(struct brf6150_info *info)
+{
+ omap_set_gpio_dataout(info->btinfo->bt_wakeup_gpio, 0);
+ omap_set_gpio_dataout(info->btinfo->reset_gpio, 0);
+ current->state = TASK_UNINTERRUPTIBLE;
+ schedule_timeout(msecs_to_jiffies(10));
+ omap_set_gpio_dataout(info->btinfo->bt_wakeup_gpio, 1);
+ current->state = TASK_UNINTERRUPTIBLE;
+ schedule_timeout(msecs_to_jiffies(100));
+ omap_set_gpio_dataout(info->btinfo->reset_gpio, 1);
+ current->state = TASK_UNINTERRUPTIBLE;
+ schedule_timeout(msecs_to_jiffies(100));
+
+ return 0;
+}
+
+static int brf6150_send_firmware(struct brf6150_info *info)
+{
+ struct sk_buff *skb;
+
+ init_completion(&info->fw_completion);
+ info->fw_error = 0;
+
+ while ((skb = brf6150_read_fw_cmd(info, GFP_KERNEL)) != NULL) {
+ clk_enable(info->uart_ck);
+ skb_queue_tail(&info->txq, skb);
+ tasklet_schedule(&info->tx_task);
+
+ if (!wait_for_completion_timeout(&info->fw_completion, HZ)) {
+ return -1;
+ }
+
+ if (info->fw_error) {
+ return -1;
+ }
+ }
+ NBT_DBG_FW("Firmware sent\n");
+
+ return 0;
+
+}
+
+/* hci callback functions */
+static int brf6150_hci_flush(struct hci_dev *hdev)
+{
+ struct brf6150_info *info;
+ info = hdev->driver_data;
+
+ skb_queue_purge(&info->txq);
+
+ return 0;
+}
+
+static int brf6150_hci_open(struct hci_dev *hdev)
+{
+ struct brf6150_info *info;
+ int err;
+
+ info = hdev->driver_data;
+
+ if (test_bit(HCI_RUNNING, &hdev->flags))
+ return 0;
+
+ if (brf6150_open_firmware(info) < 0) {
+ printk("Cannot open firmware\n");
+ return -1;
+ }
+
+ info->rx_state = WAIT_FOR_PKT_TYPE;
+ info->rx_count = 0;
+ info->garbage_bytes = 0;
+ info->rx_skb = NULL;
+ info->pm_enabled = 0;
+ set_irq_type(OMAP_GPIO_IRQ(info->btinfo->host_wakeup_gpio), IRQT_NOEDGE);
+ init_completion(&info->fw_completion);
+
+ clk_enable(info->uart_ck);
+
+ brf6150_init_uart(info);
+ brf6150_set_auto_ctsrts(info, 0);
+ brf6150_set_rts(info, 0);
+ brf6150_reset(info);
+ brf6150_wait_for_cts(info, 1, 10);
+ brf6150_set_rts(info, 1);
+ if (brf6150_send_negotiation(info)) {
+ brf6150_close_firmware(info);
+ return -1;
+ }
+
+ if (!wait_for_completion_interruptible_timeout(&info->init_completion, HZ)) {
+ brf6150_close_firmware(info);
+ clk_disable(info->uart_ck);
+ clear_bit(HCI_RUNNING, &hdev->flags);
+ return -1;
+ }
+ brf6150_set_auto_ctsrts(info, 1);
+
+ err = brf6150_send_firmware(info);
+ brf6150_close_firmware(info);
+ if (err < 0)
+ printk(KERN_ERR "brf6150: Sending firmware failed. Bluetooth won't work properly\n");
+
+ set_irq_type(OMAP_GPIO_IRQ(info->btinfo->host_wakeup_gpio), IRQT_BOTHEDGE);
+ info->pm_enabled = 1;
+ set_bit(HCI_RUNNING, &hdev->flags);
+ return 0;
+}
+
+static int brf6150_hci_close(struct hci_dev *hdev)
+{
+ struct brf6150_info *info = hdev->driver_data;
+ if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
+ return 0;
+
+ brf6150_hci_flush(hdev);
+ clk_disable(info->uart_ck);
+ del_timer_sync(&info->pm_timer);
+ omap_set_gpio_dataout(info->btinfo->bt_wakeup_gpio, 0);
+ set_irq_type(OMAP_GPIO_IRQ(info->btinfo->host_wakeup_gpio), IRQT_NOEDGE);
+
+ return 0;
+}
+
+static void brf6150_hci_destruct(struct hci_dev *hdev)
+{
+}
+
+static int brf6150_hci_send_frame(struct sk_buff *skb)
+{
+ struct brf6150_info *info;
+ struct hci_dev *hdev = (struct hci_dev *)skb->dev;
+
+ if (!hdev) {
+ printk(KERN_WARNING "brf6150: Frame for unknown device\n");
+ return -ENODEV;
+ }
+
+ if (!test_bit(HCI_RUNNING, &hdev->flags)) {
+ printk(KERN_WARNING "brf6150: Frame for non-running device\n");
+ return -EIO;
+ }
+
+ info = hdev->driver_data;
+
+ switch (bt_cb(skb)->pkt_type) {
+ case HCI_COMMAND_PKT:
+ hdev->stat.cmd_tx++;
+ break;
+ case HCI_ACLDATA_PKT:
+ hdev->stat.acl_tx++;
+ break;
+ case HCI_SCODATA_PKT:
+ hdev->stat.sco_tx++;
+ break;
+ };
+
+ /* Push frame type to skb */
+ clk_enable(info->uart_ck);
+ *skb_push(skb, 1) = bt_cb(skb)->pkt_type;
+ skb_queue_tail(&info->txq, skb);
+
+ brf6150_disable_pm_tx(info);
+
+ return 0;
+}
+
+static int brf6150_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
+{
+ return -ENOIOCTLCMD;
+}
+
+static void brf6150_device_release(struct device *dev)
+{
+}
+
+static int brf6150_register_hdev(struct brf6150_info *info)
+{
+ struct hci_dev *hdev;
+
+ /* Initialize and register HCI device */
+
+ hdev = hci_alloc_dev();
+ if (!hdev) {
+ printk(KERN_WARNING "brf6150: Can't allocate memory for device\n");
+ return -ENOMEM;
+ }
+ info->hdev = hdev;
+
+ hdev->type = HCI_UART;
+ hdev->driver_data = info;
+
+ hdev->open = brf6150_hci_open;
+ hdev->close = brf6150_hci_close;
+ hdev->destruct = brf6150_hci_destruct;
+ hdev->flush = brf6150_hci_flush;
+ hdev->send = brf6150_hci_send_frame;
+ hdev->destruct = brf6150_hci_destruct;
+ hdev->ioctl = brf6150_hci_ioctl;
+
+ hdev->owner = THIS_MODULE;
+
+ if (hci_register_dev(hdev) < 0) {
+ printk(KERN_WARNING "brf6150: Can't register HCI device %s.\n", hdev->name);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int __init brf6150_init(void)
+{
+ struct brf6150_info *info;
+ int irq, err;
+
+ info = kmalloc(sizeof(struct brf6150_info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+ memset(info, 0, sizeof(struct brf6150_info));
+
+ brf6150_device.dev.driver_data = info;
+ init_completion(&info->init_completion);
+ init_completion(&info->fw_completion);
+ info->pm_enabled = 0;
+ info->rx_pm_enabled = 0;
+ info->tx_pm_enabled = 0;
+ info->garbage_bytes = 0;
+ tasklet_init(&info->tx_task, brf6150_tx_tasklet, (unsigned long)info);
+ spin_lock_init(&info->lock);
+ skb_queue_head_init(&info->txq);
+ init_timer(&info->pm_timer);
+ info->pm_timer.function = brf6150_pm_timer;
+ info->pm_timer.data = (unsigned long)info;
+ exit_info = NULL;
+
+ info->btinfo = omap_get_config(OMAP_TAG_NOKIA_BT, struct omap_bluetooth_config);
+ if (info->btinfo == NULL)
+ return -1;
+
+ NBT_DBG("RESET gpio: %d\n", info->btinfo->reset_gpio);
+ NBT_DBG("BTWU gpio: %d\n", info->btinfo->bt_wakeup_gpio);
+ NBT_DBG("HOSTWU gpio: %d\n", info->btinfo->host_wakeup_gpio);
+ NBT_DBG("Uart: %d\n", info->btinfo->bt_uart);
+ NBT_DBG("sysclk: %d\n", info->btinfo->bt_sysclk);
+
+ err = omap_request_gpio(info->btinfo->reset_gpio);
+ if (err < 0)
+ {
+ printk(KERN_WARNING "Cannot get GPIO line %d",
+ info->btinfo->reset_gpio);
+ kfree(info);
+ return err;
+ }
+
+ err = omap_request_gpio(info->btinfo->bt_wakeup_gpio);
+ if (err < 0)
+ {
+ printk(KERN_WARNING "Cannot get GPIO line 0x%d",
+ info->btinfo->bt_wakeup_gpio);
+ omap_free_gpio(info->btinfo->reset_gpio);
+ kfree(info);
+ return err;
+ }
+
+ err = omap_request_gpio(info->btinfo->host_wakeup_gpio);
+ if (err < 0)
+ {
+ printk(KERN_WARNING "Cannot get GPIO line %d",
+ info->btinfo->host_wakeup_gpio);
+ omap_free_gpio(info->btinfo->reset_gpio);
+ omap_free_gpio(info->btinfo->bt_wakeup_gpio);
+ kfree(info);
+ return err;
+ }
+
+ omap_set_gpio_direction(info->btinfo->reset_gpio, 0);
+ omap_set_gpio_direction(info->btinfo->bt_wakeup_gpio, 0);
+ omap_set_gpio_direction(info->btinfo->host_wakeup_gpio, 1);
+ set_irq_type(OMAP_GPIO_IRQ(info->btinfo->host_wakeup_gpio), IRQT_NOEDGE);
+
+ switch (info->btinfo->bt_uart) {
+ case 1:
+ irq = INT_UART1;
+ info->uart_ck = clk_get(NULL, "uart1_ck");
+ info->uart_base = io_p2v((unsigned long)OMAP_UART1_BASE);
+ break;
+ case 2:
+ irq = INT_UART2;
+ info->uart_ck = clk_get(NULL, "uart2_ck");
+ info->uart_base = io_p2v((unsigned long)OMAP_UART2_BASE);
+ break;
+ case 3:
+ irq = INT_UART3;
+ info->uart_ck = clk_get(NULL, "uart3_ck");
+ info->uart_base = io_p2v((unsigned long)OMAP_UART3_BASE);
+ break;
+ default:
+ printk(KERN_ERR "No uart defined\n");
+ goto cleanup;
+ }
+
+ info->irq = irq;
+ err = request_irq(irq, brf6150_interrupt, 0, "brf6150", (void *)info);
+ if (err < 0) {
+ printk(KERN_ERR "brf6150: unable to get IRQ %d\n", irq);
+ goto cleanup;
+ }
+
+ err = request_irq(OMAP_GPIO_IRQ(info->btinfo->host_wakeup_gpio),
+ brf6150_wakeup_interrupt, 0, "brf6150_wkup", (void *)info);
+ if (err < 0) {
+ printk(KERN_ERR "brf6150: unable to get wakeup IRQ %d\n",
+ OMAP_GPIO_IRQ(info->btinfo->host_wakeup_gpio));
+ free_irq(irq, (void *)info);
+ goto cleanup;
+ }
+
+ /* Register with LDM */
+ if (platform_device_register(&brf6150_device)) {
+ printk(KERN_ERR "failed to register brf6150 device\n");
+ err = -ENODEV;
+ goto cleanup_irq;
+ }
+ /* Register the driver with LDM */
+ if (driver_register(&brf6150_driver)) {
+ printk(KERN_WARNING "failed to register brf6150 driver\n");
+ platform_device_unregister(&brf6150_device);
+ err = -ENODEV;
+ goto cleanup_irq;
+ }
+
+ if (brf6150_register_hdev(info) < 0) {
+ printk(KERN_WARNING "failed to register brf6150 hci device\n");
+ platform_device_unregister(&brf6150_device);
+ driver_unregister(&brf6150_driver);
+ goto cleanup_irq;
+ }
+
+ exit_info = info;
+ return 0;
+
+cleanup_irq:
+ free_irq(irq, (void *)info);
+ free_irq(OMAP_GPIO_IRQ(info->btinfo->host_wakeup_gpio), (void *)info);
+cleanup:
+ omap_free_gpio(info->btinfo->reset_gpio);
+ omap_free_gpio(info->btinfo->bt_wakeup_gpio);
+ omap_free_gpio(info->btinfo->host_wakeup_gpio);
+ kfree(info);
+
+ return err;
+}
+
+static void __exit brf6150_exit(void)
+{
+ brf6150_hci_close(exit_info->hdev);
+ hci_free_dev(exit_info->hdev);
+ omap_free_gpio(exit_info->btinfo->reset_gpio);
+ omap_free_gpio(exit_info->btinfo->bt_wakeup_gpio);
+ omap_free_gpio(exit_info->btinfo->host_wakeup_gpio);
+ free_irq(exit_info->irq, (void *)exit_info);
+ free_irq(OMAP_GPIO_IRQ(exit_info->btinfo->host_wakeup_gpio), (void *)exit_info);
+ kfree(exit_info);
+}
+
+module_init(brf6150_init);
+module_exit(brf6150_exit);
+
+MODULE_DESCRIPTION("brf6150 hci driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ville Tervo <ville.tervo@nokia.com>");
--- /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
+#
+# Makefile for the Linux Bluetooth HCI device drivers.
+#
+
+obj-$(CONFIG_BT_HCIH4P) += hci_h4p.o
+
+hci_h4p-objs := core.o fw.o uart.o sysfs.o fw-ti.o fw-csr.o
--- /dev/null
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2005, 2006 Nokia Corporation.
+ *
+ * Contact: Ville Tervo <ville.tervo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/serial_reg.h>
+#include <linux/skbuff.h>
+#include <linux/timer.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/board.h>
+#include <asm/arch/irqs.h>
+#include <asm/arch/pm.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/hci.h>
+
+#include "hci_h4p.h"
+
+#define PM_TIMEOUT 200
+
+/* This should be used in function that cannot release clocks */
+static void hci_h4p_set_clk(struct hci_h4p_info *info, int *clock, int enable)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&info->clocks_lock, flags);
+ if (enable && !*clock) {
+ NBT_DBG_POWER("Enabling %p\n", clock);
+ clk_enable(info->uart_fclk);
+#ifdef CONFIG_ARCH_OMAP2
+ if (cpu_is_omap24xx()) {
+ clk_enable(info->uart_iclk);
+ omap2_block_sleep();
+ }
+#endif
+ }
+ if (!enable && *clock) {
+ NBT_DBG_POWER("Disabling %p\n", clock);
+ clk_disable(info->uart_fclk);
+#ifdef CONFIG_ARCH_OMAP2
+ if (cpu_is_omap24xx()) {
+ clk_disable(info->uart_iclk);
+ omap2_allow_sleep();
+ }
+#endif
+ }
+
+ *clock = enable;
+ spin_unlock_irqrestore(&info->clocks_lock, flags);
+}
+
+/* Power management functions */
+static void hci_h4p_disable_tx(struct hci_h4p_info *info)
+{
+ NBT_DBG_POWER("\n");
+
+ if (!info->pm_enabled)
+ return;
+
+ mod_timer(&info->tx_pm_timer, jiffies + msecs_to_jiffies(PM_TIMEOUT));
+}
+
+static void hci_h4p_enable_tx(struct hci_h4p_info *info)
+{
+ NBT_DBG_POWER("\n");
+
+ if (!info->pm_enabled)
+ return;
+
+ del_timer_sync(&info->tx_pm_timer);
+ if (info->tx_pm_enabled) {
+ info->tx_pm_enabled = 0;
+ hci_h4p_set_clk(info, &info->tx_clocks_en, 1);
+ omap_set_gpio_dataout(info->bt_wakeup_gpio, 1);
+ }
+}
+
+static void hci_h4p_tx_pm_timer(unsigned long data)
+{
+ struct hci_h4p_info *info;
+
+ NBT_DBG_POWER("\n");
+
+ info = (struct hci_h4p_info *)data;
+
+ if (hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT) {
+ omap_set_gpio_dataout(info->bt_wakeup_gpio, 0);
+ hci_h4p_set_clk(info, &info->tx_clocks_en, 0);
+ info->tx_pm_enabled = 1;
+ }
+ else {
+ mod_timer(&info->tx_pm_timer, jiffies + msecs_to_jiffies(PM_TIMEOUT));
+ }
+}
+
+static void hci_h4p_disable_rx(struct hci_h4p_info *info)
+{
+ if (!info->pm_enabled)
+ return;
+
+ mod_timer(&info->rx_pm_timer, jiffies + msecs_to_jiffies(PM_TIMEOUT));
+}
+
+static void hci_h4p_enable_rx(struct hci_h4p_info *info)
+{
+ unsigned long flags;
+
+ if (!info->pm_enabled)
+ return;
+
+ del_timer_sync(&info->rx_pm_timer);
+ spin_lock_irqsave(&info->lock, flags);
+ if (info->rx_pm_enabled) {
+ hci_h4p_set_clk(info, &info->rx_clocks_en, 1);
+ hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) | UART_IER_RDI);
+ __hci_h4p_set_auto_ctsrts(info, 1, UART_EFR_RTS);
+ info->rx_pm_enabled = 0;
+ }
+ spin_unlock_irqrestore(&info->lock, flags);
+}
+
+static void hci_h4p_rx_pm_timer(unsigned long data)
+{
+ unsigned long flags;
+ struct hci_h4p_info *info = (struct hci_h4p_info *)data;
+
+ spin_lock_irqsave(&info->lock, flags);
+ if (!(hci_h4p_inb(info, UART_LSR) & UART_LSR_DR)) {
+ __hci_h4p_set_auto_ctsrts(info, 0, UART_EFR_RTS);
+ hci_h4p_set_rts(info, 0);
+ hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) & ~UART_IER_RDI);
+ hci_h4p_set_clk(info, &info->rx_clocks_en, 0);
+ info->rx_pm_enabled = 1;
+ }
+ else {
+ mod_timer(&info->rx_pm_timer, jiffies + msecs_to_jiffies(PM_TIMEOUT));
+ }
+ spin_unlock_irqrestore(&info->lock, flags);
+}
+
+/* Negotiation functions */
+int hci_h4p_send_alive_packet(struct hci_h4p_info *info)
+{
+ NBT_DBG("Sending alive packet\n");
+
+ if (!info->alive_cmd_skb)
+ return -EINVAL;
+
+ /* Keep reference to buffer so we can reuse it */
+ info->alive_cmd_skb = skb_get(info->alive_cmd_skb);
+
+ skb_queue_tail(&info->txq, info->alive_cmd_skb);
+ tasklet_schedule(&info->tx_task);
+
+ NBT_DBG("Alive packet sent\n");
+
+ return 0;
+}
+
+static void hci_h4p_alive_packet(struct hci_h4p_info *info, struct sk_buff *skb)
+{
+ NBT_DBG("Received alive packet\n");
+ if (skb->data[1] == 0xCC) {
+ complete(&info->init_completion);
+ }
+
+ kfree_skb(skb);
+}
+
+static int hci_h4p_send_negotiation(struct hci_h4p_info *info, struct sk_buff *skb)
+{
+ NBT_DBG("Sending negotiation..\n");
+
+ hci_h4p_change_speed(info, INIT_SPEED);
+
+ info->init_error = 0;
+ init_completion(&info->init_completion);
+ skb_queue_tail(&info->txq, skb);
+ tasklet_schedule(&info->tx_task);
+
+ if (!wait_for_completion_interruptible_timeout(&info->init_completion,
+ msecs_to_jiffies(1000)))
+ return -ETIMEDOUT;
+
+ NBT_DBG("Negotiation sent\n");
+ return info->init_error;
+}
+
+static void hci_h4p_negotiation_packet(struct hci_h4p_info *info,
+ struct sk_buff *skb)
+{
+ int err = 0;
+
+ if (skb->data[1] == 0x20) {
+ /* Change to operational settings */
+ hci_h4p_set_rts(info, 0);
+
+ err = hci_h4p_wait_for_cts(info, 0, 100);
+ if (err < 0)
+ goto neg_ret;
+
+ hci_h4p_change_speed(info, MAX_BAUD_RATE);
+
+ err = hci_h4p_wait_for_cts(info, 1, 100);
+ if (err < 0)
+ goto neg_ret;
+
+ hci_h4p_set_auto_ctsrts(info, 1, UART_EFR_CTS | UART_EFR_RTS);
+
+ err = hci_h4p_send_alive_packet(info);
+ if (err < 0)
+ goto neg_ret;
+ } else {
+ dev_err(info->dev, "Could not negotiate hci_h4p settings\n");
+ err = -EINVAL;
+ goto neg_ret;
+ }
+
+ kfree_skb(skb);
+ return;
+
+neg_ret:
+ info->init_error = err;
+ complete(&info->init_completion);
+ kfree_skb(skb);
+}
+
+/* H4 packet handling functions */
+static int hci_h4p_get_hdr_len(struct hci_h4p_info *info, u8 pkt_type)
+{
+ long retval;
+
+ switch (pkt_type) {
+ case H4_EVT_PKT:
+ retval = HCI_EVENT_HDR_SIZE;
+ break;
+ case H4_ACL_PKT:
+ retval = HCI_ACL_HDR_SIZE;
+ break;
+ case H4_SCO_PKT:
+ retval = HCI_SCO_HDR_SIZE;
+ break;
+ case H4_NEG_PKT:
+ retval = 11;
+ break;
+ case H4_ALIVE_PKT:
+ retval = 3;
+ break;
+ default:
+ dev_err(info->dev, "Unknown H4 packet type 0x%.2x\n", pkt_type);
+ retval = -1;
+ break;
+ }
+
+ return retval;
+}
+
+static unsigned int hci_h4p_get_data_len(struct hci_h4p_info *info,
+ struct sk_buff *skb)
+{
+ long retval = -1;
+ struct hci_event_hdr *evt_hdr;
+ struct hci_acl_hdr *acl_hdr;
+ struct hci_sco_hdr *sco_hdr;
+
+ switch (bt_cb(skb)->pkt_type) {
+ case H4_EVT_PKT:
+ evt_hdr = (struct hci_event_hdr *)skb->data;
+ retval = evt_hdr->plen;
+ break;
+ case H4_ACL_PKT:
+ acl_hdr = (struct hci_acl_hdr *)skb->data;
+ retval = le16_to_cpu(acl_hdr->dlen);
+ break;
+ case H4_SCO_PKT:
+ sco_hdr = (struct hci_sco_hdr *)skb->data;
+ retval = sco_hdr->dlen;
+ break;
+ case H4_NEG_PKT:
+ retval = 0;
+ break;
+ case H4_ALIVE_PKT:
+ retval = 0;
+ break;
+ }
+
+ return retval;
+}
+
+static inline void hci_h4p_recv_frame(struct hci_h4p_info *info,
+ struct sk_buff *skb)
+{
+
+ if (unlikely(!test_bit(HCI_RUNNING, &info->hdev->flags))) {
+ NBT_DBG("fw_event\n");
+ hci_h4p_parse_fw_event(info, skb);
+ } else {
+ hci_recv_frame(skb);
+ NBT_DBG("Frame sent to upper layer\n");
+ }
+}
+
+static void hci_h4p_rx_tasklet(unsigned long data)
+{
+ u8 byte;
+ unsigned long flags;
+ struct hci_h4p_info *info = (struct hci_h4p_info *)data;
+
+ NBT_DBG("tasklet woke up\n");
+ NBT_DBG_TRANSFER("rx_tasklet woke up\ndata ");
+
+ while (hci_h4p_inb(info, UART_LSR) & UART_LSR_DR) {
+ byte = hci_h4p_inb(info, UART_RX);
+ if (info->garbage_bytes) {
+ info->garbage_bytes--;
+ continue;
+ }
+ if (info->rx_skb == NULL) {
+ info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC | GFP_DMA);
+ if (!info->rx_skb) {
+ dev_err(info->dev, "Can't allocate memory for new packet\n");
+ goto finish_task;
+ }
+ info->rx_state = WAIT_FOR_PKT_TYPE;
+ info->rx_skb->dev = (void *)info->hdev;
+ }
+ info->hdev->stat.byte_rx++;
+ NBT_DBG_TRANSFER_NF("0x%.2x ", byte);
+ switch (info->rx_state) {
+ case WAIT_FOR_PKT_TYPE:
+ bt_cb(info->rx_skb)->pkt_type = byte;
+ info->rx_count = hci_h4p_get_hdr_len(info, byte);
+ if (info->rx_count < 0) {
+ info->hdev->stat.err_rx++;
+ kfree_skb(info->rx_skb);
+ info->rx_skb = NULL;
+ } else {
+ info->rx_state = WAIT_FOR_HEADER;
+ }
+ break;
+ case WAIT_FOR_HEADER:
+ info->rx_count--;
+ *skb_put(info->rx_skb, 1) = byte;
+ if (info->rx_count == 0) {
+ info->rx_count = hci_h4p_get_data_len(info, info->rx_skb);
+ if (info->rx_count > skb_tailroom(info->rx_skb)) {
+ dev_err(info->dev, "Frame is %ld bytes too long.\n",
+ info->rx_count - skb_tailroom(info->rx_skb));
+ kfree_skb(info->rx_skb);
+ info->rx_skb = NULL;
+ info->garbage_bytes = info->rx_count - skb_tailroom(info->rx_skb);
+ break;
+ }
+ info->rx_state = WAIT_FOR_DATA;
+
+ if (bt_cb(info->rx_skb)->pkt_type == H4_NEG_PKT) {
+ hci_h4p_negotiation_packet(info, info->rx_skb);
+ info->rx_skb = NULL;
+ info->rx_state = WAIT_FOR_PKT_TYPE;
+ goto finish_task;
+ }
+ if (bt_cb(info->rx_skb)->pkt_type == H4_ALIVE_PKT) {
+ hci_h4p_alive_packet(info, info->rx_skb);
+ info->rx_skb = NULL;
+ info->rx_state = WAIT_FOR_PKT_TYPE;
+ goto finish_task;
+ }
+ }
+ break;
+ case WAIT_FOR_DATA:
+ info->rx_count--;
+ *skb_put(info->rx_skb, 1) = byte;
+ if (info->rx_count == 0) {
+ /* H4+ devices should allways send word aligned packets */
+ if (!(info->rx_skb->len % 2)) {
+ info->garbage_bytes++;
+ }
+ hci_h4p_recv_frame(info, info->rx_skb);
+ info->rx_skb = NULL;
+ }
+ break;
+ default:
+ WARN_ON(1);
+ break;
+ }
+ }
+
+finish_task:
+ spin_lock_irqsave(&info->lock, flags);
+ hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) | UART_IER_RDI);
+ spin_unlock_irqrestore(&info->lock, flags);
+
+ NBT_DBG_TRANSFER_NF("\n");
+ NBT_DBG("rx_ended\n");
+}
+
+static void hci_h4p_tx_tasklet(unsigned long data)
+{
+ unsigned int sent = 0;
+ unsigned long flags;
+ struct sk_buff *skb;
+ struct hci_h4p_info *info = (struct hci_h4p_info *)data;
+
+ NBT_DBG("tasklet woke up\n");
+ NBT_DBG_TRANSFER("tx_tasklet woke up\n data ");
+
+ skb = skb_dequeue(&info->txq);
+ if (!skb) {
+ /* No data in buffer */
+ NBT_DBG("skb ready\n");
+ hci_h4p_disable_tx(info);
+ return;
+ }
+
+ /* Copy data to tx fifo */
+ while (!(hci_h4p_inb(info, UART_OMAP_SSR) & UART_OMAP_SSR_TXFULL) &&
+ (sent < skb->len)) {
+ NBT_DBG_TRANSFER_NF("0x%.2x ", skb->data[sent]);
+ hci_h4p_outb(info, UART_TX, skb->data[sent]);
+ sent++;
+ }
+
+ info->hdev->stat.byte_tx += sent;
+ NBT_DBG_TRANSFER_NF("\n");
+ if (skb->len == sent) {
+ kfree_skb(skb);
+ } else {
+ skb_pull(skb, sent);
+ skb_queue_head(&info->txq, skb);
+ }
+
+ spin_lock_irqsave(&info->lock, flags);
+ hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) | UART_IER_THRI);
+ spin_unlock_irqrestore(&info->lock, flags);
+}
+
+static irqreturn_t hci_h4p_interrupt(int irq, void *data)
+{
+ struct hci_h4p_info *info = (struct hci_h4p_info *)data;
+ u8 iir, msr;
+ int ret;
+ unsigned long flags;
+
+ ret = IRQ_NONE;
+
+ iir = hci_h4p_inb(info, UART_IIR);
+ if (iir & UART_IIR_NO_INT) {
+ dev_err(info->dev, "Interrupt but no reason irq 0x%.2x\n", iir);
+ return IRQ_HANDLED;
+ }
+
+ NBT_DBG("In interrupt handler iir 0x%.2x\n", iir);
+
+ iir &= UART_IIR_ID;
+
+ if (iir == UART_IIR_MSI) {
+ msr = hci_h4p_inb(info, UART_MSR);
+ ret = IRQ_HANDLED;
+ }
+ if (iir == UART_IIR_RLSI) {
+ hci_h4p_inb(info, UART_RX);
+ hci_h4p_inb(info, UART_LSR);
+ ret = IRQ_HANDLED;
+ }
+
+ if (iir == UART_IIR_RDI) {
+ spin_lock_irqsave(&info->lock, flags);
+ hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) & ~UART_IER_RDI);
+ spin_unlock_irqrestore(&info->lock, flags);
+ tasklet_schedule(&info->rx_task);
+ ret = IRQ_HANDLED;
+ }
+
+ if (iir == UART_IIR_THRI) {
+ spin_lock_irqsave(&info->lock, flags);
+ hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) & ~UART_IER_THRI);
+ spin_unlock_irqrestore(&info->lock, flags);
+ tasklet_schedule(&info->tx_task);
+ ret = IRQ_HANDLED;
+ }
+
+ return ret;
+}
+
+static irqreturn_t hci_h4p_wakeup_interrupt(int irq, void *dev_inst)
+{
+ struct hci_h4p_info *info = dev_inst;
+ int should_wakeup;
+ struct hci_dev *hdev;
+
+ if (!info->hdev)
+ return IRQ_HANDLED;
+
+ hdev = info->hdev;
+
+ if (!test_bit(HCI_RUNNING, &hdev->flags))
+ return IRQ_HANDLED;
+
+ should_wakeup = omap_get_gpio_datain(info->host_wakeup_gpio);
+ NBT_DBG_POWER("gpio interrupt %d\n", should_wakeup);
+ if (should_wakeup) {
+ hci_h4p_enable_rx(info);
+ } else {
+ hci_h4p_disable_rx(info);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int hci_h4p_reset(struct hci_h4p_info *info)
+{
+ int err;
+
+ hci_h4p_init_uart(info);
+ hci_h4p_set_rts(info, 0);
+
+ omap_set_gpio_dataout(info->reset_gpio, 0);
+ msleep(100);
+ omap_set_gpio_dataout(info->bt_wakeup_gpio, 1);
+ omap_set_gpio_dataout(info->reset_gpio, 1);
+ msleep(100);
+
+ err = hci_h4p_wait_for_cts(info, 1, 10);
+ if (err < 0) {
+ dev_err(info->dev, "No cts from bt chip\n");
+ return err;
+ }
+
+ hci_h4p_set_rts(info, 1);
+
+ return 0;
+}
+
+/* hci callback functions */
+static int hci_h4p_hci_flush(struct hci_dev *hdev)
+{
+ struct hci_h4p_info *info;
+ info = hdev->driver_data;
+
+ skb_queue_purge(&info->txq);
+
+ return 0;
+}
+
+static int hci_h4p_hci_open(struct hci_dev *hdev)
+{
+ struct hci_h4p_info *info;
+ int err;
+ struct sk_buff *neg_cmd_skb;
+ struct sk_buff_head fw_queue;
+
+ info = hdev->driver_data;
+
+ if (test_bit(HCI_RUNNING, &hdev->flags))
+ return 0;
+
+ skb_queue_head_init(&fw_queue);
+ err = hci_h4p_read_fw(info, &fw_queue);
+ if (err < 0) {
+ dev_err(info->dev, "Cannot read firmware\n");
+ return err;
+ }
+ neg_cmd_skb = skb_dequeue(&fw_queue);
+ if (!neg_cmd_skb) {
+ err = -EPROTO;
+ goto err_clean;
+ }
+ info->alive_cmd_skb = skb_dequeue(&fw_queue);
+ if (!info->alive_cmd_skb) {
+ err = -EPROTO;
+ goto err_clean;
+ }
+
+ hci_h4p_set_clk(info, &info->tx_clocks_en, 1);
+ hci_h4p_set_clk(info, &info->rx_clocks_en, 1);
+
+ tasklet_enable(&info->tx_task);
+ tasklet_enable(&info->rx_task);
+ info->rx_state = WAIT_FOR_PKT_TYPE;
+ info->rx_count = 0;
+ info->garbage_bytes = 0;
+ info->rx_skb = NULL;
+ info->pm_enabled = 0;
+ init_completion(&info->fw_completion);
+
+ err = hci_h4p_reset(info);
+ if (err < 0)
+ goto err_clean;
+
+ err = hci_h4p_send_negotiation(info, neg_cmd_skb);
+ neg_cmd_skb = NULL;
+ if (err < 0)
+ goto err_clean;
+
+ err = hci_h4p_send_fw(info, &fw_queue);
+ if (err < 0) {
+ dev_err(info->dev, "Sending firmware failed.\n");
+ goto err_clean;
+ }
+
+ kfree_skb(info->alive_cmd_skb);
+ info->alive_cmd_skb = NULL;
+ info->pm_enabled = 1;
+ info->tx_pm_enabled = 1;
+ info->rx_pm_enabled = 0;
+ set_bit(HCI_RUNNING, &hdev->flags);
+
+ NBT_DBG("hci up and running\n");
+ return 0;
+
+err_clean:
+ hci_h4p_hci_flush(hdev);
+ tasklet_disable(&info->tx_task);
+ tasklet_disable(&info->rx_task);
+ hci_h4p_reset_uart(info);
+ hci_h4p_set_clk(info, &info->tx_clocks_en, 0);
+ hci_h4p_set_clk(info, &info->rx_clocks_en, 0);
+ omap_set_gpio_dataout(info->reset_gpio, 0);
+ omap_set_gpio_dataout(info->bt_wakeup_gpio, 0);
+ skb_queue_purge(&fw_queue);
+ kfree_skb(neg_cmd_skb);
+ neg_cmd_skb = NULL;
+ kfree_skb(info->alive_cmd_skb);
+ info->alive_cmd_skb = NULL;
+ kfree_skb(info->rx_skb);
+
+ return err;
+}
+
+static int hci_h4p_hci_close(struct hci_dev *hdev)
+{
+ struct hci_h4p_info *info = hdev->driver_data;
+
+ if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
+ return 0;
+
+ hci_h4p_hci_flush(hdev);
+ del_timer_sync(&info->tx_pm_timer);
+ del_timer_sync(&info->rx_pm_timer);
+ tasklet_disable(&info->tx_task);
+ tasklet_disable(&info->rx_task);
+ hci_h4p_set_clk(info, &info->tx_clocks_en, 1);
+ hci_h4p_set_clk(info, &info->rx_clocks_en, 1);
+ hci_h4p_reset_uart(info);
+ hci_h4p_set_clk(info, &info->tx_clocks_en, 0);
+ hci_h4p_set_clk(info, &info->rx_clocks_en, 0);
+ omap_set_gpio_dataout(info->reset_gpio, 0);
+ omap_set_gpio_dataout(info->bt_wakeup_gpio, 0);
+ kfree_skb(info->rx_skb);
+
+ return 0;
+}
+
+static void hci_h4p_hci_destruct(struct hci_dev *hdev)
+{
+}
+
+static int hci_h4p_hci_send_frame(struct sk_buff *skb)
+{
+ struct hci_h4p_info *info;
+ struct hci_dev *hdev = (struct hci_dev *)skb->dev;
+ int err = 0;
+
+ if (!hdev) {
+ printk(KERN_WARNING "hci_h4p: Frame for unknown device\n");
+ return -ENODEV;
+ }
+
+ NBT_DBG("dev %p, skb %p\n", hdev, skb);
+
+ info = hdev->driver_data;
+
+ if (!test_bit(HCI_RUNNING, &hdev->flags)) {
+ dev_warn(info->dev, "Frame for non-running device\n");
+ return -EIO;
+ }
+
+ switch (bt_cb(skb)->pkt_type) {
+ case HCI_COMMAND_PKT:
+ hdev->stat.cmd_tx++;
+ break;
+ case HCI_ACLDATA_PKT:
+ hdev->stat.acl_tx++;
+ break;
+ case HCI_SCODATA_PKT:
+ hdev->stat.sco_tx++;
+ break;
+ }
+
+ /* Push frame type to skb */
+ *skb_push(skb, 1) = (bt_cb(skb)->pkt_type);
+ /* We should allways send word aligned data to h4+ devices */
+ if (skb->len % 2) {
+ err = skb_pad(skb, 1);
+ }
+ if (err)
+ return err;
+
+ hci_h4p_enable_tx(info);
+ skb_queue_tail(&info->txq, skb);
+ tasklet_schedule(&info->tx_task);
+
+ return 0;
+}
+
+static int hci_h4p_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
+{
+ return -ENOIOCTLCMD;
+}
+
+static int hci_h4p_register_hdev(struct hci_h4p_info *info)
+{
+ struct hci_dev *hdev;
+
+ /* Initialize and register HCI device */
+
+ hdev = hci_alloc_dev();
+ if (!hdev) {
+ dev_err(info->dev, "Can't allocate memory for device\n");
+ return -ENOMEM;
+ }
+ info->hdev = hdev;
+
+ hdev->type = HCI_UART;
+ hdev->driver_data = info;
+
+ hdev->open = hci_h4p_hci_open;
+ hdev->close = hci_h4p_hci_close;
+ hdev->flush = hci_h4p_hci_flush;
+ hdev->send = hci_h4p_hci_send_frame;
+ hdev->destruct = hci_h4p_hci_destruct;
+ hdev->ioctl = hci_h4p_hci_ioctl;
+
+ hdev->owner = THIS_MODULE;
+
+ if (hci_register_dev(hdev) < 0) {
+ dev_err(info->dev, "hci_h4p: Can't register HCI device %s.\n", hdev->name);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int hci_h4p_probe(struct platform_device *pdev)
+{
+ struct omap_bluetooth_config *bt_config;
+ struct hci_h4p_info *info;
+ int irq, err;
+
+ dev_info(&pdev->dev, "Registering HCI H4P device\n");
+ info = kzalloc(sizeof(struct hci_h4p_info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ info->dev = &pdev->dev;
+ info->pm_enabled = 0;
+ info->tx_pm_enabled = 0;
+ info->rx_pm_enabled = 0;
+ info->garbage_bytes = 0;
+ info->tx_clocks_en = 0;
+ info->rx_clocks_en = 0;
+ tasklet_init(&info->tx_task, hci_h4p_tx_tasklet, (unsigned long)info);
+ tasklet_init(&info->rx_task, hci_h4p_rx_tasklet, (unsigned long)info);
+ /* hci_h4p_hci_open assumes that tasklet is disabled in startup */
+ tasklet_disable(&info->tx_task);
+ tasklet_disable(&info->rx_task);
+ spin_lock_init(&info->lock);
+ spin_lock_init(&info->clocks_lock);
+ skb_queue_head_init(&info->txq);
+ init_timer(&info->tx_pm_timer);
+ info->tx_pm_timer.function = hci_h4p_tx_pm_timer;
+ info->tx_pm_timer.data = (unsigned long)info;
+ init_timer(&info->rx_pm_timer);
+ info->rx_pm_timer.function = hci_h4p_rx_pm_timer;
+ info->rx_pm_timer.data = (unsigned long)info;
+
+ if (pdev->dev.platform_data == NULL) {
+ dev_err(&pdev->dev, "Could not get Bluetooth config data\n");
+ return -ENODATA;
+ }
+
+ bt_config = pdev->dev.platform_data;
+ info->chip_type = bt_config->chip_type;
+ info->bt_wakeup_gpio = bt_config->bt_wakeup_gpio;
+ info->host_wakeup_gpio = bt_config->host_wakeup_gpio;
+ info->reset_gpio = bt_config->reset_gpio;
+ info->bt_sysclk = bt_config->bt_sysclk;
+
+ NBT_DBG("RESET gpio: %d\n", info->reset_gpio);
+ NBT_DBG("BTWU gpio: %d\n", info->bt_wakeup_gpio);
+ NBT_DBG("HOSTWU gpio: %d\n", info->host_wakeup_gpio);
+ NBT_DBG("Uart: %d\n", bt_config->bt_uart);
+ NBT_DBG("sysclk: %d\n", info->bt_sysclk);
+
+ err = omap_request_gpio(info->reset_gpio);
+ if (err < 0) {
+ dev_err(&pdev->dev, "Cannot get GPIO line %d\n",
+ info->reset_gpio);
+ kfree(info);
+ goto cleanup;
+ }
+
+ err = omap_request_gpio(info->bt_wakeup_gpio);
+ if (err < 0)
+ {
+ dev_err(info->dev, "Cannot get GPIO line 0x%d",
+ info->bt_wakeup_gpio);
+ omap_free_gpio(info->reset_gpio);
+ kfree(info);
+ goto cleanup;
+ }
+
+ err = omap_request_gpio(info->host_wakeup_gpio);
+ if (err < 0)
+ {
+ dev_err(info->dev, "Cannot get GPIO line %d",
+ info->host_wakeup_gpio);
+ omap_free_gpio(info->reset_gpio);
+ omap_free_gpio(info->bt_wakeup_gpio);
+ kfree(info);
+ goto cleanup;
+ }
+
+ omap_set_gpio_direction(info->reset_gpio, 0);
+ omap_set_gpio_direction(info->bt_wakeup_gpio, 0);
+ omap_set_gpio_direction(info->host_wakeup_gpio, 1);
+
+ switch (bt_config->bt_uart) {
+ case 1:
+ if (cpu_is_omap16xx()) {
+ irq = INT_UART1;
+ info->uart_fclk = clk_get(NULL, "uart1_ck");
+ } else if (cpu_is_omap24xx()) {
+ irq = INT_24XX_UART1_IRQ;
+ info->uart_iclk = clk_get(NULL, "uart1_ick");
+ info->uart_fclk = clk_get(NULL, "uart1_fck");
+ }
+ info->uart_base = (void *)io_p2v(OMAP_UART1_BASE);
+ break;
+ case 2:
+ if (cpu_is_omap16xx()) {
+ irq = INT_UART2;
+ info->uart_fclk = clk_get(NULL, "uart2_ck");
+ } else {
+ irq = INT_24XX_UART2_IRQ;
+ info->uart_iclk = clk_get(NULL, "uart2_ick");
+ info->uart_fclk = clk_get(NULL, "uart2_fck");
+ }
+ info->uart_base = (void *)io_p2v(OMAP_UART2_BASE);
+ break;
+ case 3:
+ if (cpu_is_omap16xx()) {
+ irq = INT_UART3;
+ info->uart_fclk = clk_get(NULL, "uart3_ck");
+ } else {
+ irq = INT_24XX_UART3_IRQ;
+ info->uart_iclk = clk_get(NULL, "uart3_ick");
+ info->uart_fclk = clk_get(NULL, "uart3_fck");
+ }
+ info->uart_base = (void *)io_p2v(OMAP_UART3_BASE);
+ break;
+ default:
+ dev_err(info->dev, "No uart defined\n");
+ goto cleanup;
+ }
+
+ info->irq = irq;
+ err = request_irq(irq, hci_h4p_interrupt, 0, "hci_h4p", (void *)info);
+ if (err < 0) {
+ dev_err(info->dev, "hci_h4p: unable to get IRQ %d\n", irq);
+ goto cleanup;
+ }
+
+ err = request_irq(OMAP_GPIO_IRQ(info->host_wakeup_gpio),
+ hci_h4p_wakeup_interrupt,
+ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+ "hci_h4p_wkup", (void *)info);
+ if (err < 0) {
+ dev_err(info->dev, "hci_h4p: unable to get wakeup IRQ %d\n",
+ OMAP_GPIO_IRQ(info->host_wakeup_gpio));
+ free_irq(irq, (void *)info);
+ goto cleanup;
+ }
+
+ hci_h4p_set_clk(info, &info->tx_clocks_en, 1);
+ hci_h4p_set_auto_ctsrts(info, 0, UART_EFR_CTS | UART_EFR_RTS);
+ err = hci_h4p_init_uart(info);
+ if (err < 0)
+ goto cleanup_irq;
+ err = hci_h4p_reset(info);
+ if (err < 0)
+ goto cleanup_irq;
+ err = hci_h4p_wait_for_cts(info, 1, 10);
+ if (err < 0)
+ goto cleanup_irq;
+ hci_h4p_set_clk(info, &info->tx_clocks_en, 0);
+
+ platform_set_drvdata(pdev, info);
+ err = hci_h4p_sysfs_create_files(info->dev);
+ if (err < 0)
+ goto cleanup_irq;
+
+ if (hci_h4p_register_hdev(info) < 0) {
+ dev_err(info->dev, "failed to register hci_h4p hci device\n");
+ goto cleanup_irq;
+ }
+ omap_set_gpio_dataout(info->reset_gpio, 0);
+
+ return 0;
+
+cleanup_irq:
+ free_irq(irq, (void *)info);
+ free_irq(OMAP_GPIO_IRQ(info->host_wakeup_gpio), (void *)info);
+cleanup:
+ omap_set_gpio_dataout(info->reset_gpio, 0);
+ omap_free_gpio(info->reset_gpio);
+ omap_free_gpio(info->bt_wakeup_gpio);
+ omap_free_gpio(info->host_wakeup_gpio);
+ kfree(info);
+
+ return err;
+
+}
+
+static int hci_h4p_remove(struct platform_device *dev)
+{
+ struct hci_h4p_info *info;
+
+ info = platform_get_drvdata(dev);
+
+ hci_h4p_hci_close(info->hdev);
+ free_irq(OMAP_GPIO_IRQ(info->host_wakeup_gpio), (void *) info);
+ hci_free_dev(info->hdev);
+ omap_free_gpio(info->reset_gpio);
+ omap_free_gpio(info->bt_wakeup_gpio);
+ omap_free_gpio(info->host_wakeup_gpio);
+ free_irq(info->irq, (void *) info);
+ kfree(info);
+
+ return 0;
+}
+
+static struct platform_driver hci_h4p_driver = {
+ .probe = hci_h4p_probe,
+ .remove = hci_h4p_remove,
+ .driver = {
+ .name = "hci_h4p",
+ },
+};
+
+static int __init hci_h4p_init(void)
+{
+ int err = 0;
+
+ /* Register the driver with LDM */
+ err = platform_driver_register(&hci_h4p_driver);
+ if (err < 0)
+ printk(KERN_WARNING "failed to register hci_h4p driver\n");
+
+ return err;
+}
+
+static void __exit hci_h4p_exit(void)
+{
+ platform_driver_unregister(&hci_h4p_driver);
+}
+
+module_init(hci_h4p_init);
+module_exit(hci_h4p_exit);
+
+MODULE_DESCRIPTION("h4 driver with nokia extensions");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ville Tervo");
--- /dev/null
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2005, 2006 Nokia Corporation.
+ *
+ * Contact: Ville Tervo <ville.tervo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/serial_reg.h>
+
+#include "hci_h4p.h"
+
+void hci_h4p_bc4_parse_fw_event(struct hci_h4p_info *info, struct sk_buff *skb)
+{
+ /* Check if this is fw packet */
+ if (skb->data[0] != 0xff) {
+ hci_recv_frame(skb);
+ return;
+ }
+
+ if (skb->data[11] || skb->data[12]) {
+ dev_err(info->dev, "Firmware sending command failed\n");
+ info->fw_error = -EPROTO;
+ }
+
+ kfree_skb(skb);
+ complete(&info->fw_completion);
+}
+
+int hci_h4p_bc4_send_fw(struct hci_h4p_info *info,
+ struct sk_buff_head *fw_queue)
+{
+ struct sk_buff *skb;
+ unsigned int offset;
+ int retries, count, i;
+
+ info->fw_error = 0;
+
+ NBT_DBG_FW("Sending firmware\n");
+ skb = skb_dequeue(fw_queue);
+
+ if (!skb)
+ return -ENOMSG;
+
+ /* Check if this is bd_address packet */
+ if (skb->data[15] == 0x01 && skb->data[16] == 0x00) {
+ offset = 21;
+ skb->data[offset + 1] = 0x00;
+ skb->data[offset + 5] = 0x00;
+ skb->data[offset + 7] = info->bdaddr[0];
+ skb->data[offset + 6] = info->bdaddr[1];
+ skb->data[offset + 4] = info->bdaddr[2];
+ skb->data[offset + 0] = info->bdaddr[3];
+ skb->data[offset + 3] = info->bdaddr[4];
+ skb->data[offset + 2] = info->bdaddr[5];
+ }
+
+ for (i = 0; i < 6; i++) {
+ if (info->bdaddr[i] != 0x00)
+ break;
+ }
+
+ if (i > 5) {
+ dev_info(info->dev, "Valid bluetooth address not found.\n");
+ kfree_skb(skb);
+ return -ENODEV;
+ }
+
+ for (count = 1; ; count++) {
+ NBT_DBG_FW("Sending firmware command %d\n", count);
+ init_completion(&info->fw_completion);
+ skb_queue_tail(&info->txq, skb);
+ tasklet_schedule(&info->tx_task);
+
+ skb = skb_dequeue(fw_queue);
+ if (!skb)
+ break;
+
+ if (!wait_for_completion_timeout(&info->fw_completion,
+ msecs_to_jiffies(1000))) {
+ dev_err(info->dev, "No reply to fw command\n");
+ return -ETIMEDOUT;
+ }
+
+ if (info->fw_error) {
+ dev_err(info->dev, "FW error\n");
+ return -EPROTO;
+ }
+ };
+
+ /* Wait for chip warm reset */
+ retries = 100;
+ while ((!skb_queue_empty(&info->txq) ||
+ !(hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT)) &&
+ retries--) {
+ msleep(10);
+ }
+ if (!retries) {
+ dev_err(info->dev, "Transmitter not empty\n");
+ return -ETIMEDOUT;
+ }
+
+ hci_h4p_change_speed(info, BC4_MAX_BAUD_RATE);
+
+ if (hci_h4p_wait_for_cts(info, 1, 100)) {
+ dev_err(info->dev, "cts didn't go down after final speed change\n");
+ return -ETIMEDOUT;
+ }
+
+ retries = 100;
+ do {
+ init_completion(&info->init_completion);
+ hci_h4p_send_alive_packet(info);
+ retries--;
+ } while (!wait_for_completion_timeout(&info->init_completion, 100) &&
+ retries > 0);
+
+ if (!retries) {
+ dev_err(info->dev, "No alive reply after speed change\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
--- /dev/null
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2005, 2006 Nokia Corporation.
+ *
+ * Contact: Ville Tervo <ville.tervo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/skbuff.h>
+
+#include "hci_h4p.h"
+
+void hci_h4p_brf6150_parse_fw_event(struct hci_h4p_info *info,
+ struct sk_buff *skb)
+{
+ struct hci_fw_event *ev;
+ int err = 0;
+
+ if (bt_cb(skb)->pkt_type != H4_EVT_PKT) {
+ dev_err(info->dev, "Got non event fw packet.\n");
+ err = -EPROTO;
+ goto ret;
+ }
+
+ ev = (struct hci_fw_event *)skb->data;
+ if (ev->hev.evt != HCI_EV_CMD_COMPLETE) {
+ dev_err(info->dev, "Got non cmd complete fw event\n");
+ err = -EPROTO;
+ goto ret;
+ }
+
+ if (ev->status != 0) {
+ dev_err(info->dev, "Got error status from fw command\n");
+ err = -EPROTO;
+ goto ret;
+ }
+
+ret:
+ info->fw_error = err;
+ complete(&info->fw_completion);
+}
+
+int hci_h4p_brf6150_send_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue)
+{
+ struct sk_buff *skb;
+ int err = 0;
+
+ info->fw_error = 0;
+
+ while ((skb = skb_dequeue(fw_queue)) != NULL) {
+ /* We should allways send word aligned data to h4+ devices */
+ if (skb->len % 2) {
+ err = skb_pad(skb, 1);
+ }
+ if (err)
+ return err;
+
+ init_completion(&info->fw_completion);
+ skb_queue_tail(&info->txq, skb);
+ tasklet_schedule(&info->tx_task);
+
+ if (!wait_for_completion_timeout(&info->fw_completion, HZ)) {
+ dev_err(info->dev, "Timeout while sending brf6150 fw\n");
+ return -ETIMEDOUT;
+ }
+
+ if (info->fw_error) {
+ dev_err(info->dev, "There was fw_error while sending bfr6150 fw\n");
+ return -EPROTO;
+ }
+ }
+ NBT_DBG_FW("Firmware sent\n");
+
+ return 0;
+}
--- /dev/null
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2005, 2006 Nokia Corporation.
+ *
+ * Contact: Ville Tervo <ville.tervo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/skbuff.h>
+#include <linux/firmware.h>
+#include <linux/clk.h>
+
+#include <net/bluetooth/bluetooth.h>
+
+#include "hci_h4p.h"
+
+static int fw_pos;
+
+/* Firmware handling */
+static int hci_h4p_open_firmware(struct hci_h4p_info *info,
+ const struct firmware **fw_entry)
+{
+ int err;
+
+ fw_pos = 0;
+ NBT_DBG_FW("Opening %d firmware\n", info->chip_type);
+ switch (info->chip_type) {
+ case BT_CHIP_TI:
+ err = request_firmware(fw_entry, "brf6150fw.bin", info->dev);
+ break;
+ case BT_CHIP_CSR:
+ err = request_firmware(fw_entry, "bc4fw.bin", info->dev);
+ break;
+ default:
+ dev_err(info->dev, "Invalid chip type\n");
+ *fw_entry = NULL;
+ err = -EINVAL;
+ }
+
+ return err;
+}
+
+static void hci_h4p_close_firmware(const struct firmware *fw_entry)
+{
+ release_firmware(fw_entry);
+}
+
+/* Read fw. Return length of the command. If no more commands in
+ * fw 0 is returned. In error case return value is negative.
+ */
+static int hci_h4p_read_fw_cmd(struct hci_h4p_info *info, struct sk_buff **skb,
+ const struct firmware *fw_entry, int how)
+{
+ unsigned int cmd_len;
+
+ if (fw_pos >= fw_entry->size) {
+ return 0;
+ }
+
+ cmd_len = fw_entry->data[fw_pos++];
+ if (!cmd_len)
+ return 0;
+
+ if (fw_pos + cmd_len > fw_entry->size) {
+ dev_err(info->dev, "Corrupted firmware image\n");
+ return -EMSGSIZE;
+ }
+
+ *skb = bt_skb_alloc(cmd_len, how);
+ if (!*skb) {
+ dev_err(info->dev, "Cannot reserve memory for buffer\n");
+ return -ENOMEM;
+ }
+ memcpy(skb_put(*skb, cmd_len), &fw_entry->data[fw_pos], cmd_len);
+
+ fw_pos += cmd_len;
+
+ return (*skb)->len;
+}
+
+int hci_h4p_read_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue)
+{
+ const struct firmware *fw_entry = NULL;
+ struct sk_buff *skb = NULL;
+ int err;
+
+ err = hci_h4p_open_firmware(info, &fw_entry);
+ if (err < 0 || !fw_entry)
+ goto err_clean;
+
+ while ((err = hci_h4p_read_fw_cmd(info, &skb, fw_entry, GFP_KERNEL))) {
+ if (err < 0 || !skb)
+ goto err_clean;
+
+ skb_queue_tail(fw_queue, skb);
+ }
+
+err_clean:
+ hci_h4p_close_firmware(fw_entry);
+ return err;
+}
+
+int hci_h4p_send_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue)
+{
+ int err;
+
+ switch(info->chip_type) {
+ case BT_CHIP_CSR:
+ err = hci_h4p_bc4_send_fw(info, fw_queue);
+ break;
+ case BT_CHIP_TI:
+ err = hci_h4p_brf6150_send_fw(info, fw_queue);
+ break;
+ default:
+ dev_err(info->dev, "Don't know how to send firmware\n");
+ err = -EINVAL;
+ }
+
+ return err;
+}
+
+void hci_h4p_parse_fw_event(struct hci_h4p_info *info, struct sk_buff *skb)
+{
+ switch (info->chip_type) {
+ case BT_CHIP_CSR:
+ hci_h4p_bc4_parse_fw_event(info, skb);
+ break;
+ case BT_CHIP_TI:
+ hci_h4p_brf6150_parse_fw_event(info, skb);
+ break;
+ default:
+ dev_err(info->dev, "Don't know how to parse fw event\n");
+ info->fw_error = -EINVAL;
+ }
+
+ return;
+}
--- /dev/null
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2005, 2006 Nokia Corporation.
+ *
+ * Contact: Ville Tervo <ville.tervo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <asm/arch/board.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/hci.h>
+
+#ifndef __DRIVERS_BLUETOOTH_HCI_H4P_H
+#define __DRIVERS_BLUETOOTH_HCI_H4P_H
+
+#define UART_SYSC_OMAP_RESET 0x03
+#define UART_SYSS_RESETDONE 0x01
+#define UART_OMAP_SCR_EMPTY_THR 0x08
+#define UART_OMAP_SCR_WAKEUP 0x10
+#define UART_OMAP_SSR_WAKEUP 0x02
+#define UART_OMAP_SSR_TXFULL 0x01
+
+#if 0
+#define NBT_DBG(fmt, arg...) printk("%s: " fmt "" , __FUNCTION__ , ## arg)
+#else
+#define NBT_DBG(...)
+#endif
+
+#if 0
+#define NBT_DBG_FW(fmt, arg...) printk("%s: " fmt "" , __FUNCTION__ , ## arg)
+#else
+#define NBT_DBG_FW(...)
+#endif
+
+#if 0
+#define NBT_DBG_POWER(fmt, arg...) printk("%s: " fmt "" , __FUNCTION__ , ## arg)
+#else
+#define NBT_DBG_POWER(...)
+#endif
+
+#if 0
+#define NBT_DBG_TRANSFER(fmt, arg...) printk("%s: " fmt "" , __FUNCTION__ , ## arg)
+#else
+#define NBT_DBG_TRANSFER(...)
+#endif
+
+#if 0
+#define NBT_DBG_TRANSFER_NF(fmt, arg...) printk(fmt "" , ## arg)
+#else
+#define NBT_DBG_TRANSFER_NF(...)
+#endif
+
+#if 0
+#define NBT_DBG_DMA(fmt, arg...) printk("%s: " fmt "" , __FUNCTION__ , ## arg)
+#else
+#define NBT_DBG_DMA(...)
+#endif
+
+struct hci_h4p_info {
+ struct hci_dev *hdev;
+ spinlock_t lock;
+
+ void __iomem *uart_base;
+ unsigned long uart_phys_base;
+ int irq;
+ struct device *dev;
+ u8 bdaddr[6];
+ u8 chip_type;
+ u8 bt_wakeup_gpio;
+ u8 host_wakeup_gpio;
+ u8 reset_gpio;
+ u8 bt_sysclk;
+
+
+ struct sk_buff_head fw_queue;
+ struct sk_buff *alive_cmd_skb;
+ struct completion init_completion;
+ struct completion fw_completion;
+ int fw_error;
+ int init_error;
+
+ struct sk_buff_head txq;
+ struct tasklet_struct tx_task;
+
+ struct sk_buff *rx_skb;
+ long rx_count;
+ unsigned long rx_state;
+ unsigned long garbage_bytes;
+ struct tasklet_struct rx_task;
+
+ int pm_enabled;
+ int tx_pm_enabled;
+ int rx_pm_enabled;
+ struct timer_list tx_pm_timer;
+ struct timer_list rx_pm_timer;
+
+ int tx_clocks_en;
+ int rx_clocks_en;
+ spinlock_t clocks_lock;
+ struct clk *uart_iclk;
+ struct clk *uart_fclk;
+};
+
+#define MAX_BAUD_RATE 921600
+#define BC4_MAX_BAUD_RATE 3692300
+#define UART_CLOCK 48000000
+#define BT_INIT_DIVIDER 320
+#define BT_BAUDRATE_DIVIDER 384000000
+#define BT_SYSCLK_DIV 1000
+#define INIT_SPEED 120000
+
+#define H4_TYPE_SIZE 1
+
+/* H4+ packet types */
+#define H4_CMD_PKT 0x01
+#define H4_ACL_PKT 0x02
+#define H4_SCO_PKT 0x03
+#define H4_EVT_PKT 0x04
+#define H4_NEG_PKT 0x06
+#define H4_ALIVE_PKT 0x07
+
+/* TX states */
+#define WAIT_FOR_PKT_TYPE 1
+#define WAIT_FOR_HEADER 2
+#define WAIT_FOR_DATA 3
+
+struct hci_fw_event {
+ struct hci_event_hdr hev;
+ struct hci_ev_cmd_complete cmd;
+ u8 status;
+} __attribute__ ((packed));
+
+struct hci_bc4_set_bdaddr {
+ u8 type;
+ struct hci_command_hdr cmd_hdr;
+} __attribute__ ((packed));
+
+int hci_h4p_send_alive_packet(struct hci_h4p_info *info);
+
+void hci_h4p_bc4_parse_fw_event(struct hci_h4p_info *info,
+ struct sk_buff *skb);
+int hci_h4p_bc4_send_fw(struct hci_h4p_info *info,
+ struct sk_buff_head *fw_queue);
+
+void hci_h4p_brf6150_parse_fw_event(struct hci_h4p_info *info,
+ struct sk_buff *skb);
+int hci_h4p_brf6150_send_fw(struct hci_h4p_info *info,
+ struct sk_buff_head *fw_queue);
+
+int hci_h4p_read_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue);
+int hci_h4p_send_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue);
+void hci_h4p_parse_fw_event(struct hci_h4p_info *info, struct sk_buff *skb);
+
+int hci_h4p_sysfs_create_files(struct device *dev);
+
+void hci_h4p_outb(struct hci_h4p_info *info, unsigned int offset, u8 val);
+u8 hci_h4p_inb(struct hci_h4p_info *info, unsigned int offset);
+void hci_h4p_set_rts(struct hci_h4p_info *info, int active);
+int hci_h4p_wait_for_cts(struct hci_h4p_info *info, int active, int timeout_ms);
+void __hci_h4p_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which);
+void hci_h4p_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which);
+void hci_h4p_change_speed(struct hci_h4p_info *info, unsigned long speed);
+int hci_h4p_reset_uart(struct hci_h4p_info *info);
+int hci_h4p_init_uart(struct hci_h4p_info *info);
+
+#endif /* __DRIVERS_BLUETOOTH_HCI_H4P_H */
--- /dev/null
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2005, 2006 Nokia Corporation.
+ *
+ * Contact: Ville Tervo <ville.tervo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+
+#include "hci_h4p.h"
+
+#ifdef CONFIG_SYSFS
+
+static ssize_t hci_h4p_store_bdaddr(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct hci_h4p_info *info = (struct hci_h4p_info*)dev_get_drvdata(dev);
+ unsigned int bdaddr[6];
+ int ret, i;
+
+ ret = sscanf(buf, "%2x:%2x:%2x:%2x:%2x:%2x\n",
+ &bdaddr[0], &bdaddr[1], &bdaddr[2],
+ &bdaddr[3], &bdaddr[4], &bdaddr[5]);
+
+ if (ret != 6) {
+ return -EINVAL;
+ }
+
+ for (i = 0; i < 6; i++)
+ info->bdaddr[i] = bdaddr[i] & 0xff;
+
+ return count;
+}
+
+static ssize_t hci_h4p_show_bdaddr(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct hci_h4p_info *info = (struct hci_h4p_info*)dev_get_drvdata(dev);
+
+ return sprintf(buf, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
+ info->bdaddr[0],
+ info->bdaddr[1],
+ info->bdaddr[2],
+ info->bdaddr[3],
+ info->bdaddr[4],
+ info->bdaddr[5]);
+}
+
+static DEVICE_ATTR(bdaddr, S_IRUGO | S_IWUSR, hci_h4p_show_bdaddr, hci_h4p_store_bdaddr);
+int hci_h4p_sysfs_create_files(struct device *dev)
+{
+ return device_create_file(dev, &dev_attr_bdaddr);
+}
+
+#endif
--- /dev/null
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2005, 2006 Nokia Corporation.
+ *
+ * Contact: Ville Tervo <ville.tervo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/serial_reg.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+
+#include "hci_h4p.h"
+
+inline void hci_h4p_outb(struct hci_h4p_info *info, unsigned int offset, u8 val)
+{
+ outb(val, info->uart_base + (offset << 2));
+}
+
+inline u8 hci_h4p_inb(struct hci_h4p_info *info, unsigned int offset)
+{
+ return inb(info->uart_base + (offset << 2));
+}
+
+void hci_h4p_set_rts(struct hci_h4p_info *info, int active)
+{
+ u8 b;
+
+ b = hci_h4p_inb(info, UART_MCR);
+ if (active)
+ b |= UART_MCR_RTS;
+ else
+ b &= ~UART_MCR_RTS;
+ hci_h4p_outb(info, UART_MCR, b);
+}
+
+int hci_h4p_wait_for_cts(struct hci_h4p_info *info, int active,
+ int timeout_ms)
+{
+ int okay;
+ unsigned long timeout;
+
+ okay = 0;
+ timeout = jiffies + msecs_to_jiffies(timeout_ms);
+ for (;;) {
+ int state;
+
+ state = hci_h4p_inb(info, UART_MSR) & UART_MSR_CTS;
+ if (active) {
+ if (state)
+ return 0;
+ } else {
+ if (!state)
+ return 0;
+ }
+ if (time_after(jiffies, timeout))
+ return -ETIMEDOUT;
+ }
+}
+
+void __hci_h4p_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which)
+{
+ u8 lcr, b;
+
+ lcr = hci_h4p_inb(info, UART_LCR);
+ hci_h4p_outb(info, UART_LCR, 0xbf);
+ b = hci_h4p_inb(info, UART_EFR);
+ if (on)
+ b |= which;
+ else
+ b &= ~which;
+ hci_h4p_outb(info, UART_EFR, b);
+ hci_h4p_outb(info, UART_LCR, lcr);
+}
+
+void hci_h4p_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&info->lock, flags);
+ __hci_h4p_set_auto_ctsrts(info, on, which);
+ spin_unlock_irqrestore(&info->lock, flags);
+}
+
+void hci_h4p_change_speed(struct hci_h4p_info *info, unsigned long speed)
+{
+ unsigned int divisor;
+ u8 lcr, mdr1;
+
+ NBT_DBG("Setting speed %lu\n", speed);
+
+ if (speed >= 460800) {
+ divisor = UART_CLOCK / 13 / speed;
+ mdr1 = 3;
+ } else {
+ divisor = UART_CLOCK / 16 / speed;
+ mdr1 = 0;
+ }
+
+ hci_h4p_outb(info, UART_OMAP_MDR1, 7); /* Make sure UART mode is disabled */
+ lcr = hci_h4p_inb(info, UART_LCR);
+ hci_h4p_outb(info, UART_LCR, UART_LCR_DLAB); /* Set DLAB */
+ hci_h4p_outb(info, UART_DLL, divisor & 0xff); /* Set speed */
+ hci_h4p_outb(info, UART_DLM, divisor >> 8);
+ hci_h4p_outb(info, UART_LCR, lcr);
+ hci_h4p_outb(info, UART_OMAP_MDR1, mdr1); /* Make sure UART mode is enabled */
+}
+
+int hci_h4p_reset_uart(struct hci_h4p_info *info)
+{
+ int count = 0;
+
+ /* Reset the UART */
+ hci_h4p_outb(info, UART_OMAP_SYSC, UART_SYSC_OMAP_RESET);
+ while (!(hci_h4p_inb(info, UART_OMAP_SYSS) & UART_SYSS_RESETDONE)) {
+ if (count++ > 100) {
+ dev_err(info->dev, "hci_h4p: UART reset timeout\n");
+ return -ENODEV;
+ }
+ udelay(1);
+ }
+
+ return 0;
+}
+
+int hci_h4p_init_uart(struct hci_h4p_info *info)
+{
+ int err;
+
+ err = hci_h4p_reset_uart(info);
+ if (err < 0)
+ return err;
+
+ /* Enable and setup FIFO */
+ hci_h4p_outb(info, UART_LCR, UART_LCR_WLEN8);
+ hci_h4p_outb(info, UART_OMAP_MDR1, 0x00); /* Make sure UART mode is enabled */
+ hci_h4p_outb(info, UART_OMAP_SCR, 0x80);
+ hci_h4p_outb(info, UART_EFR, UART_EFR_ECB);
+ hci_h4p_outb(info, UART_MCR, UART_MCR_TCRTLR);
+ hci_h4p_outb(info, UART_TI752_TLR, 0x1f);
+ hci_h4p_outb(info, UART_TI752_TCR, 0xef);
+ hci_h4p_outb(info, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR |
+ UART_FCR_CLEAR_XMIT | UART_FCR_R_TRIG_00);
+ hci_h4p_outb(info, UART_IER, UART_IER_RDI);
+
+ return 0;
+}
--- /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.
+
+config CBUS_RETU_HEADSET
+ depends on CBUS_RETU && SYSFS
+ tristate "Support for headset detection with Retu/Vilma"
+ ---help---
+ Say Y here if you want support detecting a headset that's connected
+ to Retu/Vilma. Detection state and events are exposed through
+ sysfs.
+
+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
+obj-$(CONFIG_CBUS_RETU_HEADSET) += retu-headset.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
+/**
+ * Retu/Vilma headset detection
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ *
+ * Written by Juha Yrjölä
+ *
+ * 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/kernel.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+
+#include "retu.h"
+
+#define RETU_ADC_CHANNEL_HOOKDET 0x05
+
+#define RETU_HEADSET_KEY KEY_PHONE
+
+struct retu_headset {
+ spinlock_t lock;
+ struct mutex mutex;
+ struct platform_device *pdev;
+ struct input_dev *idev;
+ unsigned bias_enabled;
+ unsigned detection_enabled;
+ unsigned pressed;
+ struct timer_list enable_timer;
+ struct timer_list detect_timer;
+};
+
+static void retu_headset_set_bias(int enable)
+{
+ if (enable) {
+ retu_set_clear_reg_bits(RETU_REG_AUDTXR,
+ (1 << 0) | (1 << 1), 0);
+ msleep(2);
+ retu_set_clear_reg_bits(RETU_REG_AUDTXR, 1 << 3, 0);
+ } else {
+ retu_set_clear_reg_bits(RETU_REG_AUDTXR, 0,
+ (1 << 0) | (1 << 1) | (1 << 3));
+ }
+}
+
+static void retu_headset_enable(struct retu_headset *hs)
+{
+ mutex_lock(&hs->mutex);
+ if (!hs->bias_enabled) {
+ hs->bias_enabled = 1;
+ retu_headset_set_bias(1);
+ }
+ mutex_unlock(&hs->mutex);
+}
+
+static void retu_headset_disable(struct retu_headset *hs)
+{
+ mutex_lock(&hs->mutex);
+ if (hs->bias_enabled) {
+ hs->bias_enabled = 0;
+ retu_headset_set_bias(0);
+ }
+ mutex_unlock(&hs->mutex);
+}
+
+static void retu_headset_det_enable(struct retu_headset *hs)
+{
+ mutex_lock(&hs->mutex);
+ if (!hs->detection_enabled) {
+ hs->detection_enabled = 1;
+ retu_set_clear_reg_bits(RETU_REG_CC1, (1 << 10) | (1 << 8), 0);
+ retu_enable_irq(RETU_INT_HOOK);
+ }
+ mutex_unlock(&hs->mutex);
+}
+
+static void retu_headset_det_disable(struct retu_headset *hs)
+{
+ unsigned long flags;
+
+ mutex_lock(&hs->mutex);
+ if (hs->detection_enabled) {
+ hs->detection_enabled = 0;
+ retu_disable_irq(RETU_INT_HOOK);
+ del_timer_sync(&hs->enable_timer);
+ del_timer_sync(&hs->detect_timer);
+ spin_lock_irqsave(&hs->lock, flags);
+ if (hs->pressed)
+ input_report_key(hs->idev, RETU_HEADSET_KEY, 0);
+ spin_unlock_irqrestore(&hs->lock, flags);
+ retu_set_clear_reg_bits(RETU_REG_CC1, 0, (1 << 10) | (1 << 8));
+ }
+ mutex_unlock(&hs->mutex);
+}
+
+static ssize_t retu_headset_hookdet_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int val;
+
+ val = retu_read_adc(RETU_ADC_CHANNEL_HOOKDET);
+ return sprintf(buf, "%d\n", val);
+}
+
+static DEVICE_ATTR(hookdet, S_IRUGO, retu_headset_hookdet_show, NULL);
+
+static ssize_t retu_headset_enable_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct retu_headset *hs = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%u\n", hs->bias_enabled);
+}
+
+static ssize_t retu_headset_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct retu_headset *hs = dev_get_drvdata(dev);
+ int enable;
+
+ if (sscanf(buf, "%u", &enable) != 1)
+ return -EINVAL;
+ if (enable)
+ retu_headset_enable(hs);
+ else
+ retu_headset_disable(hs);
+ return count;
+}
+
+static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR | S_IWGRP,
+ retu_headset_enable_show, retu_headset_enable_store);
+
+static ssize_t retu_headset_enable_det_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct retu_headset *hs = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%u\n", hs->detection_enabled);
+}
+
+static ssize_t retu_headset_enable_det_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct retu_headset *hs = dev_get_drvdata(dev);
+ int enable;
+
+ if (sscanf(buf, "%u", &enable) != 1)
+ return -EINVAL;
+ if (enable)
+ retu_headset_det_enable(hs);
+ else
+ retu_headset_det_disable(hs);
+ return count;
+}
+
+static DEVICE_ATTR(enable_det, S_IRUGO | S_IWUSR | S_IWGRP,
+ retu_headset_enable_det_show,
+ retu_headset_enable_det_store);
+
+static void retu_headset_hook_interrupt(unsigned long arg)
+{
+ struct retu_headset *hs = (struct retu_headset *) arg;
+ unsigned long flags;
+
+ retu_ack_irq(RETU_INT_HOOK);
+ spin_lock_irqsave(&hs->lock, flags);
+ if (!hs->pressed) {
+ /* Headset button was just pressed down. */
+ hs->pressed = 1;
+ input_report_key(hs->idev, RETU_HEADSET_KEY, 1);
+ }
+ spin_unlock_irqrestore(&hs->lock, flags);
+ retu_set_clear_reg_bits(RETU_REG_CC1, 0, (1 << 10) | (1 << 8));
+ mod_timer(&hs->enable_timer, jiffies + msecs_to_jiffies(50));
+}
+
+static void retu_headset_enable_timer(unsigned long arg)
+{
+ struct retu_headset *hs = (struct retu_headset *) arg;
+
+ retu_set_clear_reg_bits(RETU_REG_CC1, (1 << 10) | (1 << 8), 0);
+ mod_timer(&hs->detect_timer, jiffies + msecs_to_jiffies(350));
+}
+
+static void retu_headset_detect_timer(unsigned long arg)
+{
+ struct retu_headset *hs = (struct retu_headset *) arg;
+ unsigned long flags;
+
+ spin_lock_irqsave(&hs->lock, flags);
+ if (hs->pressed) {
+ hs->pressed = 0;
+ input_report_key(hs->idev, RETU_HEADSET_KEY, 0);
+ }
+ spin_unlock_irqrestore(&hs->lock, flags);
+}
+
+static int __init retu_headset_probe(struct platform_device *pdev)
+{
+ struct retu_headset *hs;
+ int r;
+
+ hs = kzalloc(sizeof(*hs), GFP_KERNEL);
+ if (hs == NULL)
+ return -ENOMEM;
+
+ hs->pdev = pdev;
+
+ hs->idev = input_allocate_device();
+ if (hs->idev == NULL) {
+ r = -ENOMEM;
+ goto err1;
+ }
+ hs->idev->name = "retu-headset";
+ hs->idev->dev.parent = &pdev->dev;
+ set_bit(EV_KEY, hs->idev->evbit);
+ set_bit(RETU_HEADSET_KEY, hs->idev->keybit);
+ r = input_register_device(hs->idev);
+ if (r < 0)
+ goto err2;
+
+ r = device_create_file(&pdev->dev, &dev_attr_hookdet);
+ if (r < 0)
+ goto err3;
+ r = device_create_file(&pdev->dev, &dev_attr_enable);
+ if (r < 0)
+ goto err4;
+ r = device_create_file(&pdev->dev, &dev_attr_enable_det);
+ if (r < 0)
+ goto err5;
+ platform_set_drvdata(pdev, hs);
+
+ spin_lock_init(&hs->lock);
+ mutex_init(&hs->mutex);
+ setup_timer(&hs->enable_timer, retu_headset_enable_timer,
+ (unsigned long) hs);
+ setup_timer(&hs->detect_timer, retu_headset_detect_timer,
+ (unsigned long) hs);
+
+ r = retu_request_irq(RETU_INT_HOOK, retu_headset_hook_interrupt,
+ (unsigned long) hs, "hookdet");
+ if (r != 0) {
+ dev_err(&pdev->dev, "hookdet IRQ not available\n");
+ goto err6;
+ }
+ retu_disable_irq(RETU_INT_HOOK);
+ return 0;
+err6:
+ device_remove_file(&pdev->dev, &dev_attr_enable_det);
+err5:
+ device_remove_file(&pdev->dev, &dev_attr_enable);
+err4:
+ device_remove_file(&pdev->dev, &dev_attr_hookdet);
+err3:
+ input_unregister_device(hs->idev);
+err2:
+ input_free_device(hs->idev);
+err1:
+ kfree(hs);
+ return r;
+}
+
+static int retu_headset_remove(struct platform_device *pdev)
+{
+ struct retu_headset *hs = platform_get_drvdata(pdev);
+
+ device_remove_file(&pdev->dev, &dev_attr_hookdet);
+ device_remove_file(&pdev->dev, &dev_attr_enable);
+ device_remove_file(&pdev->dev, &dev_attr_enable_det);
+ retu_headset_disable(hs);
+ retu_headset_det_disable(hs);
+ retu_free_irq(RETU_INT_HOOK);
+ input_unregister_device(hs->idev);
+ input_free_device(hs->idev);
+ return 0;
+}
+
+static int retu_headset_suspend(struct platform_device *pdev,
+ pm_message_t mesg)
+{
+ struct retu_headset *hs = platform_get_drvdata(pdev);
+
+ mutex_lock(&hs->mutex);
+ if (hs->bias_enabled)
+ retu_headset_set_bias(0);
+ mutex_unlock(&hs->mutex);
+
+ return 0;
+}
+
+static int retu_headset_resume(struct platform_device *pdev)
+{
+ struct retu_headset *hs = platform_get_drvdata(pdev);
+
+ mutex_lock(&hs->mutex);
+ if (hs->bias_enabled)
+ retu_headset_set_bias(1);
+ mutex_unlock(&hs->mutex);
+
+ return 0;
+}
+
+static struct platform_driver retu_headset_driver = {
+ .probe = retu_headset_probe,
+ .remove = retu_headset_remove,
+ .suspend = retu_headset_suspend,
+ .resume = retu_headset_resume,
+ .driver = {
+ .name = "retu-headset",
+ },
+};
+
+static int __init retu_headset_init(void)
+{
+ int r;
+
+ printk(KERN_INFO "Retu/Vilma headset driver initializing\n");
+
+ r = platform_driver_register(&retu_headset_driver);
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
+static void __exit retu_headset_exit(void)
+{
+ platform_driver_unregister(&retu_headset_driver);
+}
+
+module_init(retu_headset_init);
+module_exit(retu_headset_exit);
+
+MODULE_DESCRIPTION("Retu/Vilma headset detection");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Juha Yrjölä");
--- /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/kernel.h>
+#include <linux/errno.h>
+#include <linux/input.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
+#include <linux/bitops.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_MASK(EV_KEY);
+ pwrbtn_dev->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER);
+ pwrbtn_dev->name = "retu-pwrbutton";
+
+ return input_register_device(pwrbtn_dev);
+}
+
+/**
+ * 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 <linux/mutex.h>
+#include <linux/workqueue.h>
+
+#include "cbus.h"
+#include "retu.h"
+
+static struct mutex retu_rtc_mutex;
+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;
+
+ mutex_lock(&retu_rtc_mutex);
+
+ 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));
+
+ mutex_unlock(&retu_rtc_mutex);
+
+ /*
+ * 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)
+{
+ mutex_lock(&retu_rtc_mutex);
+ /*
+ * 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));
+
+ mutex_unlock(&retu_rtc_mutex);
+
+ 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;
+ mutex_lock(&retu_rtc_mutex);
+ if (choice == 0)
+ retu_rtc_reset_occurred = 0;
+ else if (choice == 1)
+ retu_rtc_do_reset();
+ mutex_unlock(&retu_rtc_mutex);
+ 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;
+
+ mutex_lock(&retu_rtc_mutex);
+ /*
+ * 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);
+ mutex_unlock(&retu_rtc_mutex);
+
+ 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;
+
+ mutex_lock(&retu_rtc_mutex);
+
+ 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);
+ }
+ mutex_unlock(&retu_rtc_mutex);
+
+ 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;
+
+ mutex_lock(&retu_rtc_mutex);
+ rtccalr1 = retu_read_reg(RETU_REG_RTCCALR);
+ mutex_unlock(&retu_rtc_mutex);
+
+ /*
+ * 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;
+
+ mutex_lock(&retu_rtc_mutex);
+ retu_rtc_barrier();
+ retu_write_reg(RETU_REG_RTCCALR, calibration_value & 0x00ff);
+ mutex_unlock(&retu_rtc_mutex);
+
+ return count;
+}
+
+static DEVICE_ATTR(cal, S_IRUGO | S_IWUSR, retu_rtc_cal_show,
+ retu_rtc_cal_store);
+
+static struct platform_device retu_rtc_device;
+
+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(struct work_struct *unused)
+{
+ retu_rtca_disable();
+ sysfs_notify(&retu_rtc_device.dev.kobj, NULL, "alarm_expired");
+}
+
+DECLARE_WORK(retu_rtca_work, retu_rtca_expired);
+
+/*
+ * 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_all(&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;
+
+ mutex_init(&retu_rtc_mutex);
+
+ /* 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 <linux/mutex.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 mutex retu_mutex;
+
+/* 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;
+
+ mutex_lock(&retu_mutex);
+ if ((retu_irq_subscr != NULL) && (retu_irq_subscr != filp)) {
+ mutex_unlock(&retu_mutex);
+ return -EBUSY;
+ }
+ /* Store the file pointer of the first user process registering IRQs */
+ retu_irq_subscr = filp;
+ mutex_unlock(&retu_mutex);
+
+ 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;
+ int ret;
+
+ 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:
+ ret = copy_from_user(&par, (void __user *) arg, sizeof(par));
+ if (ret)
+ printk(KERN_ERR "copy_from_user failed: %d\n", ret);
+ par.result = retu_user_write_with_mask(par.field, par.value);
+ ret = copy_to_user((void __user *) arg, &par, sizeof(par));
+ if (ret)
+ printk(KERN_ERR "copy_to_user failed: %d\n", ret);
+ 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);
+
+ ret = copy_to_user(buf + i * sizeof(irq_id), &irq_id,
+ sizeof(irq_id));
+ if (ret)
+ printk(KERN_ERR "copy_to_user failed: %d\n", ret);
+ }
+
+ 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);
+ mutex_init(&retu_mutex);
+
+ /* 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/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/kernel.h>
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/miscdevice.h>
+#include <linux/poll.h>
+#include <linux/fs.h>
+#include <linux/irq.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);
+}
+
+void retu_set_clear_reg_bits(int reg, u16 set, u16 clear)
+{
+ unsigned long flags;
+ u16 w;
+
+ spin_lock_irqsave(&retu_lock, flags);
+ w = retu_read_reg(reg);
+ w &= ~clear;
+ w |= set;
+ retu_write_reg(reg, w);
+ spin_unlock_irqrestore(&retu_lock, flags);
+}
+
+#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)
+{
+ 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;
+ }
+ set_irq_wake(OMAP_GPIO_IRQ(retu_irq_pin), 1);
+
+ /* 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_AUDTXR 0x18 /* Audio Codec Tx 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_HOOK 6
+#define RETU_INT_HEAD 7
+#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);
+void retu_set_clear_reg_bits(int reg, u16 set, u16 clear);
+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-2006 Nokia Corporation
+ *
+ * Parts copied from drivers/i2c/chips/isp1301_omap.c
+ * Copyright (C) 2004 Texas Instruments
+ * Copyright (C) 2004 David Brownell
+ *
+ * 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/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 <linux/mutex.h>
+
+#include <asm/irq.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
+
+struct tahvo_usb {
+ struct platform_device *pt_dev;
+ struct otg_transceiver otg;
+ int vbus_state;
+ struct work_struct irq_work;
+ struct mutex 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 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
+ OTG_SYSCON_1_REG &= ~OTG_IDLE_EN;
+ udelay(100);
+
+ /* 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, IRQF_DISABLED, DRIVER_NAME,
+ &tahvo_usb_device);
+}
+
+static int omap_otg_remove(struct device *dev)
+{
+ free_irq(tahvo_otg_dev->resource[1].start, &tahvo_usb_device);
+ tahvo_otg_dev = NULL;
+
+ 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;
+
+#if 0
+
+static int host_suspend(struct tahvo_usb *tu)
+{
+ struct device *dev;
+
+ if (!tu->otg.host)
+ return -ENODEV;
+
+ /* Currently ASSUMES only the OTG port matters;
+ * other ports could be active...
+ */
+ dev = tu->otg.host->controller;
+ return dev->driver->suspend(dev, PMSG_SUSPEND);
+}
+
+static int host_resume(struct tahvo_usb *tu)
+{
+ struct device *dev;
+
+ if (!tu->otg.host)
+ return -ENODEV;
+
+ dev = tu->otg.host->controller;
+ return dev->driver->resume(dev);
+}
+
+#else
+
+static int host_suspend(struct tahvo_usb *tu)
+{
+ return 0;
+}
+
+static int host_resume(struct tahvo_usb *tu)
+{
+ return 0;
+}
+
+#endif
+
+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;
+ host_resume(tu);
+ break;
+ default:
+ break;
+ }
+ printk("USB cable connected\n");
+ } else {
+ switch (tu->otg.state) {
+ case OTG_STATE_B_PERIPHERAL:
+ 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;
+ break;
+ default:
+ break;
+ }
+ printk("USB cable disconnected\n");
+ vbus_active = 0;
+ }
+
+ prev_state = tu->vbus_state;
+ tu->vbus_state = reg & 0x01;
+ if (prev_state != tu->vbus_state)
+ sysfs_notify(&tu->pt_dev->dev.kobj, NULL, "vbus_state");
+}
+
+static void tahvo_usb_become_host(struct tahvo_usb *tu)
+{
+ u32 l;
+
+ /* Clear system and transceiver controlled bits
+ * also mark the A-session is always valid */
+ omap_otg_init();
+
+ l = OTG_CTRL_REG;
+ l &= ~(OTG_CTRL_XCVR_MASK|OTG_CTRL_SYS_MASK);
+ l |= OTG_ASESSVLD;
+ OTG_CTRL_REG = l;
+
+ /* 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)
+{
+ host_suspend(tu);
+ 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_BSESSVLD))
+ | 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)
+{
+ u32 l;
+ int id;
+
+ /* Disable gadget controller if any */
+ if (tu->otg.gadget)
+ usb_gadget_vbus_disconnect(tu->otg.gadget);
+
+ host_suspend(tu);
+
+ /* Disable OTG and interrupts */
+ if (TAHVO_MODE(tu) == TAHVO_MODE_PERIPHERAL)
+ id = OTG_ID;
+ else
+ id = 0;
+ l = OTG_CTRL_REG;
+ l &= ~(OTG_CTRL_XCVR_MASK | OTG_CTRL_SYS_MASK | OTG_BSESSVLD);
+ l |= id | OTG_BSESSEND;
+ OTG_CTRL_REG = l;
+ OTG_IRQ_EN_REG = 0;
+
+ OTG_SYSCON_2_REG &= ~OTG_EN;
+
+ OTG_SYSCON_1_REG |= OTG_IDLE_EN;
+
+ /* 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)
+{
+ struct tahvo_usb *tu = container_of(dev, struct tahvo_usb, otg);
+
+ dev_dbg(&tu->pt_dev->dev, "set_power %d mA\n", 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)
+{
+ struct tahvo_usb *tu = container_of(dev, struct tahvo_usb, otg);
+ u16 w;
+
+ dev_dbg(&tu->pt_dev->dev, "set_suspend\n");
+
+ 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;
+
+ dev_dbg(&tu->pt_dev->dev, "start_srp\n");
+
+ 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;
+
+ return 0;
+}
+
+static int tahvo_usb_start_hnp(struct otg_transceiver *otg)
+{
+ struct tahvo_usb *tu = container_of(otg, struct tahvo_usb, otg);
+
+ dev_dbg(&tu->pt_dev->dev, "start_hnp\n");
+#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);
+
+ dev_dbg(&tu->pt_dev->dev, "set_host %p\n", host);
+
+ if (otg == NULL)
+ return -ENODEV;
+
+#if defined(CONFIG_USB_OTG) || !defined(CONFIG_USB_GADGET_OMAP)
+
+ mutex_lock(&tu->serialize);
+
+ if (host == NULL) {
+ if (TAHVO_MODE(tu) == TAHVO_MODE_HOST)
+ tahvo_usb_power_off(tu);
+ tu->otg.host = NULL;
+ mutex_unlock(&tu->serialize);
+ return 0;
+ }
+
+ OTG_SYSCON_1_REG &= ~(OTG_IDLE_EN | HST_IDLE_EN | DEV_IDLE_EN);
+
+ if (TAHVO_MODE(tu) == TAHVO_MODE_HOST) {
+ tu->otg.host = NULL;
+ tahvo_usb_become_host(tu);
+ } else
+ host_suspend(tu);
+
+ tu->otg.host = host;
+
+ mutex_unlock(&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);
+
+ dev_dbg(&tu->pt_dev->dev, "set_peripheral %p\n", gadget);
+
+ if (!otg)
+ return -ENODEV;
+
+#if defined(CONFIG_USB_OTG) || defined(CONFIG_USB_GADGET_OMAP)
+
+ mutex_lock(&tu->serialize);
+
+ if (!gadget) {
+ if (TAHVO_MODE(tu) == TAHVO_MODE_PERIPHERAL)
+ tahvo_usb_power_off(tu);
+ tu->otg.gadget = NULL;
+ mutex_unlock(&tu->serialize);
+ return 0;
+ }
+
+ tu->otg.gadget = gadget;
+ if (TAHVO_MODE(tu) == TAHVO_MODE_PERIPHERAL)
+ tahvo_usb_become_peripheral(tu);
+
+ mutex_unlock(&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(struct work_struct *work)
+{
+ struct tahvo_usb *tu = container_of(work, struct tahvo_usb, irq_work);
+
+ mutex_lock(&tu->serialize);
+ check_vbus_state(tu);
+ mutex_unlock(&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);
+ mutex_lock(&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;
+
+ mutex_unlock(&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;
+
+ dev_dbg(dev, "probe\n");
+
+ /* 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);
+ mutex_init(&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 */
+ ret = device_create_file(dev, &dev_attr_vbus_state);
+#ifdef CONFIG_USB_OTG
+ ret |= device_create_file(dev, &dev_attr_otg_mode);
+#endif
+ if (ret)
+ printk(KERN_ERR "attribute creation failed: %d\n", ret);
+
+ /* 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)
+{
+ dev_dbg(dev, "remove\n");
+
+ 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 <linux/mutex.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 mutex tahvo_mutex;
+
+/* 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;
+
+ mutex_lock(&tahvo_mutex);
+ if ((tahvo_irq_subscr != NULL) && (tahvo_irq_subscr != filp)) {
+ mutex_unlock(&tahvo_mutex);
+ return -EBUSY;
+ }
+ /* Store the file pointer of the first user process registering IRQs */
+ tahvo_irq_subscr = filp;
+ mutex_unlock(&tahvo_mutex);
+
+ 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;
+ int ret;
+
+ 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:
+ ret = copy_from_user(&par, (void __user *) arg, sizeof(par));
+ if (ret)
+ printk(KERN_ERR "copy_from_user failed: %d\n", ret);
+ par.result = tahvo_user_write_with_mask(par.field, par.value);
+ ret = copy_to_user((void __user *) arg, &par, sizeof(par));
+ if (ret)
+ printk(KERN_ERR "copy_to_user failed: %d\n", ret);
+ 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);
+
+ ret = copy_to_user(buf + i * sizeof(irq_id), &irq_id,
+ sizeof(irq_id));
+ if (ret)
+ printk(KERN_ERR "copy_to_user failed: %d\n", ret);
+ }
+
+ 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);
+ mutex_init(&tahvo_mutex);
+
+ /* 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/kernel.h>
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/miscdevice.h>
+#include <linux/poll.h>
+#include <linux/fs.h>
+#include <linux/irq.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);
+}
+
+/**
+ * tahvo_set_clear_reg_bits - set and clear register bits atomically
+ * @reg: the register to write to
+ * @bits: the bits to set
+ *
+ * This function sets and clears the specified Tahvo register bits atomically
+ */
+void tahvo_set_clear_reg_bits(int reg, u16 set, u16 clear)
+{
+ unsigned long flags;
+ u16 w;
+
+ spin_lock_irqsave(&tahvo_lock, flags);
+ w = tahvo_read_reg(reg);
+ w &= ~clear;
+ w |= set;
+ tahvo_write_reg(reg, w);
+ spin_unlock_irqrestore(&tahvo_lock, flags);
+}
+
+/*
+ * 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)
+{
+ 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);
+void tahvo_set_clear_reg_bits(int reg, u16 set, u16 clear);
+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
.name = "omap_rng",
.owner = THIS_MODULE,
},
- .probe = omap_rng_probe,
.remove = __exit_p(omap_rng_remove),
.suspend = omap_rng_suspend,
.resume = omap_rng_resume
if (!cpu_is_omap16xx() && !cpu_is_omap24xx())
return -ENODEV;
- return platform_driver_register(&omap_rng_driver);
+ return platform_driver_probe(&omap_rng_driver, omap_rng_probe);
}
static void __exit omap_rng_exit(void)
that contains all parts of the crypto device driver (ap bus,
request router and all the card drivers).
+config OMAP_SHA1_MD5
+ tristate "Support for OMAP SHA1/MD5 hw engine"
+ depends on ARCH_OMAP24XX && CRYPTO_SHA1 && CRYPTO_MD5
+ help
+ OMAP processors have SHA1/MD5 module accelerator. Select this if you
+ want to use the OMAP module for SHA1/MD5 algorithms.
+
config CRYPTO_SHA1_S390
tristate "SHA1 digest algorithm"
depends on S390
obj-$(CONFIG_CRYPTO_DEV_PADLOCK_AES) += padlock-aes.o
obj-$(CONFIG_CRYPTO_DEV_PADLOCK_SHA) += padlock-sha.o
obj-$(CONFIG_CRYPTO_DEV_GEODE) += geode-aes.o
+obj-$(CONFIG_OMAP_SHA1_MD5) += omap-sha1-md5.o
obj-$(CONFIG_CRYPTO_DEV_HIFN_795X) += hifn_795x.o
--- /dev/null
+/*
+ * Cryptographic API.
+ *
+ * Support for OMAP SHA1/MD5 HW acceleration.
+ *
+ * Copyright (c) 2007 Instituto Nokia de Tecnologia - INdT
+ * Author: David Cohen <david.cohen@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 version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This driver is based on padlock-sha.c driver.
+ */
+
+#include <asm/arch-omap/irqs.h>
+#include <crypto/algapi.h>
+#include <crypto/sha.h>
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/cryptohash.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/scatterlist.h>
+
+#define SHA_REG_DIGEST(x) (0x00 + ((x) * 0x04))
+#define SHA_REG_DIN(x) (0x1C + ((x) * 0x04))
+
+#define SHA1_MD5_BLOCK_SIZE SHA1_BLOCK_SIZE
+#define MD5_DIGEST_SIZE 16
+
+#define SHA_REG_DIGCNT 0x14
+
+#define SHA_REG_CTRL 0x18
+#define SHA_REG_CTRL_LENGTH (0xFFFFFFFF << 5)
+#define SHA_REG_CTRL_CLOSE_HASH (1 << 4)
+#define SHA_REG_CTRL_ALGO_CONST (1 << 3)
+#define SHA_REG_CTRL_ALGO (1 << 2)
+#define SHA_REG_CTRL_INPUT_READY (1 << 1)
+#define SHA_REG_CTRL_OUTPUT_READY (1 << 0)
+
+#define SHA_REG_REV 0x5C
+#define SHA_REG_REV_MAJOR 0xF0
+#define SHA_REG_REV_MINOR 0x0F
+
+#define SHA_REG_MASK 0x60
+#define SHA_REG_MASK_DMA_EN (1 << 3)
+#define SHA_REG_MASK_IT_EN (1 << 2)
+#define SHA_REG_MASK_SOFTRESET (1 << 1)
+#define SHA_REG_AUTOIDLE (1 << 0)
+
+#define SHA_REG_SYSSTATUS 0x64
+#define SHA_REG_SYSSTATUS_RESETDONE (1 << 0)
+
+#define DRIVER_NAME "OMAP SHA1/MD5"
+
+struct omap_sha1_md5_ctx {
+ unsigned int type_algo;
+ unsigned int bufcnt;
+ unsigned int digcnt;
+ int algo_const;
+ int bypass;
+ int digsize;
+ u8 hash[SHA1_DIGEST_SIZE];
+ u8 buffer[SHA1_BLOCK_SIZE];
+ struct hash_desc fallback;
+};
+
+struct omap_sha1_md5_dev {
+ unsigned long base_address;
+ int irq;
+ int digready;
+ struct clk *sha1_ick;
+ struct omap_sha1_md5_ctx
+ *hw_ctx;
+ struct device *dev;
+ wait_queue_head_t wq;
+};
+
+static struct omap_sha1_md5_dev *sha1_md5_data;
+
+#define SHA_REG_IOADDR(d, x) (void *)IO_ADDRESS((d)->base_address + (x))
+
+static u32 omap_sha1_md5_read(struct omap_sha1_md5_dev *data, u32 offset)
+{
+ return __raw_readl(SHA_REG_IOADDR(data, offset));
+}
+
+static void omap_sha1_md5_write(struct omap_sha1_md5_dev *data,
+ u32 value, u32 offset)
+{
+ __raw_writel(value, SHA_REG_IOADDR(data, offset));
+}
+
+static void omap_sha1_md5_write_mask(struct omap_sha1_md5_dev *data,
+ u32 value, u32 mask, u32 address)
+{
+ u32 val;
+
+ val = omap_sha1_md5_read(data, address);
+ val &= ~mask;
+ val |= value;
+ omap_sha1_md5_write(data, val, address);
+}
+
+static inline void omap_sha1_md5_enable_clk(struct crypto_tfm *tfm)
+{
+ struct omap_sha1_md5_dev *data = sha1_md5_data;
+
+ clk_enable(data->sha1_ick);
+}
+
+static inline void omap_sha1_md5_disable_clk(struct crypto_tfm *tfm)
+{
+ struct omap_sha1_md5_dev *data = sha1_md5_data;
+
+ clk_disable(data->sha1_ick);
+}
+
+static void omap_sha1_md5_copy_hash(struct crypto_tfm *tfm)
+{
+ struct omap_sha1_md5_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct omap_sha1_md5_dev *data = sha1_md5_data;
+
+ u32 *hash = (u32 *)ctx->hash;
+
+ if (ctx->type_algo) {
+ /* SHA1 results are in big endian */
+ hash[0] = be32_to_cpu(
+ omap_sha1_md5_read(data, SHA_REG_DIGEST(0)));
+ hash[1] = be32_to_cpu(
+ omap_sha1_md5_read(data, SHA_REG_DIGEST(1)));
+ hash[2] = be32_to_cpu(
+ omap_sha1_md5_read(data, SHA_REG_DIGEST(2)));
+ hash[3] = be32_to_cpu(
+ omap_sha1_md5_read(data, SHA_REG_DIGEST(3)));
+ hash[4] = be32_to_cpu(
+ omap_sha1_md5_read(data, SHA_REG_DIGEST(4)));
+ } else {
+ /* MD5 results are in little endian */
+ hash[0] = le32_to_cpu(
+ omap_sha1_md5_read(data, SHA_REG_DIGEST(0)));
+ hash[1] = le32_to_cpu(
+ omap_sha1_md5_read(data, SHA_REG_DIGEST(1)));
+ hash[2] = le32_to_cpu(
+ omap_sha1_md5_read(data, SHA_REG_DIGEST(2)));
+ hash[3] = le32_to_cpu(
+ omap_sha1_md5_read(data, SHA_REG_DIGEST(3)));
+ }
+}
+
+static void omap_sha1_md5_bypass(struct crypto_tfm *tfm,
+ u8 *data, unsigned int length)
+{
+ struct omap_sha1_md5_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ if (unlikely(!ctx->bypass))
+ return;
+
+ if (ctx->bypass == 1) {
+ crypto_hash_init(&ctx->fallback);
+ ctx->bypass++;
+ }
+
+ if (length) {
+ struct scatterlist sg;
+
+ sg_set_buf(&sg, data, length);
+ crypto_hash_update(&ctx->fallback, &sg, sg.length);
+ }
+}
+
+static void omap_sha1_md5_digest_buffer(struct crypto_tfm *tfm,
+ u8 *buf, unsigned int len, int close_hash)
+{
+ struct omap_sha1_md5_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct omap_sha1_md5_dev *data = sha1_md5_data;
+ unsigned int algo_const = 0;
+ int c;
+ u32 *buffer = (u32 *)buf;
+
+ if (unlikely(ctx->bypass)) {
+ omap_sha1_md5_bypass(tfm, buf, len);
+ return;
+ }
+
+ if (unlikely(ctx->algo_const)) {
+ algo_const = SHA_REG_CTRL_ALGO_CONST;
+ ctx->algo_const = 0;
+ } else
+ omap_sha1_md5_write(data, ctx->digcnt, SHA_REG_DIGCNT);
+
+ if (unlikely(close_hash))
+ close_hash = SHA_REG_CTRL_CLOSE_HASH;
+
+ /* Setting ALGO_CONST only for the first iteration
+ * and CLOSE_HASH only for the last one. */
+ omap_sha1_md5_write_mask(data,
+ ctx->type_algo | algo_const | close_hash | (len << 5),
+ SHA_REG_CTRL_ALGO_CONST | SHA_REG_CTRL_CLOSE_HASH |
+ SHA_REG_CTRL_ALGO | SHA_REG_CTRL_LENGTH,
+ SHA_REG_CTRL);
+
+ ctx->digcnt += len;
+ while (!(omap_sha1_md5_read(data, SHA_REG_CTRL)
+ & SHA_REG_CTRL_INPUT_READY));
+
+ if (len % 4)
+ len = (len/4) + 1;
+ else
+ len /= 4;
+ for (c = 0; c < len; c++)
+ omap_sha1_md5_write(data, buffer[c], SHA_REG_DIN(c));
+}
+
+static void omap_sha1_md5_append_buffer(struct crypto_tfm *tfm,
+ const uint8_t *data, unsigned int length)
+{
+ struct omap_sha1_md5_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ BUG_ON((ctx->bufcnt + length) > SHA1_MD5_BLOCK_SIZE);
+
+ memcpy(&ctx->buffer[ctx->bufcnt], data, length);
+ ctx->bufcnt += length;
+}
+
+static void omap_sha1_md5_dia_update(struct crypto_tfm *tfm,
+ const uint8_t *data, unsigned int length)
+{
+ struct omap_sha1_md5_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ /* We need to save the last buffer <= 64 to digest it with
+ * CLOSE_HASH = 1 */
+ if (ctx->bufcnt && ((ctx->bufcnt + length) > SHA1_MD5_BLOCK_SIZE)) {
+ unsigned int c = SHA1_MD5_BLOCK_SIZE - ctx->bufcnt;
+
+ omap_sha1_md5_append_buffer(tfm, data, c);
+ data += c;
+ length -= c;
+ if (length) {
+ ctx->bufcnt = 0;
+ omap_sha1_md5_digest_buffer(tfm, ctx->buffer,
+ SHA1_MD5_BLOCK_SIZE, 0);
+ }
+ }
+
+ while (length > SHA1_MD5_BLOCK_SIZE) {
+ /* Revisit: use DMA here */
+ omap_sha1_md5_digest_buffer(tfm, (u8 *)data,
+ SHA1_MD5_BLOCK_SIZE, 0);
+ length -= SHA1_MD5_BLOCK_SIZE;
+ data += SHA1_MD5_BLOCK_SIZE;
+ }
+
+ if (length)
+ omap_sha1_md5_append_buffer(tfm, data, length);
+}
+
+static void omap_sha1_md5_start_reset(struct crypto_tfm *tfm)
+{
+ struct omap_sha1_md5_dev *data = sha1_md5_data;
+
+ omap_sha1_md5_write_mask(data, SHA_REG_MASK_SOFTRESET,
+ SHA_REG_MASK_SOFTRESET, SHA_REG_MASK);
+}
+
+static void omap_sha1_md5_wait_reset(struct crypto_tfm *tfm)
+{
+ struct omap_sha1_md5_dev *data = sha1_md5_data;
+
+ while (!(omap_sha1_md5_read(data, SHA_REG_SYSSTATUS)
+ & SHA_REG_SYSSTATUS_RESETDONE));
+}
+
+static void omap_sha1_md5_dia_init(struct crypto_tfm *tfm)
+{
+ struct omap_sha1_md5_dev *data = sha1_md5_data;
+ struct omap_sha1_md5_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ if (unlikely(data->hw_ctx))
+ ctx->bypass = 1;
+ else {
+ data->hw_ctx = ctx;
+ ctx->bypass = 0;
+ omap_sha1_md5_enable_clk(tfm);
+ omap_sha1_md5_start_reset(tfm);
+ data->digready = 0;
+ }
+
+ if (ctx->bypass) {
+ omap_sha1_md5_bypass(tfm, NULL, 0);
+ return;
+ }
+
+ ctx->algo_const = 1;
+ ctx->bufcnt = 0;
+ ctx->digcnt = 0;
+
+ omap_sha1_md5_wait_reset(tfm);
+ omap_sha1_md5_write_mask(data, SHA_REG_MASK_IT_EN,
+ SHA_REG_MASK_DMA_EN | SHA_REG_MASK_IT_EN, SHA_REG_MASK);
+}
+
+static void omap_sha1_md5_dia_final(struct crypto_tfm *tfm, uint8_t *out)
+{
+ struct omap_sha1_md5_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct omap_sha1_md5_dev *data = sha1_md5_data;
+ int digsize = ctx->digsize;
+
+ /* The buffer should be >= 9 */
+ if (((ctx->digcnt + ctx->bufcnt) < 9) && !ctx->bypass)
+ ctx->bypass = 1;
+
+ omap_sha1_md5_digest_buffer(tfm, ctx->buffer, ctx->bufcnt, 1);
+
+ if (unlikely(ctx->bypass)) {
+ crypto_hash_final(&ctx->fallback, out);
+ ctx->bypass = 0;
+ goto bypass;
+ } else
+ data->digready = 1;
+
+ wait_event_interruptible(data->wq, (data->digready == 2));
+ omap_sha1_md5_copy_hash(tfm);
+
+ memcpy(out, ctx->hash, digsize);
+
+bypass:
+ if (data->hw_ctx == ctx) {
+ omap_sha1_md5_disable_clk(tfm);
+ data->hw_ctx = NULL;
+ }
+}
+
+static irqreturn_t omap_sha1_md5_irq(int irq, void *dev_id)
+{
+ struct omap_sha1_md5_dev *data = dev_id;
+
+ omap_sha1_md5_write_mask(data, SHA_REG_CTRL_OUTPUT_READY,
+ SHA_REG_CTRL_OUTPUT_READY, SHA_REG_CTRL);
+
+ if (likely(!data->digready))
+ return IRQ_HANDLED;
+
+ if (data->hw_ctx == NULL) {
+ dev_err(data->dev, "unknown interrupt.\n");
+ return IRQ_HANDLED;
+ }
+
+ data->digready = 2;
+ wake_up_interruptible(&data->wq);
+
+ return IRQ_HANDLED;
+}
+
+static int omap_sha1_md5_cra_init(struct crypto_tfm *tfm)
+{
+ struct omap_sha1_md5_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct omap_sha1_md5_dev *data = sha1_md5_data;
+ const char *fallback_driver_name = tfm->__crt_alg->cra_name;
+ struct crypto_hash *fallback_tfm;
+
+ /* Allocate a fallback and abort if it failed. */
+ fallback_tfm = crypto_alloc_hash(fallback_driver_name, 0,
+ CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_NEED_FALLBACK);
+ if (IS_ERR(fallback_tfm)) {
+ dev_err(data->dev, "fallback driver '%s' could not be"
+ "loaded.\n", fallback_driver_name);
+ return PTR_ERR(fallback_tfm);
+ }
+
+ ctx->fallback.tfm = fallback_tfm;
+
+ return 0;
+}
+
+static int omap_sha1_cra_init(struct crypto_tfm *tfm)
+{
+ struct omap_sha1_md5_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ ctx->type_algo = SHA_REG_CTRL_ALGO;
+ ctx->digsize = SHA1_DIGEST_SIZE;
+
+ return omap_sha1_md5_cra_init(tfm);
+}
+
+static int omap_md5_cra_init(struct crypto_tfm *tfm)
+{
+ struct omap_sha1_md5_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ ctx->type_algo = 0;
+ ctx->digsize = MD5_DIGEST_SIZE;
+
+ return omap_sha1_md5_cra_init(tfm);
+}
+
+static void omap_sha1_md5_cra_exit(struct crypto_tfm *tfm)
+{
+ struct omap_sha1_md5_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ crypto_free_hash(ctx->fallback.tfm);
+ ctx->fallback.tfm = NULL;
+}
+
+static struct crypto_alg omap_sha1_alg = {
+ .cra_name = "sha1",
+ .cra_driver_name = "omap-sha1",
+ .cra_flags = CRYPTO_ALG_TYPE_DIGEST |
+ CRYPTO_ALG_NEED_FALLBACK,
+ .cra_blocksize = SHA1_MD5_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct omap_sha1_md5_ctx),
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(omap_sha1_alg.cra_list),
+ .cra_init = omap_sha1_cra_init,
+ .cra_exit = omap_sha1_md5_cra_exit,
+ .cra_u = {
+ .digest = {
+ .dia_digestsize = SHA1_DIGEST_SIZE,
+ .dia_init = omap_sha1_md5_dia_init,
+ .dia_update = omap_sha1_md5_dia_update,
+ .dia_final = omap_sha1_md5_dia_final,
+ }
+ }
+};
+
+static struct crypto_alg omap_md5_alg = {
+ .cra_name = "md5",
+ .cra_driver_name = "omap-md5",
+ .cra_flags = CRYPTO_ALG_TYPE_DIGEST |
+ CRYPTO_ALG_NEED_FALLBACK,
+ .cra_blocksize = SHA1_MD5_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct omap_sha1_md5_ctx),
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(omap_md5_alg.cra_list),
+ .cra_init = omap_md5_cra_init,
+ .cra_exit = omap_sha1_md5_cra_exit,
+ .cra_u = {
+ .digest = {
+ .dia_digestsize = MD5_DIGEST_SIZE,
+ .dia_init = omap_sha1_md5_dia_init,
+ .dia_update = omap_sha1_md5_dia_update,
+ .dia_final = omap_sha1_md5_dia_final,
+ }
+ }
+};
+
+static int omap_sha1_md5_probe(struct platform_device *pdev)
+{
+ struct omap_sha1_md5_dev *data;
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ int rc;
+
+ rc = crypto_register_alg(&omap_sha1_alg);
+ if (rc)
+ goto sha1_err;
+ rc = crypto_register_alg(&omap_md5_alg);
+ if (rc)
+ goto md5_err;
+
+ data = kzalloc(sizeof(struct omap_sha1_md5_dev), GFP_KERNEL);
+ if (data == NULL) {
+ dev_err(dev, "unable to alloc data struct.\n");
+ goto data_err;
+ }
+ platform_set_drvdata(pdev, data);
+ data->dev = dev;
+
+ /* Get the base address */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(dev, "invalid resource type\n");
+ rc = -ENODEV;
+ goto res_err;
+ }
+ data->base_address = res->start;
+
+ /* Set the private data */
+ sha1_md5_data = data;
+
+ /* Get the IRQ */
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ dev_err(dev, "invalid resource type\n");
+ rc = -ENODEV;
+ goto res_err;
+ }
+ data->irq = res->start;
+
+ rc = request_irq(res->start, omap_sha1_md5_irq,
+ IRQF_TRIGGER_LOW, DRIVER_NAME, data);
+ if (rc) {
+ dev_err(dev, "unable to request irq.\n");
+ goto res_err;
+ }
+
+ /* Initializing the clock */
+ data->sha1_ick = clk_get(0, "sha_ick");
+ if (!data->sha1_ick) {
+ dev_err(dev, "clock intialization failed.\n");
+ rc = -ENODEV;
+ goto clk_err;
+ }
+
+ init_waitqueue_head(&data->wq);
+
+ dev_info(dev, "hw accel on OMAP rev %u.%u\n",
+ (omap_sha1_md5_read(data, SHA_REG_REV) & SHA_REG_REV_MAJOR)>>4,
+ omap_sha1_md5_read(data, SHA_REG_REV) & SHA_REG_REV_MINOR);
+
+ return 0;
+
+clk_err:
+ free_irq(data->irq, data);
+res_err:
+ kfree(data);
+data_err:
+ crypto_unregister_alg(&omap_md5_alg);
+md5_err:
+ crypto_unregister_alg(&omap_sha1_alg);
+sha1_err:
+ dev_err(dev, "initialization failed.\n");
+ return rc;
+}
+
+static int omap_sha1_md5_remove(struct platform_device *pdev)
+{
+ struct omap_sha1_md5_dev *data = platform_get_drvdata(pdev);
+
+ free_irq(data->irq, data);
+ kfree(data);
+ crypto_unregister_alg(&omap_sha1_alg);
+ crypto_unregister_alg(&omap_md5_alg);
+
+ return 0;
+}
+
+static struct platform_driver omap_sha1_md5_driver = {
+ .probe = omap_sha1_md5_probe,
+ .remove = omap_sha1_md5_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init omap_sha1_md5_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&omap_sha1_md5_driver);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static void __exit omap_sha1_md5_exit(void)
+{
+ platform_driver_unregister(&omap_sha1_md5_driver);
+}
+
+module_init(omap_sha1_md5_init);
+module_exit(omap_sha1_md5_exit);
+
+MODULE_DESCRIPTION("OMAP SHA1/MD5 hw acceleration support.");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("David Cohen");
--- /dev/null
+
+config OMAP_DSP
+ tristate "OMAP DSP driver (DSP Gateway)"
+ depends on ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP24XX
+ select OMAP_MMU_FWK
+ select OMAP_MBOX_FWK
+ 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_FBEXPORT
+ bool "Framebuffer export to DSP"
+ depends on OMAP_DSP && FB
+ 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
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __PLAT_OMAP_DSP_DSP_H
+#define __PLAT_OMAP_DSP_DSP_H
+
+#include "hardware_dsp.h"
+#include <asm/arch/dsp_common.h>
+#include <asm/arch/mmu.h>
+
+
+#ifdef CONFIG_ARCH_OMAP2
+#include "../../../arch/arm/mach-omap2/prm.h"
+#include "../../../arch/arm/mach-omap2/prm-regbits-24xx.h"
+#include "../../../arch/arm/mach-omap2/cm.h"
+#include "../../../arch/arm/mach-omap2/cm-regbits-24xx.h"
+#endif
+
+/*
+ * MAJOR device number: !! allocated arbitrary !!
+ */
+#define OMAP_DSP_CTL_MAJOR 96
+#define OMAP_DSP_TASK_MAJOR 97
+
+#define OLD_BINARY_SUPPORT y
+
+#ifdef OLD_BINARY_SUPPORT
+#define MBREV_3_0 0x0017
+#define MBREV_3_2 0x0018
+#endif
+
+#define DSP_INIT_PAGE 0xfff000
+
+#ifdef CONFIG_ARCH_OMAP1
+/* idle program will be placed at IDLEPG_BASE. */
+#define IDLEPG_BASE 0xfffe00
+#define IDLEPG_SIZE 0x100
+#endif /* CONFIG_ARCH_OMAP1 */
+
+/* timeout value for DSP response */
+#define DSP_TIMEOUT (10 * HZ)
+
+enum dsp_mem_type_e {
+ MEM_TYPE_CROSSING = -1,
+ MEM_TYPE_NONE = 0,
+ MEM_TYPE_DARAM,
+ MEM_TYPE_SARAM,
+ MEM_TYPE_EXTERN,
+};
+
+
+typedef int __bitwise arm_dsp_dir_t;
+#define DIR_A2D ((__force arm_dsp_dir_t) 1)
+#define DIR_D2A ((__force arm_dsp_dir_t) 2)
+
+enum cfgstat_e {
+ CFGSTAT_CLEAN = 0,
+ CFGSTAT_READY,
+ CFGSTAT_SUSPEND,
+ CFGSTAT_RESUME, /* request only */
+ CFGSTAT_MAX
+};
+
+enum errcode_e {
+ ERRCODE_WDT = 0,
+ ERRCODE_MMU,
+ ERRCODE_MAX
+};
+
+/* keep 2 entries for TID_FREE and TID_ANON */
+#define TASKDEV_MAX 254
+
+#define MK32(uw,lw) (((u32)(uw)) << 16 | (lw))
+#define MKLONG(uw,lw) (((unsigned long)(uw)) << 16 | (lw))
+#define MKVIRT(uw,lw) dspword_to_virt(MKLONG((uw), (lw)));
+
+struct sync_seq {
+ u16 da_dsp;
+ u16 da_arm;
+ u16 ad_dsp;
+ u16 ad_arm;
+};
+
+struct mem_sync_struct {
+ struct sync_seq *DARAM;
+ struct sync_seq *SARAM;
+ struct sync_seq *SDRAM;
+};
+
+/* struct mbcmd and union mbcmd_hw must be compatible */
+struct mbcmd {
+ u32 data:16;
+ u32 cmd_l:8;
+ u32 cmd_h:7;
+ u32 seq:1;
+};
+
+#define MBCMD_INIT(h, l, d) { \
+ .cmd_h = (h), \
+ .cmd_l = (l), \
+ .data = (d), \
+ }
+
+struct mb_exarg {
+ u8 tid;
+ int argc;
+ u16 *argv;
+};
+
+typedef u32 dsp_long_t; /* must have ability to carry TADD_ABORTADR */
+
+extern void dsp_mbox_start(void);
+extern void dsp_mbox_stop(void);
+extern int dsp_mbox_config(void *p);
+extern int sync_with_dsp(u16 *syncwd, u16 tid, int try_cnt);
+extern int __dsp_mbcmd_send_exarg(struct mbcmd *mb, struct mb_exarg *arg,
+ int recovery_flag);
+#define dsp_mbcmd_send(mb) __dsp_mbcmd_send_exarg((mb), NULL, 0)
+#define dsp_mbcmd_send_exarg(mb, arg) __dsp_mbcmd_send_exarg((mb), (arg), 0)
+extern int dsp_mbcmd_send_and_wait_exarg(struct mbcmd *mb, struct mb_exarg *arg,
+ wait_queue_head_t *q);
+#define dsp_mbcmd_send_and_wait(mb, q) \
+ dsp_mbcmd_send_and_wait_exarg((mb), NULL, (q))
+
+static inline int __mbcompose_send_exarg(u8 cmd_h, u8 cmd_l, u16 data,
+ struct mb_exarg *arg,
+ int recovery_flag)
+{
+ struct mbcmd mb = MBCMD_INIT(cmd_h, cmd_l, data);
+ return __dsp_mbcmd_send_exarg(&mb, arg, recovery_flag);
+}
+#define mbcompose_send(cmd_h, cmd_l, data) \
+ __mbcompose_send_exarg(MBOX_CMD_DSP_##cmd_h, (cmd_l), (data), NULL, 0)
+#define mbcompose_send_exarg(cmd_h, cmd_l, data, arg) \
+ __mbcompose_send_exarg(MBOX_CMD_DSP_##cmd_h, (cmd_l), (data), arg, 0)
+#define mbcompose_send_recovery(cmd_h, cmd_l, data) \
+ __mbcompose_send_exarg(MBOX_CMD_DSP_##cmd_h, (cmd_l), (data), NULL, 1)
+
+static inline int __mbcompose_send_and_wait_exarg(u8 cmd_h, u8 cmd_l,
+ u16 data,
+ struct mb_exarg *arg,
+ wait_queue_head_t *q)
+{
+ struct mbcmd mb = MBCMD_INIT(cmd_h, cmd_l, data);
+ return dsp_mbcmd_send_and_wait_exarg(&mb, arg, q);
+}
+#define mbcompose_send_and_wait(cmd_h, cmd_l, data, q) \
+ __mbcompose_send_and_wait_exarg(MBOX_CMD_DSP_##cmd_h, (cmd_l), (data), \
+ NULL, (q))
+#define mbcompose_send_and_wait_exarg(cmd_h, cmd_l, data, arg, q) \
+ __mbcompose_send_and_wait_exarg(MBOX_CMD_DSP_##cmd_h, (cmd_l), (data), \
+ (arg), (q))
+
+extern struct ipbuf_head *bid_to_ipbuf(u16 bid);
+extern void ipbuf_start(void);
+extern void ipbuf_stop(void);
+extern int ipbuf_config(u16 ln, u16 lsz, void *base);
+extern int ipbuf_sys_config(void *p, arm_dsp_dir_t dir);
+extern int ipbuf_p_validate(void *p, arm_dsp_dir_t dir);
+extern struct ipbuf_head *get_free_ipbuf(u8 tid);
+extern void release_ipbuf(struct ipbuf_head *ipb_h);
+extern void balance_ipbuf(void);
+extern void unuse_ipbuf(struct ipbuf_head *ipb_h);
+extern void unuse_ipbuf_nowait(struct ipbuf_head *ipb_h);
+
+#define release_ipbuf_pvt(ipbuf_pvt) \
+ do { \
+ (ipbuf_pvt)->s = TID_FREE; \
+ } while(0)
+
+extern int mbox_revision;
+
+extern int dsp_cfgstat_request(enum cfgstat_e st);
+extern enum cfgstat_e dsp_cfgstat_get_stat(void);
+extern int dsp_set_runlevel(u8 level);
+
+extern int dsp_task_config_all(u8 n);
+extern void dsp_task_unconfig_all(void);
+extern u8 dsp_task_count(void);
+extern int dsp_taskmod_busy(void);
+extern int dsp_mkdev(char *name);
+extern int dsp_rmdev(char *name);
+extern int dsp_tadd_minor(unsigned char minor, dsp_long_t adr);
+extern int dsp_tdel_minor(unsigned char minor);
+extern int dsp_tkill_minor(unsigned char minor);
+extern long taskdev_state_stale(unsigned char minor);
+extern int dsp_dbg_config(u16 *buf, u16 sz, u16 lsz);
+extern void dsp_dbg_stop(void);
+
+extern int ipbuf_is_held(u8 tid, u16 bid);
+
+extern int dsp_mem_sync_inc(void);
+extern int dsp_mem_sync_config(struct mem_sync_struct *sync);
+extern enum dsp_mem_type_e dsp_mem_type(void *vadr, size_t len);
+extern int dsp_address_validate(void *p, size_t len, char *fmt, ...);
+#ifdef CONFIG_ARCH_OMAP1
+extern void dsp_mem_usecount_clear(void);
+#endif
+extern void exmap_use(void *vadr, size_t len);
+extern void exmap_unuse(void *vadr, size_t len);
+extern unsigned long dsp_virt_to_phys(void *vadr, size_t *len);
+extern void dsp_mem_start(void);
+extern void dsp_mem_stop(void);
+
+extern void dsp_twch_start(void);
+extern void dsp_twch_stop(void);
+extern void dsp_twch_touch(void);
+
+extern void dsp_err_start(void);
+extern void dsp_err_stop(void);
+extern void dsp_err_set(enum errcode_e code, unsigned long arg);
+extern void dsp_err_clear(enum errcode_e code);
+extern int dsp_err_isset(enum errcode_e code);
+
+enum cmd_l_type_e {
+ CMD_L_TYPE_NULL,
+ CMD_L_TYPE_TID,
+ CMD_L_TYPE_SUBCMD,
+};
+
+struct cmdinfo {
+ char *name;
+ enum cmd_l_type_e cmd_l_type;
+ void (*handler)(struct mbcmd *mb);
+};
+
+extern const struct cmdinfo *cmdinfo[];
+
+#define cmd_name(mb) (cmdinfo[(mb).cmd_h]->name)
+extern char *subcmd_name(struct mbcmd *mb);
+
+extern void mblog_add(struct mbcmd *mb, arm_dsp_dir_t dir);
+
+extern struct omap_mmu dsp_mmu;
+
+#define dsp_mem_enable(addr) omap_mmu_mem_enable(&dsp_mmu, (addr))
+#define dsp_mem_disable(addr) omap_mmu_mem_disable(&dsp_mmu, (addr))
+
+#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 omap_set_bits_regl(val,mask,r) \
+ do { omap_writel((omap_readl(r) & ~(mask)) | (val), (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) \
+ ((dsp_long_t)(((unsigned long)(va) - dspmem_base) >> 1))
+#define virt_to_dspbyte(va) \
+ ((dsp_long_t)((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)
+
+#ifdef CONFIG_ARCH_OMAP1
+/*
+ * MPUI byteswap/wordswap on/off
+ * default setting: wordswap = all, byteswap = APIMEM only
+ */
+#define mpui_wordswap_on() \
+ omap_set_bits_regl(MPUI_CTRL_WORDSWAP_ALL, MPUI_CTRL_WORDSWAP_MASK, \
+ MPUI_CTRL)
+
+#define mpui_wordswap_off() \
+ omap_set_bits_regl(MPUI_CTRL_WORDSWAP_NONE, MPUI_CTRL_WORDSWAP_MASK, \
+ MPUI_CTRL)
+
+#define mpui_byteswap_on() \
+ omap_set_bits_regl(MPUI_CTRL_BYTESWAP_API, MPUI_CTRL_BYTESWAP_MASK, \
+ MPUI_CTRL)
+
+#define mpui_byteswap_off() \
+ omap_set_bits_regl(MPUI_CTRL_BYTESWAP_NONE, MPUI_CTRL_BYTESWAP_MASK, \
+ MPUI_CTRL)
+
+/*
+ * TC wordswap on / off
+ */
+#define tc_wordswap() \
+ do { \
+ omap_writel(TC_ENDIANISM_SWAP_WORD | TC_ENDIANISM_EN, \
+ TC_ENDIANISM); \
+ } while(0)
+
+#define tc_noswap() omap_clr_bit_regl(TC_ENDIANISM_EN, TC_ENDIANISM)
+
+/*
+ * 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)
+#endif /* CONFIG_ARCH_OMAP1 */
+
+#ifdef CONFIG_ARCH_OMAP2
+/*
+ * PRCM / IPI control logic
+ *
+ * REVISIT: these macros should probably be static inline functions
+ */
+#define __dsp_core_enable() \
+ do { prm_write_mod_reg(prm_read_mod_reg(OMAP24XX_DSP_MOD, RM_RSTCTRL) \
+ & ~OMAP24XX_RST1_DSP, OMAP24XX_DSP_MOD, RM_RSTCTRL); } while (0)
+#define __dsp_core_disable() \
+ do { prm_write_mod_reg(prm_read_mod_reg(OMAP24XX_DSP_MOD, RM_RSTCTRL) \
+ | OMAP24XX_RST1_DSP, OMAP24XX_DSP_MOD, RM_RSTCTRL); } while (0)
+#define __dsp_per_enable() \
+ do { prm_write_mod_reg(prm_read_mod_reg(OMAP24XX_DSP_MOD, RM_RSTCTRL) \
+ & ~OMAP24XX_RST2_DSP, OMAP24XX_DSP_MOD, RM_RSTCTRL); } while (0)
+#define __dsp_per_disable() \
+ do { prm_write_mod_reg(prm_read_mod_reg(OMAP24XX_DSP_MOD, RM_RSTCTRL) \
+ | OMAP24XX_RST2_DSP, OMAP24XX_DSP_MOD, RM_RSTCTRL); } while (0)
+#endif /* CONFIG_ARCH_OMAP2 */
+
+#if defined(CONFIG_ARCH_OMAP1)
+extern struct clk *dsp_ck_handle;
+extern struct clk *api_ck_handle;
+#elif defined(CONFIG_ARCH_OMAP2)
+extern struct clk *dsp_fck_handle;
+extern struct clk *dsp_ick_handle;
+#endif
+extern dsp_long_t dspmem_base, dspmem_size,
+ daram_base, daram_size,
+ saram_base, saram_size;
+
+enum cpustat_e {
+ CPUSTAT_RESET = 0,
+#ifdef CONFIG_ARCH_OMAP1
+ CPUSTAT_GBL_IDLE,
+ CPUSTAT_CPU_IDLE,
+#endif
+ CPUSTAT_RUN,
+ CPUSTAT_MAX
+};
+
+int dsp_set_rstvect(dsp_long_t adr);
+dsp_long_t dsp_get_rstvect(void);
+void dsp_set_idle_boot_base(dsp_long_t adr, size_t size);
+void dsp_reset_idle_boot_base(void);
+void dsp_cpustat_request(enum cpustat_e req);
+enum cpustat_e dsp_cpustat_get_stat(void);
+u16 dsp_cpustat_get_icrmask(void);
+void dsp_cpustat_set_icrmask(u16 mask);
+void dsp_register_mem_cb(int (*req_cb)(void), void (*rel_cb)(void));
+void dsp_unregister_mem_cb(void);
+
+#if defined(CONFIG_ARCH_OMAP1)
+#define command_dvfs_stop(m) (0)
+#define command_dvfs_start(m) (0)
+#elif defined(CONFIG_ARCH_OMAP2)
+#define command_dvfs_stop(m) \
+ (((m)->cmd_l == KFUNC_POWER) && ((m)->data == DVFS_STOP))
+#define command_dvfs_start(m) \
+ (((m)->cmd_l == KFUNC_POWER) && ((m)->data == DVFS_START))
+#endif
+
+extern struct omap_dsp *omap_dsp;
+
+extern int dsp_late_init(void);
+
+#endif /* __PLAT_OMAP_DSP_DSP_H */
--- /dev/null
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <asm/io.h>
+#include <asm/tlbflush.h>
+#include <asm/irq.h>
+#include <asm/arch/dsp_common.h>
+#include "dsp.h"
+
+#ifdef CONFIG_ARCH_OMAP1
+#include <asm/arch/tc.h>
+#endif
+
+#if defined(CONFIG_ARCH_OMAP1)
+#define dsp_boot_config(mode) omap_writew((mode), MPUI_DSP_BOOT_CONFIG)
+#endif
+#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
+#define dsp_boot_config(mode) writel((mode), DSP_IPI_DSPBOOTCONFIG)
+#endif
+
+struct omap_dsp *omap_dsp;
+
+#if defined(CONFIG_ARCH_OMAP1)
+struct clk *dsp_ck_handle;
+struct clk *api_ck_handle;
+#elif defined(CONFIG_ARCH_OMAP2)
+struct clk *dsp_fck_handle;
+struct clk *dsp_ick_handle;
+#endif
+dsp_long_t dspmem_base, dspmem_size,
+ daram_base, daram_size,
+ saram_base, saram_size;
+
+static struct cpustat {
+ struct mutex lock;
+ enum cpustat_e stat;
+ enum cpustat_e req;
+ u16 icrmask;
+#ifdef CONFIG_ARCH_OMAP1
+ struct {
+ int mpui;
+ int mem;
+ int mem_delayed;
+ } usecount;
+ int (*mem_req_cb)(void);
+ void (*mem_rel_cb)(void);
+#endif
+} cpustat = {
+ .stat = CPUSTAT_RESET,
+ .icrmask = 0xffff,
+};
+
+int dsp_set_rstvect(dsp_long_t 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 */
+ dsp_boot_config(DSP_BOOT_CONFIG_DIRECT);
+
+ return 0;
+}
+
+dsp_long_t dsp_get_rstvect(void)
+{
+ unsigned long *dst_adr;
+
+ dst_adr = dspbyte_to_virt(DSP_BOOT_ADR_DIRECT);
+ return ((*dst_adr & 0xffff) << 16) | (*dst_adr >> 16);
+}
+
+#ifdef CONFIG_ARCH_OMAP1
+static void simple_load_code(unsigned char *src_c, u16 *dst, int len)
+{
+ int i;
+ u16 *src = (u16 *)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 dsp_long_t 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
+ dsp_boot_config(DSP_BOOT_CONFIG_IDLE);
+#endif
+ simple_load_code(idle_text, dspbyte_to_virt(idle_boot_base),
+ GBL_IDLE_TEXT_SIZE);
+ if (idle_boot_base == DSP_BOOT_ADR_MPUI)
+ dsp_boot_config(DSP_BOOT_CONFIG_MPUI);
+ 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)
+{
+ u16 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 | DSPREG_ICR_DPLL);
+ 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)
+ dsp_boot_config(DSP_BOOT_CONFIG_MPUI);
+ 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(dsp_long_t 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();
+}
+
+void dsp_reset_idle_boot_base(void)
+{
+ idle_boot_base = DSP_BOOT_ADR_MPUI;
+}
+#else
+void dsp_reset_idle_boot_base(void) { }
+#endif /* CONFIG_ARCH_OMAP1 */
+
+static int init_done;
+
+static int omap_dsp_init(void)
+{
+ mutex_init(&cpustat.lock);
+
+ dspmem_size = 0;
+#ifdef CONFIG_ARCH_OMAP15XX
+ if (cpu_is_omap15xx()) {
+ 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
+#ifdef CONFIG_ARCH_OMAP24XX
+ if (cpu_is_omap24xx()) {
+ dspmem_base = DSP_MEM_24XX_VIRT;
+ dspmem_size = DSP_MEM_24XX_SIZE;
+ daram_base = OMAP24XX_DARAM_BASE;
+ daram_size = OMAP24XX_DARAM_SIZE;
+ saram_base = OMAP24XX_SARAM_BASE;
+ saram_size = OMAP24XX_SARAM_SIZE;
+ }
+#endif
+#ifdef CONFIG_ARCH_OMAP34XX
+ /* To be Revisited for 3430 */
+ if (cpu_is_omap34xx()) {
+ return -ENODEV;
+ }
+#endif
+ if (dspmem_size == 0) {
+ printk(KERN_ERR "omapdsp: unsupported omap architecture.\n");
+ return -ENODEV;
+ }
+
+#if defined(CONFIG_ARCH_OMAP1)
+ dsp_ck_handle = clk_get(NULL, "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(NULL, "api_ck");
+ if (IS_ERR(api_ck_handle)) {
+ printk(KERN_ERR "omapdsp: could not acquire api_ck handle.\n");
+ if (dsp_ck_handle != NULL)
+ clk_put(dsp_ck_handle);
+ 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();
+#elif defined(CONFIG_ARCH_OMAP2)
+ dsp_fck_handle = clk_get(NULL, "dsp_fck");
+ if (IS_ERR(dsp_fck_handle)) {
+ printk(KERN_ERR "omapdsp: could not acquire dsp_fck handle.\n");
+ return PTR_ERR(dsp_fck_handle);
+ }
+
+# if defined(CONFIG_ARCH_OMAP2420)
+ dsp_ick_handle = clk_get(NULL, "dsp_ick");
+# elif defined(CONFIG_ARCH_OMAP2430)
+ /*
+ * 2430 has no separate switch for DSP ICLK, but this at least
+ * involves the minimal change to the rest of the code.
+ */
+ dsp_ick_handle = clk_get(NULL, "iva2_1_ick");
+# endif
+ if (IS_ERR(dsp_ick_handle)) {
+ printk(KERN_ERR "omapdsp: could not acquire dsp_ick handle.\n");
+ if (dsp_fck_handle != NULL)
+ clk_put(dsp_fck_handle);
+ return PTR_ERR(dsp_ick_handle);
+ }
+#endif
+
+ init_done = 1;
+ pr_info("omap_dsp_init() done\n");
+ return 0;
+}
+
+#if defined(CONFIG_ARCH_OMAP1)
+static int __dsp_late_init(void)
+{
+ clk_disable(api_ck_handle);
+ return 0;
+}
+late_initcall(__dsp_late_init);
+#endif
+
+static void dsp_cpustat_update(void)
+{
+ if (!init_done)
+ omap_dsp_init();
+
+ if (cpustat.req == CPUSTAT_RUN) {
+ if (cpustat.stat < CPUSTAT_RUN) {
+#if defined(CONFIG_ARCH_OMAP1)
+ __dsp_reset();
+ clk_enable(api_ck_handle);
+ udelay(10);
+ __dsp_run();
+#elif defined(CONFIG_ARCH_OMAP2)
+ __dsp_core_disable();
+ udelay(10);
+ __dsp_core_enable();
+#endif
+ cpustat.stat = CPUSTAT_RUN;
+ }
+ return;
+ }
+
+ /* cpustat.req < CPUSTAT_RUN */
+
+ if (cpustat.stat == CPUSTAT_RUN) {
+#ifdef CONFIG_ARCH_OMAP1
+ clk_disable(api_ck_handle);
+#endif
+ }
+
+#ifdef CONFIG_ARCH_OMAP1
+ /*
+ * (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;
+ }
+#endif /* CONFIG_ARCH_OMAP1 */
+
+ /*
+ * no user, no request
+ */
+ if (cpustat.stat != CPUSTAT_RESET) {
+#if defined(CONFIG_ARCH_OMAP1)
+ __dsp_reset();
+#elif defined(CONFIG_ARCH_OMAP2)
+ __dsp_core_disable();
+#endif
+ cpustat.stat = CPUSTAT_RESET;
+ }
+}
+
+void dsp_cpustat_request(enum cpustat_e req)
+{
+ mutex_lock(&cpustat.lock);
+ cpustat.req = req;
+ dsp_cpustat_update();
+ mutex_unlock(&cpustat.lock);
+}
+
+enum cpustat_e dsp_cpustat_get_stat(void)
+{
+ return cpustat.stat;
+}
+
+u16 dsp_cpustat_get_icrmask(void)
+{
+ return cpustat.icrmask;
+}
+
+void dsp_cpustat_set_icrmask(u16 mask)
+{
+ mutex_lock(&cpustat.lock);
+ cpustat.icrmask = mask;
+ dsp_cpustat_update();
+ mutex_unlock(&cpustat.lock);
+}
+
+#ifdef CONFIG_ARCH_OMAP1
+void omap_dsp_request_mpui(void)
+{
+ mutex_lock(&cpustat.lock);
+ if (cpustat.usecount.mpui++ == 0)
+ dsp_cpustat_update();
+ mutex_unlock(&cpustat.lock);
+}
+
+void omap_dsp_release_mpui(void)
+{
+ mutex_lock(&cpustat.lock);
+ 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();
+ mutex_unlock(&cpustat.lock);
+}
+
+#if defined(CONFIG_ARCH_OMAP1) && defined(CONFIG_OMAP_MMU_FWK)
+int omap_dsp_request_mem(void)
+{
+ int ret = 0;
+
+ mutex_lock(&cpustat.lock);
+ 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:
+ mutex_unlock(&cpustat.lock);
+
+ return ret;
+}
+
+/*
+ * release_mem will be delayed.
+ */
+static void do_release_mem(struct work_struct *dummy)
+{
+ mutex_lock(&cpustat.lock);
+ cpustat.usecount.mem_delayed = 0;
+ if (cpustat.usecount.mem == 0) {
+ dsp_cpustat_update();
+ if (cpustat.mem_rel_cb)
+ cpustat.mem_rel_cb();
+ }
+ mutex_unlock(&cpustat.lock);
+}
+
+static DECLARE_DELAYED_WORK(mem_rel_work, do_release_mem);
+
+int omap_dsp_release_mem(void)
+{
+ mutex_lock(&cpustat.lock);
+
+ /* 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);
+ }
+
+ mutex_unlock(&cpustat.lock);
+
+ return 0;
+}
+#endif
+
+void dsp_register_mem_cb(int (*req_cb)(void), void (*rel_cb)(void))
+{
+ mutex_lock(&cpustat.lock);
+
+ 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);
+
+ mutex_unlock(&cpustat.lock);
+}
+
+void dsp_unregister_mem_cb(void)
+{
+ mutex_lock(&cpustat.lock);
+ cpustat.mem_req_cb = NULL;
+ cpustat.mem_rel_cb = NULL;
+ mutex_unlock(&cpustat.lock);
+}
+#else
+void dsp_register_mem_cb(int (*req_cb)(void), void (*rel_cb)(void)) { }
+void dsp_unregister_mem_cb(void) { }
+#endif /* CONFIG_ARCH_OMAP1 */
+
+arch_initcall(omap_dsp_init);
+
+#ifdef CONFIG_ARCH_OMAP1
+EXPORT_SYMBOL(omap_dsp_request_mpui);
+EXPORT_SYMBOL(omap_dsp_release_mpui);
+#if defined(CONFIG_ARCH_OMAP1) && defined(CONFIG_OMAP_MMU_FWK)
+EXPORT_SYMBOL(omap_dsp_request_mem);
+EXPORT_SYMBOL(omap_dsp_release_mem);
+#endif
+#endif /* CONFIG_ARCH_OMAP1 */
+
+#ifdef CONFIG_OMAP_DSP_MODULE
+#if defined(CONFIG_ARCH_OMAP1)
+EXPORT_SYMBOL(dsp_ck_handle);
+EXPORT_SYMBOL(api_ck_handle);
+#elif defined(CONFIG_ARCH_OMAP2)
+EXPORT_SYMBOL(dsp_fck_handle);
+EXPORT_SYMBOL(dsp_ick_handle);
+#endif
+EXPORT_SYMBOL(omap_dsp);
+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_get_rstvect);
+#ifdef CONFIG_ARCH_OMAP1
+EXPORT_SYMBOL(dsp_set_idle_boot_base);
+EXPORT_SYMBOL(dsp_reset_idle_boot_base);
+#endif /* CONFIG_ARCH_OMAP1 */
+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);
+EXPORT_SYMBOL(cpu_architecture);
+EXPORT_SYMBOL(pmd_clear_bad);
+#endif
--- /dev/null
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/mutex.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <asm/delay.h>
+#include <asm/arch/mailbox.h>
+#include <asm/arch/dsp.h>
+#include <asm/arch/dsp_common.h>
+#include "dsp_mbcmd.h"
+#include "dsp.h"
+#include "ipbuf.h"
+
+MODULE_AUTHOR("Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>");
+MODULE_DESCRIPTION("OMAP DSP driver module");
+MODULE_LICENSE("GPL");
+
+static struct sync_seq *mbseq;
+static u16 mbseq_expect_tmp;
+static u16 *mbseq_expect = &mbseq_expect_tmp;
+
+extern int dsp_mem_late_init(void);
+
+/*
+ * mailbox commands
+ */
+extern void mbox_wdsnd(struct mbcmd *mb);
+extern void mbox_wdreq(struct mbcmd *mb);
+extern void mbox_bksnd(struct mbcmd *mb);
+extern void mbox_bkreq(struct mbcmd *mb);
+extern void mbox_bkyld(struct mbcmd *mb);
+extern void mbox_bksndp(struct mbcmd *mb);
+extern void mbox_bkreqp(struct mbcmd *mb);
+extern void mbox_tctl(struct mbcmd *mb);
+extern void mbox_poll(struct mbcmd *mb);
+#ifdef OLD_BINARY_SUPPORT
+/* v3.3 obsolete */
+extern void mbox_wdt(struct mbcmd *mb);
+#endif
+extern void mbox_suspend(struct mbcmd *mb);
+static void mbox_kfunc(struct mbcmd *mb);
+extern void mbox_tcfg(struct mbcmd *mb);
+extern void mbox_tadd(struct mbcmd *mb);
+extern void mbox_tdel(struct mbcmd *mb);
+extern void mbox_dspcfg(struct mbcmd *mb);
+extern void mbox_regrw(struct mbcmd *mb);
+extern void mbox_getvar(struct mbcmd *mb);
+extern void mbox_err(struct mbcmd *mb);
+extern void mbox_dbg(struct mbcmd *mb);
+
+static const struct cmdinfo
+ cif_wdsnd = { "WDSND", CMD_L_TYPE_TID, mbox_wdsnd },
+ cif_wdreq = { "WDREQ", CMD_L_TYPE_TID, mbox_wdreq },
+ cif_bksnd = { "BKSND", CMD_L_TYPE_TID, mbox_bksnd },
+ cif_bkreq = { "BKREQ", CMD_L_TYPE_TID, mbox_bkreq },
+ cif_bkyld = { "BKYLD", CMD_L_TYPE_NULL, mbox_bkyld },
+ cif_bksndp = { "BKSNDP", CMD_L_TYPE_TID, mbox_bksndp },
+ cif_bkreqp = { "BKREQP", CMD_L_TYPE_TID, mbox_bkreqp },
+ cif_tctl = { "TCTL", CMD_L_TYPE_TID, mbox_tctl },
+ cif_poll = { "POLL", CMD_L_TYPE_NULL, mbox_poll },
+#ifdef OLD_BINARY_SUPPORT
+ /* v3.3 obsolete */
+ cif_wdt = { "WDT", CMD_L_TYPE_NULL, mbox_wdt },
+#endif
+ cif_runlevel = { "RUNLEVEL", CMD_L_TYPE_SUBCMD, NULL },
+ cif_pm = { "PM", CMD_L_TYPE_SUBCMD, NULL },
+ cif_suspend = { "SUSPEND", CMD_L_TYPE_NULL, mbox_suspend },
+ cif_kfunc = { "KFUNC", CMD_L_TYPE_SUBCMD, mbox_kfunc },
+ cif_tcfg = { "TCFG", CMD_L_TYPE_TID, mbox_tcfg },
+ cif_tadd = { "TADD", CMD_L_TYPE_TID, mbox_tadd },
+ cif_tdel = { "TDEL", CMD_L_TYPE_TID, mbox_tdel },
+ cif_tstop = { "TSTOP", CMD_L_TYPE_TID, NULL },
+ cif_dspcfg = { "DSPCFG", CMD_L_TYPE_SUBCMD, mbox_dspcfg },
+ cif_regrw = { "REGRW", CMD_L_TYPE_SUBCMD, mbox_regrw },
+ cif_getvar = { "GETVAR", CMD_L_TYPE_SUBCMD, mbox_getvar },
+ cif_setvar = { "SETVAR", CMD_L_TYPE_SUBCMD, NULL },
+ cif_err = { "ERR", CMD_L_TYPE_SUBCMD, mbox_err },
+ cif_dbg = { "DBG", CMD_L_TYPE_NULL, mbox_dbg };
+
+#define MBOX_CMD_MAX 0x80
+const struct cmdinfo *cmdinfo[MBOX_CMD_MAX] = {
+ [MBOX_CMD_DSP_WDSND] = &cif_wdsnd,
+ [MBOX_CMD_DSP_WDREQ] = &cif_wdreq,
+ [MBOX_CMD_DSP_BKSND] = &cif_bksnd,
+ [MBOX_CMD_DSP_BKREQ] = &cif_bkreq,
+ [MBOX_CMD_DSP_BKYLD] = &cif_bkyld,
+ [MBOX_CMD_DSP_BKSNDP] = &cif_bksndp,
+ [MBOX_CMD_DSP_BKREQP] = &cif_bkreqp,
+ [MBOX_CMD_DSP_TCTL] = &cif_tctl,
+ [MBOX_CMD_DSP_POLL] = &cif_poll,
+#ifdef OLD_BINARY_SUPPORT
+ [MBOX_CMD_DSP_WDT] = &cif_wdt, /* v3.3 obsolete */
+#endif
+ [MBOX_CMD_DSP_RUNLEVEL] = &cif_runlevel,
+ [MBOX_CMD_DSP_PM] = &cif_pm,
+ [MBOX_CMD_DSP_SUSPEND] = &cif_suspend,
+ [MBOX_CMD_DSP_KFUNC] = &cif_kfunc,
+ [MBOX_CMD_DSP_TCFG] = &cif_tcfg,
+ [MBOX_CMD_DSP_TADD] = &cif_tadd,
+ [MBOX_CMD_DSP_TDEL] = &cif_tdel,
+ [MBOX_CMD_DSP_TSTOP] = &cif_tstop,
+ [MBOX_CMD_DSP_DSPCFG] = &cif_dspcfg,
+ [MBOX_CMD_DSP_REGRW] = &cif_regrw,
+ [MBOX_CMD_DSP_GETVAR] = &cif_getvar,
+ [MBOX_CMD_DSP_SETVAR] = &cif_setvar,
+ [MBOX_CMD_DSP_ERR] = &cif_err,
+ [MBOX_CMD_DSP_DBG] = &cif_dbg,
+};
+
+#define list_for_each_entry_safe_natural(p,n,h,m) \
+ list_for_each_entry_safe(p,n,h,m)
+#define __BUILD_KFUNC(fn, dir) \
+static int __dsp_kfunc_##fn##_devices(struct omap_dsp *dsp, int type, int stage)\
+{ \
+ struct dsp_kfunc_device *p, *tmp; \
+ int ret, fail = 0; \
+ \
+ list_for_each_entry_safe_##dir(p, tmp, dsp->kdev_list, entry) { \
+ if (type && (p->type != type)) \
+ continue; \
+ if (p->fn == NULL) \
+ continue; \
+ ret = p->fn(p, stage); \
+ if (ret) { \
+ printk(KERN_ERR "%s %s failed\n", #fn, p->name); \
+ fail++; \
+ } \
+ } \
+ return fail; \
+}
+#define BUILD_KFUNC(fn, dir) \
+__BUILD_KFUNC(fn, dir) \
+static inline int dsp_kfunc_##fn##_devices(struct omap_dsp *dsp) \
+{ \
+ return __dsp_kfunc_##fn##_devices(dsp, 0, 0); \
+}
+#define BUILD_KFUNC_CTL(fn, dir) \
+__BUILD_KFUNC(fn, dir) \
+static inline int dsp_kfunc_##fn##_devices(struct omap_dsp *dsp, int type, int stage) \
+{ \
+ return __dsp_kfunc_##fn##_devices(dsp, type, stage); \
+}
+
+BUILD_KFUNC(probe, natural)
+BUILD_KFUNC(remove, reverse)
+BUILD_KFUNC_CTL(enable, natural)
+BUILD_KFUNC_CTL(disable, reverse)
+
+int sync_with_dsp(u16 *adr, u16 val, int try_cnt)
+{
+ int try;
+
+ if (*(volatile u16 *)adr == val)
+ return 0;
+
+ for (try = 0; try < try_cnt; try++) {
+ udelay(1);
+ if (*(volatile u16 *)adr == val) {
+ /* success! */
+ pr_info("omapdsp: sync_with_dsp(): try = %d\n", try);
+ return 0;
+ }
+ }
+
+ /* fail! */
+ return -1;
+}
+
+static int mbcmd_sender_prepare(void *data)
+{
+ struct mb_exarg *arg = data;
+ int i, ret = 0;
+ /*
+ * even if ipbuf_sys_ad is in DSP internal memory,
+ * dsp_mem_enable() never cause to call PM mailbox command
+ * because in that case DSP memory should be always enabled.
+ * (see ipbuf_sys_hold_mem_active in ipbuf.c)
+ *
+ * Therefore, we can call this function here safely.
+ */
+ dsp_mem_enable(ipbuf_sys_ad);
+ if (sync_with_dsp(&ipbuf_sys_ad->s, TID_FREE, 10) < 0) {
+ printk(KERN_ERR "omapdsp: ipbuf_sys_ad is busy.\n");
+ ret = -EBUSY;
+ goto out;
+ }
+
+ for (i = 0; i < arg->argc; i++) {
+ ipbuf_sys_ad->d[i] = arg->argv[i];
+ }
+ ipbuf_sys_ad->s = arg->tid;
+ out:
+ dsp_mem_disable(ipbuf_sys_ad);
+ return ret;
+}
+
+/*
+ * __dsp_mbcmd_send_exarg(): mailbox dispatcher
+ */
+int __dsp_mbcmd_send_exarg(struct mbcmd *mb, struct mb_exarg *arg,
+ int recovery_flag)
+{
+ int ret = 0;
+
+ if (unlikely(omap_dsp->enabled == 0)) {
+ ret = dsp_kfunc_enable_devices(omap_dsp,
+ DSP_KFUNC_DEV_TYPE_COMMON, 0);
+ if (ret == 0)
+ omap_dsp->enabled = 1;
+ }
+
+ /*
+ * while MMU fault is set,
+ * only recovery command can be executed
+ */
+ if (dsp_err_isset(ERRCODE_MMU) && !recovery_flag) {
+ printk(KERN_ERR
+ "mbox: mmu interrupt is set. %s is aborting.\n",
+ cmd_name(*mb));
+ goto out;
+ }
+
+ ret = omap_mbox_msg_send(omap_dsp->mbox,
+ *(mbox_msg_t *)mb, (void*)arg);
+ if (ret)
+ goto out;
+
+ if (mbseq)
+ mbseq->ad_arm++;
+
+ mblog_add(mb, DIR_A2D);
+ out:
+ return ret;
+}
+
+int dsp_mbcmd_send_and_wait_exarg(struct mbcmd *mb, struct mb_exarg *arg,
+ wait_queue_head_t *q)
+{
+ int ret;
+
+ DEFINE_WAIT(wait);
+ prepare_to_wait(q, &wait, TASK_INTERRUPTIBLE);
+ ret = dsp_mbcmd_send_exarg(mb, arg);
+ if (ret < 0)
+ goto out;
+ schedule_timeout(DSP_TIMEOUT);
+ out:
+ finish_wait(q, &wait);
+ return ret;
+}
+
+/*
+ * mbcmd receiver
+ */
+static int mbcmd_receiver(void* msg)
+{
+ struct mbcmd *mb = (struct mbcmd *)&msg;
+
+ if (cmdinfo[mb->cmd_h] == NULL) {
+ printk(KERN_ERR
+ "invalid message (%08x) for mbcmd_receiver().\n",
+ (mbox_msg_t)msg);
+ return -1;
+ }
+
+ (*mbseq_expect)++;
+
+ mblog_add(mb, DIR_D2A);
+
+ /* call handler for the command */
+ if (cmdinfo[mb->cmd_h]->handler)
+ cmdinfo[mb->cmd_h]->handler(mb);
+ else
+ printk(KERN_ERR "mbox: %s is not allowed from DSP.\n",
+ cmd_name(*mb));
+ return 0;
+}
+
+static int mbsync_hold_mem_active;
+
+void dsp_mbox_start(void)
+{
+ omap_mbox_init_seq(omap_dsp->mbox);
+ mbseq_expect_tmp = 0;
+}
+
+void dsp_mbox_stop(void)
+{
+ mbseq = NULL;
+ mbseq_expect = &mbseq_expect_tmp;
+}
+
+int dsp_mbox_config(void *p)
+{
+ unsigned long flags;
+
+ if (dsp_address_validate(p, sizeof(struct sync_seq), "mbseq") < 0)
+ return -1;
+ if (dsp_mem_type(p, sizeof(struct sync_seq)) != MEM_TYPE_EXTERN) {
+ printk(KERN_WARNING
+ "omapdsp: mbseq is placed in DSP internal memory.\n"
+ " It will prevent DSP from idling.\n");
+ mbsync_hold_mem_active = 1;
+ /*
+ * dsp_mem_enable() never fails because
+ * it has been already enabled in dspcfg process and
+ * this will just increment the usecount.
+ */
+ dsp_mem_enable((void *)daram_base);
+ }
+
+ local_irq_save(flags);
+ mbseq = p;
+ mbseq->da_arm = mbseq_expect_tmp;
+ mbseq_expect = &mbseq->da_arm;
+ local_irq_restore(flags);
+
+ return 0;
+}
+
+static int __init dsp_mbox_init(void)
+{
+ omap_dsp->mbox = omap_mbox_get("dsp");
+ if (IS_ERR(omap_dsp->mbox)) {
+ printk(KERN_ERR "failed to get mailbox handler for DSP.\n");
+ return -ENODEV;
+ }
+
+ omap_dsp->mbox->rxq->callback = mbcmd_receiver;
+ omap_dsp->mbox->txq->callback = mbcmd_sender_prepare;
+
+ return 0;
+}
+
+static void dsp_mbox_exit(void)
+{
+ omap_dsp->mbox->txq->callback = NULL;
+ omap_dsp->mbox->rxq->callback = NULL;
+
+ omap_mbox_put(omap_dsp->mbox);
+
+ if (mbsync_hold_mem_active) {
+ dsp_mem_disable((void *)daram_base);
+ mbsync_hold_mem_active = 0;
+ }
+}
+
+/*
+ * kernel function dispatcher
+ */
+extern void mbox_fbctl_upd(void);
+extern void mbox_fbctl_disable(struct mbcmd *mb);
+
+static void mbox_kfunc_fbctl(struct mbcmd *mb)
+{
+ switch (mb->data) {
+ case FBCTL_UPD:
+ mbox_fbctl_upd();
+ break;
+ case FBCTL_DISABLE:
+ mbox_fbctl_disable(mb);
+ break;
+ default:
+ printk(KERN_ERR
+ "mbox: Unknown FBCTL from DSP: 0x%04x\n", mb->data);
+ }
+}
+
+/*
+ * dspgw: KFUNC message handler
+ */
+static void mbox_kfunc_power(unsigned short data)
+{
+ int ret = -1;
+
+ switch (data) {
+ case DVFS_START: /* ACK from DSP */
+ /* TBD */
+ break;
+ case AUDIO_PWR_UP:
+ ret = dsp_kfunc_enable_devices(omap_dsp,
+ DSP_KFUNC_DEV_TYPE_AUDIO, 0);
+ if (ret == 0)
+ ret++;
+ break;
+ case AUDIO_PWR_DOWN: /* == AUDIO_PWR_DOWN1 */
+ ret = dsp_kfunc_disable_devices(omap_dsp,
+ DSP_KFUNC_DEV_TYPE_AUDIO, 1);
+ break;
+ case AUDIO_PWR_DOWN2:
+ ret = dsp_kfunc_disable_devices(omap_dsp,
+ DSP_KFUNC_DEV_TYPE_AUDIO, 2);
+ break;
+ case DSP_PWR_DOWN:
+ ret = dsp_kfunc_disable_devices(omap_dsp,
+ DSP_KFUNC_DEV_TYPE_COMMON, 0);
+ if (ret == 0)
+ omap_dsp->enabled = 0;
+ break;
+ default:
+ printk(KERN_ERR
+ "mailbox: Unknown PWR from DSP: 0x%04x\n", data);
+ break;
+ }
+
+ if (unlikely(ret < 0)) {
+ printk(KERN_ERR "mailbox: PWR(0x%04x) failed\n", data);
+ return;
+ }
+
+ if (likely(ret == 0))
+ return;
+
+ mbcompose_send(KFUNC, KFUNC_POWER, data);
+}
+
+static void mbox_kfunc(struct mbcmd *mb)
+{
+ switch (mb->cmd_l) {
+ case KFUNC_FBCTL:
+ mbox_kfunc_fbctl(mb);
+ break;
+ case KFUNC_POWER:
+ mbox_kfunc_power(mb->data);
+ break;
+ default:
+ printk(KERN_ERR
+ "mbox: Unknown KFUNC from DSP: 0x%02x\n", mb->cmd_l);
+ }
+}
+
+#if defined(CONFIG_ARCH_OMAP1)
+static inline void dsp_clk_enable(void) {}
+static inline void dsp_clk_disable(void) {}
+#elif defined(CONFIG_ARCH_OMAP2)
+static inline void dsp_clk_enable(void)
+{
+ /*XXX should be handled in mach-omap[1,2] XXX*/
+ prm_write_mod_reg(OMAP24XX_FORCESTATE | (1 << OMAP_POWERSTATE_SHIFT),
+ OMAP24XX_DSP_MOD, PM_PWSTCTRL);
+
+ cm_set_mod_reg_bits(OMAP2420_AUTO_DSP_IPI, OMAP24XX_DSP_MOD,
+ CM_AUTOIDLE);
+
+ cm_set_mod_reg_bits(OMAP24XX_AUTOSTATE_DSP_MASK, OMAP24XX_DSP_MOD,
+ CM_CLKSTCTRL);
+
+ clk_enable(dsp_fck_handle);
+ clk_enable(dsp_ick_handle);
+ __dsp_per_enable();
+}
+static inline void dsp_clk_disable(void)
+{
+ __dsp_per_disable();
+ clk_disable(dsp_ick_handle);
+ clk_disable(dsp_fck_handle);
+
+ prm_write_mod_reg(OMAP24XX_FORCESTATE | (3 << OMAP_POWERSTATE_SHIFT),
+ OMAP24XX_DSP_MOD, PM_PWSTCTRL);
+}
+#endif
+
+int dsp_late_init(void)
+{
+ int ret;
+
+ dsp_clk_enable();
+ ret = dsp_mem_late_init();
+ if (ret)
+ return ret;
+ ret = dsp_mbox_init();
+ if (ret)
+ goto fail_mbox;
+#ifdef CONFIG_ARCH_OMAP1
+ dsp_set_idle_boot_base(IDLEPG_BASE, IDLEPG_SIZE);
+#endif
+ ret = dsp_kfunc_enable_devices(omap_dsp,
+ DSP_KFUNC_DEV_TYPE_COMMON, 0);
+ if (ret)
+ goto fail_kfunc;
+ omap_dsp->enabled = 1;
+
+ return 0;
+
+ fail_kfunc:
+ dsp_mbox_exit();
+ fail_mbox:
+ dsp_clk_disable();
+
+ return ret;
+}
+
+extern int dsp_ctl_core_init(void);
+extern void dsp_ctl_core_exit(void);
+extern int dsp_ctl_init(void);
+extern void dsp_ctl_exit(void);
+extern int dsp_mem_init(void);
+extern void dsp_mem_exit(void);
+extern void mblog_init(void);
+extern void mblog_exit(void);
+extern int dsp_taskmod_init(void);
+extern void dsp_taskmod_exit(void);
+
+/*
+ * driver functions
+ */
+static int __init dsp_drv_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct omap_dsp *info;
+ struct dsp_platform_data *pdata = pdev->dev.platform_data;
+
+ dev_info(&pdev->dev, "OMAP DSP driver initialization\n");
+
+ info = kzalloc(sizeof(struct omap_dsp), GFP_KERNEL);
+ if (unlikely(info == NULL)) {
+ dev_dbg(&pdev->dev, "no memory for info\n");
+ return -ENOMEM;
+ }
+ platform_set_drvdata(pdev, info);
+ omap_dsp = info;
+
+ mutex_init(&info->lock);
+ info->dev = &pdev->dev;
+ info->kdev_list = &pdata->kdev_list;
+
+ ret = dsp_kfunc_probe_devices(info);
+ if (ret) {
+ ret = -ENXIO;
+ goto fail_kfunc;
+ }
+
+ ret = dsp_ctl_core_init();
+ if (ret)
+ goto fail_ctl_core;
+ ret = dsp_mem_init();
+ if (ret)
+ goto fail_mem;
+ ret = dsp_ctl_init();
+ if (unlikely(ret))
+ goto fail_ctl_init;
+ mblog_init();
+ ret = dsp_taskmod_init();
+ if (ret)
+ goto fail_taskmod;
+
+ return 0;
+
+ fail_taskmod:
+ mblog_exit();
+ dsp_ctl_exit();
+ fail_ctl_init:
+ dsp_mem_exit();
+ fail_mem:
+ dsp_ctl_core_exit();
+ fail_ctl_core:
+ dsp_kfunc_remove_devices(info);
+ fail_kfunc:
+ kfree(info);
+
+ return ret;
+}
+
+static int dsp_drv_remove(struct platform_device *pdev)
+{
+ struct omap_dsp *info = platform_get_drvdata(pdev);
+
+ dsp_cpustat_request(CPUSTAT_RESET);
+
+ dsp_cfgstat_request(CFGSTAT_CLEAN);
+ dsp_mbox_exit();
+ dsp_taskmod_exit();
+ mblog_exit();
+ dsp_ctl_exit();
+ dsp_mem_exit();
+
+ dsp_ctl_core_exit();
+
+#ifdef CONFIG_ARCH_OMAP2
+ __dsp_per_disable();
+ clk_disable(dsp_ick_handle);
+ clk_disable(dsp_fck_handle);
+#endif
+ dsp_kfunc_remove_devices(info);
+ kfree(info);
+
+ return 0;
+}
+
+#if defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP1)
+static int dsp_drv_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ dsp_cfgstat_request(CFGSTAT_SUSPEND);
+
+ return 0;
+}
+
+static int dsp_drv_resume(struct platform_device *pdev)
+{
+ dsp_cfgstat_request(CFGSTAT_RESUME);
+
+ return 0;
+}
+#else
+#define dsp_drv_suspend NULL
+#define dsp_drv_resume NULL
+#endif /* CONFIG_PM */
+
+static struct platform_driver dsp_driver = {
+ .probe = dsp_drv_probe,
+ .remove = dsp_drv_remove,
+ .suspend = dsp_drv_suspend,
+ .resume = dsp_drv_resume,
+ .driver = {
+ .name = "dsp",
+ },
+};
+
+static int __init omap_dsp_mod_init(void)
+{
+ return platform_driver_register(&dsp_driver);
+}
+
+static void __exit omap_dsp_mod_exit(void)
+{
+ platform_driver_unregister(&dsp_driver);
+}
+
+/* module dependency: need mailbox module that have mbox_dsp_info */
+extern struct omap_mbox mbox_dsp_info;
+struct omap_mbox *mbox_dep = &mbox_dsp_info;
+
+module_init(omap_dsp_mod_init);
+module_exit(omap_dsp_mod_exit);
--- /dev/null
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/ioctls.h>
+#include <asm/arch/mailbox.h>
+#include <asm/arch/dsp.h>
+#include "hardware_dsp.h"
+#include "dsp_mbcmd.h"
+#include "dsp.h"
+#include "ipbuf.h"
+
+enum dsp_space_e {
+ SPACE_MEM,
+ SPACE_IO,
+};
+
+#ifdef CONFIG_OMAP_DSP_FBEXPORT
+static enum fbstat_e {
+ FBSTAT_DISABLED = 0,
+ FBSTAT_ENABLED,
+ FBSTAT_MAX,
+} fbstat = FBSTAT_ENABLED;
+#endif
+
+static enum cfgstat_e cfgstat;
+int mbox_revision;
+static u8 n_stask;
+
+static ssize_t ifver_show(struct device *dev, struct device_attribute *attr,
+ char *buf);
+static ssize_t cpustat_show(struct device *dev, struct device_attribute *attr,
+ char *buf);
+static ssize_t icrmask_show(struct device *dev, struct device_attribute *attr,
+ char *buf);
+static ssize_t icrmask_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count);
+static ssize_t loadinfo_show(struct device *dev, struct device_attribute *attr,
+ char *buf);
+
+#define __ATTR_RW(_name, _mode) { \
+ .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE }, \
+ .show = _name##_show, \
+ .store = _name##_store, \
+}
+
+static struct device_attribute dev_attr_ifver = __ATTR_RO(ifver);
+static struct device_attribute dev_attr_cpustat = __ATTR_RO(cpustat);
+static struct device_attribute dev_attr_icrmask = __ATTR_RW(icrmask, 0644);
+static struct device_attribute dev_attr_loadinfo = __ATTR_RO(loadinfo);
+
+/*
+ * misc interactive mailbox command operations
+ */
+static struct misc_mb_wait_struct {
+ struct mutex lock;
+ wait_queue_head_t wait_q;
+ u8 cmd_h;
+ u8 cmd_l;
+ u16 *retvp;
+} misc_mb_wait = {
+ .lock = __MUTEX_INITIALIZER(misc_mb_wait.lock),
+ .wait_q = __WAIT_QUEUE_HEAD_INITIALIZER(misc_mb_wait.wait_q),
+};
+
+static int __misc_mbcompose_send_and_wait(u8 cmd_h, u8 cmd_l, u16 data,
+ u16 *retvp)
+{
+ struct mbcmd mb = MBCMD_INIT(cmd_h, cmd_l, data);
+ int ret = 0;
+
+ if (mutex_lock_interruptible(&misc_mb_wait.lock))
+ return -EINTR;
+
+ misc_mb_wait.cmd_h = mb.cmd_h;
+ misc_mb_wait.cmd_l = mb.cmd_l;
+ misc_mb_wait.retvp = retvp;
+ dsp_mbcmd_send_and_wait(&mb, &misc_mb_wait.wait_q);
+
+ if (misc_mb_wait.cmd_h != 0)
+ ret = -EINVAL;
+
+ mutex_unlock(&misc_mb_wait.lock);
+ return ret;
+}
+
+#define misc_mbcompose_send_and_wait(cmd_h, cmd_l, data, retvp) \
+ __misc_mbcompose_send_and_wait(MBOX_CMD_DSP_##cmd_h, (cmd_l), \
+ (data), (retvp));
+
+static int misc_mbcmd_response(struct mbcmd *mb, int argc, int match_cmd_l_flag)
+{
+ volatile u16 *buf;
+ int i;
+
+ /* if match_cmd_l_v flag is set, cmd_l needs to be matched as well. */
+ if (!waitqueue_active(&misc_mb_wait.wait_q) ||
+ (misc_mb_wait.cmd_h != mb->cmd_h) ||
+ (match_cmd_l_flag && (misc_mb_wait.cmd_l != mb->cmd_l))) {
+ const struct cmdinfo *ci = cmdinfo[mb->cmd_h];
+ char cmdstr[32];
+
+ if (ci->cmd_l_type == CMD_L_TYPE_SUBCMD)
+ sprintf(cmdstr, "%s:%s", ci->name, subcmd_name(mb));
+ else
+ strcpy(cmdstr, ci->name);
+ printk(KERN_WARNING
+ "mbox: unexpected command %s received!\n", cmdstr);
+ return -1;
+ }
+
+ /*
+ * if argc == 1, receive data through mbox:data register.
+ * if argc > 1, receive through ipbuf_sys.
+ */
+ if (argc == 1)
+ misc_mb_wait.retvp[0] = mb->data;
+ else if (argc > 1) {
+ if (dsp_mem_enable(ipbuf_sys_da) < 0) {
+ printk(KERN_ERR "mbox: %s - ipbuf_sys_da read failed!\n",
+ cmdinfo[mb->cmd_h]->name);
+ return -1;
+ }
+ if (sync_with_dsp(&ipbuf_sys_da->s, TID_ANON, 10) < 0) {
+ printk(KERN_ERR "mbox: %s - IPBUF sync failed!\n",
+ cmdinfo[mb->cmd_h]->name);
+ dsp_mem_disable(ipbuf_sys_da);
+ return -1;
+ }
+ /* need word access. do not use memcpy. */
+ buf = ipbuf_sys_da->d;
+ for (i = 0; i < argc; i++)
+ misc_mb_wait.retvp[i] = buf[i];
+ release_ipbuf_pvt(ipbuf_sys_da);
+ dsp_mem_disable(ipbuf_sys_da);
+ }
+
+ misc_mb_wait.cmd_h = 0;
+ wake_up_interruptible(&misc_mb_wait.wait_q);
+ return 0;
+}
+
+static int dsp_regread(enum dsp_space_e space, u16 adr, u16 *val)
+{
+ u8 cmd_l = (space == SPACE_MEM) ? REGRW_MEMR : REGRW_IOR;
+ int ret;
+
+ ret = misc_mbcompose_send_and_wait(REGRW, cmd_l, adr, val);
+ if ((ret < 0) && (ret != -EINTR))
+ printk(KERN_ERR "omapdsp: register read error!\n");
+
+ return ret;
+}
+
+static int dsp_regwrite(enum dsp_space_e space, u16 adr, u16 val)
+{
+ u8 cmd_l = (space == SPACE_MEM) ? REGRW_MEMW : REGRW_IOW;
+ struct mb_exarg arg = {
+ .tid = TID_ANON,
+ .argc = 1,
+ .argv = &val,
+ };
+
+ mbcompose_send_exarg(REGRW, cmd_l, adr, &arg);
+ return 0;
+}
+
+static int dsp_getvar(u8 varid, u16 *val)
+{
+ int ret;
+
+ ret = misc_mbcompose_send_and_wait(GETVAR, varid, 0, val);
+ if ((ret < 0) && (ret != -EINTR))
+ printk(KERN_ERR "omapdsp: variable read error!\n");
+
+ return ret;
+}
+
+static int dsp_setvar(u8 varid, u16 val)
+{
+ mbcompose_send(SETVAR, varid, val);
+ return 0;
+}
+
+/*
+ * dsp_cfg() return value
+ * = 0: OK
+ * = 1: failed, but state is clear. (DSPCFG command failed)
+ * < 0: failed. need cleanup.
+ */
+static int dsp_cfg(void)
+{
+ int ret = 0;
+
+#ifdef CONFIG_ARCH_OMAP1
+ /* for safety */
+ dsp_mem_usecount_clear();
+#endif
+
+ /*
+ * DSPCFG command and dsp_mem_start() must be called
+ * while internal mem is on.
+ */
+ dsp_mem_enable((void *)dspmem_base);
+
+ dsp_mbox_start();
+ dsp_twch_start();
+ dsp_mem_start();
+ dsp_err_start();
+
+ mbox_revision = -1;
+
+ ret = misc_mbcompose_send_and_wait(DSPCFG, DSPCFG_REQ, 0, NULL);
+ if (ret < 0) {
+ if (ret != -EINTR)
+ printk(KERN_ERR "omapdsp: configuration error!\n");
+ ret = 1;
+ goto out;
+ }
+
+#if defined(CONFIG_ARCH_OMAP1) && defined(OLD_BINARY_SUPPORT)
+ /*
+ * MBREV 3.2 or earlier doesn't assume DMA domain is on
+ * when DSPCFG command is sent
+ */
+ if ((mbox_revision == MBREV_3_0) ||
+ (mbox_revision == MBREV_3_2)) {
+ if ((ret = mbcompose_send(PM, PM_ENABLE, DSPREG_ICR_DMA)) < 0)
+ goto out;
+ }
+#endif
+
+ if ((ret = dsp_task_config_all(n_stask)) < 0)
+ goto out;
+
+ /* initialization */
+#ifdef CONFIG_OMAP_DSP_FBEXPORT
+ fbstat = FBSTAT_ENABLED;
+#endif
+
+ /* send parameter */
+ ret = dsp_setvar(VARID_ICRMASK, dsp_cpustat_get_icrmask());
+ if (ret < 0)
+ goto out;
+
+ /* create runtime sysfs entries */
+ ret = device_create_file(omap_dsp->dev, &dev_attr_loadinfo);
+ if (ret)
+ printk(KERN_ERR "device_create_file failed: %d\n", ret);
+ out:
+ dsp_mem_disable((void *)dspmem_base);
+ return ret;
+}
+
+static int dsp_uncfg(void)
+{
+ if (dsp_taskmod_busy()) {
+ printk(KERN_WARNING "omapdsp: tasks are busy.\n");
+ return -EBUSY;
+ }
+
+ /* FIXME: lock task module */
+
+ /* remove runtime sysfs entries */
+ device_remove_file(omap_dsp->dev, &dev_attr_loadinfo);
+
+ dsp_mbox_stop();
+ dsp_twch_stop();
+ dsp_mem_stop();
+ dsp_err_stop();
+ dsp_dbg_stop();
+ dsp_task_unconfig_all();
+ ipbuf_stop();
+
+ return 0;
+}
+
+static int dsp_suspend(void)
+{
+ int ret;
+
+ ret = misc_mbcompose_send_and_wait(SUSPEND, 0, 0, NULL);
+ if (ret < 0) {
+ if (ret != -EINVAL)
+ printk(KERN_ERR "omapdsp: DSP suspend error!\n");
+ return ret;
+ }
+
+ udelay(100); /* wait for DSP-side execution */
+ return 0;
+}
+
+int dsp_cfgstat_request(enum cfgstat_e st_req)
+{
+ static DEFINE_MUTEX(cfgstat_lock);
+ int ret = 0, ret_override = 0;
+
+ if (mutex_lock_interruptible(&cfgstat_lock))
+ return -EINTR;
+
+again:
+ switch (st_req) {
+
+ /* cfgstat takes CLEAN, READY or SUSPEND,
+ while st_req can take SUSPEND in addition. */
+
+ case CFGSTAT_CLEAN:
+ if (cfgstat == CFGSTAT_CLEAN)
+ goto up_out;
+ if ((ret = dsp_uncfg()) < 0)
+ goto up_out;
+ break;
+
+ case CFGSTAT_READY:
+ if (cfgstat != CFGSTAT_CLEAN) {
+ printk(KERN_ERR "omapdsp: DSP is ready already!\n");
+ ret = -EINVAL;
+ goto up_out;
+ }
+
+ ret = dsp_cfg();
+ if (ret > 0) { /* failed, but state is clear. */
+ ret = -EINVAL;
+ goto up_out;
+ } else if (ret < 0) { /* failed, need cleanup. */
+ st_req = CFGSTAT_CLEAN;
+ ret_override = ret;
+ goto again;
+ }
+ break;
+
+ /*
+ * suspend / resume
+ * DSP is not reset within this code, but done in omap_pm_suspend.
+ * so if these functions are called from sysfs,
+ * DSP should be reset / unreset out of these functions.
+ */
+ case CFGSTAT_SUSPEND:
+ switch (cfgstat) {
+
+ case CFGSTAT_CLEAN:
+ if (dsp_cpustat_get_stat() == CPUSTAT_RUN) {
+ printk(KERN_WARNING
+ "omapdsp: illegal operation -- trying "
+ "suspend DSP while it is running but "
+ "not configured.\n"
+ " Resetting DSP.\n");
+ dsp_cpustat_request(CPUSTAT_RESET);
+ ret = -EINVAL;
+ }
+ goto up_out;
+
+ case CFGSTAT_READY:
+ if ((ret = dsp_suspend()) < 0)
+ goto up_out;
+ break;
+
+ case CFGSTAT_SUSPEND:
+ goto up_out;
+
+ default:
+ BUG();
+
+ }
+
+ break;
+
+ case CFGSTAT_RESUME:
+ if (cfgstat != CFGSTAT_SUSPEND) {
+ printk(KERN_WARNING
+ "omapdsp: DSP resume request, but DSP is not in "
+ "suspend state.\n");
+ ret = -EINVAL;
+ goto up_out;
+ }
+ st_req = CFGSTAT_READY;
+ break;
+
+ default:
+ BUG();
+
+ }
+
+ cfgstat = st_req;
+up_out:
+ mutex_unlock(&cfgstat_lock);
+ return ret_override ? ret_override : ret;
+}
+
+enum cfgstat_e dsp_cfgstat_get_stat(void)
+{
+ return cfgstat;
+}
+
+/*
+ * polls all tasks
+ */
+static int dsp_poll(void)
+{
+ int ret;
+
+ ret = misc_mbcompose_send_and_wait(POLL, 0, 0, NULL);
+ if ((ret < 0) && (ret != -EINTR))
+ printk(KERN_ERR "omapdsp: poll error!\n");
+
+ return ret;
+}
+
+int dsp_set_runlevel(u8 level)
+{
+ if (level == RUNLEVEL_RECOVERY) {
+ if (mbcompose_send_recovery(RUNLEVEL, level, 0) < 0)
+ return -EINVAL;
+ } else {
+ if ((level < RUNLEVEL_USER) ||
+ (level > RUNLEVEL_SUPER))
+ return -EINVAL;
+ if (mbcompose_send(RUNLEVEL, level, 0) < 0)
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_OMAP_DSP_FBEXPORT
+static void dsp_fbctl_enable(void)
+{
+ mbcompose_send(KFUNC, KFUNC_FBCTL, FBCTL_ENABLE);
+}
+
+static int dsp_fbctl_disable(void)
+{
+ int ret;
+
+ ret = misc_mbcompose_send_and_wait(KFUNC, KFUNC_FBCTL, FBCTL_DISABLE,
+ NULL);
+ if ((ret < 0) && (ret != -EINTR))
+ printk(KERN_ERR "omapdsp: fb disable error!\n");
+
+ return 0;
+}
+
+static int dsp_fbstat_request(enum fbstat_e st)
+{
+ static DEFINE_MUTEX(fbstat_lock);
+ int ret = 0;
+
+ if (mutex_lock_interruptible(&fbstat_lock))
+ return -EINTR;
+
+ if (st == fbstat)
+ goto up_out;
+
+ switch (st) {
+ case FBSTAT_ENABLED:
+ dsp_fbctl_enable();
+ break;
+ case FBSTAT_DISABLED:
+ if ((ret = dsp_fbctl_disable()) < 0)
+ goto up_out;
+ break;
+ default:
+ BUG();
+ }
+
+ fbstat = st;
+up_out:
+ mutex_unlock(&fbstat_lock);
+ return 0;
+}
+#endif /* CONFIG_OMAP_DSP_FBEXPORT */
+
+/*
+ * DSP control device file operations
+ */
+static int dsp_ctl_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int ret = 0;
+
+ switch (cmd) {
+ /*
+ * command level 1: commands which don't need lock
+ */
+ case DSPCTL_IOCTL_RUN:
+ dsp_cpustat_request(CPUSTAT_RUN);
+ break;
+
+ case DSPCTL_IOCTL_RESET:
+ dsp_cpustat_request(CPUSTAT_RESET);
+ break;
+
+ case DSPCTL_IOCTL_SETRSTVECT:
+ ret = dsp_set_rstvect((dsp_long_t)arg);
+ break;
+
+#ifdef CONFIG_ARCH_OMAP1
+ case DSPCTL_IOCTL_CPU_IDLE:
+ dsp_cpustat_request(CPUSTAT_CPU_IDLE);
+ break;
+
+ case DSPCTL_IOCTL_GBL_IDLE:
+ dsp_cpustat_request(CPUSTAT_GBL_IDLE);
+ break;
+
+ case DSPCTL_IOCTL_MPUI_WORDSWAP_ON:
+ mpui_wordswap_on();
+ break;
+
+ case DSPCTL_IOCTL_MPUI_WORDSWAP_OFF:
+ mpui_wordswap_off();
+ break;
+
+ case DSPCTL_IOCTL_MPUI_BYTESWAP_ON:
+ mpui_byteswap_on();
+ break;
+
+ case DSPCTL_IOCTL_MPUI_BYTESWAP_OFF:
+ mpui_byteswap_off();
+ break;
+#endif /* CONFIG_ARCH_OMAP1 */
+
+ case DSPCTL_IOCTL_TASKCNT:
+ ret = dsp_task_count();
+ break;
+
+ case DSPCTL_IOCTL_MBSEND:
+ {
+ struct omap_dsp_mailbox_cmd u_cmd;
+ mbox_msg_t msg;
+ if (copy_from_user(&u_cmd, (void *)arg, sizeof(u_cmd)))
+ return -EFAULT;
+ msg = (u_cmd.cmd << 16) | u_cmd.data;
+ ret = dsp_mbcmd_send((struct mbcmd *)&msg);
+ break;
+ }
+
+ case DSPCTL_IOCTL_SETVAR:
+ {
+ struct omap_dsp_varinfo var;
+ if (copy_from_user(&var, (void *)arg, sizeof(var)))
+ return -EFAULT;
+ ret = dsp_setvar(var.varid, var.val[0]);
+ break;
+ }
+
+ case DSPCTL_IOCTL_RUNLEVEL:
+ ret = dsp_set_runlevel(arg);
+ break;
+
+#ifdef CONFIG_OMAP_DSP_FBEXPORT
+ case DSPCTL_IOCTL_FBEN:
+ ret = dsp_fbstat_request(FBSTAT_ENABLED);
+ break;
+#endif
+
+ /*
+ * command level 2: commands which need lock
+ */
+ case DSPCTL_IOCTL_DSPCFG:
+ ret = dsp_cfgstat_request(CFGSTAT_READY);
+ break;
+
+ case DSPCTL_IOCTL_DSPUNCFG:
+ ret = dsp_cfgstat_request(CFGSTAT_CLEAN);
+ break;
+
+ case DSPCTL_IOCTL_POLL:
+ ret = dsp_poll();
+ break;
+
+#ifdef CONFIG_OMAP_DSP_FBEXPORT
+ case DSPCTL_IOCTL_FBDIS:
+ ret = dsp_fbstat_request(FBSTAT_DISABLED);
+ break;
+#endif
+
+ case DSPCTL_IOCTL_SUSPEND:
+ if ((ret = dsp_cfgstat_request(CFGSTAT_SUSPEND)) < 0)
+ break;
+ dsp_cpustat_request(CPUSTAT_RESET);
+ break;
+
+ case DSPCTL_IOCTL_RESUME:
+ if ((ret = dsp_cfgstat_request(CFGSTAT_RESUME)) < 0)
+ break;
+ dsp_cpustat_request(CPUSTAT_RUN);
+ break;
+
+ case DSPCTL_IOCTL_REGMEMR:
+ {
+ struct omap_dsp_reginfo *u_reg = (void *)arg;
+ u16 adr, val;
+
+ if (copy_from_user(&adr, &u_reg->adr, sizeof(u16)))
+ return -EFAULT;
+ if ((ret = dsp_regread(SPACE_MEM, adr, &val)) < 0)
+ return ret;
+ if (copy_to_user(&u_reg->val, &val, sizeof(u16)))
+ return -EFAULT;
+ break;
+ }
+
+ case DSPCTL_IOCTL_REGMEMW:
+ {
+ struct omap_dsp_reginfo reg;
+
+ if (copy_from_user(®, (void *)arg, sizeof(reg)))
+ return -EFAULT;
+ ret = dsp_regwrite(SPACE_MEM, reg.adr, reg.val);
+ break;
+ }
+
+ case DSPCTL_IOCTL_REGIOR:
+ {
+ struct omap_dsp_reginfo *u_reg = (void *)arg;
+ u16 adr, val;
+
+ if (copy_from_user(&adr, &u_reg->adr, sizeof(u16)))
+ return -EFAULT;
+ if ((ret = dsp_regread(SPACE_IO, adr, &val)) < 0)
+ return ret;
+ if (copy_to_user(&u_reg->val, &val, sizeof(u16)))
+ return -EFAULT;
+ break;
+ }
+
+ case DSPCTL_IOCTL_REGIOW:
+ {
+ struct omap_dsp_reginfo reg;
+
+ if (copy_from_user(®, (void *)arg, sizeof(reg)))
+ return -EFAULT;
+ ret = dsp_regwrite(SPACE_IO, reg.adr, reg.val);
+ break;
+ }
+
+ case DSPCTL_IOCTL_GETVAR:
+ {
+ struct omap_dsp_varinfo *u_var = (void *)arg;
+ u8 varid;
+ u16 val[5]; /* maximum */
+ int argc;
+
+ if (copy_from_user(&varid, &u_var->varid, sizeof(u8)))
+ return -EFAULT;
+ switch (varid) {
+ case VARID_ICRMASK:
+ argc = 1;
+ break;
+ case VARID_LOADINFO:
+ argc = 5;
+ break;
+ default:
+ return -EINVAL;
+ }
+ if ((ret = dsp_getvar(varid, val)) < 0)
+ return ret;
+ if (copy_to_user(&u_var->val, val, sizeof(u16) * argc))
+ return -EFAULT;
+ break;
+ }
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+
+ return ret;
+}
+
+/*
+ * functions called from mailbox interrupt routine
+ */
+void mbox_suspend(struct mbcmd *mb)
+{
+ misc_mbcmd_response(mb, 0, 0);
+}
+
+void mbox_dspcfg(struct mbcmd *mb)
+{
+ u8 last = mb->cmd_l & 0x80;
+ u8 cfgcmd = mb->cmd_l & 0x7f;
+ static dsp_long_t tmp_ipb_adr;
+
+ if (!waitqueue_active(&misc_mb_wait.wait_q) ||
+ (misc_mb_wait.cmd_h != MBOX_CMD_DSP_DSPCFG)) {
+ printk(KERN_WARNING
+ "mbox: DSPCFG command received, "
+ "but nobody is waiting for it...\n");
+ return;
+ }
+
+ /* mailbox protocol check */
+ if (cfgcmd == DSPCFG_PROTREV) {
+ mbox_revision = mb->data;
+ if (mbox_revision == MBPROT_REVISION)
+ return;
+#ifdef OLD_BINARY_SUPPORT
+ else if ((mbox_revision == MBREV_3_0) ||
+ (mbox_revision == MBREV_3_2)) {
+ printk(KERN_WARNING
+ "mbox: ***** old DSP binary *****\n"
+ " Please update your DSP application.\n");
+ return;
+ }
+#endif
+ else {
+ printk(KERN_ERR
+ "mbox: protocol revision check error!\n"
+ " expected=0x%04x, received=0x%04x\n",
+ MBPROT_REVISION, mb->data);
+ mbox_revision = -1;
+ goto abort1;
+ }
+ }
+
+ /*
+ * following commands are accepted only after
+ * revision check has been passed.
+ */
+ if (!mbox_revision < 0) {
+ pr_info("mbox: DSPCFG command received, "
+ "but revision check has not been passed.\n");
+ return;
+ }
+
+ switch (cfgcmd) {
+ case DSPCFG_SYSADRH:
+ tmp_ipb_adr = (u32)mb->data << 16;
+ break;
+
+ case DSPCFG_SYSADRL:
+ tmp_ipb_adr |= mb->data;
+ break;
+
+ case DSPCFG_ABORT:
+ goto abort1;
+
+ default:
+ printk(KERN_ERR
+ "mbox: Unknown CFG command: cmd_l=0x%02x, data=0x%04x\n",
+ mb->cmd_l, mb->data);
+ return;
+ }
+
+ if (last) {
+ void *badr;
+ u16 bln;
+ u16 bsz;
+ volatile u16 *buf;
+ void *ipb_sys_da, *ipb_sys_ad;
+ void *mbseq; /* FIXME: 3.4 obsolete */
+ short *dbg_buf;
+ u16 dbg_buf_sz, dbg_line_sz;
+ struct mem_sync_struct mem_sync, *mem_syncp;
+
+ ipb_sys_da = dspword_to_virt(tmp_ipb_adr);
+ if (ipbuf_sys_config(ipb_sys_da, DIR_D2A) < 0)
+ goto abort1;
+
+ if (dsp_mem_enable(ipbuf_sys_da) < 0) {
+ printk(KERN_ERR "mbox: DSPCFG - ipbuf_sys_da read failed!\n");
+ goto abort1;
+ }
+ if (sync_with_dsp(&ipbuf_sys_da->s, TID_ANON, 10) < 0) {
+ printk(KERN_ERR "mbox: DSPCFG - IPBUF sync failed!\n");
+ dsp_mem_disable(ipbuf_sys_da);
+ goto abort1;
+ }
+ /*
+ * read configuration data on system IPBUF
+ * we must read with 16bit-access
+ */
+#ifdef OLD_BINARY_SUPPORT
+ if (mbox_revision == MBPROT_REVISION) {
+#endif
+ buf = ipbuf_sys_da->d;
+ n_stask = buf[0];
+ bln = buf[1];
+ bsz = buf[2];
+ badr = MKVIRT(buf[3], buf[4]);
+ /* ipb_sys_da = MKVIRT(buf[5], buf[6]); */
+ ipb_sys_ad = MKVIRT(buf[7], buf[8]);
+ mbseq = MKVIRT(buf[9], buf[10]);
+ dbg_buf = MKVIRT(buf[11], buf[12]);
+ dbg_buf_sz = buf[13];
+ dbg_line_sz = buf[14];
+ mem_sync.DARAM = MKVIRT(buf[15], buf[16]);
+ mem_sync.SARAM = MKVIRT(buf[17], buf[18]);
+ mem_sync.SDRAM = MKVIRT(buf[19], buf[20]);
+ mem_syncp = &mem_sync;
+#ifdef OLD_BINARY_SUPPORT
+ } else if (mbox_revision == MBREV_3_2) {
+ buf = ipbuf_sys_da->d;
+ n_stask = buf[0];
+ bln = buf[1];
+ bsz = buf[2];
+ badr = MKVIRT(buf[3], buf[4]);
+ /* ipb_sys_da = MKVIRT(buf[5], buf[6]); */
+ ipb_sys_ad = MKVIRT(buf[7], buf[8]);
+ mbseq = MKVIRT(buf[9], buf[10]);
+ dbg_buf = NULL;
+ dbg_buf_sz = 0;
+ dbg_line_sz = 0;
+ mem_syncp = NULL;
+ } else if (mbox_revision == MBREV_3_0) {
+ buf = ipbuf_sys_da->d;
+ n_stask = buf[0];
+ bln = buf[1];
+ bsz = buf[2];
+ badr = MKVIRT(buf[3], buf[4]);
+ /* bkeep = buf[5]; */
+ /* ipb_sys_da = MKVIRT(buf[6], buf[7]); */
+ ipb_sys_ad = MKVIRT(buf[8], buf[9]);
+ mbseq = MKVIRT(buf[10], buf[11]);
+ dbg_buf = NULL;
+ dbg_buf_sz = 0;
+ dbg_line_sz = 0;
+ mem_syncp = NULL;
+ } else { /* should not occur */
+ dsp_mem_disable(ipbuf_sys_da);
+ goto abort1;
+ }
+#endif /* OLD_BINARY_SUPPORT */
+
+ release_ipbuf_pvt(ipbuf_sys_da);
+ dsp_mem_disable(ipbuf_sys_da);
+
+ /*
+ * following configurations need to be done before
+ * waking up the dspcfg initiator process.
+ */
+ if (ipbuf_sys_config(ipb_sys_ad, DIR_A2D) < 0)
+ goto abort1;
+ if (ipbuf_config(bln, bsz, badr) < 0)
+ goto abort1;
+ if (dsp_mbox_config(mbseq) < 0)
+ goto abort2;
+ if (dsp_dbg_config(dbg_buf, dbg_buf_sz, dbg_line_sz) < 0)
+ goto abort2;
+ if (dsp_mem_sync_config(mem_syncp) < 0)
+ goto abort2;
+
+ misc_mb_wait.cmd_h = 0;
+ wake_up_interruptible(&misc_mb_wait.wait_q);
+ }
+ return;
+
+abort2:
+ ipbuf_stop();
+abort1:
+ wake_up_interruptible(&misc_mb_wait.wait_q);
+ return;
+}
+
+void mbox_poll(struct mbcmd *mb)
+{
+ misc_mbcmd_response(mb, 0, 0);
+}
+
+void mbox_regrw(struct mbcmd *mb)
+{
+ switch (mb->cmd_l) {
+ case REGRW_DATA:
+ misc_mbcmd_response(mb, 1, 0);
+ break;
+ default:
+ printk(KERN_ERR
+ "mbox: Illegal REGRW command: "
+ "cmd_l=0x%02x, data=0x%04x\n", mb->cmd_l, mb->data);
+ return;
+ }
+}
+
+void mbox_getvar(struct mbcmd *mb)
+{
+ switch (mb->cmd_l) {
+ case VARID_ICRMASK:
+ misc_mbcmd_response(mb, 1, 1);
+ break;
+ case VARID_LOADINFO:
+ misc_mbcmd_response(mb, 5, 1);
+ break;
+ default:
+ printk(KERN_ERR
+ "mbox: Illegal GETVAR command: "
+ "cmd_l=0x%02x, data=0x%04x\n", mb->cmd_l, mb->data);
+ return;
+ }
+}
+
+void mbox_fbctl_disable(struct mbcmd *mb)
+{
+ misc_mbcmd_response(mb, 0, 0);
+}
+
+struct file_operations dsp_ctl_fops = {
+ .owner = THIS_MODULE,
+ .ioctl = dsp_ctl_ioctl,
+};
+
+/*
+ * sysfs files
+ */
+
+/* ifver */
+static ssize_t ifver_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int len = 0;
+
+ /*
+ * I/F VERSION descriptions:
+ *
+ * 3.2: sysfs / udev support
+ * KMEM_RESERVE / KMEM_RELEASE ioctls for mem device
+ * 3.3: added following ioctls
+ * DSPCTL_IOCTL_GBL_IDLE
+ * DSPCTL_IOCTL_CPU_IDLE (instead of DSPCTL_IOCTL_IDLE)
+ * DSPCTL_IOCTL_POLL
+ */
+
+ /*
+ * print all supporting I/F VERSIONs, like followings.
+ *
+ * len += sprintf(buf, "3.2\n");
+ * len += sprintf(buf, "3.3\n");
+ */
+ len += sprintf(buf + len, "3.2\n");
+ len += sprintf(buf + len, "3.3\n");
+
+ return len;
+}
+
+/* cpustat */
+static char *cpustat_name[CPUSTAT_MAX] = {
+ [CPUSTAT_RESET] = "reset",
+#ifdef CONFIG_ARCH_OMAP1
+ [CPUSTAT_GBL_IDLE] = "gbl_idle",
+ [CPUSTAT_CPU_IDLE] = "cpu_idle",
+#endif
+ [CPUSTAT_RUN] = "run",
+};
+
+static ssize_t cpustat_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%s\n", cpustat_name[dsp_cpustat_get_stat()]);
+}
+
+/* icrmask */
+static ssize_t icrmask_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "0x%04x\n", dsp_cpustat_get_icrmask());
+}
+
+static ssize_t icrmask_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ u16 mask;
+ int ret;
+
+ mask = simple_strtol(buf, NULL, 16);
+ dsp_cpustat_set_icrmask(mask);
+
+ if (dsp_cfgstat_get_stat() == CFGSTAT_READY) {
+ ret = dsp_setvar(VARID_ICRMASK, mask);
+ if (ret < 0)
+ return ret;
+ }
+
+ return count;
+}
+
+/* loadinfo */
+static ssize_t loadinfo_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int len;
+ int ret;
+ u16 val[5];
+
+ if ((ret = dsp_getvar(VARID_LOADINFO, val)) < 0)
+ return ret;
+
+ /*
+ * load info value range is 0(free) - 10000(busy):
+ * if CPU load is not measured on DSP, it sets 0xffff at val[0].
+ */
+
+ if (val[0] == 0xffff) {
+ len = sprintf(buf,
+ "currently DSP load info is not available.\n");
+ goto out;
+ }
+
+ len = sprintf(buf,
+ "DSP load info:\n"
+ " 10ms average = %3d.%02d%%\n"
+ " 1sec average = %3d.%02d%% busiest 10ms = %3d.%02d%%\n"
+ " 1min average = %3d.%02d%% busiest 1s = %3d.%02d%%\n",
+ val[0]/100, val[0]%100,
+ val[1]/100, val[1]%100, val[2]/100, val[2]%100,
+ val[3]/100, val[3]%100, val[4]/100, val[4]%100);
+out:
+ return len;
+}
+
+int __init dsp_ctl_init(void)
+{
+ int ret;
+
+ ret = device_create_file(omap_dsp->dev, &dev_attr_ifver);
+ if (unlikely(ret))
+ return ret;
+ ret = device_create_file(omap_dsp->dev, &dev_attr_cpustat);
+ if (unlikely(ret))
+ goto fail_create_cpustat;
+ ret = device_create_file(omap_dsp->dev, &dev_attr_icrmask);
+ if (unlikely(ret))
+ goto fail_create_icrmask;
+
+ return 0;
+
+fail_create_icrmask:
+ device_remove_file(omap_dsp->dev, &dev_attr_cpustat);
+fail_create_cpustat:
+ device_remove_file(omap_dsp->dev, &dev_attr_ifver);
+
+ return ret;
+}
+
+void dsp_ctl_exit(void)
+{
+ device_remove_file(omap_dsp->dev, &dev_attr_ifver);
+ device_remove_file(omap_dsp->dev, &dev_attr_cpustat);
+ device_remove_file(omap_dsp->dev, &dev_attr_icrmask);
+}
--- /dev/null
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2004-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/major.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include "dsp.h"
+
+#define CTL_MINOR 0
+#define MEM_MINOR 1
+#define TWCH_MINOR 2
+#define ERR_MINOR 3
+
+static struct class *dsp_ctl_class;
+extern struct file_operations dsp_ctl_fops,
+ dsp_mem_fops,
+ dsp_twch_fops,
+ dsp_err_fops;
+
+static int dsp_ctl_core_open(struct inode *inode, struct file *file)
+{
+ static DEFINE_MUTEX(open_lock);
+ int ret = 0;
+
+ if (mutex_lock_interruptible(&open_lock))
+ return -EINTR;
+ if (omap_dsp->initialized == 0) {
+ ret = dsp_late_init();
+ if (ret != 0) {
+ mutex_unlock(&open_lock);
+ return ret;
+ }
+ omap_dsp->initialized = 1;
+ }
+ mutex_unlock(&open_lock);
+
+ switch (iminor(inode)) {
+ case CTL_MINOR:
+ file->f_op = &dsp_ctl_fops;
+ break;
+ case MEM_MINOR:
+ file->f_op = &dsp_mem_fops;
+ break;
+ case TWCH_MINOR:
+ file->f_op = &dsp_twch_fops;
+ break;
+ case ERR_MINOR:
+ file->f_op = &dsp_err_fops;
+ break;
+ default:
+ return -ENXIO;
+ }
+ if (file->f_op && file->f_op->open)
+ return file->f_op->open(inode, file);
+ return 0;
+}
+
+static struct file_operations dsp_ctl_core_fops = {
+ .owner = THIS_MODULE,
+ .open = dsp_ctl_core_open,
+};
+
+static const struct dev_list {
+ unsigned int minor;
+ char *devname;
+ umode_t mode;
+} dev_list[] = {
+ {CTL_MINOR, "dspctl", S_IRUSR | S_IWUSR},
+ {MEM_MINOR, "dspmem", S_IRUSR | S_IWUSR | S_IRGRP},
+ {TWCH_MINOR, "dsptwch", S_IRUSR | S_IWUSR | S_IRGRP},
+ {ERR_MINOR, "dsperr", S_IRUSR | S_IRGRP},
+};
+
+int __init dsp_ctl_core_init(void)
+{
+ int retval;
+ int i;
+
+ retval = register_chrdev(OMAP_DSP_CTL_MAJOR, "dspctl",
+ &dsp_ctl_core_fops);
+ if (retval < 0) {
+ printk(KERN_ERR
+ "omapdsp: failed to register dspctl device: %d\n",
+ retval);
+ return retval;
+ }
+
+ dsp_ctl_class = class_create(THIS_MODULE, "dspctl");
+ for (i = 0; i < ARRAY_SIZE(dev_list); i++) {
+ device_create(dsp_ctl_class, NULL,
+ MKDEV(OMAP_DSP_CTL_MAJOR,
+ dev_list[i].minor),
+ dev_list[i].devname);
+ }
+
+ return 0;
+}
+
+void dsp_ctl_core_exit(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(dev_list); i++) {
+ device_destroy(dsp_ctl_class,
+ MKDEV(OMAP_DSP_CTL_MAJOR,
+ dev_list[i].minor));
+ }
+ class_destroy(dsp_ctl_class);
+
+ unregister_chrdev(OMAP_DSP_CTL_MAJOR, "dspctl");
+}
--- /dev/null
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __PLAT_OMAP_DSP_MBCMD_H
+#define __PLAT_OMAP_DSP_MBCMD_H
+/*
+ * mailbox command: 0x00 - 0x7f
+ * when a driver wants to use mailbox, it must reserve mailbox commands here.
+ */
+#define MBOX_CMD_DSP_WDSND 0x10
+#define MBOX_CMD_DSP_WDREQ 0x11
+#define MBOX_CMD_DSP_BKSND 0x20
+#define MBOX_CMD_DSP_BKREQ 0x21
+#define MBOX_CMD_DSP_BKYLD 0x23
+#define MBOX_CMD_DSP_BKSNDP 0x24
+#define MBOX_CMD_DSP_BKREQP 0x25
+#define MBOX_CMD_DSP_TCTL 0x30
+#define MBOX_CMD_DSP_TCTLDATA 0x31
+#define MBOX_CMD_DSP_POLL 0x32
+#define MBOX_CMD_DSP_WDT 0x50
+#define MBOX_CMD_DSP_RUNLEVEL 0x51
+#define MBOX_CMD_DSP_PM 0x52
+#define MBOX_CMD_DSP_SUSPEND 0x53
+#define MBOX_CMD_DSP_KFUNC 0x54
+#define MBOX_CMD_DSP_TCFG 0x60
+#define MBOX_CMD_DSP_TADD 0x62
+#define MBOX_CMD_DSP_TDEL 0x63
+#define MBOX_CMD_DSP_TSTOP 0x65
+#define MBOX_CMD_DSP_DSPCFG 0x70
+#define MBOX_CMD_DSP_REGRW 0x72
+#define MBOX_CMD_DSP_GETVAR 0x74
+#define MBOX_CMD_DSP_SETVAR 0x75
+#define MBOX_CMD_DSP_ERR 0x78
+#define MBOX_CMD_DSP_DBG 0x79
+
+/*
+ * DSP mailbox protocol definitions
+ */
+#define MBPROT_REVISION 0x0019
+
+#define TCTL_TINIT 0x0000
+#define TCTL_TEN 0x0001
+#define TCTL_TDIS 0x0002
+#define TCTL_TCLR 0x0003
+#define TCTL_TCLR_FORCE 0x0004
+
+#define RUNLEVEL_USER 0x01
+#define RUNLEVEL_SUPER 0x0e
+#define RUNLEVEL_RECOVERY 0x10
+
+#define PM_DISABLE 0x00
+#define PM_ENABLE 0x01
+
+#define KFUNC_FBCTL 0x00
+#define KFUNC_POWER 0x01
+
+#define FBCTL_UPD 0x0000
+#define FBCTL_ENABLE 0x0002
+#define FBCTL_DISABLE 0x0003
+
+/* KFUNC_POWER */
+#define AUDIO_PWR_UP 0x0000 /* ARM(exe/ack) <-> DSP(req) */
+#define AUDIO_PWR_DOWN 0x0001 /* ARM(exe) <- DSP(req) */
+#define AUDIO_PWR_DOWN1 AUDIO_PWR_DOWN
+#define AUDIO_PWR_DOWN2 0x0002
+#define DSP_PWR_UP 0x0003 /* ARM(exe/snd) -> DSP(exe) */
+#define DSP_PWR_DOWN 0x0004 /* ARM(exe) <- DSP(req) */
+#define DVFS_START 0x0006 /* ARM(req) <-> DSP(exe/ack)*/
+#define DVFS_STOP 0x0007 /* ARM(req) -> DSP(exe) */
+
+#define TDEL_SAFE 0x0000
+#define TDEL_KILL 0x0001
+
+#define DSPCFG_REQ 0x00
+#define DSPCFG_SYSADRH 0x28
+#define DSPCFG_SYSADRL 0x29
+#define DSPCFG_PROTREV 0x70
+#define DSPCFG_ABORT 0x78
+#define DSPCFG_LAST 0x80
+
+#define REGRW_MEMR 0x00
+#define REGRW_MEMW 0x01
+#define REGRW_IOR 0x02
+#define REGRW_IOW 0x03
+#define REGRW_DATA 0x04
+
+#define VARID_ICRMASK 0x00
+#define VARID_LOADINFO 0x01
+
+#define TTYP_ARCV 0x0001
+#define TTYP_ASND 0x0002
+#define TTYP_BKMD 0x0004
+#define TTYP_BKDM 0x0008
+#define TTYP_PVMD 0x0010
+#define TTYP_PVDM 0x0020
+
+#define EID_BADTID 0x10
+#define EID_BADTCN 0x11
+#define EID_BADBID 0x20
+#define EID_BADCNT 0x21
+#define EID_NOTLOCKED 0x22
+#define EID_STVBUF 0x23
+#define EID_BADADR 0x24
+#define EID_BADTCTL 0x30
+#define EID_BADPARAM 0x50
+#define EID_FATAL 0x58
+#define EID_NOMEM 0xc0
+#define EID_NORES 0xc1
+#define EID_IPBFULL 0xc2
+#define EID_WDT 0xd0
+#define EID_TASKNOTRDY 0xe0
+#define EID_TASKBSY 0xe1
+#define EID_TASKERR 0xef
+#define EID_BADCFGTYP 0xf0
+#define EID_DEBUG 0xf8
+#define EID_BADSEQ 0xfe
+#define EID_BADCMD 0xff
+
+#define TNM_LEN 16
+
+#define TID_FREE 0xff
+#define TID_ANON 0xfe
+
+#define BID_NULL 0xffff
+#define BID_PVT 0xfffe
+
+#endif /* __PLAT_OMAP_DSP_MBCMD_H */
--- /dev/null
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * Conversion to mempool API and ARM MMU section mapping
+ * by Paul Mundt <paul.mundt@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/fb.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/mempool.h>
+#include <linux/clk.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+#include <asm/arch/tc.h>
+#include <asm/arch/omapfb.h>
+#include <asm/arch/dsp.h>
+#include <asm/arch/mailbox.h>
+#include <asm/arch/mmu.h>
+#include "dsp_mbcmd.h"
+#include "dsp.h"
+#include "ipbuf.h"
+
+#if 0
+#if defined(CONFIG_ARCH_OMAP1)
+#include "../../mach-omap1/mmu.h"
+#elif defined(CONFIG_ARCH_OMAP2)
+#include "../../mach-omap2/mmu.h"
+#endif
+#endif
+
+#include "mmu.h"
+
+static struct mem_sync_struct mem_sync;
+
+int dsp_mem_sync_inc(void)
+{
+ if (dsp_mem_enable((void *)dspmem_base) < 0)
+ return -1;
+ if (mem_sync.DARAM)
+ mem_sync.DARAM->ad_arm++;
+ if (mem_sync.SARAM)
+ mem_sync.SARAM->ad_arm++;
+ if (mem_sync.SDRAM)
+ mem_sync.SDRAM->ad_arm++;
+ dsp_mem_disable((void *)dspmem_base);
+
+ return 0;
+}
+
+/*
+ * dsp_mem_sync_config() is called from mbox1 workqueue
+ */
+int dsp_mem_sync_config(struct mem_sync_struct *sync)
+{
+ size_t sync_seq_sz = sizeof(struct sync_seq);
+
+#ifdef OLD_BINARY_SUPPORT
+ if (sync == NULL) {
+ memset(&mem_sync, 0, sizeof(struct mem_sync_struct));
+ return 0;
+ }
+#endif
+ if ((dsp_mem_type(sync->DARAM, sync_seq_sz) != MEM_TYPE_DARAM) ||
+ (dsp_mem_type(sync->SARAM, sync_seq_sz) != MEM_TYPE_SARAM) ||
+ (dsp_mem_type(sync->SDRAM, sync_seq_sz) != MEM_TYPE_EXTERN)) {
+ printk(KERN_ERR
+ "omapdsp: mem_sync address validation failure!\n"
+ " mem_sync.DARAM = 0x%p,\n"
+ " mem_sync.SARAM = 0x%p,\n"
+ " mem_sync.SDRAM = 0x%p,\n",
+ sync->DARAM, sync->SARAM, sync->SDRAM);
+ return -1;
+ }
+
+ memcpy(&mem_sync, sync, sizeof(struct mem_sync_struct));
+
+ return 0;
+}
+
+
+enum dsp_mem_type_e dsp_mem_type(void *vadr, size_t len)
+{
+ void *ds = (void *)daram_base;
+ void *de = (void *)daram_base + daram_size;
+ void *ss = (void *)saram_base;
+ void *se = (void *)saram_base + saram_size;
+ int ret;
+
+ if ((vadr >= ds) && (vadr < de)) {
+ if (vadr + len > de)
+ return MEM_TYPE_CROSSING;
+ else
+ return MEM_TYPE_DARAM;
+ } else if ((vadr >= ss) && (vadr < se)) {
+ if (vadr + len > se)
+ return MEM_TYPE_CROSSING;
+ else
+ return MEM_TYPE_SARAM;
+ } else {
+ down_read(&dsp_mmu.exmap_sem);
+ if (exmap_valid(&dsp_mmu, vadr, len))
+ ret = MEM_TYPE_EXTERN;
+ else
+ ret = MEM_TYPE_NONE;
+ up_read(&dsp_mmu.exmap_sem);
+ return ret;
+ }
+}
+
+int dsp_address_validate(void *p, size_t len, char *fmt, ...)
+{
+ char s[64];
+ va_list args;
+
+ if (dsp_mem_type(p, len) > 0)
+ return 0;
+
+ if (fmt == NULL)
+ goto out;
+
+ va_start(args, fmt);
+ vsprintf(s, fmt, args);
+ va_end(args);
+ printk(KERN_ERR
+ "omapdsp: %s address(0x%p) and size(0x%x) is not valid!\n"
+ "(crossing different type of memories, or external memory\n"
+ "space where no actual memory is mapped)\n", s, p, len);
+ out:
+ return -1;
+}
+
+#ifdef CONFIG_OMAP_DSP_FBEXPORT
+
+static inline unsigned long lineup_offset(unsigned long adr,
+ unsigned long ref,
+ unsigned long mask)
+{
+ unsigned long newadr;
+
+ newadr = (adr & ~mask) | (ref & mask);
+ if (newadr < adr)
+ newadr += mask + 1;
+ return newadr;
+}
+
+/*
+ * fb update functions:
+ * fbupd_response() is executed by the workqueue.
+ * fbupd_cb() is called when fb update is done, in interrupt context.
+ * mbox_fbupd() is called when KFUNC:FBCTL:UPD is received from DSP.
+ */
+static void fbupd_response(struct work_struct *unused)
+{
+ int status;
+
+ status = mbcompose_send(KFUNC, KFUNC_FBCTL, FBCTL_UPD);
+ if (status == 0)
+ return;
+
+ /* FIXME: DSP is busy !! */
+ printk(KERN_ERR
+ "omapdsp:"
+ "DSP is busy when trying to send FBCTL:UPD response!\n");
+}
+
+static DECLARE_WORK(fbupd_response_work, fbupd_response);
+
+static void fbupd_cb(void *arg)
+{
+ schedule_work(&fbupd_response_work);
+}
+
+void mbox_fbctl_upd(void)
+{
+ struct omapfb_update_window win;
+ volatile unsigned short *buf = ipbuf_sys_da->d;
+
+ if (sync_with_dsp(&ipbuf_sys_da->s, TID_ANON, 5000) < 0) {
+ printk(KERN_ERR "mbox: FBCTL:UPD - IPBUF sync failed!\n");
+ return;
+ }
+ win.x = buf[0];
+ win.y = buf[1];
+ win.width = buf[2];
+ win.height = buf[3];
+ win.format = buf[4];
+ release_ipbuf_pvt(ipbuf_sys_da);
+
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+ if (!omapfb_ready) {
+ printk(KERN_WARNING
+ "omapdsp: fbupd() called while HWA742 is not ready!\n");
+ return;
+ }
+#endif
+ omapfb_update_window_async(registered_fb[0], &win, fbupd_cb, NULL);
+}
+
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+static int omapfb_notifier_cb(struct notifier_block *omapfb_nb,
+ unsigned long event, void *fbi)
+{
+ pr_info("omapfb_notifier_cb(): event = %s\n",
+ (event == OMAPFB_EVENT_READY) ? "READY" :
+ (event == OMAPFB_EVENT_DISABLED) ? "DISABLED" : "Unknown");
+ if (event == OMAPFB_EVENT_READY)
+ omapfb_ready = 1;
+ else if (event == OMAPFB_EVENT_DISABLED)
+ omapfb_ready = 0;
+ return 0;
+}
+#endif
+
+static int dsp_fbexport(dsp_long_t *dspadr)
+{
+ dsp_long_t dspadr_actual;
+ unsigned long padr_sys, padr, fbsz_sys, fbsz;
+ int cnt;
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+ int status;
+#endif
+
+ pr_debug( "omapdsp: frame buffer export\n");
+
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+ if (omapfb_nb) {
+ printk(KERN_WARNING
+ "omapdsp: frame buffer has been exported already!\n");
+ return -EBUSY;
+ }
+#endif
+
+ if (num_registered_fb == 0) {
+ pr_info("omapdsp: frame buffer not registered.\n");
+ return -EINVAL;
+ }
+ if (num_registered_fb != 1) {
+ pr_info("omapdsp: %d frame buffers found. we use first one.\n",
+ num_registered_fb);
+ }
+ padr_sys = registered_fb[0]->fix.smem_start;
+ fbsz_sys = registered_fb[0]->fix.smem_len;
+ if (fbsz_sys == 0) {
+ printk(KERN_ERR
+ "omapdsp: framebuffer doesn't seem to be configured "
+ "correctly! (size=0)\n");
+ return -EINVAL;
+ }
+
+ /*
+ * align padr and fbsz to 4kB boundary
+ * (should be noted to the user afterwards!)
+ */
+ padr = padr_sys & ~(SZ_4K-1);
+ fbsz = (fbsz_sys + padr_sys - padr + SZ_4K-1) & ~(SZ_4K-1);
+
+ /* line up dspadr offset with padr */
+ dspadr_actual =
+ (fbsz > SZ_1M) ? lineup_offset(*dspadr, padr, SZ_1M-1) :
+ (fbsz > SZ_64K) ? lineup_offset(*dspadr, padr, SZ_64K-1) :
+ /* (fbsz > SZ_4KB) ? */ *dspadr;
+ if (dspadr_actual != *dspadr)
+ pr_debug(
+ "omapdsp: actual dspadr for FBEXPORT = %08x\n",
+ dspadr_actual);
+ *dspadr = dspadr_actual;
+
+ cnt = omap_mmu_exmap(&dsp_mmu, dspadr_actual, padr, fbsz,
+ EXMAP_TYPE_FB);
+ if (cnt < 0) {
+ printk(KERN_ERR "omapdsp: exmap failure.\n");
+ return cnt;
+ }
+
+ if ((padr != padr_sys) || (fbsz != fbsz_sys)) {
+ printk(KERN_WARNING
+" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
+" !! screen base address or size is not aligned in 4kB: !!\n"
+" !! actual screen adr = %08lx, size = %08lx !!\n"
+" !! exporting adr = %08lx, size = %08lx !!\n"
+" !! Make sure that the framebuffer is allocated with 4kB-order! !!\n"
+" !! Otherwise DSP can corrupt the kernel memory. !!\n"
+" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n",
+ padr_sys, fbsz_sys, padr, fbsz);
+ }
+
+ /* increase the DMA priority */
+ set_emiff_dma_prio(15);
+
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+ omapfb_nb = kzalloc(sizeof(struct omapfb_notifier_block), GFP_KERNEL);
+ if (omapfb_nb == NULL) {
+ printk(KERN_ERR
+ "omapdsp: failed to allocate memory for omapfb_nb!\n");
+ omap_mmu_exunmap(&dsp_mmu, (unsigned long)dspadr);
+ return -ENOMEM;
+ }
+
+ status = omapfb_register_client(omapfb_nb, omapfb_notifier_cb, NULL);
+ if (status)
+ pr_info("omapfb_register_client(): failure(%d)\n", status);
+#endif
+
+ return cnt;
+}
+#else
+void mbox_fbctl_upd(void) { }
+#endif
+
+/* dsp/mem fops: backward compatibility */
+static ssize_t dsp_mem_read(struct file *file, char __user *buf, size_t count,
+ loff_t *ppos)
+{
+ struct bin_attribute attr;
+
+ return __omap_mmu_mem_read(&dsp_mmu, &attr,
+ (char __user *)buf, *ppos, count);
+}
+
+static ssize_t dsp_mem_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct bin_attribute attr;
+
+ return __omap_mmu_mem_write(&dsp_mmu, &attr,
+ (char __user *)buf, *ppos, count);
+}
+
+static int dsp_mem_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct omap_dsp_mapinfo mapinfo;
+ __u32 size;
+
+ switch (cmd) {
+ case MEM_IOCTL_MMUINIT:
+ if (dsp_mmu.exmap_tbl)
+ omap_mmu_unregister(&dsp_mmu);
+ dsp_mem_ipi_init();
+ return omap_mmu_register(&dsp_mmu);
+
+ case MEM_IOCTL_EXMAP:
+ if (copy_from_user(&mapinfo, (void __user *)arg,
+ sizeof(mapinfo)))
+ return -EFAULT;
+ return omap_mmu_exmap(&dsp_mmu, mapinfo.dspadr,
+ 0, mapinfo.size, EXMAP_TYPE_MEM);
+
+ case MEM_IOCTL_EXUNMAP:
+ return omap_mmu_exunmap(&dsp_mmu, (unsigned long)arg);
+
+ case MEM_IOCTL_EXMAP_FLUSH:
+ omap_mmu_exmap_flush(&dsp_mmu);
+ return 0;
+#ifdef CONFIG_OMAP_DSP_FBEXPORT
+ case MEM_IOCTL_FBEXPORT:
+ {
+ dsp_long_t dspadr;
+ int ret;
+ if (copy_from_user(&dspadr, (void __user *)arg,
+ sizeof(dsp_long_t)))
+ return -EFAULT;
+ ret = dsp_fbexport(&dspadr);
+ if (copy_to_user((void __user *)arg, &dspadr,
+ sizeof(dsp_long_t)))
+ return -EFAULT;
+ return ret;
+ }
+#endif
+ case MEM_IOCTL_MMUITACK:
+ return dsp_mmu_itack();
+
+ case MEM_IOCTL_KMEM_RESERVE:
+
+ if (copy_from_user(&size, (void __user *)arg,
+ sizeof(__u32)))
+ return -EFAULT;
+ return omap_mmu_kmem_reserve(&dsp_mmu, size);
+
+
+ case MEM_IOCTL_KMEM_RELEASE:
+ omap_mmu_kmem_release();
+ return 0;
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
+struct file_operations dsp_mem_fops = {
+ .owner = THIS_MODULE,
+ .read = dsp_mem_read,
+ .write = dsp_mem_write,
+ .ioctl = dsp_mem_ioctl,
+};
+
+void dsp_mem_start(void)
+{
+ dsp_register_mem_cb(intmem_enable, intmem_disable);
+}
+
+void dsp_mem_stop(void)
+{
+ memset(&mem_sync, 0, sizeof(struct mem_sync_struct));
+ dsp_unregister_mem_cb();
+}
+
+static void dsp_mmu_irq_work(struct work_struct *work)
+{
+ struct omap_mmu *mmu = container_of(work, struct omap_mmu, irq_work);
+
+ if (dsp_cfgstat_get_stat() == CFGSTAT_READY) {
+ dsp_err_set(ERRCODE_MMU, mmu->fault_address);
+ return;
+ }
+ omap_mmu_itack(mmu);
+ pr_info("Resetting DSP...\n");
+ dsp_cpustat_request(CPUSTAT_RESET);
+ omap_mmu_enable(mmu, 0);
+}
+
+/*
+ * later half of dsp memory initialization
+ */
+int dsp_mem_late_init(void)
+{
+ int ret;
+
+ dsp_mem_ipi_init();
+
+ INIT_WORK(&dsp_mmu.irq_work, dsp_mmu_irq_work);
+ ret = omap_mmu_register(&dsp_mmu);
+ if (ret) {
+ dsp_reset_idle_boot_base();
+ goto out;
+ }
+ omap_dsp->mmu = &dsp_mmu;
+ out:
+ return ret;
+}
+
+int __init dsp_mem_init(void)
+{
+#ifdef CONFIG_ARCH_OMAP2
+ dsp_mmu.clk = dsp_fck_handle;
+ dsp_mmu.memclk = dsp_ick_handle;
+#elif defined(CONFIG_ARCH_OMAP1)
+ dsp_mmu.clk = dsp_ck_handle;
+ dsp_mmu.memclk = api_ck_handle;
+#endif
+ return 0;
+}
+
+void dsp_mem_exit(void)
+{
+ dsp_reset_idle_boot_base();
+ omap_mmu_unregister(&dsp_mmu);
+}
--- /dev/null
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <asm/arch/mailbox.h>
+#include <asm/uaccess.h>
+#include "dsp_mbcmd.h"
+#include "dsp.h"
+
+/*
+ * value seen through read()
+ */
+#define DSP_ERR_WDT 0x00000001
+#define DSP_ERR_MMU 0x00000002
+static unsigned long errval;
+
+static DECLARE_WAIT_QUEUE_HEAD(err_wait_q);
+static int errcnt;
+static u16 wdtval; /* FIXME: read through ioctl */
+static u32 mmu_fadr; /* FIXME: read through ioctl */
+
+/*
+ * DSP error detection device file operations
+ */
+static ssize_t dsp_err_read(struct file *file, char __user *buf, size_t count,
+ loff_t *ppos)
+{
+ unsigned long flags;
+ int status;
+ DEFINE_WAIT(wait);
+
+ if (count < 4)
+ return 0;
+
+ prepare_to_wait(&err_wait_q, &wait, TASK_INTERRUPTIBLE);
+ if (errcnt == 0)
+ schedule();
+ finish_wait(&err_wait_q, &wait);
+ if (signal_pending(current))
+ return -EINTR;
+
+ local_irq_save(flags);
+ status = copy_to_user(buf, &errval, 4);
+ if (status) {
+ local_irq_restore(flags);
+ return -EFAULT;
+ }
+ errcnt = 0;
+ local_irq_restore(flags);
+
+ return 4;
+}
+
+static unsigned int dsp_err_poll(struct file *file, poll_table *wait)
+{
+ unsigned int mask = 0;
+
+ poll_wait(file, &err_wait_q, wait);
+ if (errcnt != 0)
+ mask |= POLLIN | POLLRDNORM;
+
+ return mask;
+}
+
+struct file_operations dsp_err_fops = {
+ .owner = THIS_MODULE,
+ .poll = dsp_err_poll,
+ .read = dsp_err_read,
+};
+
+/*
+ * set / clear functions
+ */
+
+/* DSP MMU */
+static void dsp_err_mmu_set(unsigned long arg)
+{
+ disable_irq(omap_dsp->mmu->irq);
+ mmu_fadr = (u32)arg;
+}
+
+static void dsp_err_mmu_clr(void)
+{
+ enable_irq(omap_dsp->mmu->irq);
+}
+
+/* WDT */
+static void dsp_err_wdt_set(unsigned long arg)
+{
+ wdtval = (u16)arg;
+}
+
+/*
+ * error code handler
+ */
+static struct {
+ unsigned long val;
+ void (*set)(unsigned long arg);
+ void (*clr)(void);
+} dsp_err_desc[ERRCODE_MAX] = {
+ [ERRCODE_MMU] = { DSP_ERR_MMU, dsp_err_mmu_set, dsp_err_mmu_clr },
+ [ERRCODE_WDT] = { DSP_ERR_WDT, dsp_err_wdt_set, NULL },
+};
+
+void dsp_err_set(enum errcode_e code, unsigned long arg)
+{
+ if (dsp_err_desc[code].set != NULL)
+ dsp_err_desc[code].set(arg);
+
+ errval |= dsp_err_desc[code].val;
+ errcnt++;
+ wake_up_interruptible(&err_wait_q);
+}
+
+void dsp_err_clear(enum errcode_e code)
+{
+ errval &= ~dsp_err_desc[code].val;
+
+ if (dsp_err_desc[code].clr != NULL)
+ dsp_err_desc[code].clr();
+}
+
+int dsp_err_isset(enum errcode_e code)
+{
+ return (errval & dsp_err_desc[code].val) ? 1 : 0;
+}
+
+void dsp_err_notify(void)
+{
+ /* new error code should be assigned */
+ dsp_err_set(DSP_ERR_WDT, 0);
+}
+
+/*
+ * functions called from mailbox interrupt routine
+ */
+static void mbox_err_wdt(u16 data)
+{
+ dsp_err_set(DSP_ERR_WDT, (unsigned long)data);
+}
+
+#ifdef OLD_BINARY_SUPPORT
+/* v3.3 obsolete */
+void mbox_wdt(struct mbcmd *mb)
+{
+ mbox_err_wdt(mb->data);
+}
+#endif
+
+extern void mbox_err_ipbfull(void);
+extern void mbox_err_fatal(u8 tid);
+
+void mbox_err(struct mbcmd *mb)
+{
+ u8 eid = mb->cmd_l;
+ char *eidnm = subcmd_name(mb);
+ u8 tid;
+
+ if (eidnm) {
+ printk(KERN_WARNING
+ "mbox: ERR from DSP (%s): 0x%04x\n", eidnm, mb->data);
+ } else {
+ printk(KERN_WARNING
+ "mbox: ERR from DSP (unknown EID=%02x): %04x\n",
+ eid, mb->data);
+ }
+
+ switch (eid) {
+ case EID_IPBFULL:
+ mbox_err_ipbfull();
+ break;
+
+ case EID_FATAL:
+ tid = mb->data & 0x00ff;
+ mbox_err_fatal(tid);
+ break;
+
+ case EID_WDT:
+ mbox_err_wdt(mb->data);
+ break;
+ }
+}
+
+/*
+ *
+ */
+void dsp_err_start(void)
+{
+ enum errcode_e i;
+
+ for (i = 0; i < ERRCODE_MAX; i++) {
+ if (dsp_err_isset(i))
+ dsp_err_clear(i);
+ }
+ omap_dsp->mbox->err_notify = dsp_err_notify;
+ errcnt = 0;
+}
+
+void dsp_err_stop(void)
+{
+ wake_up_interruptible(&err_wait_q);
+ omap_dsp->mbox->err_notify = NULL;
+}
--- /dev/null
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __OMAP_DSP_HARDWARE_DSP_H
+#define __OMAP_DSP_HARDWARE_DSP_H
+
+#ifdef CONFIG_ARCH_OMAP1
+#include "omap1_dsp.h"
+#endif
+#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3430)
+#include "omap2_dsp.h"
+#endif
+
+#endif /* __OMAP_DSP_HARDWARE_DSP_H */
--- /dev/null
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/sched.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <asm/arch/mailbox.h>
+#include "dsp_mbcmd.h"
+#include "dsp.h"
+#include "ipbuf.h"
+
+static struct ipbuf_head *g_ipbuf;
+struct ipbcfg ipbcfg;
+struct ipbuf_sys *ipbuf_sys_da, *ipbuf_sys_ad;
+static struct ipblink ipb_free = IPBLINK_INIT;
+static int ipbuf_sys_hold_mem_active;
+
+static ssize_t ipbuf_show(struct device *dev, struct device_attribute *attr,
+ char *buf);
+static struct device_attribute dev_attr_ipbuf = __ATTR_RO(ipbuf);
+
+void ipbuf_stop(void)
+{
+ int i;
+
+ device_remove_file(omap_dsp->dev, &dev_attr_ipbuf);
+
+ spin_lock(&ipb_free.lock);
+ RESET_IPBLINK(&ipb_free);
+ spin_unlock(&ipb_free.lock);
+
+ ipbcfg.ln = 0;
+ if (g_ipbuf) {
+ kfree(g_ipbuf);
+ g_ipbuf = NULL;
+ }
+ for (i = 0; i < ipbuf_sys_hold_mem_active; i++) {
+ dsp_mem_disable((void *)daram_base);
+ }
+ ipbuf_sys_hold_mem_active = 0;
+}
+
+int ipbuf_config(u16 ln, u16 lsz, void *base)
+{
+ size_t lsz_byte = ((size_t)lsz) << 1;
+ size_t size;
+ int ret = 0;
+ int i;
+
+ /*
+ * global IPBUF
+ */
+ if (((unsigned long)base) & 0x3) {
+ printk(KERN_ERR
+ "omapdsp: global ipbuf address(0x%p) is not "
+ "32-bit aligned!\n", base);
+ return -EINVAL;
+ }
+ size = lsz_byte * ln;
+ if (dsp_address_validate(base, size, "global ipbuf") < 0)
+ return -EINVAL;
+
+ g_ipbuf = kmalloc(sizeof(struct ipbuf_head) * ln, GFP_KERNEL);
+ if (g_ipbuf == NULL) {
+ printk(KERN_ERR
+ "omapdsp: memory allocation for ipbuf failed.\n");
+ return -ENOMEM;
+ }
+ for (i = 0; i < ln; i++) {
+ void *top, *btm;
+
+ top = base + (sizeof(struct ipbuf) + lsz_byte) * i;
+ btm = base + (sizeof(struct ipbuf) + lsz_byte) * (i+1) - 1;
+ g_ipbuf[i].p = (struct ipbuf *)top;
+ g_ipbuf[i].bid = i;
+ if (((unsigned long)top & 0xfffe0000) !=
+ ((unsigned long)btm & 0xfffe0000)) {
+ /*
+ * an ipbuf line should not cross
+ * 64k-word boundary.
+ */
+ printk(KERN_ERR
+ "omapdsp: ipbuf[%d] crosses 64k-word boundary!\n"
+ " @0x%p, size=0x%08x\n", i, top, lsz_byte);
+ ret = -EINVAL;
+ goto free_out;
+ }
+ }
+ ipbcfg.ln = ln;
+ ipbcfg.lsz = lsz;
+ ipbcfg.base = base;
+ ipbcfg.bsycnt = ln; /* DSP holds all ipbufs initially. */
+ ipbcfg.cnt_full = 0;
+
+ pr_info("omapdsp: IPBUF configuration\n"
+ " %d words * %d lines at 0x%p.\n",
+ ipbcfg.lsz, ipbcfg.ln, ipbcfg.base);
+
+ ret = device_create_file(omap_dsp->dev, &dev_attr_ipbuf);
+ if (ret)
+ printk(KERN_ERR "device_create_file failed: %d\n", ret);
+
+ return ret;
+
+ free_out:
+ kfree(g_ipbuf);
+ g_ipbuf = NULL;
+ return ret;
+}
+
+int ipbuf_sys_config(void *p, arm_dsp_dir_t dir)
+{
+ char *dir_str = (dir == DIR_D2A) ? "D2A" : "A2D";
+
+ if (((unsigned long)p) & 0x3) {
+ printk(KERN_ERR
+ "omapdsp: system ipbuf(%s) address(0x%p) is "
+ "not 32-bit aligned!\n", dir_str, p);
+ return -1;
+ }
+ if (dsp_address_validate(p, sizeof(struct ipbuf_sys),
+ "system ipbuf(%s)", dir_str) < 0)
+ return -1;
+ if (dsp_mem_type(p, sizeof(struct ipbuf_sys)) != MEM_TYPE_EXTERN) {
+ printk(KERN_WARNING
+ "omapdsp: system ipbuf(%s) is placed in"
+ " DSP internal memory.\n"
+ " It will prevent DSP from idling.\n", dir_str);
+ ipbuf_sys_hold_mem_active++;
+ /*
+ * dsp_mem_enable() never fails because
+ * it has been already enabled in dspcfg process and
+ * this will just increment the usecount.
+ */
+ dsp_mem_enable((void *)daram_base);
+ }
+
+ if (dir == DIR_D2A)
+ ipbuf_sys_da = p;
+ else
+ ipbuf_sys_ad = p;
+
+ return 0;
+}
+
+int ipbuf_p_validate(void *p, arm_dsp_dir_t dir)
+{
+ char *dir_str = (dir == DIR_D2A) ? "D2A" : "A2D";
+
+ if (((unsigned long)p) & 0x3) {
+ printk(KERN_ERR
+ "omapdsp: private ipbuf(%s) address(0x%p) is "
+ "not 32-bit aligned!\n", dir_str, p);
+ return -1;
+ }
+ return dsp_address_validate(p, sizeof(struct ipbuf_p),
+ "private ipbuf(%s)", dir_str);
+}
+
+/*
+ * Global IPBUF operations
+ */
+struct ipbuf_head *bid_to_ipbuf(u16 bid)
+{
+ return &g_ipbuf[bid];
+}
+
+struct ipbuf_head *get_free_ipbuf(u8 tid)
+{
+ struct ipbuf_head *ipb_h;
+
+ if (dsp_mem_enable_ipbuf() < 0)
+ return NULL;
+
+ spin_lock(&ipb_free.lock);
+
+ if (ipblink_empty(&ipb_free)) {
+ /* FIXME: wait on queue when not available. */
+ ipb_h = NULL;
+ goto out;
+ }
+ ipb_h = &g_ipbuf[ipb_free.top];
+ ipb_h->p->la = tid; /* lock */
+ __ipblink_del_top(&ipb_free);
+out:
+ spin_unlock(&ipb_free.lock);
+ dsp_mem_disable_ipbuf();
+
+ return ipb_h;
+}
+
+void release_ipbuf(struct ipbuf_head *ipb_h)
+{
+ if (ipb_h->p->la == TID_FREE) {
+ printk(KERN_WARNING
+ "omapdsp: attempt to release unlocked IPBUF[%d].\n",
+ ipb_h->bid);
+ /*
+ * FIXME: re-calc bsycnt
+ */
+ return;
+ }
+ ipb_h->p->la = TID_FREE;
+ ipb_h->p->sa = TID_FREE;
+ ipblink_add_tail(&ipb_free, ipb_h->bid);
+}
+
+static int try_yld(struct ipbuf_head *ipb_h)
+{
+ int status;
+
+ ipb_h->p->sa = TID_ANON;
+ status = mbcompose_send(BKYLD, 0, ipb_h->bid);
+ if (status < 0) {
+ /* DSP is busy and ARM keeps this line. */
+ release_ipbuf(ipb_h);
+ return status;
+ }
+
+ ipb_bsycnt_inc(&ipbcfg);
+ return 0;
+}
+
+/*
+ * balancing ipbuf lines with DSP
+ */
+static void do_balance_ipbuf(struct work_struct *unused)
+{
+ while (ipbcfg.bsycnt <= ipbcfg.ln / 4) {
+ struct ipbuf_head *ipb_h;
+
+ if ((ipb_h = get_free_ipbuf(TID_ANON)) == NULL)
+ return;
+ if (try_yld(ipb_h) < 0)
+ return;
+ }
+}
+
+static DECLARE_WORK(balance_ipbuf_work, do_balance_ipbuf);
+
+void balance_ipbuf(void)
+{
+ schedule_work(&balance_ipbuf_work);
+}
+
+/* for process context */
+void unuse_ipbuf(struct ipbuf_head *ipb_h)
+{
+ if (ipbcfg.bsycnt > ipbcfg.ln / 4) {
+ /* we don't have enough IPBUF lines. let's keep it. */
+ release_ipbuf(ipb_h);
+ } else {
+ /* we have enough IPBUF lines. let's return this line to DSP. */
+ ipb_h->p->la = TID_ANON;
+ try_yld(ipb_h);
+ balance_ipbuf();
+ }
+}
+
+/* for interrupt context */
+void unuse_ipbuf_nowait(struct ipbuf_head *ipb_h)
+{
+ release_ipbuf(ipb_h);
+ balance_ipbuf();
+}
+
+/*
+ * functions called from mailbox interrupt routine
+ */
+
+void mbox_err_ipbfull(void)
+{
+ ipbcfg.cnt_full++;
+}
+
+/*
+ * sysfs files
+ */
+static ssize_t ipbuf_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int len = 0;
+ u16 bid;
+
+ for (bid = 0; bid < ipbcfg.ln; bid++) {
+ struct ipbuf_head *ipb_h = &g_ipbuf[bid];
+ u16 la = ipb_h->p->la;
+ u16 ld = ipb_h->p->ld;
+ u16 c = ipb_h->p->c;
+
+ if (len > PAGE_SIZE - 100) {
+ len += sprintf(buf + len, "out of buffer.\n");
+ goto finish;
+ }
+
+ len += sprintf(buf + len, "ipbuf[%d]: adr = 0x%p\n",
+ bid, ipb_h->p);
+ if (la == TID_FREE) {
+ len += sprintf(buf + len,
+ " DSPtask[%d]->Linux "
+ "(already read and now free for Linux)\n",
+ ld);
+ } else if (ld == TID_FREE) {
+ len += sprintf(buf + len,
+ " Linux->DSPtask[%d] "
+ "(already read and now free for DSP)\n",
+ la);
+ } else if (ipbuf_is_held(ld, bid)) {
+ len += sprintf(buf + len,
+ " DSPtask[%d]->Linux "
+ "(waiting to be read)\n"
+ " count = %d\n", ld, c);
+ } else {
+ len += sprintf(buf + len,
+ " Linux->DSPtask[%d] "
+ "(waiting to be read)\n"
+ " count = %d\n", la, c);
+ }
+ }
+
+ len += sprintf(buf + len, "\nFree IPBUF link: ");
+ spin_lock(&ipb_free.lock);
+ ipblink_for_each(bid, &ipb_free) {
+ len += sprintf(buf + len, "%d ", bid);
+ }
+ spin_unlock(&ipb_free.lock);
+ len += sprintf(buf + len, "\n");
+ len += sprintf(buf + len, "IPBFULL error count: %ld\n",
+ ipbcfg.cnt_full);
+
+finish:
+ return len;
+}
--- /dev/null
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __PLAT_OMAP_DSP_IPBUF_H
+#define __PLAT_OMAP_DSP_IPBUF_H
+
+struct ipbuf {
+ u16 c; /* count */
+ u16 next; /* link */
+ u16 la; /* lock owner (ARM side) */
+ u16 sa; /* sync word (ARM->DSP) */
+ u16 ld; /* lock owner (DSP side) */
+ u16 sd; /* sync word (DSP->ARM) */
+ unsigned char d[0]; /* data */
+};
+
+struct ipbuf_p {
+ u16 c; /* count */
+ u16 s; /* sync word */
+ u16 al; /* data address lower */
+ u16 ah; /* data address upper */
+};
+
+#define IPBUF_SYS_DLEN 31
+
+struct ipbuf_sys {
+ u16 s; /* sync word */
+ u16 d[IPBUF_SYS_DLEN]; /* data */
+};
+
+struct ipbcfg {
+ u16 ln;
+ u16 lsz;
+ void *base;
+ u16 bsycnt;
+ unsigned long cnt_full; /* count of IPBFULL error */
+};
+
+struct ipbuf_head {
+ u16 bid;
+ struct ipbuf *p;
+};
+
+extern struct ipbcfg ipbcfg;
+extern struct ipbuf_sys *ipbuf_sys_da, *ipbuf_sys_ad;
+
+#define ipb_bsycnt_inc(ipbcfg) atomic_inc((atomic_t *)&((ipbcfg)->bsycnt))
+#define ipb_bsycnt_dec(ipbcfg) atomic_dec((atomic_t *)&((ipbcfg)->bsycnt))
+
+#define dsp_mem_enable_ipbuf() dsp_mem_enable(ipbcfg.base)
+#define dsp_mem_disable_ipbuf() dsp_mem_disable(ipbcfg.base)
+
+struct ipblink {
+ spinlock_t lock;
+ u16 top;
+ u16 tail;
+};
+
+#define IPBLINK_INIT { \
+ .lock = SPIN_LOCK_UNLOCKED, \
+ .top = BID_NULL, \
+ .tail = BID_NULL, \
+ }
+
+#define INIT_IPBLINK(link) \
+ do { \
+ spin_lock_init(&(link)->lock); \
+ (link)->top = BID_NULL; \
+ (link)->tail = BID_NULL; \
+ } while(0)
+
+#define RESET_IPBLINK(link) \
+ do { \
+ (link)->top = BID_NULL; \
+ (link)->tail = BID_NULL; \
+ } while(0)
+
+#define ipblink_empty(link) ((link)->top == BID_NULL)
+
+static inline void __ipblink_del_top(struct ipblink *link)
+{
+ struct ipbuf_head *ipb_h = bid_to_ipbuf(link->top);
+
+ if ((link->top = ipb_h->p->next) == BID_NULL)
+ link->tail = BID_NULL;
+ else
+ ipb_h->p->next = BID_NULL;
+}
+
+static inline void ipblink_del_top(struct ipblink *link)
+{
+ spin_lock(&link->lock);
+ __ipblink_del_top(link);
+ spin_unlock(&link->lock);
+}
+
+static inline void __ipblink_add_tail(struct ipblink *link, u16 bid)
+{
+ if (ipblink_empty(link))
+ link->top = bid;
+ else
+ bid_to_ipbuf(link->tail)->p->next = bid;
+ link->tail = bid;
+}
+
+static inline void ipblink_add_tail(struct ipblink *link, u16 bid)
+{
+ spin_lock(&link->lock);
+ __ipblink_add_tail(link, bid);
+ spin_unlock(&link->lock);
+}
+
+static inline void __ipblink_flush(struct ipblink *link)
+{
+ u16 bid;
+
+ while (!ipblink_empty(link)) {
+ bid = link->top;
+ __ipblink_del_top(link);
+ unuse_ipbuf(bid_to_ipbuf(bid));
+ }
+}
+
+static inline void ipblink_flush(struct ipblink *link)
+{
+ spin_lock(&link->lock);
+ __ipblink_flush(link);
+ spin_unlock(&link->lock);
+}
+
+static inline void __ipblink_add_pvt(struct ipblink *link)
+{
+ link->top = BID_PVT;
+ link->tail = BID_PVT;
+}
+
+static inline void ipblink_add_pvt(struct ipblink *link)
+{
+ spin_lock(&link->lock);
+ __ipblink_add_pvt(link);
+ spin_unlock(&link->lock);
+}
+
+static inline void __ipblink_del_pvt(struct ipblink *link)
+{
+ link->top = BID_NULL;
+ link->tail = BID_NULL;
+}
+
+static inline void ipblink_del_pvt(struct ipblink *link)
+{
+ spin_lock(&link->lock);
+ __ipblink_del_pvt(link);
+ spin_unlock(&link->lock);
+}
+
+static inline void __ipblink_flush_pvt(struct ipblink *link)
+{
+ if (!ipblink_empty(link))
+ ipblink_del_pvt(link);
+}
+
+static inline void ipblink_flush_pvt(struct ipblink *link)
+{
+ spin_lock(&link->lock);
+ __ipblink_flush_pvt(link);
+ spin_unlock(&link->lock);
+}
+
+#define ipblink_for_each(bid, link) \
+ for (bid = (link)->top; bid != BID_NULL; bid = bid_to_ipbuf(bid)->p->next)
+
+#endif /* __PLAT_OMAP_DSP_IPBUF_H */
--- /dev/null
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2003-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <asm/arch/mailbox.h>
+#include "dsp_mbcmd.h"
+#include "dsp.h"
+
+char *subcmd_name(struct mbcmd *mb)
+{
+ u8 cmd_h = mb->cmd_h;
+ u8 cmd_l = mb->cmd_l;
+ char *s;
+
+ switch (cmd_h) {
+ case MBOX_CMD_DSP_RUNLEVEL:
+ s = (cmd_l == RUNLEVEL_USER) ? "USER":
+ (cmd_l == RUNLEVEL_SUPER) ? "SUPER":
+ (cmd_l == RUNLEVEL_RECOVERY) ? "RECOVERY":
+ NULL;
+ break;
+ case MBOX_CMD_DSP_PM:
+ s = (cmd_l == PM_DISABLE) ? "DISABLE":
+ (cmd_l == PM_ENABLE) ? "ENABLE":
+ NULL;
+ break;
+ case MBOX_CMD_DSP_KFUNC:
+ s = (cmd_l == KFUNC_FBCTL) ? "FBCTL":
+ (cmd_l == KFUNC_POWER) ?
+ ((mb->data == AUDIO_PWR_UP) ? "PWR AUD /UP":
+ (mb->data == AUDIO_PWR_DOWN) ? "PWR AUD /DOWN":
+ (mb->data == AUDIO_PWR_DOWN2) ? "PWR AUD /DOWN(2)":
+ (mb->data == DSP_PWR_UP) ? "PWR DSP /UP":
+ (mb->data == DSP_PWR_DOWN) ? "PWR DSP /DOWN":
+ (mb->data == DVFS_START) ? "PWR DVFS/START":
+ (mb->data == DVFS_STOP) ? "PWR DVFS/STOP":
+ NULL):
+
+ NULL;
+ break;
+ case MBOX_CMD_DSP_DSPCFG:
+ {
+ u8 cfgc = cmd_l & 0x7f;
+ s = (cfgc == DSPCFG_REQ) ? "REQ":
+ (cfgc == DSPCFG_SYSADRH) ? "SYSADRH":
+ (cfgc == DSPCFG_SYSADRL) ? "SYSADRL":
+ (cfgc == DSPCFG_ABORT) ? "ABORT":
+ (cfgc == DSPCFG_PROTREV) ? "PROTREV":
+ NULL;
+ break;
+ }
+ case MBOX_CMD_DSP_REGRW:
+ s = (cmd_l == REGRW_MEMR) ? "MEMR":
+ (cmd_l == REGRW_MEMW) ? "MEMW":
+ (cmd_l == REGRW_IOR) ? "IOR":
+ (cmd_l == REGRW_IOW) ? "IOW":
+ (cmd_l == REGRW_DATA) ? "DATA":
+ NULL;
+ break;
+ case MBOX_CMD_DSP_GETVAR:
+ case MBOX_CMD_DSP_SETVAR:
+ s = (cmd_l == VARID_ICRMASK) ? "ICRMASK":
+ (cmd_l == VARID_LOADINFO) ? "LOADINFO":
+ NULL;
+ break;
+ case MBOX_CMD_DSP_ERR:
+ s = (cmd_l == EID_BADTID) ? "BADTID":
+ (cmd_l == EID_BADTCN) ? "BADTCN":
+ (cmd_l == EID_BADBID) ? "BADBID":
+ (cmd_l == EID_BADCNT) ? "BADCNT":
+ (cmd_l == EID_NOTLOCKED) ? "NOTLOCKED":
+ (cmd_l == EID_STVBUF) ? "STVBUF":
+ (cmd_l == EID_BADADR) ? "BADADR":
+ (cmd_l == EID_BADTCTL) ? "BADTCTL":
+ (cmd_l == EID_BADPARAM) ? "BADPARAM":
+ (cmd_l == EID_FATAL) ? "FATAL":
+ (cmd_l == EID_WDT) ? "WDT":
+ (cmd_l == EID_NOMEM) ? "NOMEM":
+ (cmd_l == EID_NORES) ? "NORES":
+ (cmd_l == EID_IPBFULL) ? "IPBFULL":
+ (cmd_l == EID_TASKNOTRDY) ? "TASKNOTRDY":
+ (cmd_l == EID_TASKBSY) ? "TASKBSY":
+ (cmd_l == EID_TASKERR) ? "TASKERR":
+ (cmd_l == EID_BADCFGTYP) ? "BADCFGTYP":
+ (cmd_l == EID_DEBUG) ? "DEBUG":
+ (cmd_l == EID_BADSEQ) ? "BADSEQ":
+ (cmd_l == EID_BADCMD) ? "BADCMD":
+ NULL;
+ break;
+ default:
+ s = NULL;
+ }
+
+ return s;
+}
+
+/* output of show() method should fit to PAGE_SIZE */
+#define MBLOG_DEPTH 64
+
+struct mblogent {
+ unsigned long jiffies;
+ mbox_msg_t msg;
+ arm_dsp_dir_t dir;
+};
+
+static struct {
+ spinlock_t lock;
+ int wp;
+ unsigned long cnt, cnt_ad, cnt_da;
+ struct mblogent ent[MBLOG_DEPTH];
+} mblog = {
+ .lock = SPIN_LOCK_UNLOCKED,
+};
+
+#ifdef CONFIG_OMAP_DSP_MBCMD_VERBOSE
+static inline void mblog_print_cmd(struct mbcmd *mb, arm_dsp_dir_t dir)
+{
+ const struct cmdinfo *ci = cmdinfo[mb->cmd_h];
+ char *dir_str;
+ char *subname;
+
+ dir_str = (dir == DIR_A2D) ? "sending " : "receiving";
+ switch (ci->cmd_l_type) {
+ case CMD_L_TYPE_SUBCMD:
+ subname = subcmd_name(mb);
+ if (unlikely(!subname))
+ subname = "Unknown";
+ pr_debug("mbox: %s seq=%d, cmd=%02x:%02x(%s:%s), data=%04x\n",
+ dir_str, mb->seq, mb->cmd_h, mb->cmd_l,
+ ci->name, subname, mb->data);
+ break;
+ case CMD_L_TYPE_TID:
+ pr_debug("mbox: %s seq=%d, cmd=%02x:%02x(%s:task %d), data=%04x\n",
+ dir_str, mb->seq, mb->cmd_h, mb->cmd_l,
+ ci->name, mb->cmd_l, mb->data);
+ break;
+ case CMD_L_TYPE_NULL:
+ pr_debug("mbox: %s seq=%d, cmd=%02x:%02x(%s), data=%04x\n",
+ dir_str, mb->seq, mb->cmd_h, mb->cmd_l,
+ ci->name, mb->data);
+ break;
+ }
+}
+#else
+static inline void mblog_print_cmd(struct mbcmd *mb, arm_dsp_dir_t dir) { }
+#endif
+
+void mblog_add(struct mbcmd *mb, arm_dsp_dir_t dir)
+{
+ struct mblogent *ent;
+
+ spin_lock(&mblog.lock);
+ ent = &mblog.ent[mblog.wp];
+ ent->jiffies = jiffies;
+ ent->msg = *(mbox_msg_t *)mb;
+ ent->dir = dir;
+ if (mblog.cnt < 0xffffffff)
+ mblog.cnt++;
+ switch (dir) {
+ case DIR_A2D:
+ if (mblog.cnt_ad < 0xffffffff)
+ mblog.cnt_ad++;
+ break;
+ case DIR_D2A:
+ if (mblog.cnt_da < 0xffffffff)
+ mblog.cnt_da++;
+ break;
+ }
+ if (++mblog.wp == MBLOG_DEPTH)
+ mblog.wp = 0;
+ spin_unlock(&mblog.lock);
+
+ mblog_print_cmd(mb, dir);
+}
+
+/*
+ * sysfs file
+ */
+static ssize_t mblog_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int len = 0;
+ int wp;
+ int i;
+
+ spin_lock(&mblog.lock);
+
+ wp = mblog.wp;
+ len += sprintf(buf + len,
+ "log count:%ld / ARM->DSP:%ld, DSP->ARM:%ld\n",
+ mblog.cnt, mblog.cnt_ad, mblog.cnt_da);
+ if (mblog.cnt == 0)
+ goto done;
+
+ len += sprintf(buf + len, " ARM->DSP ARM<-DSP\n");
+ len += sprintf(buf + len, " jiffies cmd data cmd data\n");
+ i = (mblog.cnt >= MBLOG_DEPTH) ? wp : 0;
+ do {
+ struct mblogent *ent = &mblog.ent[i];
+ struct mbcmd *mb = (struct mbcmd *)&ent->msg;
+ char *subname;
+ struct cmdinfo ci_null = {
+ .name = "Unknown",
+ .cmd_l_type = CMD_L_TYPE_NULL,
+ };
+ const struct cmdinfo *ci;
+
+ len += sprintf(buf + len,
+ (ent->dir == DIR_A2D) ?
+ "%08lx %04x %04x ":
+ "%08lx %04x %04x ",
+ ent->jiffies,
+ (ent->msg >> 16) & 0x7fff, ent->msg & 0xffff);
+
+ if ((ci = cmdinfo[mb->cmd_h]) == NULL)
+ ci = &ci_null;
+
+ switch (ci->cmd_l_type) {
+ case CMD_L_TYPE_SUBCMD:
+ if ((subname = subcmd_name(mb)) == NULL)
+ subname = "Unknown";
+ len += sprintf(buf + len, "%s:%s\n",
+ ci->name, subname);
+ break;
+ case CMD_L_TYPE_TID:
+ len += sprintf(buf + len, "%s:task %d\n",
+ ci->name, mb->cmd_l);
+ break;
+ case CMD_L_TYPE_NULL:
+ len += sprintf(buf + len, "%s\n", ci->name);
+ break;
+ }
+
+ if (++i == MBLOG_DEPTH)
+ i = 0;
+ } while (i != wp);
+
+done:
+ spin_unlock(&mblog.lock);
+
+ return len;
+}
+
+static struct device_attribute dev_attr_mblog = __ATTR_RO(mblog);
+
+void __init mblog_init(void)
+{
+ int ret;
+
+ ret = device_create_file(omap_dsp->dev, &dev_attr_mblog);
+ if (ret)
+ printk(KERN_ERR "device_create_file failed: %d\n", ret);
+}
+
+void mblog_exit(void)
+{
+ device_remove_file(omap_dsp->dev, &dev_attr_mblog);
+}
--- /dev/null
+#ifndef __PLAT_OMAP_DSP_MMU_H
+#define __PLAT_OMAP_DSP_MMU_H
+
+#ifdef CONFIG_ARCH_OMAP1
+
+#ifdef CONFIG_ARCH_OMAP15XX
+struct omap_mmu dsp_mmu = {
+ .name = "mmu:dsp",
+ .type = OMAP_MMU_DSP,
+ .base = IO_ADDRESS(OMAP1510_DSP_MMU_BASE),
+ .membase = OMAP1510_DSP_BASE,
+ .memsize = OMAP1510_DSP_SIZE,
+ .nr_tlb_entries = 32,
+ .addrspace = 24,
+ .irq = INT_1510_DSP_MMU,
+ .ops = &omap1_mmu_ops,
+};
+#endif
+#ifdef CONFIG_ARCH_OMAP16XX
+struct omap_mmu dsp_mmu = {
+ .name = "mmu:dsp",
+ .type = OMAP_MMU_DSP,
+ .base = IO_ADDRESS(OMAP16XX_DSP_MMU_BASE),
+ .membase = OMAP16XX_DSP_BASE,
+ .memsize = OMAP16XX_DSP_SIZE,
+ .nr_tlb_entries = 32,
+ .addrspace = 24,
+ .irq = INT_1610_DSP_MMU,
+ .ops = &omap1_mmu_ops,
+};
+#endif
+#else /* OMAP2 */
+struct omap_mmu dsp_mmu = {
+ .name = "mmu:dsp",
+ .type = OMAP_MMU_DSP,
+ .base = DSP_MMU_24XX_VIRT,
+ .membase = DSP_MEM_24XX_VIRT,
+ .memsize = DSP_MEM_24XX_SIZE,
+ .nr_tlb_entries = 32,
+ .addrspace = 24,
+ .irq = INT_24XX_DSP_MMU,
+ .ops = &omap2_mmu_ops,
+};
+
+#define IOMAP_VAL 0x3f
+#endif
+
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+static struct omapfb_notifier_block *omapfb_nb;
+static int omapfb_ready;
+#endif
+
+/*
+ * OMAP1 EMIFF access
+ */
+#ifdef CONFIG_ARCH_OMAP1
+#define EMIF_PRIO_LB_MASK 0x0000f000
+#define EMIF_PRIO_LB_SHIFT 12
+#define EMIF_PRIO_DMA_MASK 0x00000f00
+#define EMIF_PRIO_DMA_SHIFT 8
+#define EMIF_PRIO_DSP_MASK 0x00000070
+#define EMIF_PRIO_DSP_SHIFT 4
+#define EMIF_PRIO_MPU_MASK 0x00000007
+#define EMIF_PRIO_MPU_SHIFT 0
+#define set_emiff_dma_prio(prio) \
+ do { \
+ omap_writel((omap_readl(OMAP_TC_OCPT1_PRIOR) & \
+ ~EMIF_PRIO_DMA_MASK) | \
+ ((prio) << EMIF_PRIO_DMA_SHIFT), \
+ OMAP_TC_OCPT1_PRIOR); \
+ } while(0)
+#else
+#define set_emiff_dma_prio(prio) do { } while (0)
+#endif /* CONFIG_ARCH_OMAP1 */
+
+#ifdef CONFIG_ARCH_OMAP1
+static int dsp_mmu_itack(void)
+{
+ unsigned long dspadr;
+
+ pr_info("omapdsp: sending DSP MMU interrupt ack.\n");
+ if (!dsp_err_isset(ERRCODE_MMU)) {
+ printk(KERN_ERR "omapdsp: DSP MMU error has not been set.\n");
+ return -EINVAL;
+ }
+ dspadr = dsp_mmu.fault_address & ~(SZ_4K-1);
+ /* FIXME: reserve TLB entry for this */
+ omap_mmu_exmap(&dsp_mmu, dspadr, 0, SZ_4K, EXMAP_TYPE_MEM);
+ pr_info("omapdsp: falling into recovery runlevel...\n");
+ dsp_set_runlevel(RUNLEVEL_RECOVERY);
+ omap_mmu_itack(&dsp_mmu);
+ udelay(100);
+ omap_mmu_exunmap(&dsp_mmu, dspadr);
+ dsp_err_clear(ERRCODE_MMU);
+ return 0;
+}
+
+/*
+ * intmem_enable() / disable():
+ * if the address is in DSP internal memories,
+ * we send PM mailbox commands so that DSP DMA domain won't go in idle
+ * when ARM is accessing to those memories.
+ */
+static int intmem_enable(void)
+{
+ int ret = 0;
+
+ if (dsp_cfgstat_get_stat() == CFGSTAT_READY)
+ ret = mbcompose_send(PM, PM_ENABLE, DSPREG_ICR_DMA);
+
+ return ret;
+}
+
+static void intmem_disable(void) {
+ if (dsp_cfgstat_get_stat() == CFGSTAT_READY)
+ mbcompose_send(PM, PM_DISABLE, DSPREG_ICR_DMA);
+}
+#else
+static int intmem_enable(void) { return 0; }
+static void intmem_disable(void) { }
+static int dsp_mmu_itack(void) { return 0; }
+#endif
+
+#ifdef CONFIG_ARCH_OMAP2
+static inline void dsp_mem_ipi_init(void)
+{
+ int i, dspmem_pg_count;
+ dspmem_pg_count = dspmem_size >> 12;
+ for (i = 0; i < dspmem_pg_count; i++) {
+ writel(i, DSP_IPI_INDEX);
+ writel(DSP_IPI_ENTRY_ELMSIZEVALUE_16, DSP_IPI_ENTRY);
+ }
+ writel(1, DSP_IPI_ENABLE);
+ writel(IOMAP_VAL, DSP_IPI_IOMAP);
+}
+#else
+static inline void dsp_mem_ipi_init(void) { }
+#endif
+
+#endif /* __PLAT_OMAP_DSP_MMU_H */
--- /dev/null
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __OMAP_DSP_OMAP1_DSP_H
+#define __OMAP_DSP_OMAP1_DSP_H
+
+#ifdef CONFIG_ARCH_OMAP15XX
+#define OMAP1510_DARAM_BASE (OMAP1510_DSP_BASE + 0x0)
+#define OMAP1510_DARAM_SIZE 0x10000
+#define OMAP1510_SARAM_BASE (OMAP1510_DSP_BASE + 0x10000)
+#define OMAP1510_SARAM_SIZE 0x18000
+#endif
+
+#ifdef CONFIG_ARCH_OMAP16XX
+#define OMAP16XX_DARAM_BASE (OMAP16XX_DSP_BASE + 0x0)
+#define OMAP16XX_DARAM_SIZE 0x10000
+#define OMAP16XX_SARAM_BASE (OMAP16XX_DSP_BASE + 0x10000)
+#define OMAP16XX_SARAM_SIZE 0x18000
+#endif
+
+/*
+ * 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 DSP_BOOT_CONFIG_DIRECT 0x00000000
+#define DSP_BOOT_CONFIG_PSD_DIRECT 0x00000001
+#define DSP_BOOT_CONFIG_IDLE 0x00000002
+#define DSP_BOOT_CONFIG_DL16 0x00000003
+#define DSP_BOOT_CONFIG_DL32 0x00000004
+#define DSP_BOOT_CONFIG_MPUI 0x00000005
+#define 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 ICR
+ */
+#define DSPREG_ICR_RESERVED_BITS 0xffc0
+#define DSPREG_ICR_EMIF 0x0020
+#define DSPREG_ICR_DPLL 0x0010
+#define DSPREG_ICR_PER 0x0008
+#define DSPREG_ICR_CACHE 0x0004
+#define DSPREG_ICR_DMA 0x0002
+#define DSPREG_ICR_CPU 0x0001
+
+#endif /* __OMAP_DSP_OMAP1_DSP_H */
--- /dev/null
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __OMAP_DSP_OMAP2_DSP_H
+#define __OMAP_DSP_OMAP2_DSP_H
+
+#ifdef CONFIG_ARCH_OMAP24XX
+#define OMAP24XX_DARAM_BASE (DSP_MEM_24XX_VIRT + 0x0)
+#define OMAP24XX_DARAM_SIZE 0x10000
+#define OMAP24XX_SARAM_BASE (DSP_MEM_24XX_VIRT + 0x10000)
+#define OMAP24XX_SARAM_SIZE 0x18000
+#endif
+
+#include <asm/arch/hardware.h>
+
+/*
+ * DSP IPI registers: mapped to 0xe1000000 -- use readX(), writeX()
+ */
+#ifdef CONFIG_ARCH_OMAP24XX
+#define DSP_IPI_BASE DSP_IPI_24XX_VIRT
+#endif
+
+#ifdef CONFIG_ARCH_OMAP34XX
+#define DSP_IPI_BASE DSP_IPI_34XX_VIRT
+#endif
+
+#define DSP_IPI_REVISION (DSP_IPI_BASE + 0x00)
+#define DSP_IPI_SYSCONFIG (DSP_IPI_BASE + 0x10)
+#define DSP_IPI_INDEX (DSP_IPI_BASE + 0x40)
+#define DSP_IPI_ENTRY (DSP_IPI_BASE + 0x44)
+#define DSP_IPI_ENABLE (DSP_IPI_BASE + 0x48)
+#define DSP_IPI_IOMAP (DSP_IPI_BASE + 0x4c)
+#define DSP_IPI_DSPBOOTCONFIG (DSP_IPI_BASE + 0x50)
+
+#define DSP_IPI_ENTRY_ELMSIZEVALUE_MASK 0x00000003
+#define DSP_IPI_ENTRY_ELMSIZEVALUE_8 0x00000000
+#define DSP_IPI_ENTRY_ELMSIZEVALUE_16 0x00000001
+#define DSP_IPI_ENTRY_ELMSIZEVALUE_32 0x00000002
+
+#define DSP_BOOT_CONFIG_DIRECT 0x00000000
+#define DSP_BOOT_CONFIG_PSD_DIRECT 0x00000001
+#define DSP_BOOT_CONFIG_IDLE 0x00000002
+#define DSP_BOOT_CONFIG_DL16 0x00000003
+#define DSP_BOOT_CONFIG_DL32 0x00000004
+#define DSP_BOOT_CONFIG_API 0x00000005
+#define DSP_BOOT_CONFIG_INTERNAL 0x00000006
+
+/*
+ * DSP boot mode
+ * direct: 0xffff00
+ * pseudo direct: 0x080000
+ * API: branch 0x010000
+ * internel: branch 0x024000
+ */
+#define DSP_BOOT_ADR_DIRECT 0xffff00
+#define DSP_BOOT_ADR_PSD_DIRECT 0x080000
+#define DSP_BOOT_ADR_API 0x010000
+#define DSP_BOOT_ADR_INTERNAL 0x024000
+
+/*
+ * DSP ICR
+ */
+#define DSPREG_ICR_RESERVED_BITS 0xfc00
+#define DSPREG_ICR_HWA 0x0200
+#define DSPREG_ICR_IPORT 0x0100
+#define DSPREG_ICR_MPORT 0x0080
+#define DSPREG_ICR_XPORT 0x0040
+#define DSPREG_ICR_DPORT 0x0020
+#define DSPREG_ICR_DPLL 0x0010
+#define DSPREG_ICR_PER 0x0008
+#define DSPREG_ICR_CACHE 0x0004
+#define DSPREG_ICR_DMA 0x0002
+#define DSPREG_ICR_CPU 0x0001
+
+#endif /* __OMAP_DSP_OMAP2_DSP_H */
--- /dev/null
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2004-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __PLAT_OMAP_DSP_PROCLIST_H
+#define __PLAT_OMAP_DSP_PROCLIST_H
+
+struct proc_list {
+ struct list_head list_head;
+ pid_t pid;
+ struct file *file;
+};
+
+static inline int proc_list_add(spinlock_t *lock, struct list_head *list,
+ struct task_struct *tsk, struct file *file)
+{
+ struct proc_list *new;
+
+ new = kmalloc(sizeof(struct proc_list), GFP_KERNEL);
+ if (new == NULL)
+ return -ENOMEM;
+ new->pid = tsk->pid;
+ new->file = file;
+ spin_lock(lock);
+ list_add_tail(&new->list_head, list);
+ spin_unlock(lock);
+
+ return 0;
+}
+
+static inline void proc_list_del(spinlock_t *lock, struct list_head *list,
+ struct task_struct *tsk, struct file *file)
+{
+ struct proc_list *pl;
+
+ spin_lock(lock);
+ list_for_each_entry(pl, list, list_head) {
+ if (pl->file == file) {
+ list_del(&pl->list_head);
+ kfree(pl);
+ spin_unlock(lock);
+ return;
+ }
+ }
+
+ /* correspinding file struct isn't found in the list ??? */
+ printk(KERN_ERR "proc_list_del(): proc_list is inconsistent!\n"
+ "struct file (%p) not found\n", file);
+ printk(KERN_ERR "listing proc_list...\n");
+ list_for_each_entry(pl, list, list_head)
+ printk(KERN_ERR " pid:%d file:%p\n", pl->pid, pl->file);
+ spin_unlock(lock);
+}
+
+static inline void proc_list_flush(spinlock_t *lock, struct list_head *list)
+{
+ struct proc_list *pl;
+
+ spin_lock(lock);
+ while (!list_empty(list)) {
+ pl = list_entry(list->next, struct proc_list, list_head);
+ list_del(&pl->list_head);
+ kfree(pl);
+ }
+ spin_unlock(lock);
+}
+
+#endif /* __PLAT_OMAP_DSP_PROCLIST_H */
--- /dev/null
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/major.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <linux/kfifo.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/arch/mailbox.h>
+#include <asm/arch/dsp.h>
+#include "uaccess_dsp.h"
+#include "dsp_mbcmd.h"
+#include "dsp.h"
+#include "ipbuf.h"
+#include "proclist.h"
+
+/*
+ * devstate: task device state machine
+ * NOTASK: task is not attached.
+ * ATTACHED: task is attached.
+ * GARBAGE: task is detached. waiting for all processes to close this device.
+ * ADDREQ: requesting for tadd
+ * DELREQ: requesting for tdel. no process is opening this device.
+ * FREEZED: task is attached, but reserved to be killed.
+ * ADDFAIL: tadd failed.
+ * ADDING: tadd in process.
+ * DELING: tdel in process.
+ * KILLING: tkill in process.
+ */
+#define TASKDEV_ST_NOTASK 0x00000001
+#define TASKDEV_ST_ATTACHED 0x00000002
+#define TASKDEV_ST_GARBAGE 0x00000004
+#define TASKDEV_ST_INVALID 0x00000008
+#define TASKDEV_ST_ADDREQ 0x00000100
+#define TASKDEV_ST_DELREQ 0x00000200
+#define TASKDEV_ST_FREEZED 0x00000400
+#define TASKDEV_ST_ADDFAIL 0x00001000
+#define TASKDEV_ST_ADDING 0x00010000
+#define TASKDEV_ST_DELING 0x00020000
+#define TASKDEV_ST_KILLING 0x00040000
+#define TASKDEV_ST_STATE_MASK 0x7fffffff
+#define TASKDEV_ST_STALE 0x80000000
+
+static struct {
+ long state;
+ char *name;
+} devstate_desc[] = {
+ { TASKDEV_ST_NOTASK, "notask" },
+ { TASKDEV_ST_ATTACHED, "attached" },
+ { TASKDEV_ST_GARBAGE, "garbage" },
+ { TASKDEV_ST_INVALID, "invalid" },
+ { TASKDEV_ST_ADDREQ, "addreq" },
+ { TASKDEV_ST_DELREQ, "delreq" },
+ { TASKDEV_ST_FREEZED, "freezed" },
+ { TASKDEV_ST_ADDFAIL, "addfail" },
+ { TASKDEV_ST_ADDING, "adding" },
+ { TASKDEV_ST_DELING, "deling" },
+ { TASKDEV_ST_KILLING, "killing" },
+};
+
+static char *devstate_name(long state)
+{
+ int i;
+ int max = ARRAY_SIZE(devstate_desc);
+
+ for (i = 0; i < max; i++) {
+ if (state & devstate_desc[i].state)
+ return devstate_desc[i].name;
+ }
+ return "unknown";
+}
+
+struct rcvdt_bk_struct {
+ struct ipblink link;
+ unsigned int rp;
+};
+
+struct taskdev {
+ struct bus_type *bus;
+ struct device dev; /* Generic device interface */
+
+ long state;
+ struct rw_semaphore state_sem;
+ wait_queue_head_t state_wait_q;
+ struct mutex usecount_lock;
+ unsigned int usecount;
+ char name[TNM_LEN];
+ struct file_operations fops;
+ spinlock_t proc_list_lock;
+ struct list_head proc_list;
+ struct dsptask *task;
+
+ /* read stuff */
+ wait_queue_head_t read_wait_q;
+ struct mutex read_mutex;
+ spinlock_t read_lock;
+ union {
+ struct kfifo *fifo; /* for active word */
+ struct rcvdt_bk_struct bk;
+ } rcvdt;
+
+ /* write stuff */
+ wait_queue_head_t write_wait_q;
+ struct mutex write_mutex;
+ spinlock_t wsz_lock;
+ size_t wsz;
+
+ /* tctl stuff */
+ wait_queue_head_t tctl_wait_q;
+ struct mutex tctl_mutex;
+ int tctl_stat;
+ int tctl_ret; /* return value for tctl_show() */
+
+ /* device lock */
+ struct mutex lock;
+ pid_t lock_pid;
+};
+
+#define to_taskdev(n) container_of(n, struct taskdev, dev)
+
+struct dsptask {
+ enum {
+ TASK_ST_ERR = 0,
+ TASK_ST_READY,
+ TASK_ST_CFGREQ
+ } state;
+ u8 tid;
+ char name[TNM_LEN];
+ u16 ttyp;
+ struct taskdev *dev;
+
+ /* read stuff */
+ struct ipbuf_p *ipbuf_pvt_r;
+
+ /* write stuff */
+ struct ipbuf_p *ipbuf_pvt_w;
+
+ /* mmap stuff */
+ void *map_base;
+ size_t map_length;
+};
+
+#define sndtyp_acv(ttyp) ((ttyp) & TTYP_ASND)
+#define sndtyp_psv(ttyp) (!((ttyp) & TTYP_ASND))
+#define sndtyp_bk(ttyp) ((ttyp) & TTYP_BKDM)
+#define sndtyp_wd(ttyp) (!((ttyp) & TTYP_BKDM))
+#define sndtyp_pvt(ttyp) ((ttyp) & TTYP_PVDM)
+#define sndtyp_gbl(ttyp) (!((ttyp) & TTYP_PVDM))
+#define rcvtyp_acv(ttyp) ((ttyp) & TTYP_ARCV)
+#define rcvtyp_psv(ttyp) (!((ttyp) & TTYP_ARCV))
+#define rcvtyp_bk(ttyp) ((ttyp) & TTYP_BKMD)
+#define rcvtyp_wd(ttyp) (!((ttyp) & TTYP_BKMD))
+#define rcvtyp_pvt(ttyp) ((ttyp) & TTYP_PVMD)
+#define rcvtyp_gbl(ttyp) (!((ttyp) & TTYP_PVMD))
+
+static inline int has_taskdev_lock(struct taskdev *dev);
+static int dsp_rmdev_minor(unsigned char minor);
+static int taskdev_init(struct taskdev *dev, char *name, unsigned char minor);
+static void taskdev_delete(unsigned char minor);
+static int taskdev_attach_task(struct taskdev *dev, struct dsptask *task);
+static int dsp_tdel_bh(struct taskdev *dev, u16 type);
+
+static struct bus_type dsptask_bus = {
+ .name = "dsptask",
+};
+
+static struct class *dsp_task_class;
+static DEFINE_MUTEX(devmgr_lock);
+static struct taskdev *taskdev[TASKDEV_MAX];
+static struct dsptask *dsptask[TASKDEV_MAX];
+static DEFINE_MUTEX(cfg_lock);
+static u16 cfg_cmd;
+static u8 cfg_tid;
+static DECLARE_WAIT_QUEUE_HEAD(cfg_wait_q);
+static u8 n_task; /* static task count */
+static void *heap;
+
+#define is_dynamic_task(tid) ((tid) >= n_task)
+
+#define devstate_read_lock(dev, devstate) \
+ devstate_read_lock_timeout(dev, devstate, 0)
+#define devstate_read_unlock(dev) up_read(&(dev)->state_sem)
+#define devstate_write_lock(dev, devstate) \
+ devstate_write_lock_timeout(dev, devstate, 0)
+#define devstate_write_unlock(dev) up_write(&(dev)->state_sem)
+
+static ssize_t devname_show(struct device *d, struct device_attribute *attr,
+ char *buf);
+static ssize_t devstate_show(struct device *d, struct device_attribute *attr,
+ char *buf);
+static ssize_t proc_list_show(struct device *d, struct device_attribute *attr,
+ char *buf);
+static ssize_t taskname_show(struct device *d, struct device_attribute *attr,
+ char *buf);
+static ssize_t ttyp_show(struct device *d, struct device_attribute *attr,
+ char *buf);
+static ssize_t fifosz_show(struct device *d, struct device_attribute *attr,
+ char *buf);
+static int fifosz_store(struct device *d, struct device_attribute *attr,
+ const char *buf, size_t count);
+static ssize_t fifocnt_show(struct device *d, struct device_attribute *attr,
+ char *buf);
+static ssize_t ipblink_show(struct device *d, struct device_attribute *attr,
+ char *buf);
+static ssize_t wsz_show(struct device *d, struct device_attribute *attr,
+ char *buf);
+static ssize_t mmap_show(struct device *d, struct device_attribute *attr,
+ char *buf);
+
+#define __ATTR_RW(_name,_mode) { \
+ .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE }, \
+ .show = _name##_show, \
+ .store = _name##_store, \
+}
+
+static struct device_attribute dev_attr_devname = __ATTR_RO(devname);
+static struct device_attribute dev_attr_devstate = __ATTR_RO(devstate);
+static struct device_attribute dev_attr_proc_list = __ATTR_RO(proc_list);
+static struct device_attribute dev_attr_taskname = __ATTR_RO(taskname);
+static struct device_attribute dev_attr_ttyp = __ATTR_RO(ttyp);
+static struct device_attribute dev_attr_fifosz = __ATTR_RW(fifosz, 0666);
+static struct device_attribute dev_attr_fifocnt = __ATTR_RO(fifocnt);
+static struct device_attribute dev_attr_ipblink = __ATTR_RO(ipblink);
+static struct device_attribute dev_attr_wsz = __ATTR_RO(wsz);
+static struct device_attribute dev_attr_mmap = __ATTR_RO(mmap);
+
+static inline void set_taskdev_state(struct taskdev *dev, int state)
+{
+ pr_debug("omapdsp: devstate: CHANGE %s[%d]:\"%s\"->\"%s\"\n",
+ dev->name,
+ (dev->task ? dev->task->tid : -1),
+ devstate_name(dev->state),
+ devstate_name(state));
+ dev->state = state;
+}
+
+/*
+ * devstate_read_lock_timeout()
+ * devstate_write_lock_timeout():
+ * timeout != 0: dev->state can be diffeent from what you want.
+ * timeout == 0: no timeout
+ */
+#define BUILD_DEVSTATE_LOCK_TIMEOUT(rw) \
+static int devstate_##rw##_lock_timeout(struct taskdev *dev, long devstate, \
+ int timeout) \
+{ \
+ DEFINE_WAIT(wait); \
+ down_##rw(&dev->state_sem); \
+ while (!(dev->state & devstate)) { \
+ up_##rw(&dev->state_sem); \
+ prepare_to_wait(&dev->state_wait_q, &wait, TASK_INTERRUPTIBLE); \
+ if (!timeout) \
+ timeout = MAX_SCHEDULE_TIMEOUT; \
+ timeout = schedule_timeout(timeout); \
+ finish_wait(&dev->state_wait_q, &wait); \
+ if (timeout == 0) \
+ return -ETIME; \
+ if (signal_pending(current)) \
+ return -EINTR; \
+ down_##rw(&dev->state_sem); \
+ } \
+ return 0; \
+}
+BUILD_DEVSTATE_LOCK_TIMEOUT(read)
+BUILD_DEVSTATE_LOCK_TIMEOUT(write)
+
+#define BUILD_DEVSTATE_LOCK_AND_TEST(rw) \
+static int devstate_##rw##_lock_and_test(struct taskdev *dev, long devstate) \
+{ \
+ down_##rw(&dev->state_sem); \
+ if (dev->state & devstate) \
+ return 1; /* success */ \
+ /* failure */ \
+ up_##rw(&dev->state_sem); \
+ return 0; \
+}
+BUILD_DEVSTATE_LOCK_AND_TEST(read)
+BUILD_DEVSTATE_LOCK_AND_TEST(write)
+
+static int taskdev_lock_interruptible(struct taskdev *dev,
+ struct mutex *lock)
+{
+ int ret;
+
+ if (has_taskdev_lock(dev))
+ ret = mutex_lock_interruptible(lock);
+ else {
+ if ((ret = mutex_lock_interruptible(&dev->lock)) != 0)
+ return ret;
+ ret = mutex_lock_interruptible(lock);
+ mutex_unlock(&dev->lock);
+ }
+
+ return ret;
+}
+
+static int taskdev_lock_and_statelock_attached(struct taskdev *dev,
+ struct mutex *lock)
+{
+ int ret;
+
+ if (!devstate_read_lock_and_test(dev, TASKDEV_ST_ATTACHED))
+ return -ENODEV;
+
+ if ((ret = taskdev_lock_interruptible(dev, lock)) != 0)
+ devstate_read_unlock(dev);
+
+ return ret;
+}
+
+static inline void taskdev_unlock_and_stateunlock(struct taskdev *dev,
+ struct mutex *lock)
+{
+ mutex_unlock(lock);
+ devstate_read_unlock(dev);
+}
+
+/*
+ * taskdev_flush_buf()
+ * must be called under state_lock(ATTACHED) and dev->read_mutex.
+ */
+static int taskdev_flush_buf(struct taskdev *dev)
+{
+ u16 ttyp = dev->task->ttyp;
+
+ if (sndtyp_wd(ttyp)) {
+ /* word receiving */
+ kfifo_reset(dev->rcvdt.fifo);
+ } else {
+ /* block receiving */
+ struct rcvdt_bk_struct *rcvdt = &dev->rcvdt.bk;
+
+ if (sndtyp_gbl(ttyp))
+ ipblink_flush(&rcvdt->link);
+ else {
+ ipblink_flush_pvt(&rcvdt->link);
+ release_ipbuf_pvt(dev->task->ipbuf_pvt_r);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * taskdev_set_fifosz()
+ * must be called under dev->read_mutex.
+ */
+static int taskdev_set_fifosz(struct taskdev *dev, unsigned long sz)
+{
+ u16 ttyp = dev->task->ttyp;
+
+ 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;
+ }
+
+ if (kfifo_len(dev->rcvdt.fifo)) {
+ printk(KERN_ERR "omapdsp: buffer is not empty!\n");
+ return -EIO;
+ }
+
+ kfifo_free(dev->rcvdt.fifo);
+ dev->rcvdt.fifo = kfifo_alloc(sz, GFP_KERNEL, &dev->read_lock);
+ if (IS_ERR(dev->rcvdt.fifo)) {
+ printk(KERN_ERR
+ "omapdsp: unable to change receive buffer size. "
+ "(%ld bytes for %s)\n", sz, dev->name);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static inline int has_taskdev_lock(struct taskdev *dev)
+{
+ return (dev->lock_pid == current->pid);
+}
+
+static int taskdev_lock(struct taskdev *dev)
+{
+ if (mutex_lock_interruptible(&dev->lock))
+ return -EINTR;
+ dev->lock_pid = current->pid;
+ return 0;
+}
+
+static int taskdev_unlock(struct taskdev *dev)
+{
+ if (!has_taskdev_lock(dev)) {
+ printk(KERN_ERR
+ "omapdsp: an illegal process attempted to "
+ "unlock the dsptask lock!\n");
+ return -EINVAL;
+ }
+ dev->lock_pid = 0;
+ mutex_unlock(&dev->lock);
+ return 0;
+}
+
+static int dsp_task_config(struct dsptask *task, u8 tid)
+{
+ u16 ttyp;
+ int ret;
+
+ task->tid = tid;
+ dsptask[tid] = task;
+
+ /* TCFG request */
+ task->state = TASK_ST_CFGREQ;
+ if (mutex_lock_interruptible(&cfg_lock)) {
+ ret = -EINTR;
+ goto fail_out;
+ }
+ cfg_cmd = MBOX_CMD_DSP_TCFG;
+ mbcompose_send_and_wait(TCFG, tid, 0, &cfg_wait_q);
+ cfg_cmd = 0;
+ mutex_unlock(&cfg_lock);
+
+ if (task->state != TASK_ST_READY) {
+ printk(KERN_ERR "omapdsp: task %d configuration error!\n", tid);
+ ret = -EINVAL;
+ goto fail_out;
+ }
+
+ if (strlen(task->name) <= 1)
+ sprintf(task->name, "%d", tid);
+ pr_info("omapdsp: task %d: name %s\n", tid, task->name);
+
+ ttyp = task->ttyp;
+
+ /*
+ * task info sanity check
+ */
+
+ /* task type check */
+ if (rcvtyp_psv(ttyp) && rcvtyp_pvt(ttyp)) {
+ printk(KERN_ERR "omapdsp: illegal task type(0x%04x), tid=%d\n",
+ tid, ttyp);
+ ret = -EINVAL;
+ goto fail_out;
+ }
+
+ /* private buffer address check */
+ if (sndtyp_pvt(ttyp) &&
+ (ipbuf_p_validate(task->ipbuf_pvt_r, DIR_D2A) < 0)) {
+ ret = -EINVAL;
+ goto fail_out;
+ }
+ if (rcvtyp_pvt(ttyp) &&
+ (ipbuf_p_validate(task->ipbuf_pvt_w, DIR_A2D) < 0)) {
+ ret = -EINVAL;
+ goto fail_out;
+ }
+
+ /* mmap buffer configuration check */
+ if ((task->map_length > 0) &&
+ ((!ALIGN((unsigned long)task->map_base, PAGE_SIZE)) ||
+ (!ALIGN(task->map_length, PAGE_SIZE)) ||
+ (dsp_mem_type(task->map_base, task->map_length) != MEM_TYPE_EXTERN))) {
+ printk(KERN_ERR
+ "omapdsp: illegal mmap buffer address(0x%p) or "
+ "length(0x%x).\n"
+ " It needs to be page-aligned and located at "
+ "external memory.\n",
+ task->map_base, task->map_length);
+ ret = -EINVAL;
+ goto fail_out;
+ }
+
+ return 0;
+
+fail_out:
+ dsptask[tid] = NULL;
+ return ret;
+}
+
+static void dsp_task_init(struct dsptask *task)
+{
+ mbcompose_send(TCTL, task->tid, TCTL_TINIT);
+}
+
+int dsp_task_config_all(u8 n)
+{
+ int i, ret;
+ struct taskdev *devheap;
+ struct dsptask *taskheap;
+ size_t devheapsz, taskheapsz;
+
+ pr_info("omapdsp: found %d task(s)\n", n);
+ if (n == 0)
+ return 0;
+
+ /*
+ * reducing kmalloc!
+ */
+ devheapsz = sizeof(struct taskdev) * n;
+ taskheapsz = sizeof(struct dsptask) * n;
+ heap = kzalloc(devheapsz + taskheapsz, GFP_KERNEL);
+ if (heap == NULL)
+ return -ENOMEM;
+ devheap = heap;
+ taskheap = heap + devheapsz;
+
+ n_task = n;
+ for (i = 0; i < n; i++) {
+ struct taskdev *dev = &devheap[i];
+ struct dsptask *task = &taskheap[i];
+
+ if ((ret = dsp_task_config(task, i)) < 0)
+ return ret;
+ if ((ret = taskdev_init(dev, task->name, i)) < 0)
+ return ret;
+ if ((ret = taskdev_attach_task(dev, task)) < 0)
+ return ret;
+ dsp_task_init(task);
+ pr_info("omapdsp: taskdev %s enabled.\n", dev->name);
+ }
+
+ return 0;
+}
+
+static void dsp_task_unconfig(struct dsptask *task)
+{
+ dsptask[task->tid] = NULL;
+}
+
+void dsp_task_unconfig_all(void)
+{
+ unsigned char minor;
+ u8 tid;
+ struct dsptask *task;
+
+ for (minor = 0; minor < n_task; minor++) {
+ /*
+ * taskdev[minor] can be NULL in case of
+ * configuration failure
+ */
+ if (taskdev[minor])
+ taskdev_delete(minor);
+ }
+ for (; minor < TASKDEV_MAX; minor++) {
+ if (taskdev[minor])
+ dsp_rmdev_minor(minor);
+ }
+
+ for (tid = 0; tid < n_task; tid++) {
+ /*
+ * dsptask[tid] can be NULL in case of
+ * configuration failure
+ */
+ task = dsptask[tid];
+ if (task)
+ dsp_task_unconfig(task);
+ }
+ for (; tid < TASKDEV_MAX; tid++) {
+ task = dsptask[tid];
+ if (task) {
+ /*
+ * on-demand tasks should be deleted in
+ * rmdev_minor(), but just in case.
+ */
+ dsp_task_unconfig(task);
+ kfree(task);
+ }
+ }
+
+ if (heap) {
+ kfree(heap);
+ heap = NULL;
+ }
+
+ n_task = 0;
+}
+
+static struct device_driver dsptask_driver = {
+ .name = "dsptask",
+ .bus = &dsptask_bus,
+};
+
+u8 dsp_task_count(void)
+{
+ return n_task;
+}
+
+int dsp_taskmod_busy(void)
+{
+ struct taskdev *dev;
+ unsigned char minor;
+ unsigned int usecount;
+
+ for (minor = 0; minor < TASKDEV_MAX; minor++) {
+ dev = taskdev[minor];
+ if (dev == NULL)
+ continue;
+ if ((usecount = dev->usecount) > 0) {
+ printk("dsp_taskmod_busy(): %s: usecount=%d\n",
+ dev->name, usecount);
+ return 1;
+ }
+/*
+ if ((dev->state & (TASKDEV_ST_ADDREQ |
+ TASKDEV_ST_DELREQ)) {
+*/
+ if (dev->state & TASKDEV_ST_ADDREQ) {
+ printk("dsp_taskmod_busy(): %s is in %s\n",
+ dev->name, devstate_name(dev->state));
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * DSP task device file operations
+ */
+static ssize_t dsp_task_read_wd_acv(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+ struct taskdev *dev = taskdev[minor];
+ int ret = 0;
+ DEFINE_WAIT(wait);
+
+ if (count == 0) {
+ return 0;
+ } else if (count & 0x1) {
+ printk(KERN_ERR
+ "omapdsp: odd count is illegal for DSP task device.\n");
+ return -EINVAL;
+ }
+
+ if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+ return -ENODEV;
+
+
+ prepare_to_wait(&dev->read_wait_q, &wait, TASK_INTERRUPTIBLE);
+ if (kfifo_len(dev->rcvdt.fifo) == 0)
+ schedule();
+ finish_wait(&dev->read_wait_q, &wait);
+ if (kfifo_len(dev->rcvdt.fifo) == 0) {
+ /* failure */
+ if (signal_pending(current))
+ ret = -EINTR;
+ goto up_out;
+ }
+
+
+ ret = kfifo_get_to_user(dev->rcvdt.fifo, buf, count);
+
+ up_out:
+ taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
+ return ret;
+}
+
+static ssize_t dsp_task_read_bk_acv(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+ struct taskdev *dev = taskdev[minor];
+ struct rcvdt_bk_struct *rcvdt = &dev->rcvdt.bk;
+ ssize_t ret = 0;
+ DEFINE_WAIT(wait);
+
+ if (count == 0) {
+ return 0;
+ } else if (count & 0x1) {
+ printk(KERN_ERR
+ "omapdsp: odd count is illegal for DSP task device.\n");
+ return -EINVAL;
+ } else if ((int)buf & 0x1) {
+ printk(KERN_ERR
+ "omapdsp: buf should be word aligned for "
+ "dsp_task_read().\n");
+ return -EINVAL;
+ }
+
+ if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+ return -ENODEV;
+
+ prepare_to_wait(&dev->read_wait_q, &wait, TASK_INTERRUPTIBLE);
+ if (ipblink_empty(&rcvdt->link))
+ schedule();
+ finish_wait(&dev->read_wait_q, &wait);
+ if (ipblink_empty(&rcvdt->link)) {
+ /* failure */
+ if (signal_pending(current))
+ ret = -EINTR;
+ goto up_out;
+ }
+
+ /* copy from delayed IPBUF */
+ if (sndtyp_pvt(dev->task->ttyp)) {
+ /* private */
+ if (!ipblink_empty(&rcvdt->link)) {
+ struct ipbuf_p *ipbp = dev->task->ipbuf_pvt_r;
+ unsigned char *base, *src;
+ size_t bkcnt;
+
+ if (dsp_mem_enable(ipbp) < 0) {
+ ret = -EBUSY;
+ goto up_out;
+ }
+ base = MKVIRT(ipbp->ah, ipbp->al);
+ bkcnt = ((unsigned long)ipbp->c) * 2 - rcvdt->rp;
+ if (dsp_address_validate(base, bkcnt,
+ "task %s read buffer",
+ dev->task->name) < 0) {
+ ret = -EINVAL;
+ goto pv_out1;
+ }
+ if (dsp_mem_enable(base) < 0) {
+ ret = -EBUSY;
+ goto pv_out1;
+ }
+ src = base + rcvdt->rp;
+ if (bkcnt > count) {
+ if (copy_to_user_dsp(buf, src, count)) {
+ ret = -EFAULT;
+ goto pv_out2;
+ }
+ ret = count;
+ rcvdt->rp += count;
+ } else {
+ if (copy_to_user_dsp(buf, src, bkcnt)) {
+ ret = -EFAULT;
+ goto pv_out2;
+ }
+ ret = bkcnt;
+ ipblink_del_pvt(&rcvdt->link);
+ release_ipbuf_pvt(ipbp);
+ rcvdt->rp = 0;
+ }
+ pv_out2:
+ dsp_mem_disable(src);
+ pv_out1:
+ dsp_mem_disable(ipbp);
+ }
+ } else {
+ /* global */
+ if (dsp_mem_enable_ipbuf() < 0) {
+ ret = -EBUSY;
+ goto up_out;
+ }
+ while (!ipblink_empty(&rcvdt->link)) {
+ unsigned char *src;
+ size_t bkcnt;
+ struct ipbuf_head *ipb_h = bid_to_ipbuf(rcvdt->link.top);
+
+ src = ipb_h->p->d + rcvdt->rp;
+ bkcnt = ((unsigned long)ipb_h->p->c) * 2 - rcvdt->rp;
+ if (bkcnt > count) {
+ if (copy_to_user_dsp(buf, src, count)) {
+ ret = -EFAULT;
+ goto gb_out;
+ }
+ ret += count;
+ rcvdt->rp += count;
+ break;
+ } else {
+ if (copy_to_user_dsp(buf, src, bkcnt)) {
+ ret = -EFAULT;
+ goto gb_out;
+ }
+ ret += bkcnt;
+ buf += bkcnt;
+ count -= bkcnt;
+ ipblink_del_top(&rcvdt->link);
+ unuse_ipbuf(ipb_h);
+ rcvdt->rp = 0;
+ }
+ }
+ gb_out:
+ dsp_mem_disable_ipbuf();
+ }
+
+ up_out:
+ taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
+ return ret;
+}
+
+static ssize_t dsp_task_read_wd_psv(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+ struct taskdev *dev = taskdev[minor];
+ int ret = 0;
+
+ if (count == 0) {
+ return 0;
+ } else if (count & 0x1) {
+ printk(KERN_ERR
+ "omapdsp: odd count is illegal for DSP task device.\n");
+ return -EINVAL;
+ } else {
+ /* force! */
+ count = 2;
+ }
+
+ if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+ return -ENODEV;
+
+ mbcompose_send_and_wait(WDREQ, dev->task->tid, 0, &dev->read_wait_q);
+
+ if (kfifo_len(dev->rcvdt.fifo) == 0) {
+ /* failure */
+ if (signal_pending(current))
+ ret = -EINTR;
+ goto up_out;
+ }
+
+ ret = kfifo_get_to_user(dev->rcvdt.fifo, buf, count);
+
+up_out:
+ taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
+ return ret;
+}
+
+static ssize_t dsp_task_read_bk_psv(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+ struct taskdev *dev = taskdev[minor];
+ struct rcvdt_bk_struct *rcvdt = &dev->rcvdt.bk;
+ int ret = 0;
+
+ if (count == 0) {
+ return 0;
+ } else if (count & 0x1) {
+ printk(KERN_ERR
+ "omapdsp: odd count is illegal for DSP task device.\n");
+ return -EINVAL;
+ } else if ((int)buf & 0x1) {
+ printk(KERN_ERR
+ "omapdsp: buf should be word aligned for "
+ "dsp_task_read().\n");
+ return -EINVAL;
+ }
+
+ if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+ return -ENODEV;
+
+ mbcompose_send_and_wait(BKREQ, dev->task->tid, count/2,
+ &dev->read_wait_q);
+
+ if (ipblink_empty(&rcvdt->link)) {
+ /* failure */
+ if (signal_pending(current))
+ ret = -EINTR;
+ goto up_out;
+ }
+
+ /*
+ * We will not receive more than requested count.
+ */
+ if (sndtyp_pvt(dev->task->ttyp)) {
+ /* private */
+ struct ipbuf_p *ipbp = dev->task->ipbuf_pvt_r;
+ size_t rcvcnt;
+ void *src;
+
+ if (dsp_mem_enable(ipbp) < 0) {
+ ret = -EBUSY;
+ goto up_out;
+ }
+ src = MKVIRT(ipbp->ah, ipbp->al);
+ rcvcnt = ((unsigned long)ipbp->c) * 2;
+ if (dsp_address_validate(src, rcvcnt, "task %s read buffer",
+ dev->task->name) < 0) {
+ ret = -EINVAL;
+ goto pv_out1;
+ }
+ if (dsp_mem_enable(src) < 0) {
+ ret = -EBUSY;
+ goto pv_out1;
+ }
+ if (count > rcvcnt)
+ count = rcvcnt;
+ if (copy_to_user_dsp(buf, src, count)) {
+ ret = -EFAULT;
+ goto pv_out2;
+ }
+ ipblink_del_pvt(&rcvdt->link);
+ release_ipbuf_pvt(ipbp);
+ ret = count;
+pv_out2:
+ dsp_mem_disable(src);
+pv_out1:
+ dsp_mem_disable(ipbp);
+ } else {
+ /* global */
+ struct ipbuf_head *ipb_h = bid_to_ipbuf(rcvdt->link.top);
+ size_t rcvcnt;
+
+ if (dsp_mem_enable_ipbuf() < 0) {
+ ret = -EBUSY;
+ goto up_out;
+ }
+ rcvcnt = ((unsigned long)ipb_h->p->c) * 2;
+ if (count > rcvcnt)
+ count = rcvcnt;
+ if (copy_to_user_dsp(buf, ipb_h->p->d, count)) {
+ ret = -EFAULT;
+ goto gb_out;
+ }
+ ipblink_del_top(&rcvdt->link);
+ unuse_ipbuf(ipb_h);
+ ret = count;
+gb_out:
+ dsp_mem_disable_ipbuf();
+ }
+
+up_out:
+ taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
+ return ret;
+}
+
+static ssize_t dsp_task_write_wd(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+ struct taskdev *dev = taskdev[minor];
+ u16 wd;
+ int ret = 0;
+ DEFINE_WAIT(wait);
+
+ if (count == 0) {
+ return 0;
+ } else if (count & 0x1) {
+ printk(KERN_ERR
+ "omapdsp: odd count is illegal for DSP task device.\n");
+ return -EINVAL;
+ } else {
+ /* force! */
+ count = 2;
+ }
+
+ if (taskdev_lock_and_statelock_attached(dev, &dev->write_mutex))
+ return -ENODEV;
+
+ prepare_to_wait(&dev->write_wait_q, &wait, TASK_INTERRUPTIBLE);
+ if (dev->wsz == 0)
+ schedule();
+ finish_wait(&dev->write_wait_q, &wait);
+ if (dev->wsz == 0) {
+ /* failure */
+ if (signal_pending(current))
+ ret = -EINTR;
+ goto up_out;
+ }
+
+ if (copy_from_user(&wd, buf, count)) {
+ ret = -EFAULT;
+ goto up_out;
+ }
+
+ spin_lock(&dev->wsz_lock);
+ if (mbcompose_send(WDSND, dev->task->tid, wd) < 0) {
+ spin_unlock(&dev->wsz_lock);
+ goto up_out;
+ }
+ ret = count;
+ if (rcvtyp_acv(dev->task->ttyp))
+ dev->wsz = 0;
+ spin_unlock(&dev->wsz_lock);
+
+ up_out:
+ taskdev_unlock_and_stateunlock(dev, &dev->write_mutex);
+ return ret;
+}
+
+static ssize_t dsp_task_write_bk(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+ struct taskdev *dev = taskdev[minor];
+ int ret = 0;
+ DEFINE_WAIT(wait);
+
+ if (count == 0) {
+ return 0;
+ } else if (count & 0x1) {
+ printk(KERN_ERR
+ "omapdsp: odd count is illegal for DSP task device.\n");
+ return -EINVAL;
+ } else if ((int)buf & 0x1) {
+ printk(KERN_ERR
+ "omapdsp: buf should be word aligned for "
+ "dsp_task_write().\n");
+ return -EINVAL;
+ }
+
+ if (taskdev_lock_and_statelock_attached(dev, &dev->write_mutex))
+ return -ENODEV;
+
+ prepare_to_wait(&dev->write_wait_q, &wait, TASK_INTERRUPTIBLE);
+ if (dev->wsz == 0)
+ schedule();
+ finish_wait(&dev->write_wait_q, &wait);
+ if (dev->wsz == 0) {
+ /* failure */
+ if (signal_pending(current))
+ ret = -EINTR;
+ goto up_out;
+ }
+
+ if (count > dev->wsz)
+ count = dev->wsz;
+
+ if (rcvtyp_pvt(dev->task->ttyp)) {
+ /* private */
+ struct ipbuf_p *ipbp = dev->task->ipbuf_pvt_w;
+ unsigned char *dst;
+
+ if (dsp_mem_enable(ipbp) < 0) {
+ ret = -EBUSY;
+ goto up_out;
+ }
+ dst = MKVIRT(ipbp->ah, ipbp->al);
+ if (dsp_address_validate(dst, count, "task %s write buffer",
+ dev->task->name) < 0) {
+ ret = -EINVAL;
+ goto pv_out1;
+ }
+ if (dsp_mem_enable(dst) < 0) {
+ ret = -EBUSY;
+ goto pv_out1;
+ }
+ if (copy_from_user_dsp(dst, buf, count)) {
+ ret = -EFAULT;
+ goto pv_out2;
+ }
+ ipbp->c = count/2;
+ ipbp->s = dev->task->tid;
+ spin_lock(&dev->wsz_lock);
+ if (mbcompose_send(BKSNDP, dev->task->tid, 0) == 0) {
+ if (rcvtyp_acv(dev->task->ttyp))
+ dev->wsz = 0;
+ ret = count;
+ }
+ spin_unlock(&dev->wsz_lock);
+ pv_out2:
+ dsp_mem_disable(dst);
+ pv_out1:
+ dsp_mem_disable(ipbp);
+ } else {
+ /* global */
+ struct ipbuf_head *ipb_h;
+
+ if (dsp_mem_enable_ipbuf() < 0) {
+ ret = -EBUSY;
+ goto up_out;
+ }
+ if ((ipb_h = get_free_ipbuf(dev->task->tid)) == NULL)
+ goto gb_out;
+ if (copy_from_user_dsp(ipb_h->p->d, buf, count)) {
+ release_ipbuf(ipb_h);
+ ret = -EFAULT;
+ goto gb_out;
+ }
+ ipb_h->p->c = count/2;
+ ipb_h->p->sa = dev->task->tid;
+ spin_lock(&dev->wsz_lock);
+ if (mbcompose_send(BKSND, dev->task->tid, ipb_h->bid) == 0) {
+ if (rcvtyp_acv(dev->task->ttyp))
+ dev->wsz = 0;
+ ret = count;
+ ipb_bsycnt_inc(&ipbcfg);
+ } else
+ release_ipbuf(ipb_h);
+ spin_unlock(&dev->wsz_lock);
+ gb_out:
+ dsp_mem_disable_ipbuf();
+ }
+
+ up_out:
+ taskdev_unlock_and_stateunlock(dev, &dev->write_mutex);
+ return ret;
+}
+
+static unsigned int dsp_task_poll(struct file * file, poll_table * wait)
+{
+ unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+ struct taskdev *dev = taskdev[minor];
+ struct dsptask *task = dev->task;
+ unsigned int mask = 0;
+
+ if (!devstate_read_lock_and_test(dev, TASKDEV_ST_ATTACHED))
+ return 0;
+ poll_wait(file, &dev->read_wait_q, wait);
+ poll_wait(file, &dev->write_wait_q, wait);
+ if (sndtyp_psv(task->ttyp) ||
+ (sndtyp_wd(task->ttyp) && kfifo_len(dev->rcvdt.fifo)) ||
+ (sndtyp_bk(task->ttyp) && !ipblink_empty(&dev->rcvdt.bk.link)))
+ mask |= POLLIN | POLLRDNORM;
+ if (dev->wsz)
+ mask |= POLLOUT | POLLWRNORM;
+ devstate_read_unlock(dev);
+
+ return mask;
+}
+
+static int dsp_tctl_issue(struct taskdev *dev, u16 cmd, int argc, u16 argv[])
+{
+ int tctl_argc;
+ struct mb_exarg mbarg, *mbargp;
+ int interactive;
+ u8 tid;
+ int ret = 0;
+
+ if (cmd < 0x8000) {
+ /*
+ * 0x0000 - 0x7fff
+ * system reserved TCTL commands
+ */
+ switch (cmd) {
+ case TCTL_TEN:
+ case TCTL_TDIS:
+ tctl_argc = 0;
+ interactive = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+ /*
+ * 0x8000 - 0xffff
+ * user-defined TCTL commands
+ */
+ else if (cmd < 0x8100) {
+ /* 0x8000-0x80ff: no arg, non-interactive */
+ tctl_argc = 0;
+ interactive = 0;
+ } else if (cmd < 0x8200) {
+ /* 0x8100-0x81ff: 1 arg, non-interactive */
+ tctl_argc = 1;
+ interactive = 0;
+ } else if (cmd < 0x9000) {
+ /* 0x8200-0x8fff: reserved */
+ return -EINVAL;
+ } else if (cmd < 0x9100) {
+ /* 0x9000-0x90ff: no arg, interactive */
+ tctl_argc = 0;
+ interactive = 1;
+ } else if (cmd < 0x9200) {
+ /* 0x9100-0x91ff: 1 arg, interactive */
+ tctl_argc = 1;
+ interactive = 1;
+ } else {
+ /* 0x9200-0xffff: reserved */
+ return -EINVAL;
+ }
+
+ /*
+ * if argc < 0, use tctl_argc as is.
+ * if argc >= 0, check arg count.
+ */
+ if ((argc >= 0) && (argc != tctl_argc))
+ return -EINVAL;
+
+ /*
+ * issue TCTL
+ */
+ if (taskdev_lock_interruptible(dev, &dev->tctl_mutex))
+ return -EINTR;
+
+ tid = dev->task->tid;
+ if (tctl_argc > 0) {
+ mbarg.argc = tctl_argc;
+ mbarg.tid = tid;
+ mbarg.argv = argv;
+ mbargp = &mbarg;
+ } else
+ mbargp = NULL;
+
+ if (interactive) {
+ dev->tctl_stat = -EINVAL;
+
+ mbcompose_send_and_wait_exarg(TCTL, tid, cmd, mbargp,
+ &dev->tctl_wait_q);
+ if (signal_pending(current)) {
+ ret = -EINTR;
+ goto up_out;
+ }
+ if ((ret = dev->tctl_stat) < 0) {
+ printk(KERN_ERR "omapdsp: TCTL not responding.\n");
+ goto up_out;
+ }
+ } else
+ mbcompose_send_exarg(TCTL, tid, cmd, mbargp);
+
+up_out:
+ mutex_unlock(&dev->tctl_mutex);
+ return ret;
+}
+
+static int dsp_task_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ unsigned int minor = MINOR(inode->i_rdev);
+ struct taskdev *dev = taskdev[minor];
+ int ret;
+
+ if (cmd < 0x10000) {
+ /* issue TCTL */
+ u16 mbargv[1];
+
+ mbargv[0] = arg & 0xffff;
+ return dsp_tctl_issue(dev, cmd, -1, mbargv);
+ }
+
+ /* non TCTL ioctls */
+ switch (cmd) {
+
+ case TASK_IOCTL_LOCK:
+ ret = taskdev_lock(dev);
+ break;
+
+ case TASK_IOCTL_UNLOCK:
+ ret = taskdev_unlock(dev);
+ break;
+
+ case TASK_IOCTL_BFLSH:
+ if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+ return -ENODEV;
+ ret = taskdev_flush_buf(dev);
+ taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
+ break;
+
+ case TASK_IOCTL_SETBSZ:
+ if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+ return -ENODEV;
+ ret = taskdev_set_fifosz(dev, arg);
+ taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
+ break;
+
+ case TASK_IOCTL_GETNAME:
+ ret = 0;
+ if (copy_to_user((void __user *)arg, dev->name,
+ strlen(dev->name) + 1))
+ ret = -EFAULT;
+ break;
+
+ default:
+ ret = -ENOIOCTLCMD;
+
+ }
+
+ return ret;
+}
+
+static void dsp_task_mmap_open(struct vm_area_struct *vma)
+{
+ struct taskdev *dev = (struct taskdev *)vma->vm_private_data;
+ struct dsptask *task;
+ size_t len = vma->vm_end - vma->vm_start;
+
+ BUG_ON(!(dev->state & TASKDEV_ST_ATTACHED));
+ task = dev->task;
+ omap_mmu_exmap_use(&dsp_mmu, task->map_base, len);
+}
+
+static void dsp_task_mmap_close(struct vm_area_struct *vma)
+{
+ struct taskdev *dev = (struct taskdev *)vma->vm_private_data;
+ struct dsptask *task;
+ size_t len = vma->vm_end - vma->vm_start;
+
+ BUG_ON(!(dev->state & TASKDEV_ST_ATTACHED));
+ task = dev->task;
+ omap_mmu_exmap_unuse(&dsp_mmu, task->map_base, len);
+}
+
+/**
+ * On demand page allocation is not allowed. The mapping area is defined by
+ * corresponding DSP tasks.
+ */
+static int dsp_task_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+ return VM_FAULT_NOPAGE;
+}
+
+static struct vm_operations_struct dsp_task_vm_ops = {
+ .open = dsp_task_mmap_open,
+ .close = dsp_task_mmap_close,
+ .fault = dsp_task_mmap_fault,
+};
+
+static int dsp_task_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ void *tmp_vadr;
+ unsigned long tmp_padr, tmp_vmadr, off;
+ size_t req_len, tmp_len;
+ unsigned int minor = MINOR(filp->f_dentry->d_inode->i_rdev);
+ struct taskdev *dev = taskdev[minor];
+ struct dsptask *task;
+ int ret = 0;
+
+ if (!devstate_read_lock_and_test(dev, TASKDEV_ST_ATTACHED))
+ return -ENODEV;
+ task = dev->task;
+
+ /*
+ * Don't swap this area out
+ * Don't dump this area to a core file
+ */
+ vma->vm_flags |= VM_RESERVED | VM_IO;
+
+ /* Do not cache this area */
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+ req_len = vma->vm_end - vma->vm_start;
+ off = vma->vm_pgoff << PAGE_SHIFT;
+ tmp_vmadr = vma->vm_start;
+ tmp_vadr = task->map_base + off;
+ do {
+ tmp_padr = omap_mmu_virt_to_phys(&dsp_mmu, tmp_vadr, &tmp_len);
+ if (tmp_padr == 0) {
+ printk(KERN_ERR
+ "omapdsp: task %s: illegal address "
+ "for mmap: %p", task->name, tmp_vadr);
+ /* partial mapping will be cleared in upper layer */
+ ret = -EINVAL;
+ goto unlock_out;
+ }
+ if (tmp_len > req_len)
+ tmp_len = req_len;
+
+ pr_debug("omapdsp: mmap info: "
+ "vmadr = %08lx, padr = %08lx, len = %x\n",
+ tmp_vmadr, tmp_padr, tmp_len);
+ if (remap_pfn_range(vma, tmp_vmadr, tmp_padr >> PAGE_SHIFT,
+ tmp_len, vma->vm_page_prot) != 0) {
+ printk(KERN_ERR
+ "omapdsp: task %s: remap_page_range() failed.\n",
+ task->name);
+ /* partial mapping will be cleared in upper layer */
+ ret = -EINVAL;
+ goto unlock_out;
+ }
+
+ req_len -= tmp_len;
+ tmp_vmadr += tmp_len;
+ tmp_vadr += tmp_len;
+ } while (req_len);
+
+ vma->vm_ops = &dsp_task_vm_ops;
+ vma->vm_private_data = dev;
+ omap_mmu_exmap_use(&dsp_mmu, task->map_base, vma->vm_end - vma->vm_start);
+
+unlock_out:
+ devstate_read_unlock(dev);
+ return ret;
+}
+
+static int dsp_task_open(struct inode *inode, struct file *file)
+{
+ unsigned int minor = MINOR(inode->i_rdev);
+ struct taskdev *dev;
+ int ret = 0;
+
+ if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL))
+ return -ENODEV;
+
+ restart:
+ mutex_lock(&dev->usecount_lock);
+ down_write(&dev->state_sem);
+
+ /* state can be NOTASK, ATTACHED/FREEZED, KILLING, GARBAGE or INVALID here. */
+ switch (dev->state & TASKDEV_ST_STATE_MASK) {
+ case TASKDEV_ST_NOTASK:
+ break;
+ case TASKDEV_ST_ATTACHED:
+ goto attached;
+
+ case TASKDEV_ST_INVALID:
+ up_write(&dev->state_sem);
+ mutex_unlock(&dev->usecount_lock);
+ return -ENODEV;
+
+ case TASKDEV_ST_FREEZED:
+ case TASKDEV_ST_KILLING:
+ case TASKDEV_ST_GARBAGE:
+ case TASKDEV_ST_DELREQ:
+ /* on the kill process. wait until it becomes NOTASK. */
+ up_write(&dev->state_sem);
+ mutex_unlock(&dev->usecount_lock);
+ if (devstate_write_lock(dev, TASKDEV_ST_NOTASK) < 0)
+ return -EINTR;
+ devstate_write_unlock(dev);
+ goto restart;
+ }
+
+ /* NOTASK */
+ set_taskdev_state(dev, TASKDEV_ST_ADDREQ);
+ /* wake up twch daemon for tadd */
+ dsp_twch_touch();
+ up_write(&dev->state_sem);
+ if (devstate_write_lock(dev, TASKDEV_ST_ATTACHED |
+ TASKDEV_ST_ADDFAIL) < 0) {
+ /* cancelled */
+ if (!devstate_write_lock_and_test(dev, TASKDEV_ST_ADDREQ)) {
+ mutex_unlock(&dev->usecount_lock);
+ /* out of control ??? */
+ return -EINTR;
+ }
+ set_taskdev_state(dev, TASKDEV_ST_NOTASK);
+ ret = -EINTR;
+ goto change_out;
+ }
+ if (dev->state & TASKDEV_ST_ADDFAIL) {
+ printk(KERN_ERR "omapdsp: task attach failed for %s!\n",
+ dev->name);
+ ret = -EBUSY;
+ set_taskdev_state(dev, TASKDEV_ST_NOTASK);
+ goto change_out;
+ }
+
+ attached:
+ ret = proc_list_add(&dev->proc_list_lock,
+ &dev->proc_list, current, file);
+ if (ret)
+ goto out;
+
+ dev->usecount++;
+ file->f_op = &dev->fops;
+ up_write(&dev->state_sem);
+ mutex_unlock(&dev->usecount_lock);
+
+#ifdef DSP_PTE_FREE /* not used currently. */
+ dsp_map_update(current);
+ dsp_cur_users_add(current);
+#endif /* DSP_PTE_FREE */
+ return 0;
+
+ change_out:
+ wake_up_interruptible_all(&dev->state_wait_q);
+ out:
+ up_write(&dev->state_sem);
+ mutex_unlock(&dev->usecount_lock);
+ return ret;
+}
+
+static int dsp_task_release(struct inode *inode, struct file *file)
+{
+ unsigned int minor = MINOR(inode->i_rdev);
+ struct taskdev *dev = taskdev[minor];
+
+#ifdef DSP_PTE_FREE /* not used currently. */
+ dsp_cur_users_del(current);
+#endif /* DSP_PTE_FREE */
+
+ if (has_taskdev_lock(dev))
+ taskdev_unlock(dev);
+
+ proc_list_del(&dev->proc_list_lock, &dev->proc_list, current, file);
+ mutex_lock(&dev->usecount_lock);
+ if (--dev->usecount > 0) {
+ /* other processes are using this device. no state change. */
+ mutex_unlock(&dev->usecount_lock);
+ return 0;
+ }
+
+ /* usecount == 0 */
+ down_write(&dev->state_sem);
+
+ /* state can be ATTACHED/FREEZED, KILLING or GARBAGE here. */
+ switch (dev->state & TASKDEV_ST_STATE_MASK) {
+
+ case TASKDEV_ST_KILLING:
+ break;
+
+ case TASKDEV_ST_GARBAGE:
+ set_taskdev_state(dev, TASKDEV_ST_NOTASK);
+ wake_up_interruptible_all(&dev->state_wait_q);
+ break;
+
+ case TASKDEV_ST_ATTACHED:
+ case TASKDEV_ST_FREEZED:
+ if (is_dynamic_task(minor)) {
+ set_taskdev_state(dev, TASKDEV_ST_DELREQ);
+ /* wake up twch daemon for tdel */
+ dsp_twch_touch();
+ }
+ break;
+
+ }
+
+ up_write(&dev->state_sem);
+ mutex_unlock(&dev->usecount_lock);
+ return 0;
+}
+
+/*
+ * mkdev / rmdev
+ */
+int dsp_mkdev(char *name)
+{
+ struct taskdev *dev;
+ int status;
+ unsigned char minor;
+ int ret;
+
+ if (dsp_cfgstat_get_stat() != CFGSTAT_READY) {
+ printk(KERN_ERR "omapdsp: dsp has not been configured.\n");
+ return -EINVAL;
+ }
+
+ if (mutex_lock_interruptible(&devmgr_lock))
+ return -EINTR;
+
+ /* naming check */
+ for (minor = 0; minor < TASKDEV_MAX; minor++) {
+ if (taskdev[minor] && !strcmp(taskdev[minor]->name, name)) {
+ printk(KERN_ERR
+ "omapdsp: task device name %s is already "
+ "in use.\n", name);
+ ret = -EINVAL;
+ goto out;
+ }
+ }
+
+ /* find free minor number */
+ for (minor = n_task; minor < TASKDEV_MAX; minor++) {
+ if (taskdev[minor] == NULL)
+ goto do_make;
+ }
+ printk(KERN_ERR "omapdsp: Too many task devices.\n");
+ ret = -EBUSY;
+ goto out;
+
+do_make:
+ if ((dev = kzalloc(sizeof(struct taskdev), GFP_KERNEL)) == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ if ((status = taskdev_init(dev, name, minor)) < 0) {
+ kfree(dev);
+ ret = status;
+ goto out;
+ }
+ ret = minor;
+
+out:
+ mutex_unlock(&devmgr_lock);
+ return ret;
+}
+
+int dsp_rmdev(char *name)
+{
+ unsigned char minor;
+ int status;
+ int ret;
+
+ if (dsp_cfgstat_get_stat() != CFGSTAT_READY) {
+ printk(KERN_ERR "omapdsp: dsp has not been configured.\n");
+ return -EINVAL;
+ }
+
+ if (mutex_lock_interruptible(&devmgr_lock))
+ return -EINTR;
+
+ /* find in dynamic devices */
+ for (minor = n_task; minor < TASKDEV_MAX; minor++) {
+ if (taskdev[minor] && !strcmp(taskdev[minor]->name, name))
+ goto do_remove;
+ }
+
+ /* find in static devices */
+ for (minor = 0; minor < n_task; minor++) {
+ if (taskdev[minor] && !strcmp(taskdev[minor]->name, name)) {
+ printk(KERN_ERR
+ "omapdsp: task device %s is static.\n", name);
+ ret = -EINVAL;
+ goto out;
+ }
+ }
+
+ printk(KERN_ERR "omapdsp: task device %s not found.\n", name);
+ return -EINVAL;
+
+do_remove:
+ ret = minor;
+ if ((status = dsp_rmdev_minor(minor)) < 0)
+ ret = status;
+out:
+ mutex_unlock(&devmgr_lock);
+ return ret;
+}
+
+static int dsp_rmdev_minor(unsigned char minor)
+{
+ struct taskdev *dev = taskdev[minor];
+
+ while (!down_write_trylock(&dev->state_sem)) {
+ down_read(&dev->state_sem);
+ if (dev->state & (TASKDEV_ST_ATTACHED |
+ TASKDEV_ST_FREEZED)) {
+ /*
+ * task is working. kill it.
+ * ATTACHED -> FREEZED can be changed under
+ * down_read of state_sem..
+ */
+ set_taskdev_state(dev, TASKDEV_ST_FREEZED);
+ wake_up_interruptible_all(&dev->read_wait_q);
+ wake_up_interruptible_all(&dev->write_wait_q);
+ wake_up_interruptible_all(&dev->tctl_wait_q);
+ }
+ up_read(&dev->state_sem);
+ schedule();
+ }
+
+ switch (dev->state & TASKDEV_ST_STATE_MASK) {
+
+ case TASKDEV_ST_NOTASK:
+ case TASKDEV_ST_INVALID:
+ /* fine */
+ goto notask;
+
+ case TASKDEV_ST_ATTACHED:
+ case TASKDEV_ST_FREEZED:
+ /* task is working. kill it. */
+ set_taskdev_state(dev, TASKDEV_ST_KILLING);
+ up_write(&dev->state_sem);
+ dsp_tdel_bh(dev, TDEL_KILL);
+ goto invalidate;
+
+ case TASKDEV_ST_ADDREQ:
+ /* open() is waiting. drain it. */
+ set_taskdev_state(dev, TASKDEV_ST_ADDFAIL);
+ wake_up_interruptible_all(&dev->state_wait_q);
+ break;
+
+ case TASKDEV_ST_DELREQ:
+ /* nobody is waiting. */
+ set_taskdev_state(dev, TASKDEV_ST_NOTASK);
+ wake_up_interruptible_all(&dev->state_wait_q);
+ break;
+
+ case TASKDEV_ST_ADDING:
+ case TASKDEV_ST_DELING:
+ case TASKDEV_ST_KILLING:
+ case TASKDEV_ST_GARBAGE:
+ case TASKDEV_ST_ADDFAIL:
+ /* transient state. wait for a moment. */
+ break;
+
+ }
+
+ up_write(&dev->state_sem);
+
+invalidate:
+ /* wait for some time and hope the state is settled */
+ devstate_read_lock_timeout(dev, TASKDEV_ST_NOTASK, 5 * HZ);
+ if (!(dev->state & TASKDEV_ST_NOTASK)) {
+ printk(KERN_WARNING
+ "omapdsp: illegal device state (%s) on rmdev %s.\n",
+ devstate_name(dev->state), dev->name);
+ }
+notask:
+ set_taskdev_state(dev, TASKDEV_ST_INVALID);
+ devstate_read_unlock(dev);
+
+ taskdev_delete(minor);
+ kfree(dev);
+
+ return 0;
+}
+
+static struct file_operations dsp_task_fops = {
+ .owner = THIS_MODULE,
+ .poll = dsp_task_poll,
+ .ioctl = dsp_task_ioctl,
+ .open = dsp_task_open,
+ .release = dsp_task_release,
+};
+
+static void dsptask_dev_release(struct device *dev)
+{
+}
+
+static int taskdev_init(struct taskdev *dev, char *name, unsigned char minor)
+{
+ int ret;
+ struct device *task_dev;
+
+ taskdev[minor] = dev;
+
+ spin_lock_init(&dev->proc_list_lock);
+ INIT_LIST_HEAD(&dev->proc_list);
+ init_waitqueue_head(&dev->read_wait_q);
+ init_waitqueue_head(&dev->write_wait_q);
+ init_waitqueue_head(&dev->tctl_wait_q);
+ mutex_init(&dev->read_mutex);
+ mutex_init(&dev->write_mutex);
+ mutex_init(&dev->tctl_mutex);
+ mutex_init(&dev->lock);
+ spin_lock_init(&dev->wsz_lock);
+ dev->tctl_ret = -EINVAL;
+ dev->lock_pid = 0;
+
+ strncpy(dev->name, name, TNM_LEN);
+ dev->name[TNM_LEN-1] = '\0';
+ set_taskdev_state(dev, (minor < n_task) ? TASKDEV_ST_ATTACHED : TASKDEV_ST_NOTASK);
+ dev->usecount = 0;
+ mutex_init(&dev->usecount_lock);
+ memcpy(&dev->fops, &dsp_task_fops, sizeof(struct file_operations));
+
+ dev->dev.parent = omap_dsp->dev;
+ dev->dev.bus = &dsptask_bus;
+ sprintf(dev->dev.bus_id, "dsptask%d", minor);
+ dev->dev.release = dsptask_dev_release;
+ ret = device_register(&dev->dev);
+ if (ret) {
+ printk(KERN_ERR "device_register failed: %d\n", ret);
+ return ret;
+ }
+ ret = device_create_file(&dev->dev, &dev_attr_devname);
+ if (ret)
+ goto fail_create_devname;
+ ret = device_create_file(&dev->dev, &dev_attr_devstate);
+ if (ret)
+ goto fail_create_devstate;
+ ret = device_create_file(&dev->dev, &dev_attr_proc_list);
+ if (ret)
+ goto fail_create_proclist;
+
+ task_dev = device_create(dsp_task_class, NULL,
+ MKDEV(OMAP_DSP_TASK_MAJOR, minor),
+ "dsptask%d", (int)minor);
+
+ if (unlikely(IS_ERR(task_dev))) {
+ ret = -EINVAL;
+ goto fail_create_taskclass;
+ }
+
+ init_waitqueue_head(&dev->state_wait_q);
+ init_rwsem(&dev->state_sem);
+
+ return 0;
+
+ fail_create_taskclass:
+ device_remove_file(&dev->dev, &dev_attr_proc_list);
+ fail_create_proclist:
+ device_remove_file(&dev->dev, &dev_attr_devstate);
+ fail_create_devstate:
+ device_remove_file(&dev->dev, &dev_attr_devname);
+ fail_create_devname:
+ device_unregister(&dev->dev);
+ return ret;
+}
+
+static void taskdev_delete(unsigned char minor)
+{
+ struct taskdev *dev = taskdev[minor];
+
+ if (!dev)
+ return;
+ device_remove_file(&dev->dev, &dev_attr_devname);
+ device_remove_file(&dev->dev, &dev_attr_devstate);
+ device_remove_file(&dev->dev, &dev_attr_proc_list);
+ device_destroy(dsp_task_class, MKDEV(OMAP_DSP_TASK_MAJOR, minor));
+ device_unregister(&dev->dev);
+ proc_list_flush(&dev->proc_list_lock, &dev->proc_list);
+ taskdev[minor] = NULL;
+}
+
+static int taskdev_attach_task(struct taskdev *dev, struct dsptask *task)
+{
+ u16 ttyp = task->ttyp;
+ int ret;
+
+ dev->fops.read =
+ sndtyp_acv(ttyp) ?
+ sndtyp_wd(ttyp) ? dsp_task_read_wd_acv:
+ /* sndtyp_bk */ dsp_task_read_bk_acv:
+ /* sndtyp_psv */
+ sndtyp_wd(ttyp) ? dsp_task_read_wd_psv:
+ /* sndtyp_bk */ dsp_task_read_bk_psv;
+ if (sndtyp_wd(ttyp)) {
+ /* word */
+ size_t fifosz = sndtyp_psv(ttyp) ? 2:32; /* passive:active */
+
+ dev->rcvdt.fifo = kfifo_alloc(fifosz, GFP_KERNEL,
+ &dev->read_lock);
+ if (IS_ERR(dev->rcvdt.fifo)) {
+ printk(KERN_ERR
+ "omapdsp: unable to allocate receive buffer. "
+ "(%d bytes for %s)\n", fifosz, dev->name);
+ return -ENOMEM;
+ }
+ } else {
+ /* block */
+ INIT_IPBLINK(&dev->rcvdt.bk.link);
+ dev->rcvdt.bk.rp = 0;
+ }
+
+ dev->fops.write =
+ rcvtyp_wd(ttyp) ? dsp_task_write_wd:
+ /* rcvbyp_bk */ dsp_task_write_bk;
+ dev->wsz = rcvtyp_acv(ttyp) ? 0 : /* active */
+ rcvtyp_wd(ttyp) ? 2 : /* passive word */
+ ipbcfg.lsz*2; /* passive block */
+
+ if (task->map_length)
+ dev->fops.mmap = dsp_task_mmap;
+
+ ret = device_create_file(&dev->dev, &dev_attr_taskname);
+ if (unlikely(ret))
+ goto fail_create_taskname;
+ ret = device_create_file(&dev->dev, &dev_attr_ttyp);
+ if (unlikely(ret))
+ goto fail_create_ttyp;
+ ret = device_create_file(&dev->dev, &dev_attr_wsz);
+ if (unlikely(ret))
+ goto fail_create_wsz;
+ if (task->map_length) {
+ ret = device_create_file(&dev->dev, &dev_attr_mmap);
+ if (unlikely(ret))
+ goto fail_create_mmap;
+ }
+ if (sndtyp_wd(ttyp)) {
+ ret = device_create_file(&dev->dev, &dev_attr_fifosz);
+ if (unlikely(ret))
+ goto fail_create_fifosz;
+ ret = device_create_file(&dev->dev, &dev_attr_fifocnt);
+ if (unlikely(ret))
+ goto fail_create_fifocnt;
+ } else {
+ ret = device_create_file(&dev->dev, &dev_attr_ipblink);
+ if (unlikely(ret))
+ goto fail_create_ipblink;
+ }
+
+ dev->task = task;
+ task->dev = dev;
+
+ return 0;
+
+ fail_create_fifocnt:
+ device_remove_file(&dev->dev, &dev_attr_fifosz);
+ fail_create_ipblink:
+ fail_create_fifosz:
+ if (task->map_length)
+ device_remove_file(&dev->dev, &dev_attr_mmap);
+ fail_create_mmap:
+ device_remove_file(&dev->dev, &dev_attr_wsz);
+ fail_create_wsz:
+ device_remove_file(&dev->dev, &dev_attr_ttyp);
+ fail_create_ttyp:
+ device_remove_file(&dev->dev, &dev_attr_taskname);
+ fail_create_taskname:
+ if (task->map_length)
+ dev->fops.mmap = NULL;
+
+ dev->fops.write = NULL;
+ dev->wsz = 0;
+
+ dev->fops.read = NULL;
+ taskdev_flush_buf(dev);
+
+ if (sndtyp_wd(ttyp))
+ kfifo_free(dev->rcvdt.fifo);
+
+ dev->task = NULL;
+
+ return ret;
+}
+
+static void taskdev_detach_task(struct taskdev *dev)
+{
+ u16 ttyp = dev->task->ttyp;
+
+ device_remove_file(&dev->dev, &dev_attr_taskname);
+ device_remove_file(&dev->dev, &dev_attr_ttyp);
+ if (sndtyp_wd(ttyp)) {
+ device_remove_file(&dev->dev, &dev_attr_fifosz);
+ device_remove_file(&dev->dev, &dev_attr_fifocnt);
+ } else
+ device_remove_file(&dev->dev, &dev_attr_ipblink);
+ device_remove_file(&dev->dev, &dev_attr_wsz);
+ if (dev->task->map_length) {
+ device_remove_file(&dev->dev, &dev_attr_mmap);
+ dev->fops.mmap = NULL;
+ }
+
+ dev->fops.read = NULL;
+ taskdev_flush_buf(dev);
+ if (sndtyp_wd(ttyp))
+ kfifo_free(dev->rcvdt.fifo);
+
+ dev->fops.write = NULL;
+ dev->wsz = 0;
+
+ pr_info("omapdsp: taskdev %s disabled.\n", dev->name);
+ dev->task = NULL;
+}
+
+/*
+ * tadd / tdel / tkill
+ */
+static int dsp_tadd(struct taskdev *dev, dsp_long_t adr)
+{
+ struct dsptask *task;
+ struct mb_exarg arg;
+ u8 tid, tid_response;
+ u16 argv[2];
+ int ret = 0;
+
+ if (!devstate_write_lock_and_test(dev, TASKDEV_ST_ADDREQ)) {
+ printk(KERN_ERR
+ "omapdsp: taskdev %s is not requesting for tadd. "
+ "(state is %s)\n", dev->name, devstate_name(dev->state));
+ return -EINVAL;
+ }
+ set_taskdev_state(dev, TASKDEV_ST_ADDING);
+ devstate_write_unlock(dev);
+
+ if (adr == TADD_ABORTADR) {
+ /* aborting tadd intentionally */
+ pr_info("omapdsp: tadd address is ABORTADR.\n");
+ goto fail_out;
+ }
+ if (adr >= DSPSPACE_SIZE) {
+ printk(KERN_ERR
+ "omapdsp: illegal address 0x%08x for tadd\n", adr);
+ ret = -EINVAL;
+ goto fail_out;
+ }
+
+ adr >>= 1; /* word address */
+ argv[0] = adr >> 16; /* addrh */
+ argv[1] = adr & 0xffff; /* addrl */
+
+ if (mutex_lock_interruptible(&cfg_lock)) {
+ ret = -EINTR;
+ goto fail_out;
+ }
+ cfg_tid = TID_ANON;
+ cfg_cmd = MBOX_CMD_DSP_TADD;
+ arg.tid = TID_ANON;
+ arg.argc = 2;
+ arg.argv = argv;
+
+ if (dsp_mem_sync_inc() < 0) {
+ printk(KERN_ERR "omapdsp: memory sync failed!\n");
+ ret = -EBUSY;
+ goto fail_out;
+ }
+ mbcompose_send_and_wait_exarg(TADD, 0, 0, &arg, &cfg_wait_q);
+
+ tid = cfg_tid;
+ cfg_tid = TID_ANON;
+ cfg_cmd = 0;
+ mutex_unlock(&cfg_lock);
+
+ if (tid == TID_ANON) {
+ printk(KERN_ERR "omapdsp: tadd failed!\n");
+ ret = -EINVAL;
+ goto fail_out;
+ }
+ if ((tid < n_task) || dsptask[tid]) {
+ printk(KERN_ERR "omapdsp: illegal tid (%d)!\n", tid);
+ ret = -EINVAL;
+ goto fail_out;
+ }
+ if ((task = kzalloc(sizeof(struct dsptask), GFP_KERNEL)) == NULL) {
+ ret = -ENOMEM;
+ goto del_out;
+ }
+
+ if ((ret = dsp_task_config(task, tid)) < 0)
+ goto free_out;
+
+ if (strcmp(dev->name, task->name)) {
+ printk(KERN_ERR
+ "omapdsp: task name (%s) doesn't match with "
+ "device name (%s).\n", task->name, dev->name);
+ ret = -EINVAL;
+ goto free_out;
+ }
+
+ if ((ret = taskdev_attach_task(dev, task)) < 0)
+ goto free_out;
+
+ dsp_task_init(task);
+ pr_info("omapdsp: taskdev %s enabled.\n", dev->name);
+ set_taskdev_state(dev, TASKDEV_ST_ATTACHED);
+ wake_up_interruptible_all(&dev->state_wait_q);
+ return 0;
+
+free_out:
+ kfree(task);
+
+del_out:
+ printk(KERN_ERR "omapdsp: deleting the task...\n");
+
+ set_taskdev_state(dev, TASKDEV_ST_DELING);
+
+ if (mutex_lock_interruptible(&cfg_lock)) {
+ printk(KERN_ERR "omapdsp: aborting tdel process. "
+ "DSP side could be corrupted.\n");
+ goto fail_out;
+ }
+ cfg_tid = TID_ANON;
+ cfg_cmd = MBOX_CMD_DSP_TDEL;
+ mbcompose_send_and_wait(TDEL, tid, TDEL_KILL, &cfg_wait_q);
+ tid_response = cfg_tid;
+ cfg_tid = TID_ANON;
+ cfg_cmd = 0;
+ mutex_unlock(&cfg_lock);
+
+ if (tid_response != tid)
+ printk(KERN_ERR "omapdsp: tdel failed. "
+ "DSP side could be corrupted.\n");
+
+fail_out:
+ set_taskdev_state(dev, TASKDEV_ST_ADDFAIL);
+ wake_up_interruptible_all(&dev->state_wait_q);
+ return ret;
+}
+
+int dsp_tadd_minor(unsigned char minor, dsp_long_t adr)
+{
+ struct taskdev *dev;
+ int status;
+ int ret;
+
+ if (mutex_lock_interruptible(&devmgr_lock))
+ return -EINTR;
+
+ if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL)) {
+ printk(KERN_ERR
+ "omapdsp: no task device with minor %d\n", minor);
+ ret = -EINVAL;
+ goto out;
+ }
+ ret = minor;
+ if ((status = dsp_tadd(dev, adr)) < 0)
+ ret = status;
+
+out:
+ mutex_unlock(&devmgr_lock);
+ return ret;
+}
+
+static int dsp_tdel(struct taskdev *dev)
+{
+ if (!devstate_write_lock_and_test(dev, TASKDEV_ST_DELREQ)) {
+ printk(KERN_ERR
+ "omapdsp: taskdev %s is not requesting for tdel. "
+ "(state is %s)\n", dev->name, devstate_name(dev->state));
+ return -EINVAL;
+ }
+ set_taskdev_state(dev, TASKDEV_ST_DELING);
+ devstate_write_unlock(dev);
+
+ return dsp_tdel_bh(dev, TDEL_SAFE);
+}
+
+int dsp_tdel_minor(unsigned char minor)
+{
+ struct taskdev *dev;
+ int status;
+ int ret;
+
+ if (mutex_lock_interruptible(&devmgr_lock))
+ return -EINTR;
+
+ if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL)) {
+ printk(KERN_ERR
+ "omapdsp: no task device with minor %d\n", minor);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = minor;
+ if ((status = dsp_tdel(dev)) < 0)
+ ret = status;
+
+out:
+ mutex_unlock(&devmgr_lock);
+ return ret;
+}
+
+static int dsp_tkill(struct taskdev *dev)
+{
+ while (!down_write_trylock(&dev->state_sem)) {
+ if (!devstate_read_lock_and_test(dev, (TASKDEV_ST_ATTACHED |
+ TASKDEV_ST_FREEZED))) {
+ printk(KERN_ERR
+ "omapdsp: task has not been attached for "
+ "taskdev %s\n", dev->name);
+ return -EINVAL;
+ }
+ /* ATTACHED -> FREEZED can be changed under read semaphore. */
+ set_taskdev_state(dev, TASKDEV_ST_FREEZED);
+ wake_up_interruptible_all(&dev->read_wait_q);
+ wake_up_interruptible_all(&dev->write_wait_q);
+ wake_up_interruptible_all(&dev->tctl_wait_q);
+ devstate_read_unlock(dev);
+ schedule();
+ }
+
+ if (!(dev->state & (TASKDEV_ST_ATTACHED |
+ TASKDEV_ST_FREEZED))) {
+ printk(KERN_ERR
+ "omapdsp: task has not been attached for taskdev %s\n",
+ dev->name);
+ devstate_write_unlock(dev);
+ return -EINVAL;
+ }
+ if (!is_dynamic_task(dev->task->tid)) {
+ printk(KERN_ERR "omapdsp: task %s is not a dynamic task.\n",
+ dev->name);
+ devstate_write_unlock(dev);
+ return -EINVAL;
+ }
+ set_taskdev_state(dev, TASKDEV_ST_KILLING);
+ devstate_write_unlock(dev);
+
+ return dsp_tdel_bh(dev, TDEL_KILL);
+}
+
+int dsp_tkill_minor(unsigned char minor)
+{
+ struct taskdev *dev;
+ int status;
+ int ret;
+
+ if (mutex_lock_interruptible(&devmgr_lock))
+ return -EINTR;
+
+ if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL)) {
+ printk(KERN_ERR
+ "omapdsp: no task device with minor %d\n", minor);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = minor;
+ if ((status = dsp_tkill(dev)) < 0)
+ ret = status;
+
+out:
+ mutex_unlock(&devmgr_lock);
+ return ret;
+}
+
+static int dsp_tdel_bh(struct taskdev *dev, u16 type)
+{
+ struct dsptask *task;
+ u8 tid, tid_response;
+ int ret = 0;
+
+ task = dev->task;
+ tid = task->tid;
+ if (mutex_lock_interruptible(&cfg_lock)) {
+ if (type == TDEL_SAFE) {
+ set_taskdev_state(dev, TASKDEV_ST_DELREQ);
+ return -EINTR;
+ } else {
+ tid_response = TID_ANON;
+ ret = -EINTR;
+ goto detach_out;
+ }
+ }
+ cfg_tid = TID_ANON;
+ cfg_cmd = MBOX_CMD_DSP_TDEL;
+ mbcompose_send_and_wait(TDEL, tid, type, &cfg_wait_q);
+ tid_response = cfg_tid;
+ cfg_tid = TID_ANON;
+ cfg_cmd = 0;
+ mutex_unlock(&cfg_lock);
+
+detach_out:
+ taskdev_detach_task(dev);
+ dsp_task_unconfig(task);
+ kfree(task);
+
+ if (tid_response != tid) {
+ printk(KERN_ERR "omapdsp: %s failed!\n",
+ (type == TDEL_SAFE) ? "tdel" : "tkill");
+ ret = -EINVAL;
+ }
+ down_write(&dev->state_sem);
+ set_taskdev_state(dev, (dev->usecount > 0) ? TASKDEV_ST_GARBAGE :
+ TASKDEV_ST_NOTASK);
+ wake_up_interruptible_all(&dev->state_wait_q);
+ up_write(&dev->state_sem);
+
+ return ret;
+}
+
+/*
+ * state inquiry
+ */
+long taskdev_state_stale(unsigned char minor)
+{
+ if (taskdev[minor]) {
+ long state = taskdev[minor]->state;
+ taskdev[minor]->state |= TASKDEV_ST_STALE;
+ return state;
+ } else
+ return TASKDEV_ST_NOTASK;
+}
+
+/*
+ * functions called from mailbox interrupt routine
+ */
+void mbox_wdsnd(struct mbcmd *mb)
+{
+ unsigned int n;
+ u8 tid = mb->cmd_l;
+ u16 data = mb->data;
+ struct dsptask *task = dsptask[tid];
+
+ if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+ printk(KERN_ERR "mbox: WDSND with illegal tid! %d\n", tid);
+ return;
+ }
+ if (sndtyp_bk(task->ttyp)) {
+ printk(KERN_ERR
+ "mbox: WDSND from block sending task! (task%d)\n", tid);
+ return;
+ }
+ if (sndtyp_psv(task->ttyp) &&
+ !waitqueue_active(&task->dev->read_wait_q)) {
+ printk(KERN_WARNING
+ "mbox: WDSND from passive sending task (task%d) "
+ "without request!\n", tid);
+ return;
+ }
+
+ n = kfifo_put(task->dev->rcvdt.fifo, (unsigned char *)&data,
+ sizeof(data));
+ if (n != sizeof(data))
+ printk(KERN_WARNING "Receive FIFO(%d) is full\n", tid);
+
+ wake_up_interruptible(&task->dev->read_wait_q);
+}
+
+void mbox_wdreq(struct mbcmd *mb)
+{
+ u8 tid = mb->cmd_l;
+ struct dsptask *task = dsptask[tid];
+ struct taskdev *dev;
+
+ if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+ printk(KERN_ERR "mbox: WDREQ with illegal tid! %d\n", tid);
+ return;
+ }
+ if (rcvtyp_psv(task->ttyp)) {
+ printk(KERN_ERR
+ "mbox: WDREQ from passive receiving task! (task%d)\n",
+ tid);
+ return;
+ }
+
+ dev = task->dev;
+ spin_lock(&dev->wsz_lock);
+ dev->wsz = 2;
+ spin_unlock(&dev->wsz_lock);
+ wake_up_interruptible(&dev->write_wait_q);
+}
+
+void mbox_bksnd(struct mbcmd *mb)
+{
+ u8 tid = mb->cmd_l;
+ u16 bid = mb->data;
+ struct dsptask *task = dsptask[tid];
+ struct ipbuf_head *ipb_h;
+ u16 cnt;
+
+ if (bid >= ipbcfg.ln) {
+ printk(KERN_ERR "mbox: BKSND with illegal bid! %d\n", bid);
+ return;
+ }
+ ipb_h = bid_to_ipbuf(bid);
+ ipb_bsycnt_dec(&ipbcfg);
+ if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+ printk(KERN_ERR "mbox: BKSND with illegal tid! %d\n", tid);
+ goto unuse_ipbuf_out;
+ }
+ if (sndtyp_wd(task->ttyp)) {
+ printk(KERN_ERR
+ "mbox: BKSND from word sending task! (task%d)\n", tid);
+ goto unuse_ipbuf_out;
+ }
+ if (sndtyp_pvt(task->ttyp)) {
+ printk(KERN_ERR
+ "mbox: BKSND from private sending task! (task%d)\n", tid);
+ goto unuse_ipbuf_out;
+ }
+ if (sync_with_dsp(&ipb_h->p->sd, tid, 10) < 0) {
+ printk(KERN_ERR "mbox: BKSND - IPBUF sync failed!\n");
+ return;
+ }
+
+ /* should be done in DSP, but just in case. */
+ ipb_h->p->next = BID_NULL;
+
+ cnt = ipb_h->p->c;
+ if (cnt > ipbcfg.lsz) {
+ printk(KERN_ERR "mbox: BKSND cnt(%d) > ipbuf line size(%d)!\n",
+ cnt, ipbcfg.lsz);
+ goto unuse_ipbuf_out;
+ }
+
+ if (cnt == 0) {
+ /* 0-byte send from DSP */
+ unuse_ipbuf_nowait(ipb_h);
+ goto done;
+ }
+ ipblink_add_tail(&task->dev->rcvdt.bk.link, bid);
+ /* we keep coming bid and return alternative line to DSP. */
+ balance_ipbuf();
+
+done:
+ wake_up_interruptible(&task->dev->read_wait_q);
+ return;
+
+unuse_ipbuf_out:
+ unuse_ipbuf_nowait(ipb_h);
+ return;
+}
+
+void mbox_bkreq(struct mbcmd *mb)
+{
+ u8 tid = mb->cmd_l;
+ u16 cnt = mb->data;
+ struct dsptask *task = dsptask[tid];
+ struct taskdev *dev;
+
+ if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+ printk(KERN_ERR "mbox: BKREQ with illegal tid! %d\n", tid);
+ return;
+ }
+ if (rcvtyp_wd(task->ttyp)) {
+ printk(KERN_ERR
+ "mbox: BKREQ from word receiving task! (task%d)\n", tid);
+ return;
+ }
+ if (rcvtyp_pvt(task->ttyp)) {
+ printk(KERN_ERR
+ "mbox: BKREQ from private receiving task! (task%d)\n",
+ tid);
+ return;
+ }
+ if (rcvtyp_psv(task->ttyp)) {
+ printk(KERN_ERR
+ "mbox: BKREQ from passive receiving task! (task%d)\n",
+ tid);
+ return;
+ }
+
+ dev = task->dev;
+ spin_lock(&dev->wsz_lock);
+ dev->wsz = cnt*2;
+ spin_unlock(&dev->wsz_lock);
+ wake_up_interruptible(&dev->write_wait_q);
+}
+
+void mbox_bkyld(struct mbcmd *mb)
+{
+ u16 bid = mb->data;
+ struct ipbuf_head *ipb_h;
+
+ if (bid >= ipbcfg.ln) {
+ printk(KERN_ERR "mbox: BKYLD with illegal bid! %d\n", bid);
+ return;
+ }
+ ipb_h = bid_to_ipbuf(bid);
+
+ /* should be done in DSP, but just in case. */
+ ipb_h->p->next = BID_NULL;
+
+ /* we don't need to sync with DSP */
+ ipb_bsycnt_dec(&ipbcfg);
+ release_ipbuf(ipb_h);
+}
+
+void mbox_bksndp(struct mbcmd *mb)
+{
+ u8 tid = mb->cmd_l;
+ struct dsptask *task = dsptask[tid];
+ struct ipbuf_p *ipbp;
+
+ if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+ printk(KERN_ERR "mbox: BKSNDP with illegal tid! %d\n", tid);
+ return;
+ }
+ if (sndtyp_wd(task->ttyp)) {
+ printk(KERN_ERR
+ "mbox: BKSNDP from word sending task! (task%d)\n", tid);
+ return;
+ }
+ if (sndtyp_gbl(task->ttyp)) {
+ printk(KERN_ERR
+ "mbox: BKSNDP from non-private sending task! (task%d)\n",
+ tid);
+ return;
+ }
+
+ /*
+ * we should not have delayed block at this point
+ * because read() routine releases the lock of the buffer and
+ * until then DSP can't send next data.
+ */
+
+ ipbp = task->ipbuf_pvt_r;
+ if (sync_with_dsp(&ipbp->s, tid, 10) < 0) {
+ printk(KERN_ERR "mbox: BKSNDP - IPBUF sync failed!\n");
+ return;
+ }
+ pr_debug("mbox: ipbuf_pvt_r->a = 0x%08lx\n",
+ MKLONG(ipbp->ah, ipbp->al));
+ ipblink_add_pvt(&task->dev->rcvdt.bk.link);
+ wake_up_interruptible(&task->dev->read_wait_q);
+}
+
+void mbox_bkreqp(struct mbcmd *mb)
+{
+ u8 tid = mb->cmd_l;
+ struct dsptask *task = dsptask[tid];
+ struct taskdev *dev;
+ struct ipbuf_p *ipbp;
+
+ if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+ printk(KERN_ERR "mbox: BKREQP with illegal tid! %d\n", tid);
+ return;
+ }
+ if (rcvtyp_wd(task->ttyp)) {
+ printk(KERN_ERR
+ "mbox: BKREQP from word receiving task! (task%d)\n", tid);
+ return;
+ }
+ if (rcvtyp_gbl(task->ttyp)) {
+ printk(KERN_ERR
+ "mbox: BKREQP from non-private receiving task! (task%d)\n", tid);
+ return;
+ }
+ if (rcvtyp_psv(task->ttyp)) {
+ printk(KERN_ERR
+ "mbox: BKREQP from passive receiving task! (task%d)\n", tid);
+ return;
+ }
+
+ ipbp = task->ipbuf_pvt_w;
+ if (sync_with_dsp(&ipbp->s, TID_FREE, 10) < 0) {
+ printk(KERN_ERR "mbox: BKREQP - IPBUF sync failed!\n");
+ return;
+ }
+ pr_debug("mbox: ipbuf_pvt_w->a = 0x%08lx\n",
+ MKLONG(ipbp->ah, ipbp->al));
+ dev = task->dev;
+ spin_lock(&dev->wsz_lock);
+ dev->wsz = ipbp->c*2;
+ spin_unlock(&dev->wsz_lock);
+ wake_up_interruptible(&dev->write_wait_q);
+}
+
+void mbox_tctl(struct mbcmd *mb)
+{
+ u8 tid = mb->cmd_l;
+ struct dsptask *task = dsptask[tid];
+
+ if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+ printk(KERN_ERR "mbox: TCTL with illegal tid! %d\n", tid);
+ return;
+ }
+
+ if (!waitqueue_active(&task->dev->tctl_wait_q)) {
+ printk(KERN_WARNING "mbox: unexpected TCTL from DSP!\n");
+ return;
+ }
+
+ task->dev->tctl_stat = mb->data;
+ wake_up_interruptible(&task->dev->tctl_wait_q);
+}
+
+void mbox_tcfg(struct mbcmd *mb)
+{
+ u8 tid = mb->cmd_l;
+ struct dsptask *task = dsptask[tid];
+ u16 *tnm;
+ volatile u16 *buf;
+ int i;
+
+ if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+ printk(KERN_ERR "mbox: TCFG with illegal tid! %d\n", tid);
+ return;
+ }
+ if ((task->state != TASK_ST_CFGREQ) || (cfg_cmd != MBOX_CMD_DSP_TCFG)) {
+ printk(KERN_WARNING "mbox: unexpected TCFG from DSP!\n");
+ return;
+ }
+
+ if (dsp_mem_enable(ipbuf_sys_da) < 0) {
+ printk(KERN_ERR "mbox: TCFG - ipbuf_sys_da read failed!\n");
+ dsp_mem_disable(ipbuf_sys_da);
+ goto out;
+ }
+ if (sync_with_dsp(&ipbuf_sys_da->s, tid, 10) < 0) {
+ printk(KERN_ERR "mbox: TCFG - IPBUF sync failed!\n");
+ dsp_mem_disable(ipbuf_sys_da);
+ goto out;
+ }
+
+ /*
+ * read configuration data on system IPBUF
+ */
+ buf = ipbuf_sys_da->d;
+ task->ttyp = buf[0];
+ task->ipbuf_pvt_r = MKVIRT(buf[1], buf[2]);
+ task->ipbuf_pvt_w = MKVIRT(buf[3], buf[4]);
+ task->map_base = MKVIRT(buf[5], buf[6]);
+ task->map_length = MKLONG(buf[7], buf[8]) << 1; /* word -> byte */
+ tnm = MKVIRT(buf[9], buf[10]);
+ release_ipbuf_pvt(ipbuf_sys_da);
+ dsp_mem_disable(ipbuf_sys_da);
+
+ /*
+ * copy task name string
+ */
+ if (dsp_address_validate(tnm, TNM_LEN, "task name buffer") < 0) {
+ task->name[0] = '\0';
+ goto out;
+ }
+
+ for (i = 0; i < TNM_LEN-1; i++) {
+ /* avoiding byte access */
+ u16 tmp = tnm[i];
+ task->name[i] = tmp & 0x00ff;
+ if (!tmp)
+ break;
+ }
+ task->name[TNM_LEN-1] = '\0';
+
+ task->state = TASK_ST_READY;
+out:
+ wake_up_interruptible(&cfg_wait_q);
+}
+
+void mbox_tadd(struct mbcmd *mb)
+{
+ u8 tid = mb->cmd_l;
+
+ if ((!waitqueue_active(&cfg_wait_q)) || (cfg_cmd != MBOX_CMD_DSP_TADD)) {
+ printk(KERN_WARNING "mbox: unexpected TADD from DSP!\n");
+ return;
+ }
+ cfg_tid = tid;
+ wake_up_interruptible(&cfg_wait_q);
+}
+
+void mbox_tdel(struct mbcmd *mb)
+{
+ u8 tid = mb->cmd_l;
+
+ if ((!waitqueue_active(&cfg_wait_q)) || (cfg_cmd != MBOX_CMD_DSP_TDEL)) {
+ printk(KERN_WARNING "mbox: unexpected TDEL from DSP!\n");
+ return;
+ }
+ cfg_tid = tid;
+ wake_up_interruptible(&cfg_wait_q);
+}
+
+void mbox_err_fatal(u8 tid)
+{
+ struct dsptask *task = dsptask[tid];
+ struct taskdev *dev;
+
+ if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+ printk(KERN_ERR "mbox: FATAL ERR with illegal tid! %d\n", tid);
+ return;
+ }
+
+ /* wake up waiting processes */
+ dev = task->dev;
+ wake_up_interruptible_all(&dev->read_wait_q);
+ wake_up_interruptible_all(&dev->write_wait_q);
+ wake_up_interruptible_all(&dev->tctl_wait_q);
+}
+
+static u16 *dbg_buf;
+static u16 dbg_buf_sz, dbg_line_sz;
+static int dbg_rp;
+
+int dsp_dbg_config(u16 *buf, u16 sz, u16 lsz)
+{
+#ifdef OLD_BINARY_SUPPORT
+ if ((mbox_revision == MBREV_3_0) || (mbox_revision == MBREV_3_2)) {
+ dbg_buf = NULL;
+ dbg_buf_sz = 0;
+ dbg_line_sz = 0;
+ dbg_rp = 0;
+ return 0;
+ }
+#endif
+
+ if (dsp_address_validate(buf, sz, "debug buffer") < 0)
+ return -1;
+
+ if (lsz > sz) {
+ printk(KERN_ERR
+ "omapdsp: dbg_buf lsz (%d) is greater than its "
+ "buffer size (%d)\n", lsz, sz);
+ return -1;
+ }
+
+ dbg_buf = buf;
+ dbg_buf_sz = sz;
+ dbg_line_sz = lsz;
+ dbg_rp = 0;
+
+ return 0;
+}
+
+void dsp_dbg_stop(void)
+{
+ dbg_buf = NULL;
+}
+
+#ifdef OLD_BINARY_SUPPORT
+static void mbox_dbg_old(struct mbcmd *mb);
+#endif
+
+void mbox_dbg(struct mbcmd *mb)
+{
+ u8 tid = mb->cmd_l;
+ int cnt = mb->data;
+ char s[80], *s_end = &s[79], *p;
+ u16 *src;
+ int i;
+
+#ifdef OLD_BINARY_SUPPORT
+ if ((mbox_revision == MBREV_3_0) || (mbox_revision == MBREV_3_2)) {
+ mbox_dbg_old(mb);
+ return;
+ }
+#endif
+
+ if (((tid >= TASKDEV_MAX) || (dsptask[tid] == NULL)) &&
+ (tid != TID_ANON)) {
+ printk(KERN_ERR "mbox: DBG with illegal tid! %d\n", tid);
+ return;
+ }
+ if (dbg_buf == NULL) {
+ printk(KERN_ERR "mbox: DBG command received, but "
+ "dbg_buf has not been configured yet.\n");
+ return;
+ }
+
+ if (dsp_mem_enable(dbg_buf) < 0)
+ return;
+
+ src = &dbg_buf[dbg_rp];
+ p = s;
+ for (i = 0; i < cnt; i++) {
+ u16 tmp;
+ /*
+ * Be carefull that dbg_buf should not be read with
+ * 1-byte access since it might be placed in DARAM/SARAM
+ * and it can cause unexpected byteswap.
+ * For example,
+ * *(p++) = *(src++) & 0xff;
+ * causes 1-byte access!
+ */
+ tmp = *src++;
+ *(p++) = tmp & 0xff;
+ if (*(p-1) == '\n') {
+ *p = '\0';
+ pr_info("%s", s);
+ p = s;
+ continue;
+ }
+ if (p == s_end) {
+ *p = '\0';
+ pr_info("%s\n", s);
+ p = s;
+ continue;
+ }
+ }
+ if (p > s) {
+ *p = '\0';
+ pr_info("%s\n", s);
+ }
+ if ((dbg_rp += cnt + 1) > dbg_buf_sz - dbg_line_sz)
+ dbg_rp = 0;
+
+ dsp_mem_disable(dbg_buf);
+}
+
+#ifdef OLD_BINARY_SUPPORT
+static void mbox_dbg_old(struct mbcmd *mb)
+{
+ u8 tid = mb->cmd_l;
+ char s[80], *s_end = &s[79], *p;
+ u16 *src;
+ volatile u16 *buf;
+ int cnt;
+ int i;
+
+ if (((tid >= TASKDEV_MAX) || (dsptask[tid] == NULL)) &&
+ (tid != TID_ANON)) {
+ printk(KERN_ERR "mbox: DBG with illegal tid! %d\n", tid);
+ return;
+ }
+ if (dsp_mem_enable(ipbuf_sys_da) < 0) {
+ printk(KERN_ERR "mbox: DBG - ipbuf_sys_da read failed!\n");
+ return;
+ }
+ if (sync_with_dsp(&ipbuf_sys_da->s, tid, 10) < 0) {
+ printk(KERN_ERR "mbox: DBG - IPBUF sync failed!\n");
+ goto out1;
+ }
+ buf = ipbuf_sys_da->d;
+ cnt = buf[0];
+ src = MKVIRT(buf[1], buf[2]);
+ if (dsp_address_validate(src, cnt, "dbg buffer") < 0)
+ goto out2;
+
+ if (dsp_mem_enable(src) < 0)
+ goto out2;
+
+ p = s;
+ for (i = 0; i < cnt; i++) {
+ u16 tmp;
+ /*
+ * Be carefull that ipbuf should not be read with
+ * 1-byte access since it might be placed in DARAM/SARAM
+ * and it can cause unexpected byteswap.
+ * For example,
+ * *(p++) = *(src++) & 0xff;
+ * causes 1-byte access!
+ */
+ tmp = *src++;
+ *(p++) = tmp & 0xff;
+ if (*(p-1) == '\n') {
+ *p = '\0';
+ pr_info("%s", s);
+ p = s;
+ continue;
+ }
+ if (p == s_end) {
+ *p = '\0';
+ pr_info("%s\n", s);
+ p = s;
+ continue;
+ }
+ }
+ if (p > s) {
+ *p = '\0';
+ pr_info("%s\n", s);
+ }
+
+ dsp_mem_disable(src);
+out2:
+ release_ipbuf_pvt(ipbuf_sys_da);
+out1:
+ dsp_mem_disable(ipbuf_sys_da);
+}
+#endif /* OLD_BINARY_SUPPORT */
+
+/*
+ * sysfs files: for each device
+ */
+
+/* devname */
+static ssize_t devname_show(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%s\n", to_taskdev(d)->name);
+}
+
+/* devstate */
+static ssize_t devstate_show(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%s\n", devstate_name(to_taskdev(d)->state));
+}
+
+/* proc_list */
+static ssize_t proc_list_show(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ struct taskdev *dev;
+ struct proc_list *pl;
+ int len = 0;
+
+ dev = to_taskdev(d);
+ spin_lock(&dev->proc_list_lock);
+ list_for_each_entry(pl, &dev->proc_list, list_head) {
+ /* need to lock tasklist_lock before calling
+ * find_task_by_pid_type. */
+ if (find_task_by_pid(pl->pid) != NULL)
+ len += sprintf(buf + len, "%d\n", pl->pid);
+ read_unlock(&tasklist_lock);
+ }
+ spin_unlock(&dev->proc_list_lock);
+
+ return len;
+}
+
+/* taskname */
+static ssize_t taskname_show(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ struct taskdev *dev = to_taskdev(d);
+ int len;
+
+ if (!devstate_read_lock_and_test(dev, TASKDEV_ST_ATTACHED))
+ return -ENODEV;
+
+ len = sprintf(buf, "%s\n", dev->task->name);
+
+ devstate_read_unlock(dev);
+ return len;
+}
+
+/* ttyp */
+static ssize_t ttyp_show(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ struct taskdev *dev = to_taskdev(d);
+ u16 ttyp;
+ int len = 0;
+
+ if (!devstate_read_lock_and_test(dev, TASKDEV_ST_ATTACHED))
+ return -ENODEV;
+
+ ttyp = dev->task->ttyp;
+ len += sprintf(buf + len, "0x%04x\n", ttyp);
+ len += sprintf(buf + len, "%s %s send\n",
+ (sndtyp_acv(ttyp)) ? "active" :
+ "passive",
+ (sndtyp_wd(ttyp)) ? "word" :
+ (sndtyp_pvt(ttyp)) ? "private block" :
+ "global block");
+ len += sprintf(buf + len, "%s %s receive\n",
+ (rcvtyp_acv(ttyp)) ? "active" :
+ "passive",
+ (rcvtyp_wd(ttyp)) ? "word" :
+ (rcvtyp_pvt(ttyp)) ? "private block" :
+ "global block");
+
+ devstate_read_unlock(dev);
+ return len;
+}
+
+/* fifosz */
+static ssize_t fifosz_show(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ struct kfifo *fifo = to_taskdev(d)->rcvdt.fifo;
+ return sprintf(buf, "%d\n", fifo->size);
+}
+
+static int fifosz_store(struct device *d, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct taskdev *dev = to_taskdev(d);
+ unsigned long fifosz;
+ int ret;
+
+ fifosz = simple_strtol(buf, NULL, 10);
+ if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+ return -ENODEV;
+ ret = taskdev_set_fifosz(dev, fifosz);
+ taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
+
+ return (ret < 0) ? ret : strlen(buf);
+}
+
+/* fifocnt */
+static ssize_t fifocnt_show(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ struct kfifo *fifo = to_taskdev(d)->rcvdt.fifo;
+ return sprintf(buf, "%d\n", fifo->size);
+}
+
+/* ipblink */
+static inline char *bid_name(u16 bid)
+{
+ static char s[6];
+
+ switch (bid) {
+ case BID_NULL:
+ return "NULL";
+ case BID_PVT:
+ return "PRIVATE";
+ default:
+ sprintf(s, "%d", bid);
+ return s;
+ }
+}
+
+static ssize_t ipblink_show(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ struct rcvdt_bk_struct *rcvdt = &to_taskdev(d)->rcvdt.bk;
+ int len;
+
+ spin_lock(&rcvdt->link.lock);
+ len = sprintf(buf, "top %s\ntail %s\n",
+ bid_name(rcvdt->link.top), bid_name(rcvdt->link.tail));
+ spin_unlock(&rcvdt->link.lock);
+
+ return len;
+}
+
+/* wsz */
+static ssize_t wsz_show(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d\n", to_taskdev(d)->wsz);
+}
+
+/* mmap */
+static ssize_t mmap_show(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ struct dsptask *task = to_taskdev(d)->task;
+ return sprintf(buf, "0x%p 0x%x\n", task->map_base, task->map_length);
+}
+
+/*
+ * called from ipbuf_show()
+ */
+int ipbuf_is_held(u8 tid, u16 bid)
+{
+ struct dsptask *task = dsptask[tid];
+ struct ipblink *link;
+ u16 b;
+ int ret = 0;
+
+ if (task == NULL)
+ return 0;
+
+ link = &task->dev->rcvdt.bk.link;
+ spin_lock(&link->lock);
+ ipblink_for_each(b, link) {
+ if (b == bid) { /* found */
+ ret = 1;
+ break;
+ }
+ }
+ spin_unlock(&link->lock);
+
+ return ret;
+}
+
+int __init dsp_taskmod_init(void)
+{
+ int retval;
+
+ memset(taskdev, 0, sizeof(void *) * TASKDEV_MAX);
+ memset(dsptask, 0, sizeof(void *) * TASKDEV_MAX);
+
+ retval = register_chrdev(OMAP_DSP_TASK_MAJOR, "dsptask",
+ &dsp_task_fops);
+ if (retval < 0) {
+ printk(KERN_ERR
+ "omapdsp: failed to register task device: %d\n", retval);
+ return retval;
+ }
+
+ retval = bus_register(&dsptask_bus);
+ if (retval) {
+ printk(KERN_ERR
+ "omapdsp: failed to register DSP task bus: %d\n",
+ retval);
+ unregister_chrdev(OMAP_DSP_TASK_MAJOR, "dsptask");
+ return -EINVAL;
+ }
+ retval = driver_register(&dsptask_driver);
+ if (retval) {
+ printk(KERN_ERR
+ "omapdsp: failed to register DSP task driver: %d\n",
+ retval);
+ bus_unregister(&dsptask_bus);
+ unregister_chrdev(OMAP_DSP_TASK_MAJOR, "dsptask");
+ return -EINVAL;
+ }
+ dsp_task_class = class_create(THIS_MODULE, "dsptask");
+ if (IS_ERR(dsp_task_class)) {
+ printk(KERN_ERR "omapdsp: failed to create DSP task class\n");
+ driver_unregister(&dsptask_driver);
+ bus_unregister(&dsptask_bus);
+ unregister_chrdev(OMAP_DSP_TASK_MAJOR, "dsptask");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+void dsp_taskmod_exit(void)
+{
+ class_destroy(dsp_task_class);
+ driver_unregister(&dsptask_driver);
+ bus_unregister(&dsptask_bus);
+ unregister_chrdev(OMAP_DSP_TASK_MAJOR, "dsptask");
+}
--- /dev/null
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <asm/uaccess.h>
+#include <asm/arch/dsp.h>
+#include <asm/io.h>
+#include "dsp_mbcmd.h"
+#include "dsp.h"
+
+static DECLARE_WAIT_QUEUE_HEAD(read_wait_q);
+static unsigned int change_cnt;
+
+void dsp_twch_touch(void)
+{
+ change_cnt++;
+ wake_up_interruptible(&read_wait_q);
+}
+
+/*
+ * @count: represents the device counts of the user's interst
+ */
+static ssize_t dsp_twch_read(struct file *file, char __user *buf, size_t count,
+ loff_t *ppos)
+{
+ long taskstat[TASKDEV_MAX];
+ int devcount = count / sizeof(long);
+ int i;
+ DEFINE_WAIT(wait);
+
+ if (dsp_cfgstat_get_stat() != CFGSTAT_READY) {
+ printk(KERN_ERR "omapdsp: dsp has not been configured.\n");
+ return -EINVAL;
+ }
+
+ prepare_to_wait(&read_wait_q, &wait, TASK_INTERRUPTIBLE);
+ if (change_cnt == 0) /* last check */
+ schedule();
+ finish_wait(&read_wait_q, &wait);
+
+ /* unconfigured while waiting ;-( */
+ if ((change_cnt == 0) && (dsp_cfgstat_get_stat() != CFGSTAT_READY))
+ return -EINVAL;
+
+ if (devcount > TASKDEV_MAX)
+ devcount = TASKDEV_MAX;
+
+ count = devcount * sizeof(long);
+ change_cnt = 0;
+ for (i = 0; i < devcount; i++) {
+ /*
+ * once the device state is read, the 'STALE' bit will be set
+ * so that the Dynamic Loader can distinguish the new request
+ * from the old one.
+ */
+ taskstat[i] = taskdev_state_stale(i);
+ }
+
+ if (copy_to_user(buf, taskstat, count))
+ return -EFAULT;
+
+ return count;
+}
+
+static unsigned int dsp_twch_poll(struct file *file, poll_table *wait)
+{
+ unsigned int mask = 0;
+
+ poll_wait(file, &read_wait_q, wait);
+ if (change_cnt)
+ mask |= POLLIN | POLLRDNORM;
+
+ return mask;
+}
+
+static int dsp_twch_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int ret;
+
+ switch (cmd) {
+ case TWCH_IOCTL_MKDEV:
+ {
+ char name[TNM_LEN];
+ if (copy_from_user(name, (void __user *)arg, TNM_LEN))
+ return -EFAULT;
+ name[TNM_LEN-1] = '\0';
+ ret = dsp_mkdev(name);
+ break;
+ }
+
+ case TWCH_IOCTL_RMDEV:
+ {
+ char name[TNM_LEN];
+ if (copy_from_user(name, (void __user *)arg, TNM_LEN))
+ return -EFAULT;
+ name[TNM_LEN-1] = '\0';
+ ret = dsp_rmdev(name);
+ break;
+ }
+
+ case TWCH_IOCTL_TADD:
+ {
+ struct omap_dsp_taddinfo ti;
+ if (copy_from_user(&ti, (void __user *)arg, sizeof(ti)))
+ return -EFAULT;
+ ret = dsp_tadd_minor(ti.minor, ti.taskadr);
+ break;
+ }
+
+ case TWCH_IOCTL_TDEL:
+ ret = dsp_tdel_minor(arg);
+ break;
+
+ case TWCH_IOCTL_TKILL:
+ ret = dsp_tkill_minor(arg);
+ break;
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+
+ return ret;
+}
+
+struct file_operations dsp_twch_fops = {
+ .owner = THIS_MODULE,
+ .read = dsp_twch_read,
+ .poll = dsp_twch_poll,
+ .ioctl = dsp_twch_ioctl,
+};
+
+void dsp_twch_start(void)
+{
+ change_cnt = 1; /* first read will not wait */
+}
+
+void dsp_twch_stop(void)
+{
+ wake_up_interruptible(&read_wait_q);
+}
--- /dev/null
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2004-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+
+ .text
+
+/* Prototype: int __copy_to_user_dsp_2b(void *to, const char *from)
+ * Purpose : copy 2 bytes to user memory from kernel(DSP) memory
+ * escaping from unexpected byte swap using __copy_to_user()
+ * in OMAP architecture.
+ * Params : to - user memory
+ * : from - kernel(DSP) memory
+ * Returns : success = 0, failure = 2
+ */
+
+ENTRY(__copy_to_user_dsp_2b)
+ stmfd sp!, {r4, lr}
+ ldrb r3, [r1], #1
+ ldrb r4, [r1], #1
+USER( strbt r4, [r0], #1) @ May fault
+USER( strbt r3, [r0], #1) @ May fault
+ mov r0, #0
+ ldmfd sp!, {r4, pc}
+
+ .section .fixup,"ax"
+ .align 0
+9001: mov r0, #2
+ ldmfd sp!, {r4, pc}
+ .previous
+
+/* Prototype: unsigned long __copy_from_user_dsp_2b(void *to, const void *from);
+ * Purpose : copy 2 bytes from user memory to kernel(DSP) memory
+ * escaping from unexpected byte swap using __copy_to_user()
+ * in OMAP architecture.
+ * Params : to - kernel (DSP) memory
+ * : from - user memory
+ * Returns : success = 0, failure = 2
+ */
+
+ENTRY(__copy_from_user_dsp_2b)
+ stmfd sp!, {r4, lr}
+USER( ldrbt r3, [r1], #1) @ May fault
+USER( ldrbt r4, [r1], #1) @ May fault
+ strb r4, [r0], #1
+ strb r3, [r0], #1
+ mov r0, #0
+ ldmfd sp!, {r4, pc}
+
+ .section .fixup,"ax"
+ .align 0
+9001: mov r3, #0
+ strh r3, [r0], #2
+ mov r0, #2
+ ldmfd sp!, {r4, pc}
+ .previous
--- /dev/null
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef _OMAP_DSP_UACCESS_DSP_H
+#define _OMAP_DSP_UACCESS_DSP_H
+
+#include <asm/uaccess.h>
+#include <asm/arch/dsp_common.h>
+#include "dsp.h"
+
+#define HAVE_ASM_COPY_FROM_USER_DSP_2B
+
+#ifdef HAVE_ASM_COPY_FROM_USER_DSP_2B
+extern unsigned long __copy_from_user_dsp_2b(void *to,
+ const void __user *from);
+extern unsigned long __copy_to_user_dsp_2b(void __user *to,
+ const void *from);
+#endif
+
+#ifndef HAVE_ASM_COPY_FROM_USER_DSP_2B
+static inline unsigned long copy_from_user_dsp_2b(void *to,
+ const void *from)
+{
+ unsigned short tmp;
+
+ if (__copy_from_user(&tmp, from, 2))
+ return 2;
+ /* expecting compiler to generate "strh" instruction */
+ *((unsigned short *)to) = tmp;
+ return 0;
+}
+#endif
+
+/*
+ * @n must be multiple of 2
+ */
+static inline unsigned long copy_from_user_dsp(void *to, const void *from,
+ unsigned long n)
+{
+ if (access_ok(VERIFY_READ, from, n)) {
+ if ((is_dsp_internal_mem(to)) &&
+ (((unsigned long)to & 2) || (n & 2))) {
+ /*
+ * DARAM/SARAM with odd word alignment
+ */
+ unsigned long n4;
+ unsigned long last_n;
+
+ /* dest not aligned -- copy 2 bytes */
+ if (((unsigned long)to & 2) && (n >= 2)) {
+#ifdef HAVE_ASM_COPY_FROM_USER_DSP_2B
+ if (__copy_from_user_dsp_2b(to, from))
+#else
+ if (copy_from_user_dsp_2b(to, from))
+#endif
+ return n;
+ to += 2;
+ from += 2;
+ n -= 2;
+ }
+ /* middle 4*n bytes */
+ last_n = n & 2;
+ n4 = n - last_n;
+ if ((n = __copy_from_user(to, from, n4)) != 0)
+ return n + last_n;
+ /* last 2 bytes */
+ if (last_n) {
+ to += n4;
+ from += n4;
+#ifdef HAVE_ASM_COPY_FROM_USER_DSP_2B
+ if (__copy_from_user_dsp_2b(to, from))
+#else
+ if (copy_from_user_dsp_2b(to, from))
+#endif
+ return 2;
+ n = 0;
+ }
+ } else {
+ /*
+ * DARAM/SARAM with 4-byte alignment or
+ * external memory
+ */
+ n = __copy_from_user(to, from, n);
+ }
+ }
+ else /* security hole - plug it */
+ memzero(to, n);
+ return n;
+}
+
+#ifndef HAVE_ASM_COPY_FROM_USER_DSP_2B
+static inline unsigned long copy_to_user_dsp_2b(void *to, const void *from)
+{
+ /* expecting compiler to generate "strh" instruction */
+ unsigned short tmp = *(unsigned short *)from;
+
+ return __copy_to_user(to, &tmp, 2);
+}
+#endif
+
+/*
+ * @n must be multiple of 2
+ */
+static inline unsigned long copy_to_user_dsp(void *to, const void *from,
+ unsigned long n)
+{
+ if (access_ok(VERIFY_WRITE, to, n)) {
+ if ((is_dsp_internal_mem(from)) &&
+ (((unsigned long)to & 2) || (n & 2))) {
+ /*
+ * DARAM/SARAM with odd word alignment
+ */
+ unsigned long n4;
+ unsigned long last_n;
+
+ /* dest not aligned -- copy 2 bytes */
+ if (((unsigned long)to & 2) && (n >= 2)) {
+#ifdef HAVE_ASM_COPY_FROM_USER_DSP_2B
+ if (__copy_to_user_dsp_2b(to, from))
+#else
+ if (copy_to_user_dsp_2b(to, from))
+#endif
+ return n;
+ to += 2;
+ from += 2;
+ n -= 2;
+ }
+ /* middle 4*n bytes */
+ last_n = n & 2;
+ n4 = n - last_n;
+ if ((n = __copy_to_user(to, from, n4)) != 0)
+ return n + last_n;
+ /* last 2 bytes */
+ if (last_n) {
+ to += n4;
+ from += n4;
+#ifdef HAVE_ASM_COPY_FROM_USER_DSP_2B
+ if (__copy_to_user_dsp_2b(to, from))
+#else
+ if (copy_to_user_dsp_2b(to, from))
+#endif
+ return 2;
+ n = 0;
+ }
+ } else {
+ /*
+ * DARAM/SARAM with 4-byte alignment or
+ * external memory
+ */
+ n = __copy_to_user(to, from, n);
+ }
+ }
+ return n;
+}
+
+#endif /* _OMAP_DSP_UACCESS_DSP_H */
Say Y here if you have an applicable laptop and want to experience
the awesome power of applesmc.
+config SENSORS_TSC210X
+ tristate "TI TSC210x battery & temperature sensors"
+ depends on HWMON && SPI_MASTER
+ select SPI_TSC210X
+ help
+ Say Y if your board has a TSC210x chip and you want to
+ have its battery state, auxiliary input and/or temperature
+ sensors exported through hwmon.
+
+ This driver can also be built as a module. In this case
+ the module will be called tsc210x_sensors.
+
config HWMON_DEBUG_CHIP
bool "Hardware Monitoring Chip debugging messages"
default n
obj-$(CONFIG_SENSORS_VT8231) += vt8231.o
obj-$(CONFIG_SENSORS_W83627EHF) += w83627ehf.o
obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o
+obj-$(CONFIG_SENSORS_TSC210X) += tsc210x_sensors.o
obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o
ifeq ($(CONFIG_HWMON_DEBUG_CHIP),y)
--- /dev/null
+/*
+ * tsc210x_sensors.c - hwmon interface to TI TSC210x sensors
+ *
+ * Copyright (c) 2005-2007 Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this package; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/autoconf.h>
+#ifdef CONFIG_APM
+# include <linux/apm-emulation.h>
+#endif
+
+#include <linux/spi/tsc210x.h>
+
+
+/*
+ * TI TSC210x chips include an ADC that's shared between various
+ * sensors (temperature, battery, vAUX, etc) and the touchscreen.
+ * This driver packages access to the non-touchscreen sensors
+ * available on a given board.
+ */
+
+struct tsc210x_hwmon {
+ int bat[2], aux[2], temp[2];
+
+ struct device *dev;
+ struct tsc210x_config *pdata;
+#ifdef CONFIG_APM
+ /* prevent APM from colliding with normal hwmon accessors */
+ spinlock_t apm_lock;
+#endif
+};
+
+#ifdef CONFIG_APM
+# define apm_lock(h) spin_lock(&(h)->apm_lock)
+# define apm_unlock(h) spin_unlock(&(h)->apm_lock)
+#else
+# define apm_lock(h) do { } while (0)
+# define apm_unlock(h) do { } while (0)
+#endif
+
+static void tsc210x_ports(void *context, int bat[], int aux[])
+{
+ struct tsc210x_hwmon *hwmon = context;
+
+ apm_lock(hwmon);
+
+ /* FIXME for tsc2101 and tsc2111, battery voltage is:
+ * VBAT = (5 * VREF * (bat[x])) / (2 ^ bits)
+ * For tsc2100 and tsc2102, use "6" not "5"; that formula ignores
+ * an external 100-300 Ohm resistor making the right value be just
+ * a bit over 5 (or 6).
+ *
+ * FIXME the vAUX measurements need scaling too, but in that case
+ * there's no *internal* voltage divider so just scale to VREF.
+ *
+ * --> This code needs to know VREF, the VBAT multiplier, and
+ * the precision. For now, assume VREF 1.25V and 12 bits.
+ * When an external reference is used, it normally won't
+ * match the 1.25V (or 2.5V) values supported internally...
+ *
+ * --> Output units should become milliVolts; currently they are
+ * dimensionless...
+ */
+ hwmon->bat[0] = bat[0];
+ hwmon->bat[1] = bat[1];
+
+ hwmon->aux[0] = aux[0];
+ hwmon->aux[1] = aux[1];
+
+ apm_unlock(hwmon);
+}
+
+/* FIXME temp sensors also need scaling so values are milliVolts...
+ * temperature (given calibration data) should be millidegrees C.
+ */
+
+static void tsc210x_temp1(void *context, int temp)
+{
+ struct tsc210x_hwmon *hwmon = context;
+
+ apm_lock(hwmon);
+ hwmon->temp[0] = temp;
+ apm_unlock(hwmon);
+}
+
+static void tsc210x_temp2(void *context, int temp)
+{
+ struct tsc210x_hwmon *hwmon = context;
+
+ apm_lock(hwmon);
+ hwmon->temp[1] = temp;
+ apm_unlock(hwmon);
+}
+
+#define TSC210X_INPUT(devname, field) \
+static ssize_t tsc_show_ ## devname(struct device *dev, \
+ struct device_attribute *devattr, char *buf) \
+{ \
+ struct tsc210x_hwmon *hwmon = dev_get_drvdata(dev); \
+ return sprintf(buf, "%i\n", hwmon->field); \
+} \
+static DEVICE_ATTR(devname ## _input, S_IRUGO, tsc_show_ ## devname, NULL);
+
+TSC210X_INPUT(in0, bat[0])
+TSC210X_INPUT(in1, bat[1])
+TSC210X_INPUT(in2, aux[0])
+TSC210X_INPUT(in3, aux[1])
+TSC210X_INPUT(in4, temp[0])
+TSC210X_INPUT(in5, temp[1])
+
+static ssize_t tsc_show_temp1(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct tsc210x_hwmon *hwmon = dev_get_drvdata(dev);
+ int t1 = hwmon->temp[0];
+ int t2 = hwmon->temp[1];
+ int diff;
+ int value;
+
+ /*
+ * Use method #2 (differential) to calculate current temperature.
+ * The difference between TEMP2 and TEMP1 input values is
+ * multiplied by a constant to obtain current temperature.
+ * To find this constant we use the values measured at 25 C as
+ * thermometer calibration data.
+ *
+ * 298150 is 25 degrees Celcius represented in Kelvins and
+ * multiplied by 1000 for fixed point precision (273.15 + 25).
+ * 273150 is zero degrees Celcius.
+ */
+ diff = hwmon->pdata->temp_at25c[1] - hwmon->pdata->temp_at25c[0];
+ value = (t2 - t1) * 298150 / diff; /* This is in Kelvins now */
+
+ value -= 273150; /* Celcius millidegree */
+ return sprintf(buf, "%i\n", value);
+}
+static DEVICE_ATTR(temp1_input, S_IRUGO, tsc_show_temp1, NULL);
+
+#ifdef CONFIG_APM
+static struct tsc210x_hwmon *apm_hwmon;
+
+static void tsc210x_get_power_status(struct apm_power_info *info)
+{
+ struct tsc210x_hwmon *hwmon = apm_hwmon;
+
+ apm_lock(hwmon);
+ hwmon->pdata->apm_report(info, hwmon->bat);
+ apm_unlock(hwmon);
+}
+#endif
+
+static int tsc210x_hwmon_probe(struct platform_device *pdev)
+{
+ struct tsc210x_hwmon *hwmon;
+ struct tsc210x_config *pdata = pdev->dev.platform_data;
+ int status = 0;
+
+ hwmon = (struct tsc210x_hwmon *)
+ kzalloc(sizeof(struct tsc210x_hwmon), GFP_KERNEL);
+ if (!hwmon) {
+ dev_dbg(&pdev->dev, "allocation failed\n");
+ return -ENOMEM;
+ }
+
+ hwmon->dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(hwmon->dev)) {
+ kfree(hwmon);
+ dev_dbg(&pdev->dev, "registration failed\n");
+ return PTR_ERR(hwmon->dev);
+ }
+
+ hwmon->pdata = pdata;
+
+#ifdef CONFIG_APM
+ spin_lock_init(&hwmon->apm_lock);
+
+ if (pdata->apm_report) {
+ apm_hwmon = hwmon;
+ apm_get_power_status = tsc210x_get_power_status;
+ }
+#endif
+
+ platform_set_drvdata(pdev, hwmon);
+
+ if (pdata->monitor & (TSC_BAT1 | TSC_BAT2 | TSC_AUX1 | TSC_AUX2))
+ status |= tsc210x_ports_cb(pdev->dev.parent,
+ tsc210x_ports, hwmon);
+ if (pdata->monitor & TSC_TEMP) {
+ status |= tsc210x_temp1_cb(pdev->dev.parent,
+ tsc210x_temp1, hwmon);
+ status |= tsc210x_temp2_cb(pdev->dev.parent,
+ tsc210x_temp2, hwmon);
+ }
+
+ if (status) {
+ tsc210x_ports_cb(pdev->dev.parent, NULL, NULL);
+ tsc210x_temp1_cb(pdev->dev.parent, NULL, NULL);
+ tsc210x_temp2_cb(pdev->dev.parent, NULL, NULL);
+ platform_set_drvdata(pdev, NULL);
+#ifdef CONFIG_APM
+ if (pdata->apm_report)
+ apm_get_power_status = 0;
+#endif
+ hwmon_device_unregister(hwmon->dev);
+ kfree(hwmon);
+ return status;
+ }
+
+ if (pdata->monitor & TSC_BAT1)
+ status |= device_create_file(&pdev->dev, &dev_attr_in0_input);
+ if (pdata->monitor & TSC_BAT2)
+ status |= device_create_file(&pdev->dev, &dev_attr_in1_input);
+ if (pdata->monitor & TSC_AUX1)
+ status |= device_create_file(&pdev->dev, &dev_attr_in2_input);
+ if (pdata->monitor & TSC_AUX2)
+ status |= device_create_file(&pdev->dev, &dev_attr_in3_input);
+ if (pdata->monitor & TSC_TEMP) {
+ status |= device_create_file(&pdev->dev, &dev_attr_in4_input);
+ status |= device_create_file(&pdev->dev, &dev_attr_in5_input);
+
+ if ((pdata->temp_at25c[1] - pdata->temp_at25c[0]) == 0)
+ dev_warn(&pdev->dev, "No temp calibration data.\n");
+ else
+ status |= device_create_file(&pdev->dev,
+ &dev_attr_temp1_input);
+ }
+ if (status) /* Not fatal */
+ dev_dbg(&pdev->dev, "Creating one or more "
+ "attribute files failed\n");
+
+ return 0;
+}
+
+static int __exit tsc210x_hwmon_remove(struct platform_device *pdev)
+{
+ struct tsc210x_hwmon *dev = platform_get_drvdata(pdev);
+
+ tsc210x_ports_cb(pdev->dev.parent, NULL, NULL);
+ tsc210x_temp1_cb(pdev->dev.parent, NULL, NULL);
+ tsc210x_temp2_cb(pdev->dev.parent, NULL, NULL);
+ platform_set_drvdata(pdev, NULL);
+#ifdef CONFIG_APM
+ if (dev->pdata->apm_report)
+ apm_get_power_status = 0;
+#endif
+ hwmon_device_unregister(dev->dev);
+ kfree(dev);
+ return 0;
+}
+
+static struct platform_driver tsc210x_hwmon_driver = {
+ .probe = tsc210x_hwmon_probe,
+ .remove = __exit_p(tsc210x_hwmon_remove),
+ /* Nothing to do on suspend/resume */
+ .driver = {
+ .name = "tsc210x-hwmon",
+ },
+};
+
+static int __init tsc210x_hwmon_init(void)
+{
+ /* can't use driver_probe() here since the parent device
+ * gets registered "late"
+ */
+ return platform_driver_register(&tsc210x_hwmon_driver);
+}
+module_init(tsc210x_hwmon_init);
+
+static void __exit tsc210x_hwmon_exit(void)
+{
+ platform_driver_unregister(&tsc210x_hwmon_driver);
+}
+module_exit(tsc210x_hwmon_exit);
+
+MODULE_AUTHOR("Andrzej Zaborowski");
+MODULE_DESCRIPTION("hwmon driver for TI TSC210x-connected sensors.");
+MODULE_LICENSE("GPL");
menuconfig I2C
tristate "I2C support"
depends on HAS_IOMEM
+ 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,
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
* 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
+ * Copyright (C) 2004 - 2007 Texas Instruments.
*
- * Cleaned up by Juha Yrjölä <juha.yrjola@nokia.com>
+ * Originally written by MontaVista Software, Inc.
+ * Additional contributions by:
+ * Tony Lindgren <tony@atomide.com>
+ * Imre Deak <imre.deak@nokia.com>
+ * Juha Yrjölä <juha.yrjola@nokia.com>
+ * Syed Khasim <x0khasim@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
#include <asm/io.h>
+/* Hack to enable zero length transfers and smbus quick until clean fix
+ is available */
+#define OMAP_HACK
+
/* timeout waiting for the controller to respond */
#define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000))
#define OMAP_I2C_SCLL_REG 0x34
#define OMAP_I2C_SCLH_REG 0x38
#define OMAP_I2C_SYSTEST_REG 0x3c
+#define OMAP_I2C_BUFSTAT_REG 0x40
/* I2C Interrupt Enable Register (OMAP_I2C_IE): */
+#define OMAP_I2C_IE_XDR (1 << 14) /* TX Buffer draining int enable */
+#define OMAP_I2C_IE_RDR (1 << 13) /* RX Buffer draining int enable */
#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_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_XDR (1 << 14) /* TX Buffer draining */
+#define OMAP_I2C_STAT_RDR (1 << 13) /* RX Buffer draining */
#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 */
/* I2C Buffer Configuration Register (OMAP_I2C_BUF): */
#define OMAP_I2C_BUF_RDMA_EN (1 << 15) /* RX DMA channel enable */
+#define OMAP_I2C_BUF_RXFIF_CLR (1 << 14) /* RX FIFO Clear */
#define OMAP_I2C_BUF_XDMA_EN (1 << 7) /* TX DMA channel enable */
+#define OMAP_I2C_BUF_TXFIF_CLR (1 << 6) /* TX FIFO Clear */
/* 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_OPMODE_HS (1 << 12) /* High Speed support */
#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_STP (1 << 1) /* Stop cond (master only) */
#define OMAP_I2C_CON_STT (1 << 0) /* Start condition (master) */
+/* I2C SCL time value when Master */
+#define OMAP_I2C_SCLL_HSSCLL 8
+#define OMAP_I2C_SCLH_HSSCLH 8
+
/* I2C System Test Register (OMAP_I2C_SYSTEST): */
#ifdef DEBUG
#define OMAP_I2C_SYSTEST_ST_EN (1 << 15) /* System test enable */
/* I2C System Configuration Register (OMAP_I2C_SYSC): */
#define OMAP_I2C_SYSC_SRST (1 << 1) /* Soft Reset */
-/* REVISIT: Use platform_data instead of module parameters */
-/* Fast Mode = 400 kHz, Standard = 100 kHz */
-static int clock = 100; /* Default: 100 kHz */
-module_param(clock, int, 0);
-MODULE_PARM_DESC(clock, "Set I2C clock in kHz: 400=fast mode (default == 100)");
-
struct omap_i2c_dev {
struct device *dev;
void __iomem *base; /* virtual */
struct clk *fclk; /* Functional clock */
struct completion cmd_complete;
struct resource *ioarea;
+ u32 speed; /* Speed of bus in Khz */
u16 cmd_err;
u8 *buf;
size_t buf_len;
struct i2c_adapter adapter;
+ u8 fifo_size; /* use as flag and value
+ * fifo_size==0 implies no fifo
+ * if set, should be trsh+1
+ */
unsigned rev1:1;
+ unsigned b_hw:1; /* bad h/w fixes */
unsigned idle:1;
u16 iestate; /* Saved interrupt register */
};
static int omap_i2c_get_clocks(struct omap_i2c_dev *dev)
{
- if (cpu_is_omap16xx() || cpu_is_omap24xx()) {
+ if (cpu_is_omap16xx() || cpu_class_is_omap2()) {
dev->iclk = clk_get(dev->dev, "i2c_ick");
if (IS_ERR(dev->iclk)) {
dev->iclk = NULL;
return -ENODEV;
}
}
-
- dev->fclk = clk_get(dev->dev, "i2c_fck");
- if (IS_ERR(dev->fclk)) {
- if (dev->iclk != NULL) {
- clk_put(dev->iclk);
- dev->iclk = NULL;
+ /* For I2C operations on 2430 we need 96Mhz clock */
+ if (cpu_is_omap2430()) {
+ dev->fclk = clk_get(dev->dev, "i2chs_fck");
+ if (IS_ERR(dev->fclk)) {
+ if (dev->iclk != NULL) {
+ clk_put(dev->iclk);
+ dev->iclk = NULL;
+ }
+ dev->fclk = NULL;
+ return -ENODEV;
+ }
+ } else {
+ dev->fclk = clk_get(dev->dev, "i2c_fck");
+ if (IS_ERR(dev->fclk)) {
+ if (dev->iclk != NULL) {
+ clk_put(dev->iclk);
+ dev->iclk = NULL;
+ }
+ dev->fclk = NULL;
+ return -ENODEV;
}
- dev->fclk = NULL;
- return -ENODEV;
}
-
return 0;
}
dev->iestate = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, 0);
if (dev->rev1)
- iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG); /* Read clears */
+ iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG);
else
omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, dev->iestate);
clk_disable(dev->fclk);
static int omap_i2c_init(struct omap_i2c_dev *dev)
{
- u16 psc = 0;
+ u16 psc = 0, scll = 0, sclh = 0;
+ u16 fsscll = 0, fssclh = 0, hsscll = 0, hssclh = 0;
unsigned long fclk_rate = 12000000;
unsigned long timeout;
+ unsigned long internal_clk = 0;
if (!dev->rev1) {
omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, OMAP_I2C_SYSC_SRST);
psc = fclk_rate / 12000000;
}
+ if (cpu_is_omap2430() || cpu_is_omap34xx()) {
+
+ /* HSI2C controller internal clk rate should be 19.2 Mhz */
+ internal_clk = 19200;
+ fclk_rate = clk_get_rate(dev->fclk) / 1000;
+
+ /* Compute prescaler divisor */
+ psc = fclk_rate / internal_clk;
+ psc = psc - 1;
+
+ /* If configured for High Speed */
+ if (dev->speed > 400) {
+ /* For first phase of HS mode */
+ fsscll = internal_clk / (400 * 2) - 6;
+ fssclh = internal_clk / (400 * 2) - 6;
+
+ /* For second phase of HS mode */
+ hsscll = fclk_rate / (dev->speed * 2) - 6;
+ hssclh = fclk_rate / (dev->speed * 2) - 6;
+ } else {
+ /* To handle F/S modes */
+ fsscll = internal_clk / (dev->speed * 2) - 6;
+ fssclh = internal_clk / (dev->speed * 2) - 6;
+ }
+ scll = (hsscll << OMAP_I2C_SCLL_HSSCLL) | fsscll;
+ sclh = (hssclh << OMAP_I2C_SCLH_HSSCLH) | fssclh;
+ } else {
+ /* Program desired operating rate */
+ fclk_rate /= (psc + 1) * 1000;
+ if (psc > 2)
+ psc = 2;
+ scll = fclk_rate / (dev->speed * 2) - 7 + psc;
+ sclh = fclk_rate / (dev->speed * 2) - 7 + psc;
+ }
+
/* 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;
+ /* SCL low and high time values */
+ omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, scll);
+ omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, sclh);
- 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);
+ if (dev->fifo_size)
+ /* Note: setup required fifo size - 1 */
+ omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG,
+ (dev->fifo_size - 1) << 8 | /* RTRSH */
+ OMAP_I2C_BUF_RXFIF_CLR |
+ (dev->fifo_size - 1) | /* XTRSH */
+ OMAP_I2C_BUF_TXFIF_CLR);
/* 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));
+ (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY |
+ OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK |
+ OMAP_I2C_IE_AL) | ((dev->fifo_size) ?
+ (OMAP_I2C_IE_RDR | OMAP_I2C_IE_XDR) : 0));
return 0;
}
struct i2c_msg *msg, int stop)
{
struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
+#ifdef OMAP_HACK
+ u8 zero_byte = 0;
+#endif
int r;
u16 w;
dev_dbg(dev->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
msg->addr, msg->len, msg->flags, stop);
+#ifndef OMAP_HACK
if (msg->len == 0)
return -EINVAL;
dev->buf = msg->buf;
dev->buf_len = msg->len;
+#else
+
+ omap_i2c_write_reg(dev, OMAP_I2C_SA_REG, msg->addr);
+ /* REVISIT: Remove this hack when we can get I2C chips from board-*.c
+ * files
+ * 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.
+ */
+ if (msg->len == 0) {
+ dev->buf = &zero_byte;
+ dev->buf_len = 1;
+ } else {
+ dev->buf = msg->buf;
+ dev->buf_len = msg->len;
+ }
+#endif
+
omap_i2c_write_reg(dev, OMAP_I2C_CNT_REG, dev->buf_len);
+ /* Clear the FIFO Buffers */
+ w = omap_i2c_read_reg(dev, OMAP_I2C_BUF_REG);
+ w |= OMAP_I2C_BUF_RXFIF_CLR | OMAP_I2C_BUF_TXFIF_CLR;
+ omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, w);
+
init_completion(&dev->cmd_complete);
dev->cmd_err = 0;
w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT;
+
+ /* High speed configuration */
+ if (dev->speed > 400)
+ w |= OMAP_I2C_CON_OPMODE_HS;
+
if (msg->flags & I2C_M_TEN)
w |= OMAP_I2C_CON_XA;
if (!(msg->flags & I2C_M_RD))
w |= OMAP_I2C_CON_TRX;
- if (stop)
+
+ if (!dev->b_hw && 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);
+ if (dev->b_hw && stop) {
+ /* H/w behavior: dont write stt and stp together.. */
+ while (omap_i2c_read_reg(dev, OMAP_I2C_CON_REG) & OMAP_I2C_CON_STT) {
+ /* Dont do anything - this will come in a couple of loops at max*/
+ }
+ w |= OMAP_I2C_CON_STP;
+ w &= ~OMAP_I2C_CON_STT;
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
+ }
+ r = wait_for_completion_timeout(&dev->cmd_complete,
+ OMAP_I2C_TIMEOUT);
dev->buf_len = 0;
if (r < 0)
return r;
static u32
omap_i2c_func(struct i2c_adapter *adap)
{
+#ifndef OMAP_HACK
return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
+#else
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+#endif
}
static inline void
struct omap_i2c_dev *dev = dev_id;
u16 bits;
u16 stat, w;
- int count = 0;
+ int err, count = 0;
if (dev->idle)
return IRQ_NONE;
omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat);
- if (stat & OMAP_I2C_STAT_ARDY) {
- omap_i2c_complete_cmd(dev, 0);
- continue;
+ err = 0;
+ if (stat & OMAP_I2C_STAT_NACK) {
+ err |= OMAP_I2C_STAT_NACK;
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG,
+ OMAP_I2C_CON_STP);
}
- 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 (stat & OMAP_I2C_STAT_AL) {
+ dev_err(dev->dev, "Arbitration lost\n");
+ err |= OMAP_I2C_STAT_AL;
+ }
+ if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK |
+ OMAP_I2C_STAT_AL))
+ omap_i2c_complete_cmd(dev, err);
+ if (stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)) {
+ u8 num_bytes = 1;
+ if (dev->fifo_size) {
+ num_bytes = (stat & OMAP_I2C_STAT_RRDY) ? dev->fifo_size :
+ omap_i2c_read_reg(dev, OMAP_I2C_BUFSTAT_REG);
+ }
+ while (num_bytes) {
+ num_bytes--;
+ w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG);
if (dev->buf_len) {
- *dev->buf++ = w >> 8;
+ *dev->buf++ = w;
dev->buf_len--;
+ /* Data reg from 2430 is 8 bit wide */
+ if (!cpu_is_omap2430() &&
+ !cpu_is_omap34xx()) {
+ if (dev->buf_len) {
+ *dev->buf++ = w >> 8;
+ dev->buf_len--;
+ }
+ }
+ } else {
+ if (stat & OMAP_I2C_STAT_RRDY)
+ dev_err(dev->dev, "RRDY IRQ while no data "
+ "requested\n");
+ if (stat & OMAP_I2C_STAT_RDR)
+ dev_err(dev->dev, "RDR IRQ while no data "
+ "requested\n");
+ break;
}
- } else
- dev_err(dev->dev, "RRDY IRQ while no data "
- "requested\n");
- omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RRDY);
- continue;
+ }
+ omap_i2c_ack_stat(dev, stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR));
}
- if (stat & OMAP_I2C_STAT_XRDY) {
- w = 0;
- if (dev->buf_len) {
- w = *dev->buf++;
- dev->buf_len--;
+ if (stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)) {
+ u8 num_bytes = 1;
+ if (dev->fifo_size) {
+ num_bytes = (stat & OMAP_I2C_STAT_XRDY) ? dev->fifo_size :
+ omap_i2c_read_reg(dev, OMAP_I2C_BUFSTAT_REG);
+ }
+ while (num_bytes) {
+ num_bytes--;
+ w = 0;
if (dev->buf_len) {
- w |= *dev->buf++ << 8;
+ w = *dev->buf++;
dev->buf_len--;
+ /* Data reg from 2430 is 8 bit wide */
+ if (!cpu_is_omap2430() &&
+ !cpu_is_omap34xx()) {
+ if (dev->buf_len) {
+ w |= *dev->buf++ << 8;
+ dev->buf_len--;
+ }
+ }
+ } else {
+ if (stat & OMAP_I2C_STAT_XRDY)
+ dev_err(dev->dev, "XRDY IRQ while no "
+ "data to send\n");
+ if (stat & OMAP_I2C_STAT_XDR)
+ dev_err(dev->dev, "XDR IRQ while no "
+ "data to send\n");
+ break;
}
- } else
- dev_err(dev->dev, "XRDY IRQ while no "
- "data to send\n");
- omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
- omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XRDY);
- continue;
+ omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
+ }
+ omap_i2c_ack_stat(dev, stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR));
}
if (stat & OMAP_I2C_STAT_ROVR) {
dev_err(dev->dev, "Receive overrun\n");
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;
struct i2c_adapter *adap;
struct resource *mem, *irq, *ioarea;
int r;
+ u32 *speed = NULL;
/* NOTE: driver uses the static register mapping */
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
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 err_release_region;
}
+ if (pdev->dev.platform_data != NULL)
+ speed = (u32 *) pdev->dev.platform_data;
+ else
+ *speed = 100; /* Defualt speed */
+
+ dev->speed = *speed;
dev->dev = &pdev->dev;
dev->irq = irq->start;
dev->base = (void __iomem *) IO_ADDRESS(mem->start);
if (cpu_is_omap15xx())
dev->rev1 = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) < 0x20;
+ if (cpu_is_omap2430() || cpu_is_omap34xx()) {
+ /* Set up the fifo size - Get total size */
+ dev->fifo_size = 0x8 <<
+ ((omap_i2c_read_reg(dev, OMAP_I2C_BUFSTAT_REG) >> 14) & 0x3);
+ /*
+ * Set up notification threshold as half the total available size
+ * This is to ensure that we can handle the status on int call back
+ * latencies
+ */
+ dev->fifo_size = (dev->fifo_size / 2);
+ dev->b_hw = 1; /* Enable hardware fixes */
+ }
+
/* reset ASAP, clearing any IRQs */
omap_i2c_init(dev);
}
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, r >> 4, r & 0xf, clock);
+ pdev->id, r >> 4, r & 0xf, dev->speed);
adap = &dev->adapter;
i2c_set_adapdata(adap, dev);
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 TWL4030_CORE
+ bool "TI's TWL4030 companion chip Core Driver Support"
+ depends on I2C=y && (ARCH_OMAP24XX || ARCH_OMAP34XX)
+ help
+ Say yes here if you have TWL4030 chip on your board
+
+config TWL4030_GPIO
+ bool "TWL4030 GPIO Driver"
+ depends on TWL4030_CORE
+
+config TWL4030_MADC
+ tristate "TWL4030 MADC Driver"
+ depends on TWL4030_CORE
+ help
+ The TWL4030 Monitoring ADC driver enables the host
+ processor to monitor analog signals using analog-to-digital
+ conversions on the input source. TWL4030 MADC provides the
+ following features:
+ - Single 10-bit ADC with successive approximation register (SAR) conversion;
+ - Analog multiplexer for 16 inputs;
+ - Seven (of the 16) inputs are freely available;
+ - Battery voltage monitoring;
+ - Concurrent conversion request management;
+ - Interrupt signal to Primary Interrupt Handler;
+ - Averaging feature;
+ - Selective enable/disable of the averaging feature.
+
+ Say 'y' here to statically link this module into the kernel or 'm'
+ to build it as a dinamically loadable module. The module will be
+ called twl4030-madc.ko
+
+config TWL4030_USB
+ bool "TWL4030 USB Transceiver Driver"
+ depends on TWL4030_CORE
+
+choice
+ prompt "Transceiver mode"
+ depends on TWL4030_USB
+ help
+ TWL4030 USB transceiver can operate in various
+ mutually-exclusive modes. Select one of them.
+
+config TWL4030_USB_HS_ULPI
+ depends on TWL4030_USB
+ bool "High-speed ULPI"
+ help
+ Say Y here if the TWL4030 is connected to high-speed USB
+ controller through a ULPI interface.
+
+endchoice
+
+config TWL4030_PWRBUTTON
+ bool "TWL4030 Power button Driver"
+ depends on TWL4030_CORE
+
+config TWL4030_POWEROFF
+ bool "TWL4030 device poweroff"
+ depends on TWL4030_CORE
+
config SENSORS_MAX6875
tristate "Maxim MAX6875 Power supply supervisor"
depends on EXPERIMENTAL
This driver can also be built as a module. If so, the module
will be called tsl2550.
+config SENSORS_TSL2563
+ tristate "Taos TSL2563 ambient light sensor"
+ depends on I2C && HWMON
+ help
+ If you say yes here you get support for the Taos TSL2563
+ ambient light sensor.
+
+ This driver can also be built as a module. If so, the module
+ will be called tsl2563.
+
+config LP5521
+ tristate "LP5521 LED driver chip"
+ depends on I2C
+ help
+ If you say yes here you get support for the National Semiconductor
+ LP5521 LED driver.
+
config MENELAUS
bool "TWL92330/Menelaus PM chip"
depends on I2C=y && ARCH_OMAP24XX
obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.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_SENSORS_TSL2550) += tsl2550.o
+obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o
+obj-$(CONFIG_TWL4030_CORE) += twl4030-core.o twl4030-pwrirq.o
+obj-$(CONFIG_TWL4030_GPIO) += twl4030-gpio.o
+obj-$(CONFIG_TWL4030_USB) += twl4030-usb.o
+obj-$(CONFIG_TWL4030_POWEROFF) += twl4030-poweroff.o
+obj-$(CONFIG_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o
+obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o
+obj-$(CONFIG_RTC_X1205_I2C) += x1205.o
+obj-$(CONFIG_LP5521) += lp5521.o
ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
EXTRA_CFLAGS += -DDEBUG
endif
-
--- /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(1);
+ 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(1);
+ 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);
+
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#undef DEBUG
+#undef VERBOSE
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/usb/otg.h>
#include <linux/i2c.h>
#include <linux/workqueue.h>
-
-#include <asm/irq.h>
#include <asm/arch/usb.h>
+#include <asm/mach-types.h> /* FIXME: Move machine_is_* to board-*.c files */
#ifndef DEBUG
#undef VERBOSE
#endif
-
#define DRIVER_VERSION "24 August 2004"
#define DRIVER_NAME (isp1301_driver.driver.name)
struct isp1301 {
struct otg_transceiver otg;
- struct i2c_client client;
+ struct i2c_client *client;
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/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
/*-------------------------------------------------------------------------*/
-/* only two addresses possible */
-#define ISP_BASE 0x2c
-static unsigned short normal_i2c[] = {
- ISP_BASE, ISP_BASE + 1,
- I2C_CLIENT_END };
+/* products will deliver OTG messages with LEDs, GUI, etc */
+static inline void notresponding(struct isp1301 *isp)
+{
+ printk(KERN_NOTICE "OTG device not responding.\n");
+}
-I2C_CLIENT_INSMOD;
+/*-------------------------------------------------------------------------*/
+/* only two addresses possible */
static struct i2c_driver isp1301_driver;
/* smbus apis are used for portability */
static inline u8
isp1301_get_u8(struct isp1301 *isp, u8 reg)
{
- return i2c_smbus_read_byte_data(&isp->client, reg + 0);
+ return i2c_smbus_read_byte_data(isp->client, reg + 0);
}
static inline int
isp1301_get_u16(struct isp1301 *isp, u8 reg)
{
- return i2c_smbus_read_word_data(&isp->client, reg);
+ return i2c_smbus_read_word_data(isp->client, reg);
}
static inline int
isp1301_set_bits(struct isp1301 *isp, u8 reg, u8 bits)
{
- return i2c_smbus_write_byte_data(&isp->client, reg + 0, bits);
+ return i2c_smbus_write_byte_data(isp->client, reg + 0, bits);
}
static inline int
isp1301_clear_bits(struct isp1301 *isp, u8 reg, u8 bits)
{
- return i2c_smbus_write_byte_data(&isp->client, reg + 1, bits);
+ return i2c_smbus_write_byte_data(isp->client, reg + 1, bits);
}
/*-------------------------------------------------------------------------*/
int status;
if (isp && !test_and_set_bit(work, &isp->todo)) {
- (void) get_device(&isp->client.dev);
+ (void) get_device(&isp->client->dev);
status = schedule_work(&isp->work);
if (!status && !isp->working)
- dev_vdbg(&isp->client.dev,
+ dev_vdbg(&isp->client->dev,
"work item %d may be lost\n", work);
}
}
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, __func__);
#endif
/* transfer state from otg engine to isp1301 */
if (test_and_clear_bit(WORK_UPDATE_ISP, &isp->todo)) {
otg_update_isp(isp);
- put_device(&isp->client.dev);
+ put_device(&isp->client->dev);
}
#endif
/* transfer state from isp1301 to otg engine */
u8 stat = isp1301_clear_latch(isp);
isp_update_otg(isp, stat);
- put_device(&isp->client.dev);
+ put_device(&isp->client->dev);
}
if (test_and_clear_bit(WORK_HOST_RESUME, &isp->todo)) {
}
host_resume(isp);
// mdelay(10);
- put_device(&isp->client.dev);
+ put_device(&isp->client->dev);
}
if (test_and_clear_bit(WORK_TIMER, &isp->todo)) {
if (!stop)
mod_timer(&isp->timer, jiffies + TIMER_JIFFIES);
#endif
- put_device(&isp->client.dev);
+ put_device(&isp->client->dev);
}
if (isp->todo)
- dev_vdbg(&isp->client.dev,
+ dev_vdbg(&isp->client->dev,
"work done, todo = 0x%lx\n",
isp->todo);
if (stop) {
- dev_dbg(&isp->client.dev, "stop\n");
+ dev_dbg(&isp->client->dev, "stop\n");
break;
}
} while (isp->todo);
static void isp1301_release(struct device *dev)
{
- struct isp1301 *isp;
+ struct i2c_client *client;
+ struct isp1301 *isp;
- isp = container_of(dev, struct isp1301, client.dev);
+ client = container_of(dev, struct i2c_client, dev);
+ isp = i2c_get_clientdata(client);
/* ugly -- i2c hijacks our memory hook to wait_for_completion() */
if (isp->i2c_release)
static struct isp1301 *the_transceiver;
-static int isp1301_detach_client(struct i2c_client *i2c)
+static int __exit isp1301_remove(struct i2c_client *client)
{
- struct isp1301 *isp;
-
- isp = container_of(i2c, struct isp1301, client);
+ struct isp1301 *isp = i2c_get_clientdata(client);
isp1301_clear_bits(isp, ISP1301_INTERRUPT_FALLING, ~0);
isp1301_clear_bits(isp, ISP1301_INTERRUPT_RISING, ~0);
- free_irq(isp->irq, isp);
+
+ if (client->irq > 0)
+ free_irq(client->irq, isp);
#ifdef CONFIG_USB_OTG
otg_unbind(isp);
#endif
- if (machine_is_omap_h2())
- omap_free_gpio(2);
-
isp->timer.data = 0;
set_bit(WORK_STOP, &isp->todo);
del_timer_sync(&isp->timer);
flush_scheduled_work();
- put_device(&i2c->dev);
+ put_device(&client->dev);
the_transceiver = 0;
- return i2c_detach_client(i2c);
+ return 0;
}
/*-------------------------------------------------------------------------*/
isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
INTR_VBUS_VLD | INTR_SESS_VLD | INTR_ID_GND);
- dev_info(&isp->client.dev, "ready for dual-role USB ...\n");
+ dev_info(&isp->client->dev, "ready for dual-role USB ...\n");
return 0;
}
#ifdef CONFIG_USB_OTG
isp->otg.host = host;
- dev_dbg(&isp->client.dev, "registered host\n");
+ dev_dbg(&isp->client->dev, "registered host\n");
host_suspend(isp);
if (isp->otg.gadget)
return isp1301_otg_enable(isp);
power_up(isp);
- if (machine_is_omap_h2())
- isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0);
-
- dev_info(&isp->client.dev, "A-Host sessions ok\n");
+ dev_info(&isp->client->dev, "A-Host sessions ok\n");
isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING,
INTR_ID_GND);
isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
return 0;
#else
- dev_dbg(&isp->client.dev, "host sessions not allowed\n");
+ dev_dbg(&isp->client->dev, "host sessions not allowed\n");
return -EINVAL;
#endif
#ifdef CONFIG_USB_OTG
isp->otg.gadget = gadget;
- dev_dbg(&isp->client.dev, "registered gadget\n");
+ dev_dbg(&isp->client->dev, "registered gadget\n");
/* gadget driver may be suspended until vbus_connect () */
if (isp->otg.host)
return isp1301_otg_enable(isp);
power_up(isp);
isp->otg.state = OTG_STATE_B_IDLE;
- if (machine_is_omap_h2())
+// XXX h4 too?
+ 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);
- dev_info(&isp->client.dev, "B-Peripheral sessions ok\n");
+ INTR_VBUS_VLD | INTR_SESS_VLD);
+ dev_info(&isp->client->dev, "B-Peripheral sessions ok\n");
dump_regs(isp, __func__);
/* If this has a Mini-AB connector, this mode is highly
return 0;
#else
- dev_dbg(&isp->client.dev, "peripheral sessions not allowed\n");
+ dev_dbg(&isp->client->dev, "peripheral sessions not allowed\n");
return -EINVAL;
#endif
}
* 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 */
/*-------------------------------------------------------------------------*/
/* no error returns, they'd just make bus scanning stop */
-static int isp1301_probe(struct i2c_adapter *bus, int address, int kind)
+static int __init isp1301_probe(struct i2c_client *client)
{
int status;
struct isp1301 *isp;
- struct i2c_client *i2c;
if (the_transceiver)
return 0;
init_timer(&isp->timer);
isp->timer.function = isp1301_timer;
isp->timer.data = (unsigned long) isp;
-
- isp->irq = -1;
- isp->client.addr = address;
- i2c_set_clientdata(&isp->client, isp);
- isp->client.adapter = bus;
- isp->client.driver = &isp1301_driver;
- strlcpy(isp->client.name, DRIVER_NAME, I2C_NAME_SIZE);
- i2c = &isp->client;
+ isp->client = client;
/* if this is a true probe, verify the chip ... */
- if (kind < 0) {
- status = isp1301_get_u16(isp, ISP1301_VENDOR_ID);
- if (status != I2C_VENDOR_ID_PHILIPS) {
- dev_dbg(&bus->dev, "addr %d not philips id: %d\n",
- address, status);
- goto fail1;
- }
- status = isp1301_get_u16(isp, ISP1301_PRODUCT_ID);
- if (status != I2C_PRODUCT_ID_PHILIPS_1301) {
- dev_dbg(&bus->dev, "%d not isp1301, %d\n",
- address, status);
- goto fail1;
- }
+ status = isp1301_get_u16(isp, ISP1301_VENDOR_ID);
+ if (status != I2C_VENDOR_ID_PHILIPS) {
+ dev_dbg(&client->dev, "not philips id: %d\n",
+ status);
+ goto fail1;
+ }
+ status = isp1301_get_u16(isp, ISP1301_PRODUCT_ID);
+ if (status != I2C_PRODUCT_ID_PHILIPS_1301) {
+ dev_dbg(&client->dev, "not isp1301, %d\n",
+ status);
+ goto fail1;
}
- status = i2c_attach_client(i2c);
if (status < 0) {
- dev_dbg(&bus->dev, "can't attach %s to device %d, err %d\n",
- DRIVER_NAME, address, status);
+ dev_dbg(&client->dev, "can't attach %s to device, err %d\n",
+ DRIVER_NAME, status);
fail1:
kfree(isp);
return 0;
}
- isp->i2c_release = i2c->dev.release;
- i2c->dev.release = isp1301_release;
+ isp->i2c_release = client->dev.release;
+ client->dev.release = isp1301_release;
/* initial development used chiprev 2.00 */
- status = i2c_smbus_read_word_data(i2c, ISP1301_BCD_DEVICE);
- dev_info(&i2c->dev, "chiprev %x.%02x, driver " DRIVER_VERSION "\n",
+ status = i2c_smbus_read_word_data(client, ISP1301_BCD_DEVICE);
+ dev_info(&client->dev, "chiprev %x.%02x, driver " DRIVER_VERSION "\n",
status >> 8, status & 0xff);
/* make like power-on reset */
#ifdef CONFIG_USB_OTG
status = otg_bind(isp);
if (status < 0) {
- dev_dbg(&i2c->dev, "can't bind OTG\n");
+ dev_dbg(&client->dev, "can't bind OTG\n");
goto fail2;
}
#endif
- if (machine_is_omap_h2()) {
- /* 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);
-
- /* IRQ wired at M14 */
- omap_cfg_reg(M14_1510_GPIO2);
- isp->irq = OMAP_GPIO_IRQ(2);
- if (gpio_request(2, "isp1301") == 0)
- gpio_direction_input(2);
- isp->irq_type = IRQF_TRIGGER_FALLING;
- }
-
- isp->irq_type |= IRQF_SAMPLE_RANDOM;
- status = request_irq(isp->irq, isp1301_irq,
- isp->irq_type, DRIVER_NAME, isp);
+ status = request_irq(client->irq, isp1301_irq,
+ IRQF_SAMPLE_RANDOM | IRQF_TRIGGER_FALLING,
+ DRIVER_NAME, isp);
if (status < 0) {
- dev_dbg(&i2c->dev, "can't get IRQ %d, err %d\n",
- isp->irq, status);
+ dev_dbg(&client->dev, "can't get IRQ %d, err %d\n",
+ client->irq, status);
#ifdef CONFIG_USB_OTG
fail2:
#endif
- i2c_detach_client(i2c);
+ i2c_detach_client(client);
goto fail1;
}
- isp->otg.dev = &isp->client.dev;
+ isp->otg.dev = &client->dev;
isp->otg.label = DRIVER_NAME;
isp->otg.set_host = isp1301_set_host,
update_otg1(isp, isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE));
update_otg2(isp, isp1301_get_u8(isp, ISP1301_OTG_STATUS));
#endif
-
dump_regs(isp, __func__);
#ifdef VERBOSE
mod_timer(&isp->timer, jiffies + TIMER_JIFFIES);
- dev_dbg(&i2c->dev, "scheduled timer, %d min\n", TIMER_MINUTES);
+ dev_dbg(&client->dev, "scheduled timer, %d min\n", TIMER_MINUTES);
#endif
status = otg_set_transceiver(&isp->otg);
if (status < 0)
- dev_err(&i2c->dev, "can't register transceiver, %d\n",
+ dev_err(&client->dev, "can't register transceiver, %d\n",
status);
return 0;
}
-static int isp1301_scan_bus(struct i2c_adapter *bus)
-{
- if (!i2c_check_functionality(bus, I2C_FUNC_SMBUS_BYTE_DATA
- | I2C_FUNC_SMBUS_READ_WORD_DATA))
- return -EINVAL;
- return i2c_probe(bus, &addr_data, isp1301_probe);
-}
-
static struct i2c_driver isp1301_driver = {
.driver = {
.name = "isp1301_omap",
},
- .attach_adapter = isp1301_scan_bus,
- .detach_client = isp1301_detach_client,
+ .probe = isp1301_probe,
+ .remove = __exit_p(isp1301_remove),
};
/*-------------------------------------------------------------------------*/
--- /dev/null
+/*
+ * drivers/i2c/chips/lp5521.c
+ *
+ * Copyright (C) 2007 Nokia Corporation
+ *
+ * Written by Mathias Nyman <mathias.nyman@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/init.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <asm/arch/gpio.h>
+
+#define LP5521_DRIVER_NAME "lp5521"
+
+#ifdef LED_CONNECTED_WRONG
+#define LP5521_REG_R_PWM 0x04
+#define LP5521_REG_B_PWM 0x02
+#else
+#define LP5521_REG_R_PWM 0x02
+#define LP5521_REG_B_PWM 0x04
+#endif
+#define LP5521_REG_ENABLE 0x00
+#define LP5521_REG_OP_MODE 0x01
+#define LP5521_REG_G_PWM 0x03
+#define LP5521_REG_R_CNTRL 0x05
+#define LP5521_REG_G_CNTRL 0x06
+#define LP5521_REG_B_CNTRL 0x07
+#define LP5521_REG_MISC 0x08
+#define LP5521_REG_R_CHANNEL_PC 0x09
+#define LP5521_REG_G_CHANNEL_PC 0x0a
+#define LP5521_REG_B_CHANNEL_PC 0x0b
+#define LP5521_REG_STATUS 0x0c
+#define LP5521_REG_RESET 0x0d
+#define LP5521_REG_GPO 0x0e
+#define LP5521_REG_R_PROG_MEM 0x10
+#define LP5521_REG_G_PROG_MEM 0x30
+#define LP5521_REG_B_PROG_MEM 0x50
+
+#define LP5521_MODE_LOAD "load"
+#define LP5521_MODE_RUN "run"
+#define LP5521_MODE_DIRECT_CONTROL "direct"
+
+#define LP5521_CURRENT_1m5 0x0f
+#define LP5521_CURRENT_3m1 0x1f
+#define LP5521_CURRENT_4m7 0x2f
+#define LP5521_CURRENT_6m3 0x3f
+#define LP5521_CURRENT_7m9 0x4f
+#define LP5521_CURRENT_9m5 0x5f
+#define LP5521_CURRENT_11m1 0x6f
+#define LP5521_CURRENT_12m7 0x7f
+#define LP5521_CURRENT_14m3 0x8f
+#define LP5521_CURRENT_15m9 0x9f
+#define LP5521_CURRENT_17m5 0xaf
+#define LP5521_CURRENT_19m1 0xbf
+#define LP5521_CURRENT_20m7 0xcf
+#define LP5521_CURRENT_22m3 0xdf
+#define LP5521_CURRENT_23m9 0xef
+#define LP5521_CURRENT_25m5 0xff
+
+#define LP5521_PROGRAM_LENGTH 32 /* in bytes */
+
+struct lp5521_chip {
+ struct mutex lock;
+ struct i2c_client *client;
+ char *mode;
+ int red;
+ int green;
+ int blue;
+};
+
+static int lp5521_set_mode(struct lp5521_chip *chip, char *mode);
+
+static int lp5521_write(struct i2c_client *client, u8 reg, u8 value)
+{
+ return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static int lp5521_read(struct i2c_client *client, u8 reg, u8 *buf)
+{
+ s32 ret = i2c_smbus_read_byte_data(client, reg);
+
+ if (ret < 0)
+ return -EIO;
+
+ *buf = ret;
+ return 0;
+}
+
+static int lp5521_configure(struct i2c_client *client)
+{
+ int ret = 0;
+
+ /* Enable chip and set light to logarithmic mode*/
+ ret |= lp5521_write(client, LP5521_REG_ENABLE, 0xc0);
+
+ /* setting all color pwms to direct control mode */
+ ret |= lp5521_write(client, LP5521_REG_OP_MODE, 0x3f);
+
+ /* setting current to 4.7 mA for all channels */
+ ret |= lp5521_write(client, LP5521_REG_R_CNTRL, LP5521_CURRENT_4m7);
+ ret |= lp5521_write(client, LP5521_REG_G_CNTRL, LP5521_CURRENT_4m7);
+ ret |= lp5521_write(client, LP5521_REG_B_CNTRL, LP5521_CURRENT_4m7);
+
+ /* Enable auto-powersave, set charge pump to auto, red to battery */
+ ret |= lp5521_write(client, LP5521_REG_MISC, 0x3c);
+
+ /* initialize all channels pwm to zero */
+ ret |= lp5521_write(client, LP5521_REG_R_PWM, 0);
+ ret |= lp5521_write(client, LP5521_REG_G_PWM, 0);
+ ret |= lp5521_write(client, LP5521_REG_B_PWM, 0);
+
+ /* Not much can be done about errors at this point */
+ return ret;
+}
+
+static int lp5521_load_program(struct lp5521_chip *chip, u8 *pattern)
+{
+ struct i2c_client *client = chip->client;
+ int ret = 0;
+
+ /* Enter load program mode for all led channels */
+ ret |= lp5521_write(client, LP5521_REG_OP_MODE, 0x15); /* 0001 0101 */
+ if (ret)
+ return ret;
+
+ if (chip->red)
+ ret |= i2c_smbus_write_i2c_block_data(client,
+ LP5521_REG_R_PROG_MEM,
+ LP5521_PROGRAM_LENGTH,
+ pattern);
+ if (chip->green)
+ ret |= i2c_smbus_write_i2c_block_data(client,
+ LP5521_REG_G_PROG_MEM,
+ LP5521_PROGRAM_LENGTH,
+ pattern);
+ if (chip->blue)
+ ret |= i2c_smbus_write_i2c_block_data(client,
+ LP5521_REG_B_PROG_MEM,
+ LP5521_PROGRAM_LENGTH,
+ pattern);
+
+ return ret;
+}
+
+static int lp5521_run_program(struct lp5521_chip *chip)
+{
+ struct i2c_client *client = chip->client;
+ int ret;
+ u8 mask = 0xc0;
+ u8 exec_state = 0;
+ u8 enable_reg;
+
+ ret = lp5521_read(client, LP5521_REG_ENABLE, &enable_reg);
+ if (ret)
+ goto fail;
+
+ enable_reg &= mask;
+
+ /* set all active channels exec state to countinous run*/
+ exec_state |= (chip->red << 5);
+ exec_state |= (chip->green << 3);
+ exec_state |= (chip->blue << 1);
+
+ enable_reg |= exec_state;
+
+ ret |= lp5521_write(client, LP5521_REG_ENABLE, enable_reg);
+
+ /* set op-mode to run for active channels, disabled for others */
+ ret |= lp5521_write(client, LP5521_REG_OP_MODE, exec_state);
+
+fail:
+ return ret;
+}
+
+/*--------------------------------------------------------------*/
+/* Sysfs interface */
+/*--------------------------------------------------------------*/
+
+static ssize_t show_active_channels(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct lp5521_chip *chip = dev_get_drvdata(dev);
+ char channels[4];
+ int pos = 0;
+
+#ifdef LED_CONNECTED_WRONG
+ if (chip->blue)
+ pos += sprintf(channels + pos, "r");
+ if (chip->green)
+ pos += sprintf(channels + pos, "g");
+ if (chip->red)
+ pos += sprintf(channels + pos, "b");
+
+#else
+ if (chip->red)
+ pos += sprintf(channels + pos, "r");
+ if (chip->green)
+ pos += sprintf(channels + pos, "g");
+ if (chip->blue)
+ pos += sprintf(channels + pos, "b");
+#endif
+
+ channels[pos] = '\0';
+
+ return sprintf(buf, "%s\n", channels);
+}
+
+static ssize_t store_active_channels(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct lp5521_chip *chip = dev_get_drvdata(dev);
+
+ chip->red = 0;
+ chip->green = 0;
+ chip->blue = 0;
+
+#ifdef LED_CONNECTED_WRONG
+ if (strchr(buf, 'r') != NULL)
+ chip->blue = 1;
+ if (strchr(buf, 'b') != NULL)
+ chip->red = 1;
+#else
+ if (strchr(buf, 'r') != NULL)
+ chip->red = 1;
+ if (strchr(buf, 'b') != NULL)
+ chip->blue = 1;
+#endif
+ if (strchr(buf, 'g') != NULL)
+ chip->green = 1;
+
+ return len;
+}
+
+static ssize_t show_color(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ int ret = 0;
+ u8 r, g, b;
+
+ ret |= lp5521_read(client, LP5521_REG_R_PWM, &r);
+ ret |= lp5521_read(client, LP5521_REG_G_PWM, &g);
+ ret |= lp5521_read(client, LP5521_REG_B_PWM, &b);
+
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "%.2x:%.2x:%.2x\n", r, g, b);
+}
+
+static ssize_t store_color(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lp5521_chip *chip = i2c_get_clientdata(client);
+ int ret;
+ unsigned r, g, b;
+
+
+ ret = sscanf(buf, "%2x:%2x:%2x", &r, &g, &b);
+ if (ret != 3)
+ return -EINVAL;
+
+ mutex_lock(&chip->lock);
+
+ ret = lp5521_write(client, LP5521_REG_R_PWM, (u8)r);
+ ret = lp5521_write(client, LP5521_REG_G_PWM, (u8)g);
+ ret = lp5521_write(client, LP5521_REG_B_PWM, (u8)b);
+
+ mutex_unlock(&chip->lock);
+
+ return len;
+}
+
+static ssize_t store_load(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct lp5521_chip *chip = dev_get_drvdata(dev);
+ int ret, nrchars, offset = 0, i = 0;
+ char c[3];
+ unsigned cmd;
+ u8 pattern[LP5521_PROGRAM_LENGTH] = {0};
+
+ while ((offset < len - 1) && (i < LP5521_PROGRAM_LENGTH)) {
+
+ /* separate sscanfs because length is working only for %s */
+ ret = sscanf(buf + offset, "%2s%n ", c, &nrchars);
+ ret = sscanf(c, "%2x", &cmd);
+ if (ret != 1)
+ goto fail;
+ pattern[i] = (u8)cmd;
+
+ offset += nrchars;
+ i++;
+ }
+
+ /* pattern commands are always two bytes long */
+ if (i % 2)
+ goto fail;
+
+ mutex_lock(&chip->lock);
+
+ ret = lp5521_load_program(chip, pattern);
+ mutex_unlock(&chip->lock);
+
+ if (ret) {
+ dev_err(dev, "lp5521 failed loading pattern\n");
+ return ret;
+ }
+
+ return len;
+fail:
+ dev_err(dev, "lp5521 wrong pattern format\n");
+ return -EINVAL;
+}
+
+static ssize_t show_mode(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct lp5521_chip *chip = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%s\n", chip->mode);
+}
+
+static ssize_t store_mode(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct lp5521_chip *chip = dev_get_drvdata(dev);
+
+ mutex_lock(&chip->lock);
+
+ if (!strncmp(buf, "run", 3))
+ lp5521_set_mode(chip, LP5521_MODE_RUN);
+ else if (!strncmp(buf, "load", 4))
+ lp5521_set_mode(chip, LP5521_MODE_LOAD);
+ else if (!strncmp(buf, "direct", 6))
+ lp5521_set_mode(chip, LP5521_MODE_DIRECT_CONTROL);
+
+ mutex_unlock(&chip->lock);
+
+ return len;
+}
+
+static ssize_t show_current(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ int ret = 0;
+ u8 r_curr, g_curr, b_curr;
+
+ ret |= lp5521_read(client, LP5521_REG_R_CNTRL, &r_curr);
+ ret |= lp5521_read(client, LP5521_REG_G_CNTRL, &g_curr);
+ ret |= lp5521_read(client, LP5521_REG_B_CNTRL, &b_curr);
+
+ if (ret)
+ return ret;
+
+ r_curr = r_curr >> 4;
+ g_curr = g_curr >> 4;
+ b_curr = b_curr >> 4;
+
+ if (r_curr == g_curr && g_curr == b_curr)
+ return sprintf(buf, "%x\n", r_curr);
+ else
+ return sprintf(buf, "%x %x %x\n", r_curr, g_curr, b_curr);
+}
+
+static ssize_t store_current(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct lp5521_chip *chip = dev_get_drvdata(dev);
+ struct i2c_client *client = chip->client;
+ int ret;
+ unsigned curr;
+
+ ret = sscanf(buf, "%1x", &curr);
+ if (ret != 1)
+ return -EINVAL;
+
+ /* current level is determined by the 4 upper bits, rest is ones */
+ curr = (curr << 4) | 0x0f;
+
+ mutex_lock(&chip->lock);
+
+ ret |= lp5521_write(client, LP5521_REG_R_CNTRL, (u8)curr);
+ ret |= lp5521_write(client, LP5521_REG_G_CNTRL, (u8)curr);
+ ret |= lp5521_write(client, LP5521_REG_B_CNTRL, (u8)curr);
+
+ mutex_unlock(&chip->lock);
+
+ return len;
+}
+
+static DEVICE_ATTR(color, S_IRUGO | S_IWUGO, show_color, store_color);
+static DEVICE_ATTR(load, S_IWUGO, NULL, store_load);
+static DEVICE_ATTR(mode, S_IRUGO | S_IWUGO, show_mode, store_mode);
+static DEVICE_ATTR(active_channels, S_IRUGO | S_IWUGO,
+ show_active_channels, store_active_channels);
+static DEVICE_ATTR(led_current, S_IRUGO | S_IWUGO, show_current, store_current);
+
+static int lp5521_register_sysfs(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ int ret;
+
+ ret = device_create_file(dev, &dev_attr_color);
+ if (ret)
+ goto fail1;
+ ret = device_create_file(dev, &dev_attr_load);
+ if (ret)
+ goto fail2;
+ ret = device_create_file(dev, &dev_attr_active_channels);
+ if (ret)
+ goto fail3;
+ ret = device_create_file(dev, &dev_attr_mode);
+ if (ret)
+ goto fail4;
+ ret = device_create_file(dev, &dev_attr_led_current);
+ if (ret)
+ goto fail5;
+ return 0;
+
+fail5:
+ device_remove_file(dev, &dev_attr_mode);
+fail4:
+ device_remove_file(dev, &dev_attr_active_channels);
+fail3:
+ device_remove_file(dev, &dev_attr_load);
+fail2:
+ device_remove_file(dev, &dev_attr_color);
+fail1:
+ return ret;
+}
+
+static void lp5521_unregister_sysfs(struct i2c_client *client)
+{
+ struct lp5521_chip *chip = i2c_get_clientdata(client);
+ struct device *dev = &client->dev;
+
+ device_remove_file(dev, &dev_attr_led_current);
+ device_remove_file(dev, &dev_attr_mode);
+ device_remove_file(dev, &dev_attr_active_channels);
+ device_remove_file(dev, &dev_attr_color);
+
+ if (!strcmp(chip->mode, LP5521_MODE_LOAD))
+ device_remove_file(dev, &dev_attr_load);
+}
+
+/*--------------------------------------------------------------*/
+/* Set chip operating mode */
+/*--------------------------------------------------------------*/
+
+static int lp5521_set_mode(struct lp5521_chip *chip, char *mode)
+{
+ struct i2c_client *client = chip->client ;
+ int ret = 0;
+
+ /* if in that mode already do nothing, except for run */
+ if (!strcmp(mode, chip->mode) && strcmp(mode, LP5521_MODE_RUN))
+ return 0;
+
+ if (!strcmp(mode, LP5521_MODE_RUN))
+ ret = lp5521_run_program(chip);
+
+ if (!strcmp(mode, LP5521_MODE_LOAD))
+ ret |= lp5521_write(client, LP5521_REG_OP_MODE, 0x15);
+
+ if (!strcmp(mode, LP5521_MODE_DIRECT_CONTROL))
+ ret |= lp5521_write(client, LP5521_REG_OP_MODE, 0x3F);
+
+ chip->mode = mode;
+
+ return ret;
+}
+
+/*--------------------------------------------------------------*/
+/* Probe, Attach, Remove */
+/*--------------------------------------------------------------*/
+static struct i2c_driver lp5521_driver;
+
+static int lp5521_probe(struct i2c_client *client)
+{
+ struct lp5521_chip *chip;
+ int ret = 0;
+
+ chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ chip->client = client;
+ strncpy(client->name, LP5521_DRIVER_NAME, I2C_NAME_SIZE);
+ i2c_set_clientdata(client, chip);
+
+ mutex_init(&chip->lock);
+
+ ret = lp5521_configure(client);
+ if (ret < 0) {
+ dev_err(&client->dev, "lp5521 error configuring chip \n");
+ goto fail1;
+ }
+
+ /* Set default values */
+ chip->mode = LP5521_MODE_DIRECT_CONTROL;
+ chip->red = 1;
+ chip->green = 1;
+ chip->blue = 1;
+
+ ret = lp5521_register_sysfs(client);
+ if (ret)
+ dev_err(&client->dev, "lp5521 registering sysfs failed \n");
+
+ return ret;
+
+fail1:
+ kfree(chip);
+ return ret;
+}
+
+static int lp5521_remove(struct i2c_client *client)
+{
+ struct lp5521_chip *chip = i2c_get_clientdata(client);
+
+ lp5521_unregister_sysfs(client);
+ kfree(chip);
+
+ return 0;
+}
+
+static struct i2c_driver lp5521_driver = {
+ .driver = {
+ .name = LP5521_DRIVER_NAME,
+ },
+ .probe = lp5521_probe,
+ .remove = __exit_p(lp5521_remove),
+};
+
+static int __init lp5521_init(void)
+{
+ return i2c_add_driver(&lp5521_driver);
+}
+
+static void __exit lp5521_exit(void)
+{
+ i2c_del_driver(&lp5521_driver);
+}
+
+MODULE_AUTHOR("Mathias Nyman <mathias.nyman@nokia.com>");
+MODULE_DESCRIPTION("lp5521 LED driver");
+MODULE_LICENSE("GPL");
+
+module_init(lp5521_init);
+module_exit(lp5521_exit);
+
/*
* Copyright (C) 2004 Texas Instruments, Inc.
*
int val = i2c_smbus_write_byte_data(the_menelaus->client, reg, value);
if (val < 0) {
- pr_err(DRIVER_NAME ": write error");
+ dev_err(&the_menelaus->client->dev, "write error");
return val;
}
int val = i2c_smbus_read_byte_data(the_menelaus->client, reg);
if (val < 0)
- pr_err(DRIVER_NAME ": read error");
+ dev_err(&the_menelaus->client->dev, "read error");
return val;
}
}
EXPORT_SYMBOL(menelaus_set_slot_sel);
+int menelaus_enable_slot(int slot, int enable)
+{
+ int ret, val;
+
+ mutex_lock(&the_menelaus->lock);
+ ret = menelaus_read_reg(MENELAUS_MCT_CTRL3);
+ if (ret < 0)
+ goto out;
+ val = ret;
+ if (slot == 1) {
+ if (enable)
+ val |= 1 << 0;
+ else
+ val &= ~(1 << 0);
+ } else {
+ if (enable)
+ val |= 1 << 1;
+ else
+ val &= ~(1 << 1);
+ }
+ ret = menelaus_write_reg(MENELAUS_MCT_CTRL3, val);
+
+out:
+ mutex_unlock(&the_menelaus->lock);
+ return ret;
+}
+EXPORT_SYMBOL(menelaus_enable_slot);
+
int menelaus_set_mmc_slot(int slot, int enable, int power, int cd_en)
{
int ret, val;
int b;
if (enable)
- ret |= 1 << 1;
+ val |= 1 << 1;
else
- ret &= ~(1 << 1);
+ val &= ~(1 << 1);
b = menelaus_read_reg(MENELAUS_MCT_CTRL2);
b &= ~0x03;
b |= power;
return status;
status = menelaus_write_reg(MENELAUS_RTC_WKDAY, BIN2BCD(t->tm_wday));
if (status < 0) {
- dev_err(&the_menelaus->client->dev, "rtc write reg %02x "
+ dev_err(&the_menelaus->client->dev, "rtc write reg %02x"
"err %d\n", MENELAUS_RTC_WKDAY, status);
return status;
}
/* If a true probe check the device */
rev = menelaus_read_reg(MENELAUS_REV);
if (rev < 0) {
- pr_err(DRIVER_NAME ": device not found");
+ dev_err(&client->dev, "device not found");
err = -ENODEV;
goto fail1;
}
err = request_irq(client->irq, menelaus_irq, IRQF_DISABLED,
DRIVER_NAME, menelaus);
if (err) {
- dev_dbg(&client->dev, "can't get IRQ %d, err %d\n",
+ dev_dbg(&client->dev, "can't get IRQ %d, err %d",
client->irq, err);
goto fail1;
}
mutex_init(&menelaus->lock);
INIT_WORK(&menelaus->work, menelaus_work);
- pr_info("Menelaus rev %d.%d\n", rev >> 4, rev & 0x0f);
+ dev_info(&client->dev, "Menelaus rev %d.%d\n", rev >> 4, rev & 0x0f);
val = menelaus_read_reg(MENELAUS_VCORE_CTRL1);
if (val < 0)
static int __init menelaus_init(void)
{
- int res;
-
- res = i2c_add_driver(&menelaus_i2c_driver);
- if (res < 0) {
- pr_err(DRIVER_NAME ": driver registration failed\n");
- return res;
- }
-
- return 0;
+ return i2c_add_driver(&menelaus_i2c_driver);
}
static void __exit menelaus_exit(void)
--- /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/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 aic23_driver;
+static struct i2c_client *new_client;
+static int selftest;
+static struct platform_device audio_i2c_device;
+
+static struct aic23_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 initialized;
+} aic23_info_l;
+
+static int _aic23_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 aic23_write_value(u8 reg, u16 value)
+{
+ static struct i2c_client *client;
+ client = new_client;
+ _aic23_write_value(client, reg, value);
+
+ return 0;
+}
+
+/*
+ * 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_aic23_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 int aic23_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 functionality 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 = &aic23_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;
+ }
+
+ if (platform_device_register(&audio_i2c_device)) {
+ printk(KERN_WARNING "Failed to register audio i2c device\n");
+ selftest = -ENODEV;
+ return selftest;
+ }
+ /* FIXME: Do in board-specific file */
+ omap_mcbsp3_aic23_clock_init();
+
+ if (!aic23_info_l.power_down)
+ aic23_power_up();
+ aic23_info_l.initialized = 1;
+
+ return 0;
+}
+
+static int aic23_detach_client(struct i2c_client *client)
+{
+ int err;
+
+ platform_device_unregister(&audio_i2c_device);
+
+ if ((err = i2c_detach_client(client))) {
+ printk("aic23.o: Client deregistration failed, \
+ client not detached.\n");
+ return err;
+ }
+ kfree(client);
+ return 0;
+}
+
+static int aic23_attach_adapter(struct i2c_adapter *adapter)
+{
+ int res;
+
+ res = i2c_probe(adapter, &addr_data, &aic23_detect_client);
+ return res;
+}
+
+static struct i2c_driver aic23_driver = {
+ .driver = {
+ .name = "OMAP+TLV320AIC23 codec",
+ /*.flags = I2C_DF_NOTIFY,*/
+ },
+ .id = I2C_DRIVERID_MISC, /* Experimental ID */
+ .attach_adapter = aic23_attach_adapter,
+ .detach_client = aic23_detach_client,
+};
+
+static void update_volume_left(int volume)
+{
+ u16 val = 0;
+ val = ((volume * OUTPUT_VOLUME_RANGE) / 100) + OUTPUT_VOLUME_MIN;
+ aic23_write_value(LEFT_CHANNEL_VOLUME_ADDR, val);
+ aic23_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;
+ aic23_write_value(RIGHT_CHANNEL_VOLUME_ADDR, val);
+ aic23_info_l.volume_reg_right = volume;
+}
+
+static void set_mic(int mic_en)
+{
+ u16 dg_ctrl;
+
+ if (mic_en) {
+ aic23_info_l.power = OSC_OFF | LINE_OFF;
+ dg_ctrl = ADCHP_ON;
+ aic23_info_l.mask &= ~MICM_MUTED;
+ aic23_info_l.mask |= MICB_20DB; /* STE_ENABLED */
+ } else {
+ aic23_info_l.power =
+ OSC_OFF | ADC_OFF | MIC_OFF | LINE_OFF;
+ dg_ctrl = 0x00;
+ aic23_info_l.mask =
+ DAC_SELECTED | INSEL_MIC | MICM_MUTED;
+ }
+ aic23_write_value(POWER_DOWN_CONTROL_ADDR,
+ aic23_info_l.power);
+ aic23_write_value(DIGITAL_AUDIO_CONTROL_ADDR, dg_ctrl);
+ aic23_write_value(ANALOG_AUDIO_CONTROL_ADDR,
+ aic23_info_l.mask);
+ aic23_info_l.mic_enable = mic_en;
+
+ printk(KERN_INFO "aic23 mic state: %i\n", mic_en);
+}
+
+static void aic23_init_power(void)
+{
+ aic23_write_value(RESET_CONTROL_ADDR, 0x00);
+
+ if (aic23_info_l.initialized == 0) {
+ aic23_write_value(LEFT_CHANNEL_VOLUME_ADDR, LHV_MIN);
+ aic23_write_value(RIGHT_CHANNEL_VOLUME_ADDR, LHV_MIN);
+ }
+ else {
+ update_volume_left(aic23_info_l.volume_reg_left);
+ update_volume_right(aic23_info_l.volume_reg_right);
+ }
+
+ aic23_info_l.mask = DAC_SELECTED | INSEL_MIC | MICM_MUTED;
+ aic23_write_value(ANALOG_AUDIO_CONTROL_ADDR,
+ aic23_info_l.mask);
+ aic23_write_value(DIGITAL_AUDIO_CONTROL_ADDR, 0x00);
+ aic23_write_value(DIGITAL_AUDIO_FORMAT_ADDR, LRP_ON | FOR_DSP);
+ aic23_write_value(SAMPLE_RATE_CONTROL_ADDR, USB_CLK_ON);
+ aic23_write_value(DIGITAL_INTERFACE_ACT_ADDR, ACT_ON);
+ aic23_info_l.power = OSC_OFF | ADC_OFF | MIC_OFF | LINE_OFF;
+ aic23_write_value(POWER_DOWN_CONTROL_ADDR,
+ aic23_info_l.power);
+
+ /* enable mic input */
+ if (aic23_info_l.mic_enable)
+ set_mic(aic23_info_l.mic_enable);
+
+ printk(KERN_INFO "aic23_init_power() done\n");
+}
+
+void aic23_power_down(void)
+{
+ if (aic23_info_l.initialized) {
+ printk("aic23 powering down\n");
+ aic23_write_value(POWER_DOWN_CONTROL_ADDR, 0xff);
+ }
+ aic23_info_l.power_down = 1;
+}
+
+void aic23_power_up(void)
+{
+ if (aic23_info_l.initialized) {
+ printk("aic23 powering up\n");
+ aic23_init_power();
+ }
+ aic23_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) {
+ aic23_power_down();
+ return count;
+ } else if (volume > MIN_VOL && aic23_info_l.power_down) {
+ aic23_info_l.volume_reg_left = volume;
+ aic23_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", aic23_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) {
+ aic23_power_down();
+ return count;
+ } else if (volume > MIN_VOL && aic23_info_l.power_down) {
+ aic23_info_l.volume_reg_right = volume;
+ aic23_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", aic23_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;
+ aic23_write_value(LEFT_LINE_VOLUME_ADDR, val);
+ aic23_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", aic23_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;
+ aic23_write_value(RIGHT_LINE_VOLUME_ADDR, val);
+ aic23_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", aic23_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) {
+ aic23_write_value(POWER_DOWN_CONTROL_ADDR, \
+ OSC_OFF | ADC_OFF | LINE_OFF);
+ aic23_info_l.mask = STE_ENABLED | DAC_SELECTED \
+ | INSEL_MIC | MICB_20DB;
+ aic23_write_value(ANALOG_AUDIO_CONTROL_ADDR,
+ aic23_info_l.mask);
+ mic = 1;
+ }
+ else {
+ aic23_write_value(POWER_DOWN_CONTROL_ADDR, \
+ OSC_OFF | ADC_OFF | MIC_OFF | LINE_OFF);
+ mic = 0;
+ }
+ aic23_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", aic23_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 = aic23_info_l.mask;
+ tmp &= 0x3f;
+
+ aic23_info_l.mask = tmp | STA_REG(sta);
+ aic23_write_value(ANALOG_AUDIO_CONTROL_ADDR,
+ aic23_info_l.mask);
+ aic23_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", aic23_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", aic23_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
+ */
+ aic23_write_value(LEFT_CHANNEL_VOLUME_ADDR, LHV_MIN);
+ aic23_write_value(RIGHT_CHANNEL_VOLUME_ADDR, LHV_MIN);
+ aic23_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
+ */
+ aic23_write_value(LEFT_CHANNEL_VOLUME_ADDR, LHV_MIN);
+ aic23_write_value(RIGHT_CHANNEL_VOLUME_ADDR, LHV_MIN);
+ aic23_power_down();
+
+ return 0;
+}
+
+static int audio_i2c_resume(struct platform_device *dev)
+{
+ aic23_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 aic23_init(void)
+{
+ selftest = 0;
+ aic23_info_l.initialized = 0;
+
+ if (i2c_add_driver(&aic23_driver)) {
+ printk("aic23 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;
+ }
+
+ printk("TLV320AIC23 I2C version %s (%s)\n",
+ TLV320AIC23_VERSION, TLV320AIC23_DATE);
+
+ return selftest;
+}
+
+static void __exit aic23_exit(void)
+{
+ aic23_power_down();
+ i2c_del_driver(&aic23_driver);
+
+ 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(aic23_init)
+module_exit(aic23_exit)
+
+EXPORT_SYMBOL(aic23_write_value);
+EXPORT_SYMBOL(aic23_power_up);
+EXPORT_SYMBOL(aic23_power_down);
--- /dev/null
+/*
+ * drivers/i2c/chips/tsl2563.c
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Written by Timo O. Karjalainen <timo.o.karjalainen@nokia.com>
+ * Contact: Mathias Nyman <mathias.nyman@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
+#include <asm/arch/board.h>
+
+#define DRIVER_NAME "tsl2563"
+
+/* Use this many bits for fraction part. */
+#define ADC_FRAC_BITS (14)
+
+/* Given number of 1/10000's in ADC_FRAC_BITS precision. */
+#define FRAC10K(f) (((f) * (1L << (ADC_FRAC_BITS))) / (10000))
+
+/* Bits used for fraction in calibration coefficients.*/
+#define CALIB_FRAC_BITS (10)
+/* 0.5 in CALIB_FRAC_BITS precision */
+#define CALIB_FRAC_HALF (1 << (CALIB_FRAC_BITS - 1))
+/* Make a fraction from a number n that was multiplied with b. */
+#define CALIB_FRAC(n, b) (((n) << CALIB_FRAC_BITS) / (b))
+/* Decimal 10^(digits in sysfs presentation) */
+#define CALIB_BASE_SYSFS (1000)
+
+#define TSL2563_CMD (0x80)
+#define TSL2563_CLEARINT (0x40)
+
+#define TSL2563_REG_CTRL (0x00)
+#define TSL2563_REG_TIMING (0x01)
+#define TSL2563_REG_LOWLOW (0x02) /* data0 low threshold, 2 bytes */
+#define TSL2563_REG_LOWHIGH (0x03)
+#define TSL2563_REG_HIGHLOW (0x04) /* data0 high threshold, 2 bytes */
+#define TSL2563_REG_HIGHHIGH (0x05)
+#define TSL2563_REG_INT (0x06)
+#define TSL2563_REG_ID (0x0a)
+#define TSL2563_REG_DATA0LOW (0x0c) /* broadband sensor value, 2 bytes */
+#define TSL2563_REG_DATA0HIGH (0x0d)
+#define TSL2563_REG_DATA1LOW (0x0e) /* infrared sensor value, 2 bytes */
+#define TSL2563_REG_DATA1HIGH (0x0f)
+
+#define TSL2563_CMD_POWER_ON (0x03)
+#define TSL2563_CMD_POWER_OFF (0x00)
+#define TSL2563_CTRL_POWER_MASK (0x03)
+
+#define TSL2563_TIMING_13MS (0x00)
+#define TSL2563_TIMING_100MS (0x01)
+#define TSL2563_TIMING_400MS (0x02)
+#define TSL2563_TIMING_MASK (0x03)
+#define TSL2563_TIMING_GAIN16 (0x10)
+#define TSL2563_TIMING_GAIN1 (0x00)
+
+#define TSL2563_INT_DISBLED (0x00)
+#define TSL2563_INT_LEVEL (0x10)
+#define TSL2563_INT_PERSIST(n) ((n) & 0x0F)
+
+struct tsl2563_gainlevel_coeff {
+ u8 gaintime;
+ u16 min;
+ u16 max;
+};
+
+static struct tsl2563_gainlevel_coeff tsl2563_gainlevel_table[] = {
+ {
+ .gaintime = TSL2563_TIMING_400MS | TSL2563_TIMING_GAIN16,
+ .min = 0,
+ .max = 65534,
+ }, {
+ .gaintime = TSL2563_TIMING_400MS | TSL2563_TIMING_GAIN1,
+ .min = 2048,
+ .max = 65534,
+ }, {
+ .gaintime = TSL2563_TIMING_100MS | TSL2563_TIMING_GAIN1,
+ .min = 4095,
+ .max = 37177,
+ }, {
+ .gaintime = TSL2563_TIMING_13MS | TSL2563_TIMING_GAIN1,
+ .min = 3000,
+ .max = 65535,
+ },
+};
+
+struct tsl2563_chip {
+ struct mutex lock;
+ struct i2c_client *client;
+ struct device *hwmon_dev;
+
+ /* Remember state for suspend and resume functions */
+ pm_message_t state;
+
+ struct tsl2563_gainlevel_coeff *gainlevel;
+
+ /* Thresholds are in lux */
+ u16 low_thres;
+ u16 high_thres;
+ u8 intr;
+
+ /* Calibration coefficients */
+ u32 calib0;
+ u32 calib1;
+
+ /* Cache current values, to be returned while suspended */
+ u32 data0;
+ u32 data1;
+};
+
+static int tsl2563_write(struct i2c_client *client, u8 reg, u8 value)
+{
+ int ret;
+ u8 buf[2];
+
+ buf[0] = TSL2563_CMD | reg;
+ buf[1] = value;
+
+ ret = i2c_master_send(client, buf, sizeof(buf));
+ return (ret == sizeof(buf)) ? 0 : ret;
+}
+
+static int tsl2563_read(struct i2c_client *client, u8 reg, void *buf, int len)
+{
+ int ret;
+ u8 cmd = TSL2563_CMD | reg;
+
+ ret = i2c_master_send(client, &cmd, sizeof(cmd));
+ if (ret != sizeof(cmd))
+ return ret;
+
+ return i2c_master_recv(client, buf, len);
+}
+
+static int tsl2563_set_power(struct tsl2563_chip *chip, int on)
+{
+ struct i2c_client *client = chip->client;
+ u8 cmd;
+
+ cmd = on ? TSL2563_CMD_POWER_ON : TSL2563_CMD_POWER_OFF;
+ return tsl2563_write(client, TSL2563_REG_CTRL, cmd);
+}
+
+/*
+ * Return value is 0 for off, 1 for on, or a negative error
+ * code if reading failed.
+ */
+static int tsl2563_get_power(struct tsl2563_chip *chip)
+{
+ struct i2c_client *client = chip->client;
+ int ret;
+ u8 val;
+
+ ret = tsl2563_read(client, TSL2563_REG_CTRL, &val, sizeof(val));
+ if (ret != sizeof(val))
+ return ret;
+
+ return (val & TSL2563_CTRL_POWER_MASK) == TSL2563_CMD_POWER_ON;
+}
+
+static int tsl2563_configure(struct tsl2563_chip *chip)
+{
+ struct i2c_client *client = chip->client;
+ int ret;
+
+ ret = tsl2563_write(client, TSL2563_REG_TIMING,
+ chip->gainlevel->gaintime);
+ if (ret)
+ goto out;
+
+ ret = tsl2563_write(client, TSL2563_REG_INT, chip->intr);
+
+out:
+ return ret;
+}
+
+static int tsl2563_detect(struct tsl2563_chip *chip)
+{
+ int ret;
+
+ ret = tsl2563_set_power(chip, 1);
+ if (ret)
+ return ret;
+
+ ret = tsl2563_get_power(chip);
+ if (ret < 0)
+ return ret;
+
+ return ret ? 0 : -ENODEV;
+}
+
+static int tsl2563_read_id(struct tsl2563_chip *chip, u8 *id)
+{
+ struct i2c_client *client = chip->client;
+ int ret;
+
+ ret = tsl2563_read(client, TSL2563_REG_ID, id, sizeof(*id));
+ if (ret != sizeof(*id))
+ return ret;
+
+ return 0;
+}
+
+/*
+ * "Normalized" ADC value is one obtained with 400ms of integration time and
+ * 16x gain. This function returns the number of bits of shift needed to
+ * convert between normalized values and HW values obtained using given
+ * timing and gain settings.
+ */
+static int adc_shiftbits(u8 timing)
+{
+ int shift = 0;
+
+ switch (timing & TSL2563_TIMING_MASK) {
+ case TSL2563_TIMING_13MS:
+ shift += 5;
+ break;
+ case TSL2563_TIMING_100MS:
+ shift += 2;
+ break;
+ case TSL2563_TIMING_400MS:
+ /* no-op */
+ break;
+ }
+
+ if (!(timing & TSL2563_TIMING_GAIN16))
+ shift += 4;
+
+ return shift;
+}
+
+/* Convert a HW ADC value to normalized scale. */
+static u32 normalize_adc(u16 adc, u8 timing)
+{
+ return adc << adc_shiftbits(timing);
+}
+
+static void tsl2563_wait_adc(struct tsl2563_chip *chip)
+{
+ unsigned int delay;
+
+ switch (chip->gainlevel->gaintime & TSL2563_TIMING_MASK) {
+ case TSL2563_TIMING_13MS:
+ delay = 14;
+ break;
+ case TSL2563_TIMING_100MS:
+ delay = 101;
+ break;
+ default:
+ delay = 402;
+ }
+ /*
+ * TODO: Make sure that we wait at least required delay but why we
+ * have to extend it one tick more?
+ */
+ schedule_timeout_interruptible(msecs_to_jiffies(delay) + 2);
+}
+
+static int tsl2563_adjust_gainlevel(struct tsl2563_chip *chip, u16 adc)
+{
+ struct i2c_client *client = chip->client;
+
+ if (adc > chip->gainlevel->max || adc < chip->gainlevel->min) {
+
+ (adc > chip->gainlevel->max) ?
+ chip->gainlevel++ : chip->gainlevel--;
+
+ tsl2563_write(client, TSL2563_REG_TIMING,
+ chip->gainlevel->gaintime);
+
+ tsl2563_wait_adc(chip);
+ tsl2563_wait_adc(chip);
+
+ return 1;
+ } else
+ return 0;
+}
+
+static int tsl2563_get_adc(struct tsl2563_chip *chip)
+{
+ struct i2c_client *client = chip->client;
+ u8 buf0[2], buf1[2];
+ u16 adc0, adc1;
+ int retry = 1;
+ int ret = 0;
+
+ if (chip->state.event != PM_EVENT_ON)
+ goto out;
+
+ while (retry) {
+ ret = tsl2563_read(client,
+ TSL2563_REG_DATA0LOW | TSL2563_CLEARINT,
+ buf0, sizeof(buf0));
+ if (ret != sizeof(buf0))
+ goto out;
+
+ ret = tsl2563_read(client, TSL2563_REG_DATA1LOW,
+ buf1, sizeof(buf1));
+ if (ret != sizeof(buf1))
+ goto out;
+
+ adc0 = (buf0[1] << 8) + buf0[0];
+ adc1 = (buf1[1] << 8) + buf1[0];
+
+ retry = tsl2563_adjust_gainlevel(chip, adc0);
+ }
+
+ chip->data0 = normalize_adc(adc0, chip->gainlevel->gaintime);
+ chip->data1 = normalize_adc(adc1, chip->gainlevel->gaintime);
+
+ ret = 0;
+out:
+ return ret;
+}
+
+static inline int calib_to_sysfs(u32 calib)
+{
+ return (int) (((calib * CALIB_BASE_SYSFS) +
+ CALIB_FRAC_HALF) >> CALIB_FRAC_BITS);
+}
+
+static inline u32 calib_from_sysfs(int value)
+{
+ return (((u32) value) << CALIB_FRAC_BITS) / CALIB_BASE_SYSFS;
+}
+
+/*
+ * Conversions between lux and ADC values.
+ *
+ * The basic formula is lux = c0 * adc0 - c1 * adc1, where c0 and c1 are
+ * appropriate constants. Different constants are needed for different
+ * kinds of light, determined by the ratio adc1/adc0 (basically the ratio
+ * of the intensities in infrared and visible wavelengths). lux_table below
+ * lists the upper threshold of the adc1/adc0 ratio and the corresponding
+ * constants.
+ */
+
+struct tsl2563_lux_coeff {
+ unsigned long ch_ratio;
+ unsigned long ch0_coeff;
+ unsigned long ch1_coeff;
+};
+
+static const struct tsl2563_lux_coeff lux_table[] = {
+ {
+ .ch_ratio = FRAC10K(1300),
+ .ch0_coeff = FRAC10K(315),
+ .ch1_coeff = FRAC10K(262),
+ }, {
+ .ch_ratio = FRAC10K(2600),
+ .ch0_coeff = FRAC10K(337),
+ .ch1_coeff = FRAC10K(430),
+ }, {
+ .ch_ratio = FRAC10K(3900),
+ .ch0_coeff = FRAC10K(363),
+ .ch1_coeff = FRAC10K(529),
+ }, {
+ .ch_ratio = FRAC10K(5200),
+ .ch0_coeff = FRAC10K(392),
+ .ch1_coeff = FRAC10K(605),
+ }, {
+ .ch_ratio = FRAC10K(6500),
+ .ch0_coeff = FRAC10K(229),
+ .ch1_coeff = FRAC10K(291),
+ }, {
+ .ch_ratio = FRAC10K(8000),
+ .ch0_coeff = FRAC10K(157),
+ .ch1_coeff = FRAC10K(180),
+ }, {
+ .ch_ratio = FRAC10K(13000),
+ .ch0_coeff = FRAC10K(34),
+ .ch1_coeff = FRAC10K(26),
+ }, {
+ .ch_ratio = ULONG_MAX,
+ .ch0_coeff = 0,
+ .ch1_coeff = 0,
+ },
+};
+
+/*
+ * Convert normalized, scaled ADC values to lux.
+ */
+static unsigned int adc_to_lux(u32 adc0, u32 adc1)
+{
+ const struct tsl2563_lux_coeff *lp = lux_table;
+ unsigned long ratio, lux, ch0 = adc0, ch1 = adc1;
+
+ ratio = ch0 ? ((ch1 << ADC_FRAC_BITS) / ch0) : ULONG_MAX;
+
+ while (lp->ch_ratio < ratio)
+ lp++;
+
+ lux = ch0 * lp->ch0_coeff - ch1 * lp->ch1_coeff;
+
+ return (unsigned int) (lux >> ADC_FRAC_BITS);
+}
+
+/*--------------------------------------------------------------*/
+/* Sysfs interface */
+/*--------------------------------------------------------------*/
+
+static ssize_t tsl2563_adc0_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tsl2563_chip *chip = dev_get_drvdata(dev);
+ int ret;
+
+ mutex_lock(&chip->lock);
+
+ ret = tsl2563_get_adc(chip);
+ if (ret)
+ return ret;
+
+ ret = snprintf(buf, PAGE_SIZE, "%d\n", chip->data0);
+ mutex_unlock(&chip->lock);
+
+ return ret;
+}
+
+static ssize_t tsl2563_adc1_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tsl2563_chip *chip = dev_get_drvdata(dev);
+ int ret;
+
+ mutex_lock(&chip->lock);
+
+ ret = tsl2563_get_adc(chip);
+ if (ret)
+ return ret;
+
+ ret = snprintf(buf, PAGE_SIZE, "%d\n", chip->data1);
+ mutex_unlock(&chip->lock);
+
+ return ret;
+}
+
+/* Apply calibration coefficient to ADC count. */
+static u32 calib_adc(u32 adc, u32 calib)
+{
+ unsigned long scaled = adc;
+
+ scaled *= calib;
+ scaled >>= CALIB_FRAC_BITS;
+
+ return (u32) scaled;
+}
+
+static ssize_t tsl2563_lux_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tsl2563_chip *chip = dev_get_drvdata(dev);
+ u32 calib0, calib1;
+ int ret;
+
+ mutex_lock(&chip->lock);
+
+ ret = tsl2563_get_adc(chip);
+ if (ret)
+ goto out;
+
+ calib0 = calib_adc(chip->data0, chip->calib0);
+ calib1 = calib_adc(chip->data1, chip->calib1);
+
+ ret = snprintf(buf, PAGE_SIZE, "%d\n", adc_to_lux(calib0, calib1));
+
+out:
+ mutex_unlock(&chip->lock);
+ return ret;
+}
+
+static ssize_t format_calib(char *buf, int len, u32 calib)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", calib_to_sysfs(calib));
+}
+
+static ssize_t tsl2563_calib0_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tsl2563_chip *chip = dev_get_drvdata(dev);
+ int ret;
+
+ mutex_lock(&chip->lock);
+ ret = format_calib(buf, PAGE_SIZE, chip->calib0);
+ mutex_unlock(&chip->lock);
+ return ret;
+}
+
+static ssize_t tsl2563_calib1_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tsl2563_chip *chip = dev_get_drvdata(dev);
+ int ret;
+
+ mutex_lock(&chip->lock);
+ ret = format_calib(buf, PAGE_SIZE, chip->calib1);
+ mutex_unlock(&chip->lock);
+ return ret;
+}
+
+static int do_calib_store(struct device *dev, const char *buf, size_t len,
+ int ch)
+{
+ struct tsl2563_chip *chip = dev_get_drvdata(dev);
+ int value;
+ u32 calib;
+
+ if (1 != sscanf(buf, "%d", &value))
+ return -EINVAL;
+
+ calib = calib_from_sysfs(value);
+
+ if (ch)
+ chip->calib1 = calib;
+ else
+ chip->calib0 = calib;
+
+ return len;
+}
+
+static ssize_t tsl2563_calib0_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ return do_calib_store(dev, buf, len, 0);
+}
+
+static ssize_t tsl2563_calib1_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ return do_calib_store(dev, buf, len, 1);
+}
+
+static DEVICE_ATTR(adc0, S_IRUGO, tsl2563_adc0_show, NULL);
+static DEVICE_ATTR(adc1, S_IRUGO, tsl2563_adc1_show, NULL);
+static DEVICE_ATTR(lux, S_IRUGO, tsl2563_lux_show, NULL);
+static DEVICE_ATTR(calib0, S_IRUGO | S_IWUSR,
+ tsl2563_calib0_show, tsl2563_calib0_store);
+static DEVICE_ATTR(calib1, S_IRUGO | S_IWUSR,
+ tsl2563_calib1_show, tsl2563_calib1_store);
+
+static struct attribute *tsl2563_attributes[] = {
+ &dev_attr_adc0.attr,
+ &dev_attr_adc1.attr,
+ &dev_attr_lux.attr,
+ &dev_attr_calib0.attr,
+ &dev_attr_calib1.attr,
+ NULL
+};
+
+static const struct attribute_group tsl2563_group = {
+ .attrs = tsl2563_attributes,
+};
+
+static int tsl2563_register_sysfs(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+
+ return sysfs_create_group(&dev->kobj, &tsl2563_group);
+}
+
+static void tsl2563_unregister_sysfs(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+
+ sysfs_remove_group(&dev->kobj, &tsl2563_group);
+}
+
+/*--------------------------------------------------------------*/
+/* Probe, Attach, Remove */
+/*--------------------------------------------------------------*/
+static struct i2c_driver tsl2563_i2c_driver;
+
+static int tsl2563_probe(struct i2c_client *client)
+{
+ struct tsl2563_chip *chip;
+ int err = 0;
+ u8 id;
+
+ chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, chip);
+ chip->client = client;
+
+ err = tsl2563_detect(chip);
+ if (err) {
+ dev_err(&client->dev, "device not found, error %d \n", -err);
+ goto fail1;
+ }
+
+ err = tsl2563_read_id(chip, &id);
+ if (err)
+ goto fail1;
+
+ mutex_init(&chip->lock);
+
+ /* Default values used until userspace says otherwise */
+ chip->low_thres = 0x0;
+ chip->high_thres = 0xffff;
+ chip->gainlevel = tsl2563_gainlevel_table;
+ chip->intr = TSL2563_INT_PERSIST(4);
+ chip->calib0 = calib_from_sysfs(CALIB_BASE_SYSFS);
+ chip->calib1 = calib_from_sysfs(CALIB_BASE_SYSFS);
+
+ dev_info(&client->dev, "model %d, rev. %d\n", id >> 4, id & 0x0f);
+
+ err = tsl2563_configure(chip);
+ if (err)
+ goto fail1;
+
+ chip->hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(chip->hwmon_dev))
+ goto fail1;
+
+ err = tsl2563_register_sysfs(client);
+ if (err) {
+ dev_err(&client->dev, "sysfs registration failed, %d\n", err);
+ goto fail2;
+ }
+
+ return 0;
+fail2:
+ hwmon_device_unregister(chip->hwmon_dev);
+fail1:
+ kfree(chip);
+ return err;
+}
+
+static int tsl2563_remove(struct i2c_client *client)
+{
+ struct tsl2563_chip *chip = i2c_get_clientdata(client);
+
+ tsl2563_unregister_sysfs(client);
+ hwmon_device_unregister(chip->hwmon_dev);
+
+ kfree(chip);
+ return 0;
+}
+
+static int tsl2563_suspend(struct i2c_client *client, pm_message_t state)
+{
+ struct tsl2563_chip *chip = i2c_get_clientdata(client);
+ int ret;
+
+ mutex_lock(&chip->lock);
+
+ ret = tsl2563_set_power(chip, 0);
+ if (ret)
+ goto out;
+
+ chip->state = state;
+
+out:
+ mutex_unlock(&chip->lock);
+ return ret;
+}
+
+static int tsl2563_resume(struct i2c_client *client)
+{
+ struct tsl2563_chip *chip = i2c_get_clientdata(client);
+ int ret;
+
+ mutex_lock(&chip->lock);
+
+ ret = tsl2563_set_power(chip, 1);
+ if (ret)
+ goto out;
+
+ ret = tsl2563_configure(chip);
+ if (ret)
+ goto out;
+
+ chip->state.event = PM_EVENT_ON;
+
+out:
+ mutex_unlock(&chip->lock);
+ return ret;
+}
+
+static struct i2c_driver tsl2563_i2c_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ },
+ .suspend = tsl2563_suspend,
+ .resume = tsl2563_resume,
+ .probe = tsl2563_probe,
+ .remove = __exit_p(tsl2563_remove),
+};
+
+static int __init tsl2563_init(void)
+{
+ return i2c_add_driver(&tsl2563_i2c_driver);
+}
+
+static void __exit tsl2563_exit(void)
+{
+ i2c_del_driver(&tsl2563_i2c_driver);
+}
+
+MODULE_AUTHOR("Nokia Corporation");
+MODULE_DESCRIPTION("tsl2563 light sensor driver");
+MODULE_LICENSE("GPL");
+
+module_init(tsl2563_init);
+module_exit(tsl2563_exit);
--- /dev/null
+/*
+ * twl4030_core.c - driver for TWL4030 PM and audio CODEC device
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * Modifications to defer interrupt handling to a kernel thread:
+ * Copyright (C) 2006 MontaVista Software, Inc.
+ *
+ * Based on tlv320aic23.c:
+ * Copyright (c) by Kai Svahn <kai.svahn@nokia.com>
+ *
+ * Code cleanup and modifications to IRQ handler.
+ * by syed khasim <x0khasim@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/module.h>
+#include <linux/kernel_stat.h>
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <linux/random.h>
+#include <linux/syscalls.h>
+#include <linux/kthread.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c/twl4030.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/irq.h>
+
+#include <asm/mach/irq.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/mux.h>
+
+#define DRIVER_NAME "twl4030"
+
+/* Macro Definitions */
+#define TWL_CLIENT_STRING "TWL4030-ID"
+#define TWL_CLIENT_USED 1
+#define TWL_CLIENT_FREE 0
+
+/* IRQ Flags */
+#define FREE 0
+#define USED 1
+
+/* Primary Interrupt Handler on TWL4030 Registers */
+
+/* Register Definitions */
+
+#define REG_PIH_ISR_P1 (0x1)
+#define REG_PIH_ISR_P2 (0x2)
+#define REG_PIH_SIR (0x3)
+
+/* Triton Core internal information (BEGIN) */
+
+/* Last - for index max*/
+#define TWL4030_MODULE_LAST TWL4030_MODULE_SECURED_REG
+
+/* Slave address */
+#define TWL4030_NUM_SLAVES 0x04
+#define TWL4030_SLAVENUM_NUM0 0x00
+#define TWL4030_SLAVENUM_NUM1 0x01
+#define TWL4030_SLAVENUM_NUM2 0x02
+#define TWL4030_SLAVENUM_NUM3 0x03
+#define TWL4030_SLAVEID_ID0 0x48
+#define TWL4030_SLAVEID_ID1 0x49
+#define TWL4030_SLAVEID_ID2 0x4A
+#define TWL4030_SLAVEID_ID3 0x4B
+
+/* Base Address defns */
+/* USB ID */
+#define TWL4030_BASEADD_USB 0x0000
+/* AUD ID */
+#define TWL4030_BASEADD_AUDIO_VOICE 0x0000
+#define TWL4030_BASEADD_GPIO 0x0098
+
+#define TWL4030_BASEADD_INTBR 0x0085
+#define TWL4030_BASEADD_PIH 0x0080
+#define TWL4030_BASEADD_TEST 0x004C
+/* AUX ID */
+#define TWL4030_BASEADD_INTERRUPTS 0x00B9
+#define TWL4030_BASEADD_LED 0x00EE
+#define TWL4030_BASEADD_MADC 0x0000
+#define TWL4030_BASEADD_MAIN_CHARGE 0x0074
+#define TWL4030_BASEADD_PRECHARGE 0x00AA
+#define TWL4030_BASEADD_PWM0 0x00F8
+#define TWL4030_BASEADD_PWM1 0x00FB
+#define TWL4030_BASEADD_PWMA 0x00EF
+#define TWL4030_BASEADD_PWMB 0x00F1
+#define TWL4030_BASEADD_KEYPAD 0x00D2
+/* POWER ID */
+#define TWL4030_BASEADD_BACKUP 0x0014
+#define TWL4030_BASEADD_INT 0x002E
+#define TWL4030_BASEADD_PM_MASTER 0x0036
+#define TWL4030_BASEADD_PM_RECEIVER 0x005B
+#define TWL4030_BASEADD_RTC 0x001C
+#define TWL4030_BASEADD_SECURED_REG 0x0000
+
+/* Triton Core internal information (END) */
+
+/* Few power values */
+#define R_CFG_BOOT 0x05
+#define R_PROTECT_KEY 0x0E
+
+/* access control */
+#define KEY_UNLOCK1 0xce
+#define KEY_UNLOCK2 0xec
+#define KEY_LOCK 0x00
+
+#define HFCLK_FREQ_19p2_MHZ (1 << 0)
+#define HFCLK_FREQ_26_MHZ (2 << 0)
+#define HFCLK_FREQ_38p4_MHZ (3 << 0)
+#define HIGH_PERF_SQ (1 << 3)
+
+/* on I2C-1 for 2430SDP */
+#define CONFIG_I2C_TWL4030_ID 1
+
+/* Helper functions */
+static int
+twl4030_detect_client(struct i2c_adapter *adapter, unsigned char sid);
+static int twl4030_attach_adapter(struct i2c_adapter *adapter);
+static int twl4030_detach_client(struct i2c_client *client);
+static void do_twl4030_irq(unsigned int irq, irq_desc_t *desc);
+
+static void twl_init_irq(void);
+
+/* Data Structures */
+/* To have info on T2 IRQ substem activated or not */
+static unsigned char twl_irq_used = FREE;
+static struct completion irq_event;
+
+/* Structure to define on TWL4030 Slave ID */
+struct twl4030_client {
+ struct i2c_client client;
+ const char client_name[sizeof(TWL_CLIENT_STRING) + 1];
+ const unsigned char address;
+ const char adapter_index;
+ unsigned char inuse;
+
+ /* max numb of i2c_msg required is for read =2 */
+ struct i2c_msg xfer_msg[2];
+
+ /* To lock access to xfer_msg */
+ struct mutex xfer_lock;
+};
+
+/* Module Mapping */
+struct twl4030mapping {
+ unsigned char sid; /* Slave ID */
+ unsigned char base; /* base address */
+};
+
+/* mapping the module id to slave id and base address */
+static struct twl4030mapping twl4030_map[TWL4030_MODULE_LAST + 1] = {
+ { TWL4030_SLAVENUM_NUM0, TWL4030_BASEADD_USB },
+ { TWL4030_SLAVENUM_NUM1, TWL4030_BASEADD_AUDIO_VOICE },
+ { TWL4030_SLAVENUM_NUM1, TWL4030_BASEADD_GPIO },
+ { TWL4030_SLAVENUM_NUM1, TWL4030_BASEADD_INTBR },
+ { TWL4030_SLAVENUM_NUM1, TWL4030_BASEADD_PIH },
+ { TWL4030_SLAVENUM_NUM1, TWL4030_BASEADD_TEST },
+ { TWL4030_SLAVENUM_NUM2, TWL4030_BASEADD_KEYPAD },
+ { TWL4030_SLAVENUM_NUM2, TWL4030_BASEADD_MADC },
+ { TWL4030_SLAVENUM_NUM2, TWL4030_BASEADD_INTERRUPTS },
+ { TWL4030_SLAVENUM_NUM2, TWL4030_BASEADD_LED },
+ { TWL4030_SLAVENUM_NUM2, TWL4030_BASEADD_MAIN_CHARGE },
+ { TWL4030_SLAVENUM_NUM2, TWL4030_BASEADD_PRECHARGE },
+ { TWL4030_SLAVENUM_NUM2, TWL4030_BASEADD_PWM0 },
+ { TWL4030_SLAVENUM_NUM2, TWL4030_BASEADD_PWM1 },
+ { TWL4030_SLAVENUM_NUM2, TWL4030_BASEADD_PWMA },
+ { TWL4030_SLAVENUM_NUM2, TWL4030_BASEADD_PWMB },
+ { TWL4030_SLAVENUM_NUM3, TWL4030_BASEADD_BACKUP },
+ { TWL4030_SLAVENUM_NUM3, TWL4030_BASEADD_INT },
+ { TWL4030_SLAVENUM_NUM3, TWL4030_BASEADD_PM_MASTER },
+ { TWL4030_SLAVENUM_NUM3, TWL4030_BASEADD_PM_RECEIVER },
+ { TWL4030_SLAVENUM_NUM3, TWL4030_BASEADD_RTC },
+ { TWL4030_SLAVENUM_NUM3, TWL4030_BASEADD_SECURED_REG },
+};
+
+static struct twl4030_client twl4030_modules[TWL4030_NUM_SLAVES] = {
+ {
+ .address = TWL4030_SLAVEID_ID0,
+ .client_name = TWL_CLIENT_STRING "0",
+ .adapter_index = CONFIG_I2C_TWL4030_ID,
+ },
+ {
+ .address = TWL4030_SLAVEID_ID1,
+ .client_name = TWL_CLIENT_STRING "1",
+ .adapter_index = CONFIG_I2C_TWL4030_ID,
+ },
+ {
+ .address = TWL4030_SLAVEID_ID2,
+ .client_name = TWL_CLIENT_STRING "2",
+ .adapter_index = CONFIG_I2C_TWL4030_ID,
+ },
+ {
+ .address = TWL4030_SLAVEID_ID3,
+ .client_name = TWL_CLIENT_STRING "3",
+ .adapter_index = CONFIG_I2C_TWL4030_ID,
+ },
+};
+
+/* One Client Driver , 4 Clients */
+static struct i2c_driver twl4030_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+ .attach_adapter = twl4030_attach_adapter,
+ .detach_client = twl4030_detach_client,
+};
+
+/*
+ * TWL4030 doesn't have PIH mask, hence dummy function for mask
+ * and unmask.
+ */
+
+static void twl4030_i2c_ackirq(unsigned int irq) {}
+static void twl4030_i2c_disableint(unsigned int irq) {}
+static void twl4030_i2c_enableint(unsigned int irq) {}
+
+/* information for processing in the Work Item */
+static struct irq_chip twl4030_irq_chip = {
+ .ack = twl4030_i2c_ackirq,
+ .mask = twl4030_i2c_disableint,
+ .unmask = twl4030_i2c_enableint,
+};
+
+/* Global Functions */
+/*
+ * @brief twl4030_i2c_write - Writes a n bit register in TWL4030
+ *
+ * @param mod_no - module number
+ * @param *value - an array of num_bytes+1 containing data to write
+ * IMPORTANT - Allocate value num_bytes+1 and valid data starts at
+ * Offset 1.
+ * @param reg - register address (just offset will do)
+ * @param num_bytes - number of bytes to transfer
+ *
+ * @return result of operation - 0 is success
+ */
+int twl4030_i2c_write(u8 mod_no, u8 *value, u8 reg, u8 num_bytes)
+{
+ int ret;
+ int sid;
+ struct twl4030_client *twl;
+ struct i2c_msg *msg;
+
+ if (unlikely(mod_no > TWL4030_MODULE_LAST)) {
+ pr_err("Invalid module Number\n");
+ return -EPERM;
+ }
+ sid = twl4030_map[mod_no].sid;
+ twl = &twl4030_modules[sid];
+
+ if (unlikely(twl->inuse != TWL_CLIENT_USED)) {
+ pr_err("I2C Client[%d] is not initialized[%d]\n",
+ sid, __LINE__);
+ return -EPERM;
+ }
+ mutex_lock(&twl->xfer_lock);
+ /*
+ * [MSG1]: fill the register address data
+ * fill the data Tx buffer
+ */
+ msg = &twl->xfer_msg[0];
+ msg->addr = twl->address;
+ msg->len = num_bytes + 1;
+ msg->flags = 0;
+ msg->buf = value;
+ /* over write the first byte of buffer with the register address */
+ *value = twl4030_map[mod_no].base + reg;
+ ret = i2c_transfer(twl->client.adapter, twl->xfer_msg, 1);
+ mutex_unlock(&twl->xfer_lock);
+
+ /* i2cTransfer returns num messages.translate it pls.. */
+ if (ret >= 0)
+ ret = 0;
+ return ret;
+}
+EXPORT_SYMBOL(twl4030_i2c_write);
+
+/**
+ * @brief twl4030_i2c_read - Reads a n bit register in TWL4030
+ *
+ * @param mod_no - module number
+ * @param *value - an array of num_bytes containing data to be read
+ * @param reg - register address (just offset will do)
+ * @param num_bytes - number of bytes to transfer
+ *
+ * @return result of operation - num_bytes is success else failure.
+ */
+int twl4030_i2c_read(u8 mod_no, u8 *value, u8 reg, u8 num_bytes)
+{
+ int ret;
+ u8 val;
+ int sid;
+ struct twl4030_client *twl;
+ struct i2c_msg *msg;
+
+ if (unlikely(mod_no > TWL4030_MODULE_LAST)) {
+ pr_err("Invalid module Number\n");
+ return -EPERM;
+ }
+ sid = twl4030_map[mod_no].sid;
+ twl = &twl4030_modules[sid];
+
+ if (unlikely(twl->inuse != TWL_CLIENT_USED)) {
+ pr_err("I2C Client[%d] is not initialized[%d]\n", sid,
+ __LINE__);
+ return -EPERM;
+ }
+ mutex_lock(&twl->xfer_lock);
+ /* [MSG1] fill the register address data */
+ msg = &twl->xfer_msg[0];
+ msg->addr = twl->address;
+ msg->len = 1;
+ msg->flags = 0; /* Read the register value */
+ val = twl4030_map[mod_no].base + reg;
+ msg->buf = &val;
+ /* [MSG2] fill the data rx buffer */
+ msg = &twl->xfer_msg[1];
+ msg->addr = twl->address;
+ msg->flags = I2C_M_RD; /* Read the register value */
+ msg->len = num_bytes; /* only n bytes */
+ msg->buf = value;
+ ret = i2c_transfer(twl->client.adapter, twl->xfer_msg, 2);
+ mutex_unlock(&twl->xfer_lock);
+
+ /* i2cTransfer returns num messages.translate it pls.. */
+ if (ret >= 0)
+ ret = 0;
+ return ret;
+}
+EXPORT_SYMBOL(twl4030_i2c_read);
+
+/**
+ * @brief twl4030_i2c_write_u8 - Writes a 8 bit register in TWL4030
+ *
+ * @param mod_no - module number
+ * @param value - the value to be written 8 bit
+ * @param reg - register address (just offset will do)
+ *
+ * @return result of operation - 0 is success
+ */
+int twl4030_i2c_write_u8(u8 mod_no, u8 value, u8 reg)
+{
+
+ /* 2 bytes offset 1 contains the data offset 0 is used by i2c_write */
+ u8 temp_buffer[2] = { 0 };
+ /* offset 1 contains the data */
+ temp_buffer[1] = value;
+ return twl4030_i2c_write(mod_no, temp_buffer, reg, 1);
+}
+EXPORT_SYMBOL(twl4030_i2c_write_u8);
+
+/**
+ * @brief twl4030_i2c_read_u8 - Reads a 8 bit register from TWL4030
+ *
+ * @param mod_no - module number
+ * @param *value - the value read 8 bit
+ * @param reg - register address (just offset will do)
+ *
+ * @return result of operation - 0 is success
+ */
+int twl4030_i2c_read_u8(u8 mod_no, u8 *value, u8 reg)
+{
+ return twl4030_i2c_read(mod_no, value, reg, 1);
+}
+EXPORT_SYMBOL(twl4030_i2c_read_u8);
+
+/* Helper Functions */
+
+/*
+ * do_twl4030_module_irq() is the desc->handle method for each of the twl4030
+ * module interrupts. It executes in kernel thread context.
+ * On entry, cpu interrupts are disabled.
+ */
+static void do_twl4030_module_irq(unsigned int irq, irq_desc_t *desc)
+{
+ struct irqaction *action;
+ const unsigned int cpu = smp_processor_id();
+
+ /*
+ * Earlier this was desc->triggered = 1;
+ */
+ desc->status |= IRQ_LEVEL;
+
+ /*
+ * The desc->handle method would normally call the desc->chip->ack
+ * method here, but we won't bother since our ack method is NULL.
+ */
+
+ if (!desc->depth) {
+ kstat_cpu(cpu).irqs[irq]++;
+
+ action = desc->action;
+ if (action) {
+ int ret;
+ int status = 0;
+ int retval = 0;
+
+ local_irq_enable();
+
+ do {
+ /* Call the ISR with cpu interrupts enabled */
+ ret = action->handler(irq, action->dev_id);
+ if (ret == IRQ_HANDLED)
+ status |= action->flags;
+ retval |= ret;
+ action = action->next;
+ } while (action);
+
+ if (status & IRQF_SAMPLE_RANDOM)
+ add_interrupt_randomness(irq);
+
+ local_irq_disable();
+
+ if (retval != IRQ_HANDLED)
+ printk(KERN_ERR "ISR for TWL4030 module"
+ " irq %d can't handle interrupt\n",
+ irq);
+
+ /*
+ * Here is where we should call the unmask method, but
+ * again we won't bother since it is NULL.
+ */
+ } else
+ printk(KERN_CRIT "TWL4030 module irq %d has no ISR"
+ " but can't be masked!\n", irq);
+ } else
+ printk(KERN_CRIT "TWL4030 module irq %d is disabled but can't"
+ " be masked!\n", irq);
+}
+
+/*
+ * twl4030_irq_thread() runs as a kernel thread. It queries the twl4030
+ * interrupt controller to see which modules are generating interrupt requests
+ * and then calls the desc->handle method for each module requesting service.
+ */
+static int twl4030_irq_thread(void *data)
+{
+ int irq = (int)data;
+ irq_desc_t *desc = irq_desc + irq;
+ static unsigned i2c_errors;
+ const static unsigned max_i2c_errors = 100;
+
+ daemonize("twl4030-irq");
+ current->flags |= PF_NOFREEZE;
+
+ while (!kthread_should_stop()) {
+ int ret;
+ int module_irq;
+ u8 pih_isr;
+
+ wait_for_completion_interruptible(&irq_event);
+
+ ret = twl4030_i2c_read_u8(TWL4030_MODULE_PIH, &pih_isr,
+ REG_PIH_ISR_P1);
+ if (ret) {
+ printk(KERN_WARNING "I2C error %d while reading TWL4030"
+ " PIH ISR register.\n", ret);
+ if (++i2c_errors >= max_i2c_errors) {
+ printk(KERN_ERR "Maximum I2C error count"
+ " exceeded. Terminating %s.\n",
+ __func__);
+ break;
+ }
+ continue;
+ }
+
+ for (module_irq = TWL4030_IRQ_BASE; 0 != pih_isr;
+ pih_isr >>= 1, module_irq++) {
+ if (pih_isr & 0x1) {
+ irq_desc_t *d = irq_desc + module_irq;
+
+ local_irq_disable();
+
+ d->handle_irq(module_irq, d);
+
+ local_irq_enable();
+ }
+ }
+
+ desc->chip->unmask(irq);
+ }
+
+ return 0;
+}
+
+/*
+ * do_twl4030_irq() is the desc->handle method for the twl4030 interrupt.
+ * This is a chained interrupt, so there is no desc->action method for it.
+ * Now we need to query the interrupt controller in the twl4030 to determine
+ * which module is generating the interrupt request. However, we can't do i2c
+ * transactions in interrupt context, so we must defer that work to a kernel
+ * thread. All we do here is acknowledge and mask the interrupt and wakeup
+ * the kernel thread.
+ */
+static void do_twl4030_irq(unsigned int irq, irq_desc_t *desc)
+{
+ const unsigned int cpu = smp_processor_id();
+
+ /*
+ * Earlier this was desc->triggered = 1;
+ */
+ desc->status |= IRQ_LEVEL;
+
+ /*
+ * Acknowledge, clear _AND_ disable the interrupt.
+ */
+ desc->chip->ack(irq);
+
+ if (!desc->depth) {
+ kstat_cpu(cpu).irqs[irq]++;
+
+ complete(&irq_event);
+ }
+}
+
+/* attach a client to the adapter */
+static int twl4030_detect_client(struct i2c_adapter *adapter, unsigned char sid)
+{
+ int err = 0;
+ struct twl4030_client *twl;
+
+ if (unlikely(sid >= TWL4030_NUM_SLAVES)) {
+ pr_err("sid[%d] > MOD_LAST[%d]\n", sid, TWL4030_NUM_SLAVES);
+ return -EPERM;
+ }
+
+ /* Check basic functionality */
+ err = i2c_check_functionality(adapter,
+ I2C_FUNC_SMBUS_WORD_DATA
+ | I2C_FUNC_SMBUS_WRITE_BYTE);
+ if (!err) {
+ pr_err("SlaveID=%d functionality check failed\n", sid);
+ return err;
+ }
+ twl = &twl4030_modules[sid];
+ if (unlikely(twl->inuse)) {
+ pr_err("Client %s is already in use\n", twl->client_name);
+ return -EPERM;
+ }
+
+ memset(&twl->client, 0, sizeof(struct i2c_client));
+
+ twl->client.addr = twl->address;
+ twl->client.adapter = adapter;
+ twl->client.driver = &twl4030_driver;
+
+ memcpy(&twl->client.name, twl->client_name,
+ sizeof(TWL_CLIENT_STRING) + 1);
+
+ pr_info("TWL4030: TRY attach Slave %s on Adapter %s [%x]\n",
+ twl->client_name, adapter->name, err);
+
+ err = i2c_attach_client(&twl->client);
+ if (err) {
+ pr_err("Couldn't attach Slave %s on Adapter"
+ "%s [%x]\n", twl->client_name, adapter->name, err);
+ } else {
+ twl->inuse = TWL_CLIENT_USED;
+ mutex_init(&twl->xfer_lock);
+ }
+
+ return err;
+}
+
+/* adapter callback */
+static int twl4030_attach_adapter(struct i2c_adapter *adapter)
+{
+ int i;
+ int ret = 0;
+ static int twl_i2c_adapter = 1;
+
+ for (i = 0; i < TWL4030_NUM_SLAVES; i++) {
+ /* Check if I need to hook on to this adapter or not */
+ if (twl4030_modules[i].adapter_index == twl_i2c_adapter) {
+ ret = twl4030_detect_client(adapter, i);
+ if (ret)
+ goto free_client;
+ }
+ }
+ twl_i2c_adapter++;
+
+ /*
+ * Check if the PIH module is initialized, if yes, then init
+ * the T2 Interrupt subsystem
+ */
+ if ((twl4030_modules[twl4030_map[TWL4030_MODULE_PIH].sid].inuse ==
+ TWL_CLIENT_USED) && (twl_irq_used != USED)) {
+ twl_init_irq();
+ twl_irq_used = USED;
+ }
+ return 0;
+
+free_client:
+ pr_err("TWL_CLIENT(Idx=%d] registration failed[0x%x]\n", i, ret);
+
+ /* ignore current slave..it never got registered */
+ i--;
+ while (i >= 0) {
+ /* now remove all those from the current adapter... */
+ if (twl4030_modules[i].adapter_index == twl_i2c_adapter)
+ (void)twl4030_detach_client(&twl4030_modules[i].client);
+ i--;
+ }
+ return ret;
+}
+
+/* adapter's callback */
+static int twl4030_detach_client(struct i2c_client *client)
+{
+ int err;
+ err = i2c_detach_client(client);
+ if (err) {
+ pr_err("Client detach failed\n");
+ return err;
+ }
+ return 0;
+}
+
+static struct task_struct *start_twl4030_irq_thread(int irq)
+{
+ struct task_struct *thread;
+
+ init_completion(&irq_event);
+ thread = kthread_run(twl4030_irq_thread, (void *)irq,
+ "twl4030 irq %d", irq);
+ if (!thread)
+ pr_err("%s: could not create twl4030 irq %d thread!\n",
+ __func__, irq);
+
+ return thread;
+}
+
+/*
+ * These three functions should be part of Voltage frame work
+ * added here to complete the functionality for now.
+ */
+static int protect_pm_master(void)
+{
+ int e = 0;
+
+ e = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_LOCK,
+ R_PROTECT_KEY);
+ return e;
+}
+
+static int unprotect_pm_master(void)
+{
+ int e = 0;
+
+ e |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_UNLOCK1,
+ R_PROTECT_KEY);
+ e |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_UNLOCK2,
+ R_PROTECT_KEY);
+ return e;
+}
+
+static int power_companion_init(void)
+{
+ struct clk *osc;
+ u32 rate;
+ u8 ctrl = HFCLK_FREQ_26_MHZ;
+ int e = 0;
+
+ if (cpu_is_omap2430())
+ osc = clk_get(NULL, "osc_ck");
+ else
+ osc = clk_get(NULL, "osc_sys_ck");
+ if (IS_ERR(osc)) {
+ printk(KERN_WARNING "Skipping twl3040 internal clock init and "
+ "using bootloader value (unknown osc rate)\n");
+ return 0;
+ }
+
+ rate = clk_get_rate(osc);
+ clk_put(osc);
+
+ switch (rate) {
+ case 19200000 : ctrl = HFCLK_FREQ_19p2_MHZ; break;
+ case 26000000 : ctrl = HFCLK_FREQ_26_MHZ; break;
+ case 38400000 : ctrl = HFCLK_FREQ_38p4_MHZ; break;
+ }
+
+ ctrl |= HIGH_PERF_SQ;
+ e |= unprotect_pm_master();
+ /* effect->MADC+USB ck en */
+ e |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, ctrl, R_CFG_BOOT);
+ e |= protect_pm_master();
+
+ return e;
+}
+
+static void twl_init_irq(void)
+{
+ int i = 0;
+ int res = 0;
+ char *msg = "Unable to register interrupt subsystem";
+ unsigned int irq_num;
+
+ /*
+ * We end up with interrupts from other modules before
+ * they get a chance to handle them...
+ */
+ /* PWR_ISR1 */
+ res = twl4030_i2c_write_u8(TWL4030_MODULE_INT, 0xFF, 0x00);
+ if (res < 0) {
+ pr_err("%s[%d][%d]\n", msg, res, __LINE__);
+ return;
+ }
+
+ /* PWR_ISR2 */
+ res = twl4030_i2c_write_u8(TWL4030_MODULE_INT, 0xFF, 0x02);
+ if (res < 0) {
+ pr_err("%s[%d][%d]\n", msg, res, __LINE__);
+ return;
+ }
+
+ /* PWR_IMR1 */
+ res = twl4030_i2c_write_u8(TWL4030_MODULE_INT, 0xFF, 0x1);
+ if (res < 0) {
+ pr_err("%s[%d][%d]\n", msg, res, __LINE__);
+ return;
+ }
+
+ /* PWR_IMR2 */
+ res = twl4030_i2c_write_u8(TWL4030_MODULE_INT, 0xFF, 0x3);
+ if (res < 0) {
+ pr_err("%s[%d][%d]\n", msg, res, __LINE__);
+ return;
+ }
+
+ /* Clear off any other pending interrupts on power */
+ /* PWR_ISR1 */
+ res = twl4030_i2c_write_u8(TWL4030_MODULE_INT, 0xFF, 0x00);
+ if (res < 0) {
+ pr_err("%s[%d][%d]\n", msg, res, __LINE__);
+ return;
+ }
+
+ /* PWR_ISR2 */
+ res = twl4030_i2c_write_u8(TWL4030_MODULE_INT, 0xFF, 0x02);
+ if (res < 0) {
+ pr_err("%s[%d][%d]\n", msg, res, __LINE__);
+ return;
+ }
+ /* POWER HACK (END) */
+ /* Slave address 0x4A */
+
+ /* BCIIMR1_1 */
+ res = twl4030_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xFF, 0x3);
+ if (res < 0) {
+ pr_err("%s[%d][%d]\n", msg, res, __LINE__);
+ return;
+ }
+
+ /* BCIIMR1_2 */
+ res = twl4030_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xFF, 0x4);
+ if (res < 0) {
+ pr_err("%s[%d][%d]\n", msg, res, __LINE__);
+ return;
+ }
+
+ /* BCIIMR2_1 */
+ res = twl4030_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xFF, 0x7);
+ if (res < 0) {
+ pr_err("%s[%d][%d]\n", msg, res, __LINE__);
+ return;
+ }
+
+ /* BCIIMR2_2 */
+ res = twl4030_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xFF, 0x8);
+ if (res < 0) {
+ pr_err("%s[%d][%d]\n", msg, res, __LINE__);
+ return;
+ }
+
+ /* MAD C */
+ /* MADC_IMR1 */
+ res = twl4030_i2c_write_u8(TWL4030_MODULE_MADC, 0xFF, 0x62);
+ if (res < 0) {
+ pr_err("%s[%d][%d]\n", msg, res, __LINE__);
+ return;
+ }
+
+ /* MADC_IMR2 */
+ res = twl4030_i2c_write_u8(TWL4030_MODULE_MADC, 0xFF, 0x64);
+ if (res < 0) {
+ pr_err("%s[%d][%d]\n", msg, res, __LINE__);
+ return;
+ }
+
+ /* key Pad */
+ /* KEYPAD - IMR1 */
+ res = twl4030_i2c_write_u8(TWL4030_MODULE_KEYPAD, 0xFF, (0x12));
+ if (res < 0) {
+ pr_err("%s[%d][%d]\n", msg, res, __LINE__);
+ return;
+ }
+ {
+ u8 clear;
+ /* Clear ISR */
+ twl4030_i2c_read_u8(TWL4030_MODULE_KEYPAD, &clear, 0x11);
+ twl4030_i2c_read_u8(TWL4030_MODULE_KEYPAD, &clear, 0x11);
+ }
+
+ /* KEYPAD - IMR2 */
+ res = twl4030_i2c_write_u8(TWL4030_MODULE_KEYPAD, 0xFF, (0x14));
+ if (res < 0) {
+ pr_err("%s[%d][%d]\n", msg, res, __LINE__);
+ return;
+ }
+
+ /* Slave address 0x49 */
+ /* GPIO_IMR1A */
+ res = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xFF, (0x1C));
+ if (res < 0) {
+ pr_err("%s[%d][%d]\n", msg, res, __LINE__);
+ return;
+ }
+
+ /* GPIO_IMR2A */
+ res = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xFF, (0x1D));
+ if (res < 0) {
+ pr_err("%s[%d][%d]\n", msg, res, __LINE__);
+ return;
+ }
+
+ /* GPIO_IMR3A */
+ res = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xFF, (0x1E));
+ if (res < 0) {
+ pr_err("%s[%d][%d]\n", msg, res, __LINE__);
+ return;
+ }
+
+ /* GPIO_IMR1B */
+ res = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xFF, (0x22));
+ if (res < 0) {
+ pr_err("%s[%d][%d]\n", msg, res, __LINE__);
+ return;
+ }
+
+ /* GPIO_IMR2B */
+ res = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xFF, (0x23));
+ if (res < 0) {
+ pr_err("%s[%d][%d]\n", msg, res, __LINE__);
+ return;
+ }
+
+ /* GPIO_IMR3B */
+ res = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xFF, (0x24));
+ if (res < 0) {
+ pr_err("%s[%d][%d]\n", msg, res, __LINE__);
+ return;
+ }
+
+ /* install an irq handler for each of the PIH modules */
+ for (i = TWL4030_IRQ_BASE; i < TWL4030_IRQ_END; i++) {
+ set_irq_chip(i, &twl4030_irq_chip);
+ set_irq_handler(i, do_twl4030_module_irq);
+ set_irq_flags(i, IRQF_VALID);
+ }
+
+ irq_num = (cpu_is_omap2430()) ? INT_24XX_SYS_NIRQ : INT_34XX_SYS_NIRQ;
+
+ /* install an irq handler to demultiplex the TWL4030 interrupt */
+ set_irq_data(irq_num, start_twl4030_irq_thread(irq_num));
+ set_irq_type(irq_num, IRQT_FALLING);
+ set_irq_chained_handler(irq_num, do_twl4030_irq);
+
+ res = power_companion_init();
+ if (res < 0)
+ pr_err("%s[%d][%d]\n", msg, res, __LINE__);
+}
+
+static int __init twl4030_init(void)
+{
+ return i2c_add_driver(&twl4030_driver);
+}
+
+static void __exit twl4030_exit(void)
+{
+ i2c_del_driver(&twl4030_driver);
+ twl_irq_used = FREE;
+}
+
+subsys_initcall(twl4030_init);
+module_exit(twl4030_exit);
+
+MODULE_AUTHOR("Texas Instruments, Inc.");
+MODULE_DESCRIPTION("I2C Core interface for TWL4030");
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * linux/drivers/i2c/chips/twl4030_gpio.c
+ *
+ * Copyright (C) 2006-2007 Texas Instruments, Inc.
+ * Copyright (C) 2006 MontaVista Software, Inc.
+ *
+ * Code re-arranged and cleaned up by:
+ * Syed Mohammed Khasim <x0khasim@ti.com>
+ *
+ * Initial Code:
+ * Andy Lowe / Nishanth Menon
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel_stat.h>
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/interrupt.h>
+#include <linux/random.h>
+#include <linux/syscalls.h>
+#include <linux/kthread.h>
+#include <linux/irq.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c/twl4030.h>
+#include <linux/slab.h>
+
+#include <asm/arch/irqs.h>
+#include <asm/mach/irq.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/mux.h>
+
+#include <linux/device.h>
+
+/*
+ * GPIO Block Register definitions
+ */
+
+#define REG_GPIODATAIN1 0x0
+#define REG_GPIODATAIN2 0x1
+#define REG_GPIODATAIN3 0x2
+#define REG_GPIODATADIR1 0x3
+#define REG_GPIODATADIR2 0x4
+#define REG_GPIODATADIR3 0x5
+#define REG_GPIODATAOUT1 0x6
+#define REG_GPIODATAOUT2 0x7
+#define REG_GPIODATAOUT3 0x8
+#define REG_CLEARGPIODATAOUT1 0x9
+#define REG_CLEARGPIODATAOUT2 0xA
+#define REG_CLEARGPIODATAOUT3 0xB
+#define REG_SETGPIODATAOUT1 0xC
+#define REG_SETGPIODATAOUT2 0xD
+#define REG_SETGPIODATAOUT3 0xE
+#define REG_GPIO_DEBEN1 0xF
+#define REG_GPIO_DEBEN2 0x10
+#define REG_GPIO_DEBEN3 0x11
+#define REG_GPIO_CTRL 0x12
+#define REG_GPIOPUPDCTR1 0x13
+#define REG_GPIOPUPDCTR2 0x14
+#define REG_GPIOPUPDCTR3 0x15
+#define REG_GPIOPUPDCTR4 0x16
+#define REG_GPIOPUPDCTR5 0x17
+#define REG_GPIO_ISR1A 0x19
+#define REG_GPIO_ISR2A 0x1A
+#define REG_GPIO_ISR3A 0x1B
+#define REG_GPIO_IMR1A 0x1C
+#define REG_GPIO_IMR2A 0x1D
+#define REG_GPIO_IMR3A 0x1E
+#define REG_GPIO_ISR1B 0x1F
+#define REG_GPIO_ISR2B 0x20
+#define REG_GPIO_ISR3B 0x21
+#define REG_GPIO_IMR1B 0x22
+#define REG_GPIO_IMR2B 0x23
+#define REG_GPIO_IMR3B 0x24
+#define REG_GPIO_EDR1 0x28
+#define REG_GPIO_EDR2 0x29
+#define REG_GPIO_EDR3 0x2A
+#define REG_GPIO_EDR4 0x2B
+#define REG_GPIO_EDR5 0x2C
+#define REG_GPIO_SIH_CTRL 0x2D
+
+/* BitField Definitions */
+
+/* Data banks : 3 banks for 8 gpios each */
+#define DATA_BANK_MAX 8
+#define GET_GPIO_DATA_BANK(x) ((x)/DATA_BANK_MAX)
+#define GET_GPIO_DATA_OFF(x) ((x)%DATA_BANK_MAX)
+
+/* GPIODATADIR Fields each block 0-7 */
+#define BIT_GPIODATADIR_GPIOxDIR(x) (x)
+#define MASK_GPIODATADIR_GPIOxDIR(x) (0x01 << (x))
+
+/* GPIODATAIN Fields each block 0-7 */
+#define BIT_GPIODATAIN_GPIOxIN(x) (x)
+#define MASK_GPIODATAIN_GPIOxIN(x) (0x01 << (x))
+
+/* GPIODATAOUT Fields each block 0-7 */
+#define BIT_GPIODATAOUT_GPIOxOUT(x) (x)
+#define MASK_GPIODATAOUT_GPIOxOUT(x) (0x01 << (x))
+
+/* CLEARGPIODATAOUT Fields */
+#define BIT_CLEARGPIODATAOUT_GPIOxOUT(x) (x)
+#define MASK_CLEARGPIODATAOUT_GPIOxOUT(x) (0x01 << (x))
+
+/* SETGPIODATAOUT Fields */
+#define BIT_SETGPIODATAOUT_GPIOxOUT(x) (x)
+#define MASK_SETGPIODATAOUT_GPIOxOUT(x) (0x01 << (x))
+
+/* GPIO_DEBEN Fields */
+#define BIT_GPIO_DEBEN_GPIOxDEB(x) (x)
+#define MASK_GPIO_DEBEN_GPIOxDEB(x) (0x01 << (x))
+
+/* GPIO_ISR1A Fields */
+#define BIT_GPIO_ISR_GPIOxISR(x) (x)
+#define MASK_GPIO_ISR_GPIOxISR(x) (0x01 << (x))
+
+/* GPIO_IMR1A Fields */
+#define BIT_GPIO_IMR1A_GPIOxIMR(x) (x)
+#define MASK_GPIO_IMR1A_GPIOxIMR(x) (0x01 << (x))
+
+/* GPIO_SIR1 Fields */
+#define BIT_GPIO_SIR1_GPIOxSIR(x) (x)
+#define MASK_GPIO_SIR1_GPIO0SIR (0x01 << (x))
+
+
+/* Control banks : 5 banks for 4 gpios each */
+#define DATA_CTL_MAX 4
+#define GET_GPIO_CTL_BANK(x) ((x)/DATA_CTL_MAX)
+#define GET_GPIO_CTL_OFF(x) ((x)%DATA_CTL_MAX)
+#define GPIO_BANK_MAX GET_GPIO_CTL_BANK(TWL4030_GPIO_MAX)
+
+/* GPIOPUPDCTRx Fields 5 banks of 4 gpios each */
+#define BIT_GPIOPUPDCTR1_GPIOxPD(x) (2 * (x))
+#define MASK_GPIOPUPDCTR1_GPIOxPD(x) (0x01 << (2 * (x)))
+#define BIT_GPIOPUPDCTR1_GPIOxPU(x) ((x) + 1)
+#define MASK_GPIOPUPDCTR1_GPIOxPU(x) (0x01 << (((2 * (x)) + 1)))
+
+/* GPIO_EDR1 Fields */
+#define BIT_GPIO_EDR1_GPIOxFALLING(x) (2 * (x))
+#define MASK_GPIO_EDR1_GPIOxFALLING(x) (0x01 << (2 * (x)))
+#define BIT_GPIO_EDR1_GPIOxRISING(x) ((x) + 1)
+#define MASK_GPIO_EDR1_GPIOxRISING(x) (0x01 << (((2 * (x)) + 1)))
+
+/* GPIO_SIH_CTRL Fields */
+#define BIT_GPIO_SIH_CTRL_EXCLEN (0x000)
+#define MASK_GPIO_SIH_CTRL_EXCLEN (0x00000001)
+#define BIT_GPIO_SIH_CTRL_PENDDIS (0x001)
+#define MASK_GPIO_SIH_CTRL_PENDDIS (0x00000002)
+#define BIT_GPIO_SIH_CTRL_COR (0x002)
+#define MASK_GPIO_SIH_CTRL_COR (0x00000004)
+
+/* GPIO_CTRL Fields */
+#define BIT_GPIO_CTRL_GPIO0CD1 (0x000)
+#define MASK_GPIO_CTRL_GPIO0CD1 (0x00000001)
+#define BIT_GPIO_CTRL_GPIO1CD2 (0x001)
+#define MASK_GPIO_CTRL_GPIO1CD2 (0x00000002)
+#define BIT_GPIO_CTRL_GPIO_ON (0x002)
+#define MASK_GPIO_CTRL_GPIO_ON (0x00000004)
+
+/* Mask for GPIO registers when aggregated into a 32-bit integer */
+#define GPIO_32_MASK 0x0003ffff
+
+/* Data structures */
+static struct semaphore gpio_sem;
+
+/* store usage of each GPIO. - each bit represents one GPIO */
+static unsigned int gpio_usage_count;
+
+/* shadow the imr register */
+static unsigned int gpio_imr_shadow;
+
+/* bitmask of pending requests to unmask gpio interrupts */
+static unsigned int gpio_pending_unmask;
+
+/* pointer to gpio unmask thread struct */
+static struct task_struct *gpio_unmask_thread;
+
+/*
+ * Helper functions to read and write the GPIO ISR and IMR registers as
+ * 32-bit integers. Functions return 0 on success, non-zero otherwise.
+ * The caller must hold a lock on gpio_sem.
+ */
+
+static int gpio_read_isr(unsigned int *isr)
+{
+ int ret;
+
+ *isr = 0;
+ ret = twl4030_i2c_read(TWL4030_MODULE_GPIO, (u8 *) isr,
+ REG_GPIO_ISR1A, 3);
+ le32_to_cpup(isr);
+ *isr &= GPIO_32_MASK;
+
+ return ret;
+}
+
+static int gpio_write_isr(unsigned int isr)
+{
+ isr &= GPIO_32_MASK;
+ /*
+ * The buffer passed to the twl4030_i2c_write() routine must have an
+ * extra byte at the beginning reserved for its internal use.
+ */
+ isr <<= 8;
+ isr = cpu_to_le32(isr);
+ return twl4030_i2c_write(TWL4030_MODULE_GPIO, (u8 *) &isr,
+ REG_GPIO_ISR1A, 3);
+}
+
+static int gpio_write_imr(unsigned int imr)
+{
+ imr &= GPIO_32_MASK;
+ /*
+ * The buffer passed to the twl4030_i2c_write() routine must have an
+ * extra byte at the beginning reserved for its internal use.
+ */
+ imr <<= 8;
+ imr = cpu_to_le32(imr);
+ return twl4030_i2c_write(TWL4030_MODULE_GPIO, (u8 *) &imr,
+ REG_GPIO_IMR1A, 3);
+}
+
+/*
+ * These routines are analagous to the irqchip methods, but they are designed
+ * to be called from thread context with cpu interrupts enabled and with no
+ * locked spinlocks. We call these routines from our custom IRQ handler
+ * instead of the usual irqchip methods.
+ */
+static void twl4030_gpio_mask_and_ack(unsigned int irq)
+{
+ int gpio = irq - TWL4030_GPIO_IRQ_BASE;
+
+ down(&gpio_sem);
+ /* mask */
+ gpio_imr_shadow |= (1 << gpio);
+ gpio_write_imr(gpio_imr_shadow);
+ /* ack */
+ gpio_write_isr(1 << gpio);
+ up(&gpio_sem);
+}
+
+static void twl4030_gpio_unmask(unsigned int irq)
+{
+ int gpio = irq - TWL4030_GPIO_IRQ_BASE;
+
+ down(&gpio_sem);
+ gpio_imr_shadow &= ~(1 << gpio);
+ gpio_write_imr(gpio_imr_shadow);
+ up(&gpio_sem);
+}
+
+/*
+ * These are the irqchip methods for the TWL4030 GPIO interrupts.
+ * Our IRQ handle method doesn't call these, but they will be called by
+ * other routines such as setup_irq() and enable_irq(). They are called
+ * with cpu interrupts disabled and with a lock on the irq_controller_lock
+ * spinlock. This complicates matters, because accessing the TWL4030 GPIO
+ * interrupt controller requires I2C bus transactions that can't be initiated
+ * in this context. Our solution is to defer accessing the interrupt
+ * controller to a kernel thread. We only need to support the unmask method.
+ */
+
+static void twl4030_gpio_mask_and_ack_irqchip(unsigned int irq) {}
+static void twl4030_gpio_mask_irqchip(unsigned int irq) {}
+
+static void twl4030_gpio_unmask_irqchip(unsigned int irq)
+{
+ int gpio = irq - TWL4030_GPIO_IRQ_BASE;
+
+ gpio_pending_unmask |= (1 << gpio);
+ if (gpio_unmask_thread && gpio_unmask_thread->state != TASK_RUNNING)
+ wake_up_process(gpio_unmask_thread);
+}
+
+static struct irq_chip twl4030_gpio_irq_chip = {
+ .name = "twl4030-gpio",
+ .ack = twl4030_gpio_mask_and_ack_irqchip,
+ .mask = twl4030_gpio_mask_irqchip,
+ .unmask = twl4030_gpio_unmask_irqchip,
+};
+
+/*
+ * These are the irqchip methods for the TWL4030 PIH GPIO module interrupt.
+ * The PIH module doesn't have interrupt masking capability, so these
+ * methods are NULL.
+ */
+static void twl4030_gpio_module_ack(unsigned int irq) {}
+static void twl4030_gpio_module_mask(unsigned int irq) {}
+static void twl4030_gpio_module_unmask(unsigned int irq) {}
+static struct irq_chip twl4030_gpio_module_irq_chip = {
+ .ack = twl4030_gpio_module_ack,
+ .mask = twl4030_gpio_module_mask,
+ .unmask = twl4030_gpio_module_unmask,
+};
+
+/*
+ * To configure TWL4030 GPIO module registers
+ */
+static inline int gpio_twl4030_write(u8 address, u8 data)
+{
+ int ret = 0;
+
+ ret = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, data, address);
+ return ret;
+}
+
+/*
+ * To read a TWL4030 GPIO module register
+ */
+static inline int gpio_twl4030_read(u8 address)
+{
+ u8 data;
+ int ret = 0;
+
+ ret = twl4030_i2c_read_u8(TWL4030_MODULE_GPIO, &data, address);
+ if (ret >= 0)
+ ret = data;
+ return ret;
+}
+
+/*
+ * twl4030 GPIO request function
+ */
+int twl4030_request_gpio(int gpio)
+{
+ int ret = 0;
+
+ if (unlikely(gpio >= TWL4030_GPIO_MAX))
+ return -EPERM;
+
+ down(&gpio_sem);
+ if (gpio_usage_count & (0x1 << gpio))
+ ret = -EBUSY;
+ else {
+ u8 clear_pull[6] = { 0, 0, 0, 0, 0, 0 };
+ /* First time usage? - switch on GPIO module */
+ if (!gpio_usage_count) {
+ ret =
+ gpio_twl4030_write(REG_GPIO_CTRL,
+ MASK_GPIO_CTRL_GPIO_ON);
+ ret = gpio_twl4030_write(REG_GPIO_SIH_CTRL, 0x00);
+ }
+ if (!ret)
+ gpio_usage_count |= (0x1 << gpio);
+
+ ret =
+ twl4030_i2c_write(TWL4030_MODULE_GPIO, clear_pull,
+ REG_GPIOPUPDCTR1, 5);
+ }
+ up(&gpio_sem);
+ return ret;
+}
+EXPORT_SYMBOL(twl4030_request_gpio);
+
+/*
+ * TWL4030 GPIO free module
+ */
+int twl4030_free_gpio(int gpio)
+{
+ int ret = 0;
+
+ if (unlikely(gpio >= TWL4030_GPIO_MAX))
+ return -EPERM;
+
+ down(&gpio_sem);
+
+ if ((gpio_usage_count & (0x1 << gpio)) == 0)
+ ret = -EPERM;
+ else
+ gpio_usage_count &= ~(0x1 << gpio);
+
+ /* Last time usage? - switch off GPIO module */
+ if (!gpio_usage_count)
+ ret = gpio_twl4030_write(REG_GPIO_CTRL, 0x0);
+
+ up(&gpio_sem);
+ return ret;
+}
+EXPORT_SYMBOL(twl4030_free_gpio);
+
+/*
+ * Set direction for TWL4030 GPIO
+ */
+int twl4030_set_gpio_direction(int gpio, int is_input)
+{
+ u8 d_bnk = GET_GPIO_DATA_BANK(gpio);
+ u8 d_msk = MASK_GPIODATADIR_GPIOxDIR(GET_GPIO_DATA_OFF(gpio));
+ u8 reg = 0;
+ u8 base = 0;
+ int ret = 0;
+
+ if (unlikely((gpio >= TWL4030_GPIO_MAX)
+ || !(gpio_usage_count & (0x1 << gpio))))
+ return -EPERM;
+
+ base = REG_GPIODATADIR1 + d_bnk;
+
+ down(&gpio_sem);
+ ret = gpio_twl4030_read(base);
+ if (ret >= 0) {
+ if (is_input)
+ reg = (u8) ((ret) & ~(d_msk));
+ else
+ reg = (u8) ((ret) | (d_msk));
+
+ ret = gpio_twl4030_write(base, reg);
+ }
+ up(&gpio_sem);
+ return ret;
+}
+EXPORT_SYMBOL(twl4030_set_gpio_direction);
+
+/*
+ * To enable/disable GPIO pin on TWL4030
+ */
+int twl4030_set_gpio_dataout(int gpio, int enable)
+{
+ u8 d_bnk = GET_GPIO_DATA_BANK(gpio);
+ u8 d_msk = MASK_GPIODATAOUT_GPIOxOUT(GET_GPIO_DATA_OFF(gpio));
+ u8 base = 0;
+ int ret = 0;
+
+ if (unlikely((gpio >= TWL4030_GPIO_MAX)
+ || !(gpio_usage_count & (0x1 << gpio))))
+ return -EPERM;
+
+ if (enable)
+ base = REG_SETGPIODATAOUT1 + d_bnk;
+ else
+ base = REG_CLEARGPIODATAOUT1 + d_bnk;
+
+ down(&gpio_sem);
+ ret = gpio_twl4030_write(base, d_msk);
+ up(&gpio_sem);
+ return ret;
+}
+EXPORT_SYMBOL(twl4030_set_gpio_dataout);
+
+/*
+ * To get the status of a GPIO pin on TWL4030
+ */
+int twl4030_get_gpio_datain(int gpio)
+{
+ u8 d_bnk = GET_GPIO_DATA_BANK(gpio);
+ u8 d_off = BIT_GPIODATAIN_GPIOxIN(GET_GPIO_DATA_OFF(gpio));
+ u8 base = 0;
+ int ret = 0;
+
+ if (unlikely((gpio >= TWL4030_GPIO_MAX)
+ || !(gpio_usage_count & (0x1 << gpio))))
+ return -EPERM;
+
+ base = REG_GPIODATAIN1 + d_bnk;
+ down(&gpio_sem);
+ ret = gpio_twl4030_read(base);
+ up(&gpio_sem);
+ if (ret > 0)
+ ret = (ret >> d_off) & 0x1;
+
+ return ret;
+}
+EXPORT_SYMBOL(twl4030_get_gpio_datain);
+
+/*
+ * Configure PULL type for a GPIO pin on TWL4030
+ */
+int twl4030_set_gpio_pull(int gpio, int pull_dircn)
+{
+ u8 c_bnk = GET_GPIO_CTL_BANK(gpio);
+ u8 c_off = GET_GPIO_CTL_OFF(gpio);
+ u8 c_msk = 0;
+ u8 reg = 0;
+ u8 base = 0;
+ int ret = 0;
+
+ if (unlikely((gpio >= TWL4030_GPIO_MAX) ||
+ !(gpio_usage_count & (0x1 << gpio))))
+ return -EPERM;
+
+ base = REG_GPIOPUPDCTR1 + c_bnk;
+ if (pull_dircn == TWL4030_GPIO_PULL_DOWN)
+ c_msk = MASK_GPIOPUPDCTR1_GPIOxPD(c_off);
+ else if (pull_dircn == TWL4030_GPIO_PULL_UP)
+ c_msk = MASK_GPIOPUPDCTR1_GPIOxPU(c_off);
+
+ down(&gpio_sem);
+ ret = gpio_twl4030_read(base);
+ if (ret >= 0) {
+ /* clear the previous up/down values */
+ reg = (u8) (ret);
+ reg &= ~(MASK_GPIOPUPDCTR1_GPIOxPU(c_off) |
+ MASK_GPIOPUPDCTR1_GPIOxPD(c_off));
+ reg |= c_msk;
+ ret = gpio_twl4030_write(base, reg);
+ }
+ up(&gpio_sem);
+ return ret;
+}
+EXPORT_SYMBOL(twl4030_set_gpio_pull);
+
+/*
+ * Configure Edge control for a GPIO pin on TWL4030
+ */
+int twl4030_set_gpio_edge_ctrl(int gpio, int edge)
+{
+ u8 c_bnk = GET_GPIO_CTL_BANK(gpio);
+ u8 c_off = GET_GPIO_CTL_OFF(gpio);
+ u8 c_msk = 0;
+ u8 reg = 0;
+ u8 base = 0;
+ int ret = 0;
+
+ if (unlikely((gpio >= TWL4030_GPIO_MAX)
+ || !(gpio_usage_count & (0x1 << gpio))))
+ return -EPERM;
+
+ base = REG_GPIO_EDR1 + c_bnk;
+
+ if (edge & TWL4030_GPIO_EDGE_RISING)
+ c_msk |= MASK_GPIO_EDR1_GPIOxRISING(c_off);
+
+ if (edge & TWL4030_GPIO_EDGE_FALLING)
+ c_msk |= MASK_GPIO_EDR1_GPIOxFALLING(c_off);
+
+ down(&gpio_sem);
+ ret = gpio_twl4030_read(base);
+ if (ret >= 0) {
+ /* clear the previous rising/falling values */
+ reg =
+ (u8) (ret &
+ ~(MASK_GPIO_EDR1_GPIOxFALLING(c_off) |
+ MASK_GPIO_EDR1_GPIOxRISING(c_off)));
+ reg |= c_msk;
+ ret = gpio_twl4030_write(base, reg);
+ }
+ up(&gpio_sem);
+ return ret;
+}
+EXPORT_SYMBOL(twl4030_set_gpio_edge_ctrl);
+
+/*
+ * Configure debounce timing value for a GPIO pin on TWL4030
+ */
+int twl4030_set_gpio_debounce(int gpio, int enable)
+{
+ u8 d_bnk = GET_GPIO_DATA_BANK(gpio);
+ u8 d_msk = MASK_GPIO_DEBEN_GPIOxDEB(GET_GPIO_DATA_OFF(gpio));
+ u8 reg = 0;
+ u8 base = 0;
+ int ret = 0;
+
+ if (unlikely((gpio >= TWL4030_GPIO_MAX)
+ || !(gpio_usage_count & (0x1 << gpio))))
+ return -EPERM;
+
+ base = REG_GPIO_DEBEN1 + d_bnk;
+ down(&gpio_sem);
+ ret = gpio_twl4030_read(base);
+ if (ret >= 0) {
+ if (enable)
+ reg = (u8) ((ret) | (d_msk));
+ else
+ reg = (u8) ((ret) & ~(d_msk));
+
+ ret = gpio_twl4030_write(base, reg);
+ }
+ up(&gpio_sem);
+ return ret;
+}
+EXPORT_SYMBOL(twl4030_set_gpio_debounce);
+
+/*
+ * Configure Card detect for GPIO pin on TWL4030
+ */
+int twl4030_set_gpio_card_detect(int gpio, int enable)
+{
+ u8 reg = 0;
+ u8 msk = (1 << gpio);
+ int ret = 0;
+
+ /* Only GPIO 0 or 1 can be used for CD feature.. */
+ if (unlikely((gpio >= TWL4030_GPIO_MAX)
+ || !(gpio_usage_count & (0x1 << gpio))
+ || (gpio >= TWL4030_GPIO_MAX_CD))) {
+ return -EPERM;
+ }
+
+ down(&gpio_sem);
+ ret = gpio_twl4030_read(REG_GPIO_CTRL);
+ if (ret >= 0) {
+ if (enable)
+ reg = (u8) (ret | msk);
+ else
+ reg = (u8) (ret & ~msk);
+
+ ret = gpio_twl4030_write(REG_GPIO_CTRL, reg);
+ }
+ up(&gpio_sem);
+ return (ret);
+}
+EXPORT_SYMBOL(twl4030_set_gpio_card_detect);
+
+/* MODULE FUNCTIONS */
+
+/*
+ * gpio_unmask_thread() runs as a kernel thread. It is awakened by the unmask
+ * method for the GPIO interrupts. It unmasks all of the GPIO interrupts
+ * specified in the gpio_pending_unmask bitmask. We have to do the unmasking
+ * in a kernel thread rather than directly in the unmask method because of the
+ * need to access the TWL4030 via the I2C bus. Note that we don't need to be
+ * concerned about race conditions where the request to unmask a GPIO interrupt
+ * has already been cancelled before this thread does the unmasking. If a GPIO
+ * interrupt is improperly unmasked, then the IRQ handler for it will mask it
+ * when an interrupt occurs.
+ */
+static int twl4030_gpio_unmask_thread(void *data)
+{
+ current->flags |= PF_NOFREEZE;
+
+ while (!kthread_should_stop()) {
+ int irq;
+ unsigned int gpio_unmask;
+
+ local_irq_disable();
+ gpio_unmask = gpio_pending_unmask;
+ gpio_pending_unmask = 0;
+ local_irq_enable();
+
+ for (irq = TWL4030_GPIO_IRQ_BASE; 0 != gpio_unmask;
+ gpio_unmask >>= 1, irq++) {
+ if (gpio_unmask & 0x1)
+ twl4030_gpio_unmask(irq);
+ }
+
+ local_irq_disable();
+ if (!gpio_pending_unmask)
+ set_current_state(TASK_INTERRUPTIBLE);
+ local_irq_enable();
+
+ schedule();
+ }
+ set_current_state(TASK_RUNNING);
+ return 0;
+}
+
+/*
+ * do_twl4030_gpio_irq() is the desc->handle method for each of the twl4030
+ * gpio interrupts. It executes in kernel thread context.
+ * On entry, cpu interrupts are enabled.
+ */
+static void do_twl4030_gpio_irq(unsigned int irq, irq_desc_t *desc)
+{
+ struct irqaction *action;
+ const unsigned int cpu = smp_processor_id();
+
+ desc->status |= IRQ_LEVEL;
+
+ /*
+ * Acknowledge, clear _AND_ disable the interrupt.
+ */
+ twl4030_gpio_mask_and_ack(irq);
+
+ if (!desc->depth) {
+ kstat_cpu(cpu).irqs[irq]++;
+
+ action = desc->action;
+ if (action) {
+ int ret;
+ int status = 0;
+ int retval = 0;
+ do {
+ /* Call the ISR with cpu interrupts enabled. */
+ ret = action->handler(irq, action->dev_id);
+ if (ret == IRQ_HANDLED)
+ status |= action->flags;
+ retval |= ret;
+ action = action->next;
+ } while (action);
+
+ if (retval != IRQ_HANDLED)
+ printk(KERN_ERR "ISR for TWL4030 GPIO"
+ " irq %d can't handle interrupt\n",
+ irq);
+
+ if (!desc->depth)
+ twl4030_gpio_unmask(irq);
+ }
+ }
+}
+
+/*
+ * do_twl4030_gpio_module_irq() is the desc->handle method for the twl4030 gpio
+ * module interrupt. It executes in kernel thread context.
+ * This is a chained interrupt, so there is no desc->action method for it.
+ * We query the gpio module interrupt controller in the twl4030 to determine
+ * which gpio lines are generating interrupt requests, and then call the
+ * desc->handle method for each gpio that needs service.
+ * On entry, cpu interrupts are disabled.
+ */
+static void do_twl4030_gpio_module_irq(unsigned int irq, irq_desc_t *desc)
+{
+ const unsigned int cpu = smp_processor_id();
+
+ desc->status |= IRQ_LEVEL;
+ /*
+ * The desc->handle method would normally call the desc->chip->ack
+ * method here, but we won't bother since our ack method is NULL.
+ */
+ if (!desc->depth) {
+ int gpio_irq;
+ unsigned int gpio_isr;
+
+ kstat_cpu(cpu).irqs[irq]++;
+ local_irq_enable();
+
+ down(&gpio_sem);
+ if (gpio_read_isr(&gpio_isr))
+ gpio_isr = 0;
+ up(&gpio_sem);
+
+ for (gpio_irq = TWL4030_GPIO_IRQ_BASE; 0 != gpio_isr;
+ gpio_isr >>= 1, gpio_irq++) {
+ if (gpio_isr & 0x1) {
+ irq_desc_t *d = irq_desc + gpio_irq;
+ d->handle_irq(gpio_irq, d);
+ }
+ }
+
+ local_irq_disable();
+ /*
+ * Here is where we should call the unmask method, but again we
+ * won't bother since it is NULL.
+ */
+ }
+}
+
+/* TWL4030 Initialization module */
+static int __init gpio_twl4030_init(void)
+{
+ int ret;
+ int irq = 0;
+
+ /* init the global locking sem */
+ sema_init(&gpio_sem, 1);
+
+ /* All GPIO interrupts are initially masked */
+ gpio_pending_unmask = 0;
+ gpio_imr_shadow = GPIO_32_MASK;
+ ret = gpio_write_imr(gpio_imr_shadow);
+ if (!ret) {
+ /*
+ * Create a kernel thread to handle deferred unmasking of gpio
+ * interrupts.
+ */
+ gpio_unmask_thread = kthread_create(twl4030_gpio_unmask_thread,
+ NULL, "twl4030 gpio");
+ if (!gpio_unmask_thread) {
+ printk(KERN_ERR
+ "%s: could not create twl4030 gpio unmask"
+ " thread!\n", __func__);
+ ret = -ENOMEM;
+ }
+ }
+
+ if (!ret) {
+ /* install an irq handler for each of the gpio interrupts */
+ for (irq = TWL4030_GPIO_IRQ_BASE; irq < TWL4030_GPIO_IRQ_END;
+ irq++) {
+ set_irq_chip(irq, &twl4030_gpio_irq_chip);
+ set_irq_handler(irq, do_twl4030_gpio_irq);
+ set_irq_flags(irq, IRQF_VALID);
+ }
+
+ /*
+ * Install an irq handler to demultiplex the gpio module
+ * interrupt.
+ */
+ set_irq_chip(TWL4030_MODIRQ_GPIO,
+ &twl4030_gpio_module_irq_chip);
+ set_irq_chained_handler(TWL4030_MODIRQ_GPIO,
+ do_twl4030_gpio_module_irq);
+ }
+
+ printk(KERN_INFO "TWL4030 GPIO Demux: IRQ Range %d to %d,"
+ " Initialization %s\n", TWL4030_GPIO_IRQ_BASE,
+ TWL4030_GPIO_IRQ_END, (ret) ? "Failed" : "Success");
+ return ret;
+}
+
+/* TWL GPIO exit module */
+static void __exit gpio_twl4030_exit(void)
+{
+ int irq;
+
+ /* uninstall the gpio demultiplexing interrupt handler */
+ set_irq_handler(TWL4030_MODIRQ_GPIO, NULL);
+ set_irq_flags(TWL4030_MODIRQ_GPIO, 0);
+
+ /* uninstall the irq handler for each of the gpio interrupts */
+ for (irq = TWL4030_GPIO_IRQ_BASE; irq < TWL4030_GPIO_IRQ_END; irq++) {
+ set_irq_handler(irq, NULL);
+ set_irq_flags(irq, 0);
+ }
+
+ /* stop the gpio unmask kernel thread */
+ if (gpio_unmask_thread) {
+ kthread_stop(gpio_unmask_thread);
+ gpio_unmask_thread = NULL;
+ }
+}
+
+module_init(gpio_twl4030_init);
+module_exit(gpio_twl4030_exit);
+
+MODULE_AUTHOR("Texas Instruments, Inc.");
+MODULE_DESCRIPTION("GPIO interface for TWL4030");
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * drivers/i2c/chips/twl4030-madc.c
+ *
+ * TWL4030 MADC module driver
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Mikko Ylinen <mikko.k.ylinen@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/i2c/twl4030.h>
+#include <linux/i2c/twl4030-madc.h>
+
+#include <asm/uaccess.h>
+
+#define TWL4030_MADC_PFX "twl4030-madc: "
+
+static struct twl4030_madc_data {
+ struct mutex lock;
+ struct work_struct ws;
+ struct twl4030_madc_request requests[TWL4030_MADC_NUM_METHODS];
+} twl4030_madc;
+
+static const char irq_pin = 1; /* XXX Read from platfrom data */
+
+static
+const struct twl4030_madc_conversion_method twl4030_conversion_methods[] = {
+ [TWL4030_MADC_RT] = {
+ .sel = TWL4030_MADC_RTSELECT_LSB,
+ .avg = TWL4030_MADC_RTAVERAGE_LSB,
+ .rbase = TWL4030_MADC_RTCH0_LSB,
+ },
+ [TWL4030_MADC_SW1] = {
+ .sel = TWL4030_MADC_SW1SELECT_LSB,
+ .avg = TWL4030_MADC_SW1AVERAGE_LSB,
+ .rbase = TWL4030_MADC_GPCH0_LSB,
+ .ctrl = TWL4030_MADC_CTRL_SW1,
+ },
+ [TWL4030_MADC_SW2] = {
+ .sel = TWL4030_MADC_SW2SELECT_LSB,
+ .avg = TWL4030_MADC_SW2AVERAGE_LSB,
+ .rbase = TWL4030_MADC_GPCH0_LSB,
+ .ctrl = TWL4030_MADC_CTRL_SW2,
+ },
+};
+
+static void twl4030_madc_read(u8 reg, u8 *val)
+{
+ int ret = twl4030_i2c_read_u8(TWL4030_MODULE_MADC, val, reg);
+ if (ret)
+ printk(KERN_ERR TWL4030_MADC_PFX
+ "unable to read register 0x%X\n", reg);
+}
+
+static void twl4030_madc_write(u8 reg, u8 val)
+{
+ int ret = twl4030_i2c_write_u8(TWL4030_MODULE_MADC, val, reg);
+ if (ret)
+ printk(KERN_ERR TWL4030_MADC_PFX
+ "unable to write register 0x%X\n", reg);
+}
+
+static int twl4030_madc_channel_raw_read(u8 reg)
+{
+ u8 msb, lsb;
+
+ /* For each ADC channel, we have MSB and LSB register pair. MSB address
+ * is always LSB address+1. reg parameter is the addr of LSB register */
+ twl4030_madc_read(reg+1, &msb);
+ twl4030_madc_read(reg, &lsb);
+
+ return (int)(((msb << 8) | lsb) >> 6);
+}
+
+static int twl4030_madc_read_channels(u8 reg_base, u16 channels, int *buf)
+{
+ int count = 0;
+ u8 reg, i;
+
+ if (unlikely(!buf))
+ return 0;
+
+ for (i = 0; i < TWL4030_MADC_MAX_CHANNELS; i++) {
+ if (channels & (1<<i)) {
+ reg = reg_base + 2*i;
+ buf[i] = twl4030_madc_channel_raw_read(reg);
+ count++;
+ }
+ }
+ return count;
+}
+
+static void twl4030_madc_enable_irq(int id)
+{
+ u8 val;
+
+ static u8 imr = (irq_pin == 1) ? TWL4030_MADC_IMR1 : TWL4030_MADC_IMR2;
+
+ twl4030_madc_read(imr, &val);
+ val &= ~(1 << id);
+ twl4030_madc_write(imr, val);
+}
+
+static void twl4030_madc_disable_irq(int id)
+{
+ u8 val;
+
+ static u8 imr = (irq_pin == 1) ? TWL4030_MADC_IMR1 : TWL4030_MADC_IMR2;
+
+ twl4030_madc_read(imr, &val);
+ val |= (1 << id);
+ twl4030_madc_write(imr, val);
+}
+
+static irqreturn_t twl4030_madc_irq_handler(int irq, void *madc_dev)
+{
+ u8 isr_val, imr_val;
+ static u8 isr, imr;
+ int i;
+
+ imr = (irq_pin == 1) ? TWL4030_MADC_IMR1 : TWL4030_MADC_IMR2;
+ isr = (irq_pin == 1) ? TWL4030_MADC_ISR1 : TWL4030_MADC_ISR2;
+
+ /* Use COR to ack interrupts since we have no shared IRQs in ISRx */
+ twl4030_madc_read(isr, &isr_val);
+ twl4030_madc_read(imr, &imr_val);
+
+ isr_val &= ~imr_val;
+
+ for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
+
+ if (!(isr_val & (1<<i)))
+ continue;
+
+ twl4030_madc_disable_irq(i);
+ twl4030_madc.requests[i].result_pending = 1;
+ }
+
+ schedule_work(&twl4030_madc.ws);
+
+ return IRQ_HANDLED;
+}
+
+static void twl4030_madc_work(struct work_struct *ws)
+{
+ const struct twl4030_madc_conversion_method *method;
+ struct twl4030_madc_request *r;
+ int len, i;
+
+ mutex_lock(&twl4030_madc.lock);
+
+ for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
+
+ r = &twl4030_madc.requests[i];
+
+ /* No pending results for this method, move to next one */
+ if (!r->result_pending)
+ continue;
+
+ method = &twl4030_conversion_methods[r->method];
+
+ /* Read results */
+ len = twl4030_madc_read_channels(method->rbase,
+ r->channels, r->rbuf);
+
+ /* Return results to caller */
+ if (r->func_cb != NULL) {
+ r->func_cb(len, r->channels, r->rbuf);
+ r->func_cb = NULL;
+ }
+
+ /* Free request */
+ r->result_pending = 0;
+ r->active = 0;
+ }
+
+ mutex_unlock(&twl4030_madc.lock);
+}
+
+static int twl4030_madc_set_irq(struct twl4030_madc_request *req)
+{
+ struct twl4030_madc_request *p;
+
+ p = &twl4030_madc.requests[req->method];
+
+ memcpy(p, req, sizeof *req);
+
+ twl4030_madc_enable_irq(req->method);
+
+ return 0;
+}
+
+static inline void twl4030_madc_start_conversion(int conv_method)
+{
+ const struct twl4030_madc_conversion_method *method;
+
+ method = &twl4030_conversion_methods[conv_method];
+
+ switch (conv_method) {
+ case TWL4030_MADC_SW1:
+ case TWL4030_MADC_SW2:
+ twl4030_madc_write(method->ctrl, TWL4030_MADC_SW_START);
+ break;
+ case TWL4030_MADC_RT:
+ default:
+ break;
+ }
+}
+
+static void twl4030_madc_wait_conversion_ready_ms(u8 *time, u8 status_reg)
+{
+ u8 reg = 0;
+
+ do {
+ msleep(1);
+ (*time)--;
+ twl4030_madc_read(status_reg, ®);
+ } while (((reg & TWL4030_MADC_BUSY) && !(reg & TWL4030_MADC_EOC_SW)) &&
+ (*time != 0));
+}
+
+int twl4030_madc_conversion(struct twl4030_madc_request *req)
+{
+ const struct twl4030_madc_conversion_method *method;
+ u8 wait_time, ch_msb, ch_lsb;
+ int ret;
+
+ if (unlikely(!req))
+ return -EINVAL;
+
+ /* Do we have a conversion request ongoing */
+ if (twl4030_madc.requests[req->method].active)
+ return -EBUSY;
+
+ ch_msb = (req->channels >> 8) & 0xff;
+ ch_lsb = req->channels & 0xff;
+
+ method = &twl4030_conversion_methods[req->method];
+
+ mutex_lock(&twl4030_madc.lock);
+
+ /* Select channels to be converted */
+ twl4030_madc_write(method->sel + 1, ch_msb);
+ twl4030_madc_write(method->sel, ch_lsb);
+
+ /* Select averaging for all channels if do_avg is set */
+ if (req->do_avg) {
+ twl4030_madc_write(method->avg + 1, ch_msb);
+ twl4030_madc_write(method->avg, ch_lsb);
+ }
+
+ if ((req->type == TWL4030_MADC_IRQ_ONESHOT) && (req->func_cb != NULL)) {
+ twl4030_madc_set_irq(req);
+ twl4030_madc_start_conversion(req->method);
+ twl4030_madc.requests[req->method].active = 1;
+ ret = 0;
+ goto out;
+ }
+
+ /* With RT method we should not be here anymore */
+ if (req->method == TWL4030_MADC_RT) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ twl4030_madc_start_conversion(req->method);
+ twl4030_madc.requests[req->method].active = 1;
+
+ /* Wait until conversion is ready (ctrl register returns EOC) */
+ wait_time = 50;
+ twl4030_madc_wait_conversion_ready_ms(&wait_time, method->ctrl);
+ if (wait_time == 0) {
+ printk(KERN_ERR TWL4030_MADC_PFX "conversion timeout!\n");
+ ret = -EAGAIN;
+ goto out;
+ }
+
+ ret = twl4030_madc_read_channels(method->rbase, req->channels,
+ req->rbuf);
+
+ twl4030_madc.requests[req->method].active = 0;
+
+out:
+ mutex_unlock(&twl4030_madc.lock);
+
+ return ret;
+}
+
+EXPORT_SYMBOL(twl4030_madc_conversion);
+
+static int twl4030_madc_set_current_generator(int chan, int on)
+{
+ int ret;
+ u8 regval;
+
+ /* Current generator is only available for ADCIN0 and ADCIN1. NB:
+ * ADCIN1 current generator only works when AC or VBUS is present */
+ if (chan > 1)
+ return EINVAL;
+
+ ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
+ ®val, TWL4030_BCI_BCICTL1);
+ if (on)
+ regval |= (chan) ? TWL4030_BCI_ITHEN : TWL4030_BCI_TYPEN;
+ else
+ regval &= (chan) ? ~TWL4030_BCI_ITHEN : ~TWL4030_BCI_TYPEN;
+ ret = twl4030_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE,
+ regval, TWL4030_BCI_BCICTL1);
+
+ return ret;
+}
+
+static int twl4030_madc_set_power(int on)
+{
+ u8 regval;
+
+ twl4030_madc_read(TWL4030_MADC_CTRL1, ®val);
+ if (on)
+ regval |= TWL4030_MADC_MADCON;
+ else
+ regval &= ~TWL4030_MADC_MADCON;
+ twl4030_madc_write(TWL4030_MADC_CTRL1, regval);
+
+ return 0;
+}
+
+static int twl4030_madc_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ struct twl4030_madc_user_parms par;
+ int val, ret;
+
+ ret = copy_from_user(&par, (void __user *) arg, sizeof(par));
+ if (ret) {
+ printk(KERN_ERR TWL4030_MADC_PFX "copy_from_user: %d\n", ret);
+ return -EACCES;
+ }
+
+ switch (cmd) {
+ case TWL4030_MADC_IOCX_ADC_RAW_READ: {
+ struct twl4030_madc_request req;
+ if (par.channel >= TWL4030_MADC_MAX_CHANNELS)
+ return -EINVAL;
+
+ req.channels = (1<<par.channel);
+ req.do_avg = par.average;
+ req.method = TWL4030_MADC_SW1;
+
+ val = twl4030_madc_conversion(&req);
+ if (val <= 0) {
+ par.status = -1;
+ } else {
+ par.status = 0;
+ par.result = (u16)req.rbuf[par.channel];
+ }
+ break;
+ }
+ default:
+ return -EINVAL;
+ }
+
+ ret = copy_to_user((void __user *) arg, &par, sizeof(par));
+ if (ret) {
+ printk(KERN_ERR TWL4030_MADC_PFX "copy_to_user: %d\n", ret);
+ return -EACCES;
+ }
+
+ return 0;
+}
+
+static struct file_operations twl4030_madc_fileops = {
+ .owner = THIS_MODULE,
+ .ioctl = twl4030_madc_ioctl
+};
+
+static struct miscdevice twl4030_madc_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "twl4030-adc",
+ .fops = &twl4030_madc_fileops
+};
+
+static int __init twl4030_madc_init(void)
+{
+ int ret;
+ u8 regval;
+
+ ret = misc_register(&twl4030_madc_device);
+ if (ret == -1) {
+ printk(KERN_ERR TWL4030_MADC_PFX "misc_register() failed!\n");
+ return ret;
+ }
+ twl4030_madc_set_power(1);
+ twl4030_madc_set_current_generator(0, 1);
+
+ ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
+ ®val, TWL4030_BCI_BCICTL1);
+
+ regval |= TWL4030_BCI_MESBAT;
+
+ ret = twl4030_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE,
+ regval, TWL4030_BCI_BCICTL1);
+
+ ret = request_irq(TWL4030_MODIRQ_MADC, twl4030_madc_irq_handler,
+ IRQF_DISABLED, "twl4030_madc", &twl4030_madc);
+ if (ret)
+ printk(KERN_ERR TWL4030_MADC_PFX "request_irq: %d\n", ret);
+
+ mutex_init(&twl4030_madc.lock);
+
+ INIT_WORK(&twl4030_madc.ws, twl4030_madc_work);
+
+ printk(KERN_INFO TWL4030_MADC_PFX "initialised\n");
+
+ return ret;
+}
+
+static void __exit twl4030_madc_exit(void)
+{
+ twl4030_madc_set_power(0);
+ twl4030_madc_set_current_generator(0, 0);
+ free_irq(TWL4030_MODIRQ_MADC, &twl4030_madc);
+ cancel_work_sync(&twl4030_madc.ws);
+ misc_deregister(&twl4030_madc_device);
+}
+
+module_init(twl4030_madc_init);
+module_exit(twl4030_madc_exit);
+
+MODULE_AUTHOR("Nokia Corporation");
+MODULE_DESCRIPTION("twl4030 ADC driver");
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * linux/drivers/i2c/chips/twl4030_poweroff.c
+ *
+ * Power off device
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Written by Peter De Schrijver <peter.de-schrijver@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/pm.h>
+#include <linux/i2c/twl4030.h>
+
+#define PWR_P1_SW_EVENTS 0x10
+#define PWR_DEVOFF (1<<0)
+
+static void twl4030_poweroff(void)
+{
+ u8 val;
+ int err;
+
+ err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &val,
+ PWR_P1_SW_EVENTS);
+ if (err) {
+ printk(KERN_WARNING "I2C error %d while reading TWL4030"
+ "PM_MASTER P1_SW_EVENTS\n", err);
+ return ;
+ }
+
+ val |= PWR_DEVOFF;
+
+ err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, val,
+ PWR_P1_SW_EVENTS);
+
+ if (err) {
+ printk(KERN_WARNING "I2C error %d while writing TWL4030"
+ "PM_MASTER P1_SW_EVENTS\n", err);
+ return ;
+ }
+
+ return;
+}
+
+static int __init twl4030_poweroff_init(void)
+{
+ pm_power_off = twl4030_poweroff;
+
+ return 0;
+}
+
+static void __exit twl4030_poweroff_exit(void)
+{
+ pm_power_off = NULL;
+}
+
+module_init(twl4030_poweroff_init);
+module_exit(twl4030_poweroff_exit);
+
+MODULE_DESCRIPTION("Triton2 device power off");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Peter De Schrijver");
--- /dev/null
+/**
+ * drivers/i2c/chips/twl4030-pwrbutton.c
+ *
+ * Driver for sending triton2 power button event to input-layer
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Written by Peter De Schrijver <peter.de-schrijver@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/kernel.h>
+#include <linux/errno.h>
+#include <linux/input.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
+#include <linux/kthread.h>
+#include <linux/interrupt.h>
+#include <linux/i2c/twl4030.h>
+
+#define PWR_ISR1 0
+#define PWR_IMR1 1
+#define PWR_PWRON_IRQ (1<<0)
+
+#define PWR_EDR1 5
+#define PWR_PWRON_RISING (1<<1)
+#define PWR_PWRON_FALLING (1<<0)
+#define PWR_PWRON_BOTH (PWR_PWRON_RISING | PWR_PWRON_FALLING)
+
+#define PWR_SIH_CTRL 7
+
+#define STS_HW_CONDITIONS 0xf
+
+static struct input_dev *powerbutton_dev;
+
+/*
+ * Note : the following function runs in kernel thread context
+ * with IRQs enabled
+ */
+
+static irqreturn_t powerbutton_irq(int irq, void *dev_id)
+{
+ int err;
+ u8 value;
+
+ err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &value,
+ STS_HW_CONDITIONS);
+ if (!err) {
+ input_report_key(powerbutton_dev, KEY_POWER,
+ value & PWR_PWRON_IRQ);
+ } else {
+ printk(KERN_WARNING "I2C error %d while reading TWL4030"
+ " PM_MASTER STS_HW_CONDITIONS register\n", err);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int __init twl4030_pwrbutton_init(void)
+{
+ int err = 0;
+ u8 value;
+
+ if (request_irq(TWL4030_PWRIRQ_PWRBTN, powerbutton_irq, 0,
+ "PwrButton", NULL) < 0) {
+ printk(KERN_ERR "Unable to allocate IRQ for power button\n");
+ err = -EBUSY;
+ goto out;
+ }
+
+ powerbutton_dev = input_allocate_device();
+ if (!powerbutton_dev) {
+ printk(KERN_ERR
+ "Unable to allocate input device for power button\n");
+ err = -ENOMEM;
+ goto free_irq_and_out;
+ }
+
+ powerbutton_dev->evbit[0] = BIT_MASK(EV_KEY);
+ powerbutton_dev->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER);
+ powerbutton_dev->name = "triton2-pwrbutton";
+
+ err = input_register_device(powerbutton_dev);
+ if (err)
+ goto free_input_dev;
+
+ err = twl4030_i2c_read_u8(TWL4030_MODULE_INT, &value, PWR_IMR1);
+ if (err) {
+ printk(KERN_WARNING "I2C error %d while reading TWL4030"
+ " INT PWR_IMR1 register\n", err);
+
+ goto free_input_dev;
+ }
+
+ err = twl4030_i2c_write_u8(TWL4030_MODULE_INT,
+ value & (~PWR_PWRON_IRQ), PWR_IMR1);
+ if (err) {
+ printk(KERN_WARNING "I2C error %d while writing TWL4030"
+ " INT PWR_IMR1 register\n", err);
+ goto free_input_dev;
+ }
+
+ err = twl4030_i2c_read_u8(TWL4030_MODULE_INT, &value, PWR_EDR1);
+ if (err) {
+ printk(KERN_WARNING "I2C error %d while reading TWL4030"
+ " INT PWR_EDR1 register\n", err);
+ goto free_input_dev;
+ }
+
+ err = twl4030_i2c_write_u8(TWL4030_MODULE_INT,
+ value | PWR_PWRON_BOTH , PWR_EDR1);
+
+ if (err) {
+ printk(KERN_WARNING "I2C error %d while writing TWL4030"
+ " INT PWR_EDR1 register\n", err);
+ goto free_input_dev;
+ }
+
+ printk(KERN_INFO "triton2 power button driver initialized\n");
+
+ return 0;
+
+
+free_input_dev:
+ input_free_device(powerbutton_dev);
+free_irq_and_out:
+ free_irq(TWL4030_PWRIRQ_PWRBTN, NULL);
+out:
+ return err;
+}
+
+static void __exit twl4030_pwrbutton_exit(void)
+{
+ free_irq(TWL4030_PWRIRQ_PWRBTN, NULL);
+ input_unregister_device(powerbutton_dev);
+ input_free_device(powerbutton_dev);
+
+}
+
+module_init(twl4030_pwrbutton_init);
+module_exit(twl4030_pwrbutton_exit);
+
+MODULE_DESCRIPTION("Triton2 Power Button");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Peter De Schrijver");
+
--- /dev/null
+/*
+ * twl4030-pwrirq.c - handle power interrupts from TWL3040
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Written by Peter De Schrijver <peter.de-schrijver@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_stat.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/i2c.h>
+#include <linux/random.h>
+#include <linux/kthread.h>
+#include <linux/i2c/twl4030.h>
+
+#define PWR_ISR1 0
+#define PWR_IMR1 1
+#define PWR_SIH_CTRL 7
+#define PWR_SIH_CTRL_COR (1<<2)
+
+static u8 twl4030_pwrirq_mask;
+static u8 twl4030_pwrirq_pending_unmask;
+
+static struct task_struct *twl4030_pwrirq_unmask_thread;
+
+static void twl4030_pwrirq_ack(unsigned int irq) {}
+
+static void twl4030_pwrirq_disableint(unsigned int irq) {}
+
+static void twl4030_pwrirq_enableint(unsigned int irq)
+{
+ twl4030_pwrirq_pending_unmask |= 1 << (irq - TWL4030_PWR_IRQ_BASE);
+ if (twl4030_pwrirq_unmask_thread &&
+ twl4030_pwrirq_unmask_thread->state != TASK_RUNNING)
+ wake_up_process(twl4030_pwrirq_unmask_thread);
+}
+
+static struct irq_chip twl4030_pwrirq_chip = {
+ .name = "twl4030-pwr",
+ .ack = twl4030_pwrirq_ack,
+ .mask = twl4030_pwrirq_disableint,
+ .unmask = twl4030_pwrirq_enableint,
+};
+
+static void do_twl4030_pwrmodule_irq(unsigned int irq, irq_desc_t *desc)
+{
+ struct irqaction *action;
+ const unsigned int cpu = smp_processor_id();
+
+ desc->status |= IRQ_LEVEL;
+
+ if (!desc->depth) {
+ kstat_cpu(cpu).irqs[irq]++;
+
+ action = desc->action;
+ if (action) {
+ int ret;
+ int status = 0;
+ int retval = 0;
+
+ do {
+ ret = action->handler(irq, action->dev_id);
+ if (ret == IRQ_HANDLED)
+ status |= action->flags;
+ retval |= ret;
+ action = action->next;
+ } while (action);
+
+ if (status & IRQF_SAMPLE_RANDOM)
+ add_interrupt_randomness(irq);
+
+ if (retval != IRQ_HANDLED)
+ printk(KERN_ERR "ISR for TWL4030 power module"
+ " irq %d can't handle interrupt\n",
+ irq);
+ } else {
+ local_irq_disable();
+ twl4030_pwrirq_mask |= 1 << (irq - TWL4030_PWR_IRQ_BASE);
+ local_irq_enable();
+ twl4030_i2c_write_u8(TWL4030_MODULE_INT,
+ twl4030_pwrirq_mask, PWR_IMR1);
+ }
+ }
+}
+
+static void do_twl4030_pwrirq(unsigned int irq, irq_desc_t *desc)
+{
+ const unsigned int cpu = smp_processor_id();
+
+ desc->status |= IRQ_LEVEL;
+
+ desc->chip->ack(irq);
+
+ if (!desc->depth) {
+ int ret;
+ int module_irq;
+ u8 pwr_isr;
+
+ kstat_cpu(cpu).irqs[irq]++;
+
+ local_irq_enable();
+ ret = twl4030_i2c_read_u8(TWL4030_MODULE_INT, &pwr_isr,
+ PWR_ISR1);
+ if (ret) {
+ printk(KERN_WARNING
+ "I2C error %d while reading TWL4030"
+ "INT PWR_ISR1 register\n", ret);
+ return;
+ }
+
+ for (module_irq = TWL4030_PWR_IRQ_BASE; pwr_isr != 0;
+ module_irq++, pwr_isr >>= 1) {
+ if (pwr_isr & 1) {
+ irq_desc_t *d = irq_desc + module_irq;
+ d->handle_irq(module_irq, d);
+ }
+ }
+
+ local_irq_disable();
+ desc->chip->unmask(irq);
+ }
+}
+
+static int twl4030_pwrirq_thread(void *data)
+{
+ current->flags |= PF_NOFREEZE;
+
+ while (!kthread_should_stop()) {
+ u8 local_unmask;
+
+ local_irq_disable();
+ local_unmask = twl4030_pwrirq_pending_unmask;
+ twl4030_pwrirq_pending_unmask = 0;
+ local_irq_enable();
+
+ twl4030_pwrirq_mask &= ~local_unmask;
+
+ twl4030_i2c_write_u8(TWL4030_MODULE_INT, twl4030_pwrirq_mask,
+ PWR_IMR1);
+
+ local_irq_disable();
+ if (!twl4030_pwrirq_pending_unmask)
+ set_current_state(TASK_INTERRUPTIBLE);
+ local_irq_enable();
+
+ schedule();
+ }
+ set_current_state(TASK_RUNNING);
+ return 0;
+}
+
+static int __init twl4030_pwrirq_init(void)
+{
+ int i, err;
+
+ twl4030_pwrirq_mask = 0xff;
+ twl4030_pwrirq_pending_unmask = 0;
+
+ err = twl4030_i2c_write_u8(TWL4030_MODULE_INT, twl4030_pwrirq_mask,
+ PWR_IMR1);
+ if (err)
+ return err;
+
+ /* Enable clear on read */
+
+ err = twl4030_i2c_write_u8(TWL4030_MODULE_INT, PWR_SIH_CTRL_COR,
+ PWR_SIH_CTRL);
+ if (err)
+ return err;
+
+ twl4030_pwrirq_unmask_thread = kthread_create(twl4030_pwrirq_thread,
+ NULL, "twl4030 pwrirq");
+ if (!twl4030_pwrirq_unmask_thread) {
+ printk(KERN_ERR
+ "%s: could not create twl4030 pwrirq unmask thread!\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ for (i = TWL4030_PWR_IRQ_BASE; i < TWL4030_PWR_IRQ_END; i++) {
+ set_irq_chip(i, &twl4030_pwrirq_chip);
+ set_irq_handler(i, do_twl4030_pwrmodule_irq);
+ set_irq_flags(i, IRQF_VALID);
+ }
+
+ set_irq_chained_handler(TWL4030_MODIRQ_PWR, do_twl4030_pwrirq);
+
+ return 0;
+}
+
+static void __exit twl4030_pwrirq_exit(void)
+{
+
+ int i;
+
+ set_irq_handler(TWL4030_MODIRQ_PWR, NULL);
+ set_irq_flags(TWL4030_MODIRQ_PWR, 0);
+
+ for (i = TWL4030_PWR_IRQ_BASE; i < TWL4030_PWR_IRQ_END; i++) {
+ set_irq_handler(i, NULL);
+ set_irq_flags(i, 0);
+ }
+
+ if (twl4030_pwrirq_unmask_thread) {
+ kthread_stop(twl4030_pwrirq_unmask_thread);
+ twl4030_pwrirq_unmask_thread = NULL;
+ }
+}
+
+subsys_initcall(twl4030_pwrirq_init);
+module_exit(twl4030_pwrirq_exit);
--- /dev/null
+/*
+ * twl4030_usb - TWL4030 USB transceiver, talking to OMAP OTG controller
+ *
+ * Copyright (C) 2004-2007 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Current status:
+ * - HS USB ULPI mode works.
+ * - 3-pin mode support may be added in future.
+ */
+
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/interrupt.h>
+#include <linux/usb.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
+#include <linux/i2c/twl4030.h>
+#include <asm/arch/usb.h>
+
+/* Register defines */
+
+#define VENDOR_ID_LO 0x00
+#define VENDOR_ID_HI 0x01
+#define PRODUCT_ID_LO 0x02
+#define PRODUCT_ID_HI 0x03
+
+#define FUNC_CTRL 0x04
+#define FUNC_CTRL_SET 0x05
+#define FUNC_CTRL_CLR 0x06
+#define FUNC_CTRL_SUSPENDM (1 << 6)
+#define FUNC_CTRL_RESET (1 << 5)
+#define FUNC_CTRL_OPMODE_MASK (3 << 3) /* bits 3 and 4 */
+#define FUNC_CTRL_OPMODE_NORMAL (0 << 3)
+#define FUNC_CTRL_OPMODE_NONDRIVING (1 << 3)
+#define FUNC_CTRL_OPMODE_DISABLE_BIT_NRZI (2 << 3)
+#define FUNC_CTRL_TERMSELECT (1 << 2)
+#define FUNC_CTRL_XCVRSELECT_MASK (3 << 0) /* bits 0 and 1 */
+#define FUNC_CTRL_XCVRSELECT_HS (0 << 0)
+#define FUNC_CTRL_XCVRSELECT_FS (1 << 0)
+#define FUNC_CTRL_XCVRSELECT_LS (2 << 0)
+#define FUNC_CTRL_XCVRSELECT_FS4LS (3 << 0)
+
+#define IFC_CTRL 0x07
+#define IFC_CTRL_SET 0x08
+#define IFC_CTRL_CLR 0x09
+#define IFC_CTRL_INTERFACE_PROTECT_DISABLE (1 << 7)
+#define IFC_CTRL_AUTORESUME (1 << 4)
+#define IFC_CTRL_CLOCKSUSPENDM (1 << 3)
+#define IFC_CTRL_CARKITMODE (1 << 2)
+#define IFC_CTRL_FSLSSERIALMODE_3PIN (1 << 1)
+
+#define OTG_CTRL 0x0A
+#define OTG_CTRL_SET 0x0B
+#define OTG_CTRL_CLR 0x0C
+#define OTG_CTRL_DRVVBUS (1 << 5)
+#define OTG_CTRL_CHRGVBUS (1 << 4)
+#define OTG_CTRL_DISCHRGVBUS (1 << 3)
+#define OTG_CTRL_DMPULLDOWN (1 << 2)
+#define OTG_CTRL_DPPULLDOWN (1 << 1)
+#define OTG_CTRL_IDPULLUP (1 << 0)
+
+#define USB_INT_EN_RISE 0x0D
+#define USB_INT_EN_RISE_SET 0x0E
+#define USB_INT_EN_RISE_CLR 0x0F
+#define USB_INT_EN_FALL 0x10
+#define USB_INT_EN_FALL_SET 0x11
+#define USB_INT_EN_FALL_CLR 0x12
+#define USB_INT_STS 0x13
+#define USB_INT_LATCH 0x14
+#define USB_INT_IDGND (1 << 4)
+#define USB_INT_SESSEND (1 << 3)
+#define USB_INT_SESSVALID (1 << 2)
+#define USB_INT_VBUSVALID (1 << 1)
+#define USB_INT_HOSTDISCONNECT (1 << 0)
+
+#define CARKIT_CTRL 0x19
+#define CARKIT_CTRL_SET 0x1A
+#define CARKIT_CTRL_CLR 0x1B
+#define CARKIT_CTRL_MICEN (1 << 6)
+#define CARKIT_CTRL_SPKRIGHTEN (1 << 5)
+#define CARKIT_CTRL_SPKLEFTEN (1 << 4)
+#define CARKIT_CTRL_RXDEN (1 << 3)
+#define CARKIT_CTRL_TXDEN (1 << 2)
+#define CARKIT_CTRL_IDGNDDRV (1 << 1)
+#define CARKIT_CTRL_CARKITPWR (1 << 0)
+#define CARKIT_PLS_CTRL 0x22
+#define CARKIT_PLS_CTRL_SET 0x23
+#define CARKIT_PLS_CTRL_CLR 0x24
+#define CARKIT_PLS_CTRL_SPKRRIGHT_BIASEN (1 << 3)
+#define CARKIT_PLS_CTRL_SPKRLEFT_BIASEN (1 << 2)
+#define CARKIT_PLS_CTRL_RXPLSEN (1 << 1)
+#define CARKIT_PLS_CTRL_TXPLSEN (1 << 0)
+
+#define MCPC_CTRL 0x30
+#define MCPC_CTRL_SET 0x31
+#define MCPC_CTRL_CLR 0x32
+#define MCPC_CTRL_RTSOL (1 << 7)
+#define MCPC_CTRL_EXTSWR (1 << 6)
+#define MCPC_CTRL_EXTSWC (1 << 5)
+#define MCPC_CTRL_VOICESW (1 << 4)
+#define MCPC_CTRL_OUT64K (1 << 3)
+#define MCPC_CTRL_RTSCTSSW (1 << 2)
+#define MCPC_CTRL_HS_UART (1 << 0)
+
+#define MCPC_IO_CTRL 0x33
+#define MCPC_IO_CTRL_SET 0x34
+#define MCPC_IO_CTRL_CLR 0x35
+#define MCPC_IO_CTRL_MICBIASEN (1 << 5)
+#define MCPC_IO_CTRL_CTS_NPU (1 << 4)
+#define MCPC_IO_CTRL_RXD_PU (1 << 3)
+#define MCPC_IO_CTRL_TXDTYP (1 << 2)
+#define MCPC_IO_CTRL_CTSTYP (1 << 1)
+#define MCPC_IO_CTRL_RTSTYP (1 << 0)
+
+#define MCPC_CTRL2 0x36
+#define MCPC_CTRL2_SET 0x37
+#define MCPC_CTRL2_CLR 0x38
+#define MCPC_CTRL2_MCPC_CK_EN (1 << 0)
+
+#define OTHER_FUNC_CTRL 0x80
+#define OTHER_FUNC_CTRL_SET 0x81
+#define OTHER_FUNC_CTRL_CLR 0x82
+#define OTHER_FUNC_CTRL_BDIS_ACON_EN (1 << 4)
+#define OTHER_FUNC_CTRL_FIVEWIRE_MODE (1 << 2)
+
+#define OTHER_IFC_CTRL 0x83
+#define OTHER_IFC_CTRL_SET 0x84
+#define OTHER_IFC_CTRL_CLR 0x85
+#define OTHER_IFC_CTRL_OE_INT_EN (1 << 6)
+#define OTHER_IFC_CTRL_CEA2011_MODE (1 << 5)
+#define OTHER_IFC_CTRL_FSLSSERIALMODE_4PIN (1 << 4)
+#define OTHER_IFC_CTRL_HIZ_ULPI_60MHZ_OUT (1 << 3)
+#define OTHER_IFC_CTRL_HIZ_ULPI (1 << 2)
+#define OTHER_IFC_CTRL_ALT_INT_REROUTE (1 << 0)
+
+#define OTHER_INT_EN_RISE 0x86
+#define OTHER_INT_EN_RISE_SET 0x87
+#define OTHER_INT_EN_RISE_CLR 0x88
+#define OTHER_INT_EN_FALL 0x89
+#define OTHER_INT_EN_FALL_SET 0x8A
+#define OTHER_INT_EN_FALL_CLR 0x8B
+#define OTHER_INT_STS 0x8C
+#define OTHER_INT_LATCH 0x8D
+#define OTHER_INT_VB_SESS_VLD (1 << 7)
+#define OTHER_INT_DM_HI (1 << 6) /* not valid for "latch" reg */
+#define OTHER_INT_DP_HI (1 << 5) /* not valid for "latch" reg */
+#define OTHER_INT_BDIS_ACON (1 << 3) /* not valid for "fall" regs */
+#define OTHER_INT_MANU (1 << 1)
+#define OTHER_INT_ABNORMAL_STRESS (1 << 0)
+
+#define ID_STATUS 0x96
+#define ID_RES_FLOAT (1 << 4)
+#define ID_RES_440K (1 << 3)
+#define ID_RES_200K (1 << 2)
+#define ID_RES_102K (1 << 1)
+#define ID_RES_GND (1 << 0)
+
+#define POWER_CTRL 0xAC
+#define POWER_CTRL_SET 0xAD
+#define POWER_CTRL_CLR 0xAE
+#define POWER_CTRL_OTG_ENAB (1 << 5)
+
+#define OTHER_IFC_CTRL2 0xAF
+#define OTHER_IFC_CTRL2_SET 0xB0
+#define OTHER_IFC_CTRL2_CLR 0xB1
+#define OTHER_IFC_CTRL2_ULPI_STP_LOW (1 << 4)
+#define OTHER_IFC_CTRL2_ULPI_TXEN_POL (1 << 3)
+#define OTHER_IFC_CTRL2_ULPI_4PIN_2430 (1 << 2)
+#define OTHER_IFC_CTRL2_USB_INT_OUTSEL_MASK (3 << 0) /* bits 0 and 1 */
+#define OTHER_IFC_CTRL2_USB_INT_OUTSEL_INT1N (0 << 0)
+#define OTHER_IFC_CTRL2_USB_INT_OUTSEL_INT2N (1 << 0)
+
+#define REG_CTRL_EN 0xB2
+#define REG_CTRL_EN_SET 0xB3
+#define REG_CTRL_EN_CLR 0xB4
+#define REG_CTRL_ERROR 0xB5
+#define ULPI_I2C_CONFLICT_INTEN (1 << 0)
+
+#define OTHER_FUNC_CTRL2 0xB8
+#define OTHER_FUNC_CTRL2_SET 0xB9
+#define OTHER_FUNC_CTRL2_CLR 0xBA
+#define OTHER_FUNC_CTRL2_VBAT_TIMER_EN (1 << 0)
+
+/* following registers do not have separate _clr and _set registers */
+#define VBUS_DEBOUNCE 0xC0
+#define ID_DEBOUNCE 0xC1
+#define VBAT_TIMER 0xD3
+#define PHY_PWR_CTRL 0xFD
+#define PHY_PWR_PHYPWD (1 << 0)
+#define PHY_CLK_CTRL 0xFE
+#define PHY_CLK_CTRL_CLOCKGATING_EN (1 << 2)
+#define PHY_CLK_CTRL_CLK32K_EN (1 << 1)
+#define REQ_PHY_DPLL_CLK (1 << 0)
+#define PHY_CLK_CTRL_STS 0xFF
+#define PHY_DPLL_CLK (1 << 0)
+
+/* In module TWL4030_MODULE_PM_MASTER */
+#define PROTECT_KEY 0x0E
+
+/* In module TWL4030_MODULE_PM_RECEIVER */
+#define VUSB_DEDICATED1 0x7D
+#define VUSB_DEDICATED2 0x7E
+#define VUSB1V5_DEV_GRP 0x71
+#define VUSB1V5_TYPE 0x72
+#define VUSB1V5_REMAP 0x73
+#define VUSB1V8_DEV_GRP 0x74
+#define VUSB1V8_TYPE 0x75
+#define VUSB1V8_REMAP 0x76
+#define VUSB3V1_DEV_GRP 0x77
+#define VUSB3V1_TYPE 0x78
+#define VUSB3V1_REMAP 0x79
+
+#define ID_STATUS 0x96
+#define ID_RES_FLOAT (1 << 4) /* mini-B */
+#define ID_RES_440K (1 << 3) /* type 2 charger */
+#define ID_RES_200K (1 << 2) /* 5-wire carkit or
+ type 1 charger */
+#define ID_RES_102K (1 << 1) /* phone */
+#define ID_RES_GND (1 << 0) /* mini-A */
+
+/* In module TWL4030_MODULE_INTBR */
+#define PMBR1 0x0D
+#define GPIO_USB_4PIN_ULPI_2430C (3 << 0)
+
+/* In module TWL4030_MODULE_INT */
+#define REG_PWR_ISR1 0x00
+#define REG_PWR_IMR1 0x01
+#define USB_PRES (1 << 2)
+#define REG_PWR_EDR1 0x05
+#define USB_PRES_FALLING (1 << 4)
+#define USB_PRES_RISING (1 << 5)
+#define REG_PWR_SIH_CTRL 0x07
+#define COR (1 << 2)
+
+/* internal define on top of container_of */
+#define xceiv_to_twl(x) container_of((x), struct twl4030_usb, otg);
+
+/* bits in OTG_CTRL_REG */
+
+#define OTG_XCEIV_OUTPUTS \
+ (OTG_ASESSVLD|OTG_BSESSEND|OTG_BSESSVLD|OTG_VBUSVLD|OTG_ID)
+#define OTG_XCEIV_INPUTS \
+ (OTG_PULLDOWN|OTG_PULLUP|OTG_DRV_VBUS|OTG_PD_VBUS|OTG_PU_VBUS|OTG_PU_ID)
+#define OTG_CTRL_BITS \
+ (OTG_A_BUSREQ|OTG_A_SETB_HNPEN|OTG_B_BUSREQ|OTG_B_HNPEN|OTG_BUSDROP)
+ /* and OTG_PULLUP is sometimes written */
+
+#define OTG_CTRL_MASK (OTG_DRIVER_SEL| \
+ OTG_XCEIV_OUTPUTS|OTG_XCEIV_INPUTS| \
+ OTG_CTRL_BITS)
+
+
+/*-------------------------------------------------------------------------*/
+
+struct twl4030_usb {
+ struct otg_transceiver otg;
+ int irq;
+ u8 usb_mode; /* pin configuration */
+#define T2_USB_MODE_ULPI 1
+/* #define T2_USB_MODE_CEA2011_3PIN 2 */
+ u8 asleep;
+};
+
+static struct twl4030_usb *the_transceiver;
+
+/*-------------------------------------------------------------------------*/
+
+static int twl4030_i2c_write_u8_verify(u8 module, u8 data, u8 address)
+{
+ u8 check;
+
+ if ((twl4030_i2c_write_u8(module, data, address) >= 0) &&
+ (twl4030_i2c_read_u8(module, &check, address) >= 0) &&
+ (check == data))
+ return 0;
+ /* Failed once: Try again */
+ if ((twl4030_i2c_write_u8(module, data, address) >= 0) &&
+ (twl4030_i2c_read_u8(module, &check, address) >= 0) &&
+ (check == data))
+ return 0;
+ /* Failed again: Return error */
+ return -EBUSY;
+}
+
+#define twl4030_usb_write_verify(address, data) \
+ twl4030_i2c_write_u8_verify(TWL4030_MODULE_USB, (data), (address))
+
+static inline int twl4030_usb_write(u8 address, u8 data)
+{
+ int ret = 0;
+ ret = twl4030_i2c_write_u8(TWL4030_MODULE_USB, data, address);
+ if (ret >= 0) {
+#if 0 /* debug */
+ u8 data1;
+ if (twl4030_i2c_read_u8(TWL4030_MODULE_USB, &data1,
+ address) < 0)
+ printk(KERN_ERR "re-read failed\n");
+ else
+ printk(KERN_INFO
+ "Write %s wrote %x read %x from reg %x\n",
+ (data1 == data) ? "succeed" : "mismatch",
+ data, data1, address);
+#endif
+ } else {
+ printk(KERN_WARNING
+ "TWL4030:USB:Write[0x%x] Error %d\n", address, ret);
+ }
+ return ret;
+}
+
+static inline int twl4030_usb_read(u8 address)
+{
+ u8 data;
+ int ret = 0;
+ ret = twl4030_i2c_read_u8(TWL4030_MODULE_USB, &data, address);
+ if (ret >= 0) {
+ ret = data;
+ } else {
+ printk(KERN_WARNING
+ "TWL4030:USB:Read[0x%x] Error %d\n", address, ret);
+ }
+ return ret;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static inline int
+twl4030_usb_set_bits(struct twl4030_usb *twl, u8 reg, u8 bits)
+{
+ return twl4030_usb_write(reg + 1, bits);
+}
+
+static inline int
+twl4030_usb_clear_bits(struct twl4030_usb *twl, u8 reg, u8 bits)
+{
+ return twl4030_usb_write(reg + 2, bits);
+
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void twl4030_usb_set_mode(struct twl4030_usb *twl, int mode)
+{
+ twl->usb_mode = mode;
+
+ switch (mode) {
+ case T2_USB_MODE_ULPI:
+ twl4030_usb_clear_bits(twl, IFC_CTRL, IFC_CTRL_CARKITMODE);
+ twl4030_usb_set_bits(twl, POWER_CTRL, POWER_CTRL_OTG_ENAB);
+ twl4030_usb_clear_bits(twl, FUNC_CTRL,
+ FUNC_CTRL_XCVRSELECT_MASK |
+ FUNC_CTRL_OPMODE_MASK);
+ break;
+/*
+ case T2_USB_MODE_CEA2011_3PIN:
+ twl4030_cea2011_3_pin_FS_setup(twl);
+ break;
+*/
+ default:
+ /* FIXME: power on defaults */
+ break;
+ };
+}
+
+#ifdef CONFIG_TWL4030_USB_HS_ULPI
+static void hs_usb_init(struct twl4030_usb *twl)
+{
+ twl->usb_mode = T2_USB_MODE_ULPI;
+ return;
+}
+
+#endif
+
+static void twl4030_i2c_access(int on)
+{
+ unsigned long timeout;
+ int val = twl4030_usb_read(PHY_CLK_CTRL);
+
+ if (val >= 0) {
+ if (on) {
+ /* enable DPLL to access PHY registers over I2C */
+ val |= REQ_PHY_DPLL_CLK;
+ if (twl4030_usb_write_verify(PHY_CLK_CTRL,
+ (u8)val) < 0) {
+ printk(KERN_ERR "twl4030_usb: i2c write failed,"
+ " line %d\n", __LINE__);
+ return;
+ }
+
+ timeout = jiffies + HZ;
+ while (!(twl4030_usb_read(PHY_CLK_CTRL_STS) &
+ PHY_DPLL_CLK)
+ && time_before(jiffies, timeout))
+ udelay(10);
+ if (!(twl4030_usb_read(PHY_CLK_CTRL_STS) &
+ PHY_DPLL_CLK))
+ printk(KERN_ERR "Timeout setting T2 HSUSB "
+ "PHY DPLL clock\n");
+ } else {
+ /* let ULPI control the DPLL clock */
+ val &= ~REQ_PHY_DPLL_CLK;
+ if (twl4030_usb_write_verify(PHY_CLK_CTRL,
+ (u8)val) < 0) {
+ printk(KERN_ERR "twl4030_usb: i2c write failed,"
+ " line %d\n", __LINE__);
+ }
+ }
+ }
+ return;
+}
+
+static void usb_irq_enable(int rising, int falling)
+{
+ u8 val;
+
+ /* edge setup */
+ if (twl4030_i2c_read_u8(TWL4030_MODULE_INT, &val, REG_PWR_EDR1) < 0) {
+ printk(KERN_ERR "twl4030_usb: i2c read failed,"
+ " line %d\n", __LINE__);
+ return;
+ }
+ val &= ~(USB_PRES_RISING | USB_PRES_FALLING);
+ if (rising)
+ val = val | USB_PRES_RISING;
+ if (falling)
+ val = val | USB_PRES_FALLING;
+ if (twl4030_i2c_write_u8_verify(TWL4030_MODULE_INT, val,
+ REG_PWR_EDR1) < 0) {
+ printk(KERN_ERR "twl4030_usb: i2c write failed,"
+ " line %d\n", __LINE__);
+ return;
+ }
+
+ /* un-mask interrupt */
+ if (twl4030_i2c_read_u8(TWL4030_MODULE_INT, &val, REG_PWR_IMR1) < 0) {
+ printk(KERN_ERR "twl4030_usb: i2c read failed,"
+ " line %d\n", __LINE__);
+ return;
+ }
+ val &= ~USB_PRES;
+ if (twl4030_i2c_write_u8_verify(TWL4030_MODULE_INT, val,
+ REG_PWR_IMR1) < 0)
+ printk(KERN_ERR "twl4030_usb: i2c write failed,"
+ " line %d\n", __LINE__);
+
+ return;
+}
+
+static void usb_irq_disable(void)
+{
+ u8 val;
+
+ /* undo edge setup */
+ if (twl4030_i2c_read_u8(TWL4030_MODULE_INT, &val, REG_PWR_EDR1) < 0) {
+ printk(KERN_ERR "twl4030_usb: i2c read failed,"
+ " line %d\n", __LINE__);
+ return;
+ }
+ val &= ~(USB_PRES_RISING | USB_PRES_FALLING);
+ if (twl4030_i2c_write_u8_verify(TWL4030_MODULE_INT, val,
+ REG_PWR_EDR1) < 0) {
+ printk(KERN_ERR "twl4030_usb: i2c write failed,"
+ " line %d\n", __LINE__);
+ return;
+ }
+
+ /* mask interrupt */
+ if (twl4030_i2c_read_u8(TWL4030_MODULE_INT, &val, REG_PWR_IMR1) < 0) {
+ printk(KERN_ERR "twl4030_usb: i2c read failed,"
+ " line %d\n", __LINE__);
+ return;
+ }
+ val |= USB_PRES;
+ if (twl4030_i2c_write_u8_verify(TWL4030_MODULE_INT, val,
+ REG_PWR_IMR1) < 0)
+ printk(KERN_ERR "twl4030_usb: i2c write failed,"
+ " line %d\n", __LINE__);
+
+ return;
+}
+
+static void twl4030_phy_power(struct twl4030_usb *twl, int on)
+{
+ u8 pwr;
+
+ pwr = twl4030_usb_read(PHY_PWR_CTRL);
+ if (on) {
+ pwr &= ~PHY_PWR_PHYPWD;
+ if (twl4030_usb_write_verify(PHY_PWR_CTRL, pwr) < 0) {
+ printk(KERN_ERR "twl4030_usb: i2c write failed,"
+ " line %d\n", __LINE__);
+ return;
+ }
+ twl4030_usb_write(PHY_CLK_CTRL,
+ twl4030_usb_read(PHY_CLK_CTRL) |
+ (PHY_CLK_CTRL_CLOCKGATING_EN |
+ PHY_CLK_CTRL_CLK32K_EN));
+ } else {
+ pwr |= PHY_PWR_PHYPWD;
+ if (twl4030_usb_write_verify(PHY_PWR_CTRL, pwr) < 0) {
+ printk(KERN_ERR "twl4030_usb: i2c write failed,"
+ " line %d\n", __LINE__);
+ }
+ }
+ return;
+}
+
+static void twl4030_phy_suspend(int controller_off)
+{
+ struct twl4030_usb *twl = the_transceiver;
+
+ if (controller_off)
+ usb_irq_disable();
+
+ if (twl->asleep)
+ return;
+
+ if (!controller_off)
+ /* enable rising edge interrupt to detect cable attach */
+ usb_irq_enable(1, 0);
+
+ twl4030_phy_power(twl, 0);
+ twl->asleep = 1;
+ return;
+}
+
+static void twl4030_phy_resume(void)
+{
+ struct twl4030_usb *twl = the_transceiver;
+
+ if (!twl->asleep)
+ return;
+
+ /* enable falling edge interrupt to detect cable detach */
+ usb_irq_enable(0, 1);
+
+ twl4030_phy_power(twl, 1);
+ twl4030_i2c_access(1);
+ twl4030_usb_set_mode(twl, twl->usb_mode);
+ if (twl->usb_mode == T2_USB_MODE_ULPI)
+ twl4030_i2c_access(0);
+ twl->asleep = 0;
+ return;
+}
+
+static void twl4030_usb_ldo_init(struct twl4030_usb *twl)
+{
+ /* Enable writing to power configuration registers */
+ twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0xC0, PROTECT_KEY);
+ twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0x0C, PROTECT_KEY);
+
+ /* put VUSB3V1 LDO in active state */
+ twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB_DEDICATED2);
+
+ /* input to VUSB3V1 LDO is from VBAT, not VBUS */
+ twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x14, VUSB_DEDICATED1);
+
+ /* turn on 3.1V regulator */
+ twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x20, VUSB3V1_DEV_GRP);
+ twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB3V1_TYPE);
+
+ /* turn on 1.5V regulator */
+ twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x20, VUSB1V5_DEV_GRP);
+ twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V5_TYPE);
+
+ /* turn on 1.8V regulator */
+ twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x20, VUSB1V8_DEV_GRP);
+ twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V8_TYPE);
+
+ /* disable access to power configuration registers */
+ twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, PROTECT_KEY);
+}
+
+static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
+{
+ int ret = IRQ_NONE;
+ u8 val;
+
+ /* action based on cable attach or detach */
+ if (twl4030_i2c_read_u8(TWL4030_MODULE_INT, &val, REG_PWR_EDR1) < 0) {
+ printk(KERN_ERR "twl4030_usb: i2c read failed,"
+ " line %d\n", __LINE__);
+ goto done;
+ }
+
+ if (val & USB_PRES_RISING)
+ twl4030_phy_resume();
+ else
+ twl4030_phy_suspend(0);
+
+ ret = IRQ_HANDLED;
+
+done:
+ return ret;
+}
+
+static int twl4030_set_suspend(struct otg_transceiver *x, int suspend)
+{
+ if (suspend)
+ twl4030_phy_suspend(1);
+ else
+ twl4030_phy_resume();
+
+ return 0;
+}
+
+static int twl4030_set_peripheral(struct otg_transceiver *xceiv,
+ struct usb_gadget *gadget)
+{
+ struct twl4030_usb *twl = xceiv_to_twl(xceiv);
+
+ if (!xceiv)
+ return -ENODEV;
+
+ if (!gadget) {
+ OTG_IRQ_EN_REG = 0;
+ twl4030_phy_suspend(1);
+ twl->otg.gadget = NULL;
+
+ return -ENODEV;
+ }
+
+ twl->otg.gadget = gadget;
+ twl4030_phy_resume();
+
+ OTG_CTRL_REG = (OTG_CTRL_REG & OTG_CTRL_MASK
+ & ~(OTG_XCEIV_OUTPUTS|OTG_CTRL_BITS))
+ | OTG_ID;
+
+ twl->otg.state = OTG_STATE_B_IDLE;
+
+ twl4030_usb_set_bits(twl, USB_INT_EN_RISE,
+ USB_INT_SESSVALID | USB_INT_VBUSVALID);
+ twl4030_usb_set_bits(twl, USB_INT_EN_FALL,
+ USB_INT_SESSVALID | USB_INT_VBUSVALID);
+
+ return 0;
+}
+
+static int twl4030_set_host(struct otg_transceiver *xceiv, struct usb_bus *host)
+{
+ struct twl4030_usb *twl = xceiv_to_twl(xceiv);
+
+ if (!xceiv)
+ return -ENODEV;
+
+ if (!host) {
+ OTG_IRQ_EN_REG = 0;
+ twl4030_phy_suspend(1);
+ twl->otg.host = NULL;
+
+ return -ENODEV;
+ }
+
+ twl->otg.host = host;
+ twl4030_phy_resume();
+
+ twl4030_usb_set_bits(twl, OTG_CTRL,
+ OTG_CTRL_DMPULLDOWN | OTG_CTRL_DPPULLDOWN);
+ twl4030_usb_set_bits(twl, USB_INT_EN_RISE, USB_INT_IDGND);
+ twl4030_usb_set_bits(twl, USB_INT_EN_FALL, USB_INT_IDGND);
+ twl4030_usb_set_bits(twl, FUNC_CTRL, FUNC_CTRL_SUSPENDM);
+ twl4030_usb_set_bits(twl, OTG_CTRL, OTG_CTRL_DRVVBUS);
+
+ return 0;
+}
+
+static int __init twl4030_usb_init(void)
+{
+ struct twl4030_usb *twl;
+ int status;
+
+ if (the_transceiver)
+ return 0;
+
+ twl = kzalloc(sizeof *twl, GFP_KERNEL);
+ if (!twl)
+ return 0;
+
+ the_transceiver = twl;
+
+ twl->irq = TWL4030_PWRIRQ_USB_PRES;
+ twl->otg.set_host = twl4030_set_host;
+ twl->otg.set_peripheral = twl4030_set_peripheral;
+ twl->otg.set_suspend = twl4030_set_suspend;
+
+ usb_irq_disable();
+ status = request_irq(twl->irq, twl4030_usb_irq, 0, "twl4030_usb", twl);
+ if (status < 0) {
+ printk(KERN_DEBUG "can't get IRQ %d, err %d\n",
+ twl->irq, status);
+ kfree(twl);
+ return -ENODEV;
+ }
+
+#if defined(CONFIG_TWL4030_USB_HS_ULPI)
+ hs_usb_init(twl);
+#endif
+ twl4030_usb_ldo_init(twl);
+ twl4030_phy_power(twl, 1);
+ twl4030_i2c_access(1);
+ twl4030_usb_set_mode(twl, twl->usb_mode);
+ if (twl->usb_mode == T2_USB_MODE_ULPI)
+ twl4030_i2c_access(0);
+
+ twl->asleep = 0;
+
+ if (twl->usb_mode == T2_USB_MODE_ULPI)
+ twl4030_phy_suspend(1);
+
+ otg_set_transceiver(&twl->otg);
+
+ printk(KERN_INFO "Initialized TWL4030 USB module\n");
+
+ return 0;
+}
+
+
+static void __exit twl4030_usb_exit(void)
+{
+ struct twl4030_usb *twl = the_transceiver;
+ int val;
+
+ usb_irq_disable();
+ free_irq(twl->irq, twl);
+
+ /* set transceiver mode to power on defaults */
+ twl4030_usb_set_mode(twl, -1);
+
+ /* autogate 60MHz ULPI clock,
+ * clear dpll clock request for i2c access,
+ * disable 32KHz
+ */
+ val = twl4030_usb_read(PHY_CLK_CTRL);
+ if (val >= 0) {
+ val |= PHY_CLK_CTRL_CLOCKGATING_EN;
+ val &= ~(PHY_CLK_CTRL_CLK32K_EN | REQ_PHY_DPLL_CLK);
+ twl4030_usb_write(PHY_CLK_CTRL, (u8)val);
+ }
+
+ /* disable complete OTG block */
+ twl4030_usb_clear_bits(twl, POWER_CTRL, POWER_CTRL_OTG_ENAB);
+
+ twl4030_phy_power(twl, 0);
+
+ kfree(twl);
+}
+
+subsys_initcall(twl4030_usb_init);
+module_exit(twl4030_usb_exit);
+
+MODULE_AUTHOR("Texas Instruments, Inc.");
+MODULE_DESCRIPTION("TWL4030 USB transceiver driver");
+MODULE_LICENSE("GPL");
To compile this driver as a module, choose M here: the
module will be called omap-keypad.
+config KEYBOARD_TWL4030
+ tristate "TI TWL4030 keypad support"
+ depends on TWL4030_CORE && (MACH_OMAP_2430SDP || MACH_OMAP_3430SDP)
+ help
+ Say Y here if you want to use the OMAP TWL4030 keypad.
+
+ To compile this driver as a module, choose M here: the
+ module will be called omap-twl4030keypad. This driver depends on
+ TWL4030 Core and TWL4030 GPIO I2C client driver
+
+config OMAP_PS2
+ tristate "TI OMAP Innovator 1510 PS/2 keyboard & mouse support"
+ depends on ARCH_OMAP15XX && MACH_OMAP_INNOVATOR
+ help
+ Say Y here if you want to use the OMAP Innovator 1510 PS/2
+ keyboard and mouse.
+
+ To compile this driver as a module, choose M here: the
+ module will be called innovator_ps2.
+
+config KEYBOARD_TSC2301
+ tristate "TSC2301 keypad support"
+ depends on SPI_TSC2301
+ help
+ Say Y here for if you are using the keypad features of TSC2301.
+
+config KEYBOARD_LM8323
+ tristate "LM8323 keypad chip"
+ depends on I2C
+ help
+ If you say yes here you get support for the National Semiconductor
+ LM8323 keypad controller.
+
config KEYBOARD_PXA27x
tristate "PXA27x/PXA3xx keypad support"
depends on PXA27x || PXA3xx
obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o
obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o
obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o
+obj-$(CONFIG_OMAP_PS2) += innovator_ps2.o
+obj-$(CONFIG_KEYBOARD_TSC2301) += tsc2301_kp.o
+obj-$(CONFIG_KEYBOARD_LM8323) += lm8323.o
+obj-$(CONFIG_KEYBOARD_TWL4030) += omap-twl4030keypad.o
obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keypad.o
obj-$(CONFIG_KEYBOARD_AAED2000) += aaed2000_kbd.o
obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.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 void do_hid_tasklet(unsigned long);
+DECLARE_TASKLET(hid_tasklet, do_hid_tasklet, 0);
+static struct innovator_hid_dev *hid;
+
+struct innovator_hid_dev {
+ struct input_dev *mouse, *keyboard;
+ int open;
+ int irq_enabled;
+};
+
+/****************************************************************************/
+
+/*
+ * Low-level TI Innovator/OMAP1510 FPGA HID SPI interface helper functions:
+ */
+
+static u8
+innovator_fpga_hid_rd(void)
+{
+ u8 val = inb(INNOVATOR_FPGA_HID_SPI);
+ return val;
+}
+
+static void
+innovator_fpga_hid_wr(u8 val)
+{
+ outb(val, INNOVATOR_FPGA_HID_SPI);
+}
+
+static void
+innovator_fpga_hid_frob(u8 mask, u8 val)
+{
+ unsigned long flags;
+ local_irq_save(flags);
+ innovator_fpga_hid_wr((innovator_fpga_hid_rd() & ~mask) | val);
+ local_irq_restore(flags);
+}
+
+static void
+innovator_fpga_hid_set_bits(u8 x)
+{
+ innovator_fpga_hid_frob(x, x);
+}
+
+static void
+SS(int value)
+{
+ innovator_fpga_hid_frob(OMAP1510_FPGA_HID_nSS, value ? OMAP1510_FPGA_HID_nSS : 0);
+}
+
+static void
+SCLK(int value)
+{
+ innovator_fpga_hid_frob(OMAP1510_FPGA_HID_SCLK, value ? OMAP1510_FPGA_HID_SCLK : 0);
+}
+
+static void
+MOSI(int value)
+{
+ innovator_fpga_hid_frob(OMAP1510_FPGA_HID_MOSI, value ? OMAP1510_FPGA_HID_MOSI : 0);
+}
+
+static u8
+MISO(void)
+{
+ return ((innovator_fpga_hid_rd() & OMAP1510_FPGA_HID_MISO) ? 1 : 0);
+}
+
+static u8
+ATN(void)
+{
+ return ((innovator_fpga_hid_rd() & OMAP1510_FPGA_HID_ATN) ? 1 : 0);
+}
+
+static int
+wait_for_ATN(int assert, int timeout)
+{
+ do {
+ if (ATN() == assert)
+ return 0;
+ udelay(1);
+ } while (timeout -= 1);
+ return -1;
+}
+
+static u8
+innovator_fpga_hid_xfer_byte(u8 xbyte)
+{
+ int i;
+ u8 rbyte;
+
+ for (rbyte = 0, i = 7; i >= 0; i -= 1) {
+ SCLK(0);
+ MOSI((xbyte >> i) & 1);
+ udelay(tSLOW);
+ SCLK(1);
+ rbyte = (rbyte << 1) | MISO();
+ udelay(tSLOW);
+ }
+
+ return rbyte;
+}
+
+static void
+innovator_fpga_hid_reset(void)
+{
+ innovator_fpga_hid_wr(OMAP1510_FPGA_HID_SCLK | OMAP1510_FPGA_HID_MOSI);
+ mdelay(1);
+ innovator_fpga_hid_set_bits(OMAP1510_FPGA_HID_RESETn);
+}
+
+
+/*****************************************************************************
+
+ Refer to Reference [1], Chapter 7 / Low-level communications, Serial
+ Peripheral Interface (SPI) implementation Host (master) packet
+ transmission timing, pg. 7-3, for timing and implementation details
+ for spi_xmt().
+
+ *****************************************************************************/
+
+int
+spi_xmt(u8 * p, u8 n)
+{
+ unsigned long flags;
+
+ dump_packet(p, n);
+ local_irq_save(flags);
+ disable_irq(OMAP1510_INT_FPGA_ATN);
+
+ if (ATN()) {
+ /* Oops, we have a collision. */
+ enable_irq(OMAP1510_INT_FPGA_ATN);
+ local_irq_restore(flags);
+ dbg("Protocol error: ATN is asserted\n");
+ return -EAGAIN;
+ }
+
+ SS(1);
+
+ if (wait_for_ATN(1, tMSA) < 0) {
+ SS(0);
+ enable_irq(OMAP1510_INT_FPGA_ATN);
+ local_irq_restore(flags);
+ dbg("timeout waiting for ATN assertion\n");
+ return -EREMOTEIO;
+ }
+
+ udelay(tMAC);
+
+ while (n--) {
+ innovator_fpga_hid_xfer_byte(*p++);
+ if (n) {
+ udelay(tMIB - 8 * tSCK);
+ }
+ }
+
+ MOSI(1); /* Set MOSI to idle high. */
+
+ /* NOTE: The data sheet does not specify a minimum delay
+ * here. But innovator_fpga_hid_xfer_byte() gives us a half-clock
+ * delay (tSLOW) after the last bit is sent. So I'm happy with
+ * that.
+ */
+
+ SS(0);
+
+ if (wait_for_ATN(0, tMNSA) < 0) {
+ enable_irq(OMAP1510_INT_FPGA_ATN);
+ local_irq_restore(flags);
+ dbg("timeout waiting for ATN negation\n");
+ return -EREMOTEIO;
+ }
+
+ udelay(tMNEXT);
+ enable_irq(OMAP1510_INT_FPGA_ATN);
+ local_irq_restore(flags);
+ return 0;
+}
+
+
+/*****************************************************************************
+
+ Refer to Reference [1], Chapter 7 / Low-level communications, Serial
+ Peripheral Interface (SPI) implementation, Slave packet transmission
+ timing, pg. 7-5, for timing and implementation details for spi_rcv().
+
+ *****************************************************************************/
+
+int
+spi_rcv(u8 * p, int len)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ if (len > 256) {
+ /* Limit packet size to something reasonable */
+ return -1;
+ }
+
+ local_irq_save(flags);
+
+ if (wait_for_ATN(1, tMSA) < 0) {
+ local_irq_restore(flags);
+ dbg("Protocol error: ATN is not asserted\n");
+ return -EREMOTEIO;
+ }
+
+ SS(1);
+
+ udelay(tSSC);
+
+ while (ATN()) {
+ if (ret >= len) {
+ err("over run error\n");
+ ret = -1;
+ break;
+ }
+ p[ret++] = innovator_fpga_hid_xfer_byte(0xff);
+ udelay(tSNA); /* Wait long enough to detect negation of ATN
+ * after last clock pulse of packet.
+ *
+ * NOTE: Normally, we need a minimum delay of
+ * tSIB between the start of one byte
+ * and the start of the next. However,
+ * we also need to wait long enough
+ * for the USAR to negate ATN before
+ * starting the next byte. So we use
+ * max(tSIB - 8 * tSCK, tSNA) here to
+ * satisfy both constraints.
+ */
+ }
+
+ SS(0); /* NOTE: The data sheet does not specify a minimum delay
+ * here. But innovator_fpga_hid_xfer_byte() gives us a
+ * half-clock delay (tSLOW) after the last bit is sent. So
+ * I'm happy with that (rather than no delay at all : ).
+ */
+
+
+ udelay(tSNEXT); /* This isn't quite right. Assertion of ATN after
+ * negation of SS is an USAR timing constraint.
+ * What we need here is a spec for the minimum
+ * delay from SS negation to SS assertion. But
+ * for now, just use this brain dead delay.
+ */
+
+ local_irq_restore(flags);
+
+ if (ret > 0) {
+ dump_packet(p, ret);
+ }
+
+ return ret;
+}
+
+
+/*****************************************************************************
+ Calculate Host/Controller Command/Response Longitudinal Redundancy Check (LRC)
+
+ The algorithm implemented in calculate_LRC() below is taken directly from
+ the reference [1], Chapter 7 / Low-level communications, LRC (Longitudinal
+ Redundancy Check), pg 5-10.
+
+ *****************************************************************************/
+
+static u8
+calculate_LRC(u8 * p, int n)
+{
+ u8 LRC;
+ int i;
+
+ /*
+ * Init the LRC using the first two message bytes.
+ */
+ LRC = p[0] ^ p[1];
+
+ /*
+ * Update the LRC using the remainder of the p.
+ */
+ for (i = 2; i < n; i++)
+ LRC ^= p[i];
+
+ /*
+ * If the MSB is set then clear the MSB and change the next
+ * most significant bit
+ */
+ if (LRC & 0x80)
+ LRC ^= 0xC0;
+
+ return LRC;
+}
+
+
+/*
+ * Controller response helper functions:
+ */
+
+static inline int
+report_mouse(mse_report_t * p, int n)
+{
+ if (p->header != POINTING_REPORT)
+ return -E_BAD_HEADER;
+
+ if (n != sizeof(mse_report_t))
+ return -E_PKT_SZ;
+
+ return (p->LRC != calculate_LRC((u8 *) p, sizeof(mse_report_t) - 1)) ?
+ -E_BAD_LRC : POINTING_REPORT;
+}
+
+static inline int
+report_keyboard(kdb_report_t * p, int n)
+{
+ if (p->header != KEYBOARD_REPORT)
+ return -E_BAD_HEADER;
+
+ if (n != sizeof(kdb_report_t))
+ return -E_PKT_SZ;
+
+ return (p->LRC != calculate_LRC((u8 *) p, sizeof(kdb_report_t) - 1)) ?
+ -E_BAD_LRC : KEYBOARD_REPORT;
+}
+
+
+/*
+ * Miscellaneous helper functions:
+ */
+
+static inline int
+report_type(u8 * type)
+{
+ /* check the header to find out what kind of report it is */
+ if ((*type) == KEYBOARD_REPORT)
+ return KEYBOARD_REPORT;
+ else if ((*type) == POINTING_REPORT)
+ return POINTING_REPORT;
+ else
+ return -E_BAD_HEADER;
+}
+
+static inline int
+report_async(void * p, int n)
+{
+ int ret;
+
+ if ((ret = spi_rcv((u8 *) p, n)) < 0)
+ return ret;
+
+ if (report_type((u8 *) p) == POINTING_REPORT)
+ ret = report_mouse((mse_report_t *) p, ret);
+ else if (report_type((u8 *) p) == KEYBOARD_REPORT)
+ ret = report_keyboard((kdb_report_t *) p, ret);
+
+ return ret;
+}
+
+/*
+ * Host command helper functions:
+ */
+
+#if 0
+/* REVISIT/TODO: Wrapper for command/response with resend handing. */
+static int
+spi_xfer(u8 * optr, u8 osz, u8 * iptr, u8 isz)
+{
+ static u8 buf[256];
+ int ret;
+ int xretries = 3;
+
+ do {
+ if (optr != NULL && osz) {
+ do {
+ ret = spi_xmt((u8 *) optr, osz);
+ } while (ret < 0);
+ }
+
+ ret = spi_rcv((u8 *) buf, 256);
+
+ if (ret == -EREMOTEIO) {
+ if (iptr == NULL) {
+ break;
+ }
+ }
+ } while (xretries--);
+
+ return ret;
+}
+#endif
+
+/* REVISIT: Enable these when/if additional Juno features are required. */
+static inline int
+simple(u8 cmd)
+{
+ static simple_t p;
+ int ret;
+
+ p.header = SIMPLE;
+ p.cmd_code = cmd;
+ p.LRC = calculate_LRC((u8 *) & p, sizeof(p) - 1);
+
+ if ((ret = spi_xmt((u8 *) & p, sizeof(p))) < 0)
+ return ret;
+
+ if ((ret = spi_rcv((u8 *) & p, sizeof(p))) < 0)
+ return ret;
+
+ if (ret == 0)
+ return -E_ZERO_BYTES;
+
+ if (ret != sizeof(p))
+ return -E_PKT_SZ;
+
+ if (p.header != SIMPLE)
+ return -E_BAD_HEADER;
+
+ if (p.LRC != calculate_LRC((u8 *) & p, sizeof(p) - 1))
+ return -E_BAD_LRC;
+
+ /* REVISIT: Need to check or return response code here? */
+}
+
+static inline int
+write_bit(u8 offset, u8 bit, u8 value)
+{
+ static write_bit_t p;
+
+ p.header = WRITE_REGISTER_BIT;
+ p.offset = offset;
+ p.value_bit = (bit << 1) | (value & 1);
+ p.LRC = calculate_LRC((u8 *) & p, sizeof(p) - 1);
+
+ return spi_xmt((u8 *) & p, sizeof(p));
+}
+
+static inline int
+read_bit(u8 offset, u8 bit, u8 * data)
+{
+ static read_bit_t p;
+ static report_bit_t q;
+ int ret;
+
+ p.header = READ_REGISTER_BIT;
+ p.offset = offset;
+ p.bit = bit;
+ p.LRC = calculate_LRC((u8 *) & p, sizeof(p) - 1);
+
+ if ((ret = spi_xmt((u8 *) & p, sizeof(p))) < 0)
+ return ret;
+
+ if ((ret = spi_rcv((u8 *) & q, sizeof(q))) < 0)
+ return ret;
+
+ if (ret == 0)
+ return -E_ZERO_BYTES;
+
+ if (ret != sizeof(q))
+ return -E_PKT_SZ;
+
+ if (q.header != REPORT_REGISTER_BIT)
+ return -E_BAD_HEADER;
+
+ if (q.LRC != calculate_LRC((u8 *) & q, sizeof(q) - 1))
+ return -E_BAD_LRC;
+
+ *data = q.value_bit;
+
+ return 0;
+}
+
+static inline int
+write_reg(u8 offset, u8 value)
+{
+ static write_reg_t p;
+
+ p.header = WRITE_REGISTER;
+ p.offset = offset;
+ p.value = value;
+ p.LRC = calculate_LRC((u8 *) & p, sizeof(p) - 1);
+
+ return spi_xmt((u8 *) & p, sizeof(p));
+}
+
+static inline int
+read_reg(u8 offset, u8 * data)
+{
+ static read_reg_t p;
+ static report_reg_t q;
+ int ret;
+
+ p.header = READ_REGISTER;
+ p.offset = offset;
+ p.LRC = calculate_LRC((u8 *) & p, sizeof(p) - 1);
+
+ if ((ret = spi_xmt((u8 *) & p, sizeof(p))) < 0)
+ return ret;
+
+ if ((ret = spi_rcv((u8 *) & q, sizeof(q))) < 0)
+ return ret;
+
+ if (ret == 0)
+ return -E_ZERO_BYTES;
+
+ if (ret != sizeof(q))
+ return -E_PKT_SZ;
+
+ if (q.header != REPORT_REGISTER)
+ return -E_BAD_HEADER;
+
+ if (q.LRC != calculate_LRC((u8 *) & q, sizeof(q) - 1))
+ return -E_BAD_LRC;
+
+ *data = q.value;
+
+ return 0;
+}
+
+static inline int
+write_block(u8 offset, u8 length, u8 * block)
+{
+ static write_block_t p;
+
+ p.header = WRITE_BLOCK;
+ p.offset = offset;
+ p.length = length;
+ memcpy(&p.block, block, length);
+ p.block[length] = calculate_LRC((u8 *) & p, 3 + length);
+
+ return spi_xmt((u8 *) & p, 4 + length);
+}
+
+static inline int
+read_block(u8 offset, u8 length, u8 * buf)
+{
+ static read_block_t p;
+ static report_block_t q;
+ int ret;
+
+ p.header = READ_BLOCK;
+ p.offset = offset;
+ p.length = length;
+ p.LRC = calculate_LRC((u8 *) & p, sizeof(p) - 1);
+
+ if ((ret = spi_xmt((u8 *) & p, sizeof(p))) < 0)
+ return ret;
+
+ if ((ret = spi_rcv((u8 *) & q, sizeof(q))) < 0)
+ return ret;
+
+ if (ret == 0)
+ return -E_ZERO_BYTES;
+
+ if (ret != sizeof(4 + q.length))
+ return -E_PKT_SZ;
+
+ if (q.header != REPORT_BLOCK)
+ return -E_BAD_HEADER;
+
+ if (q.block[q.length] != calculate_LRC((u8 *) & q, 3 + q.length))
+ return -E_BAD_LRC;
+
+ if (length != q.length)
+ return -E_PKT_SZ;
+
+ memcpy(buf, &q.block, length);
+
+ return 0;
+}
+
+#ifdef INNOVATOR_KEYB_DEBUG
+static void
+ctrl_dump_regs(void)
+{
+ int i;
+ int n;
+
+ for (i = 0; i < 256; i += 8) {
+ read_block(i, 16, buffer);
+ mdelay(1);
+ }
+}
+#endif
+
+/*****************************************************************************/
+
+static void
+process_pointing_report(struct innovator_hid_dev *hid, u8 * buffer)
+{
+ static int prev_x, prev_y, prev_btn;
+ int x, y, btn;
+ hid->keyboard = input_allocate_device();
+ hid->mouse = input_allocate_device();
+
+ if (buffer[1] & (1 << 3)) {
+ /* relative pointing device report */
+ x = buffer[2];
+ y = buffer[3];
+
+ /* check the sign and convert from 2's complement if negative */
+ if (buffer[1] & (1<<4))
+ x = ~(-x) - 255;
+
+ /* input driver wants -y */
+ if (buffer[1] & (1<<5))
+ y = -(~(-y) - 255);
+ else
+ y = -y;
+
+ input_report_key(hid->mouse,
+ BTN_LEFT, buffer[1] & (1<<0));
+ input_report_key(hid->mouse,
+ BTN_RIGHT, buffer[1] & (1<<1));
+ input_report_key(hid->mouse,
+ BTN_MIDDLE, buffer[1] & (1<<2));
+ input_report_rel(hid->mouse, REL_X, x);
+ input_report_rel(hid->mouse, REL_Y, y);
+ } else {
+ /* REVISIT: Does this work? */
+ /* absolute pointing device report */
+ x = buffer[2] + ((buffer[1] & X_MSB_MASK) << X_MSB_SHIFT);
+ y = buffer[3] + ((buffer[1] & Y_MSB_MASK) << Y_MSB_SHIFT);
+ btn = buffer[1] & (1<<0);
+
+ if ((prev_x == x) && (prev_y == y)
+ && (prev_btn == btn))
+ return;
+
+ input_report_key(hid->mouse, BTN_LEFT, btn);
+ input_report_abs(hid->mouse, ABS_X, x);
+ input_report_abs(hid->mouse, ABS_Y, y);
+ prev_x = x;
+ prev_y = y;
+ prev_btn = btn;
+ }
+ input_sync(hid->mouse);
+ dbg("HID X: %d Y: %d Functions: %x\n", x, y, buffer[1]);
+}
+
+/*
+ * Reference [1], Appendix A, Semtech standard PS/2 key number definitions,
+ * pgs. A-1 through A-3. The following table lists standard PS/2 key numbers
+ * used by the Juno® 01 keyboard manager.
+ *
+ * NOTES:
+ * 1. The following table indices are E0 codes which require special handling:
+ * 53..62, 77..78, 94, 96, 100, 102..104, 108..110
+ * 2. The following table indices are E1 codes which require special handling:
+ * 101
+ */
+
+static unsigned char usar2scancode[128] = {
+ 0x00, 0x29, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x2b, 0x1e, 0x1f, 0x20,
+ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+ 0x1c, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32,
+ 0x33, 0x34, 0x35, 0x39, 0x01, 0x52, 0x53, 0x4b,
+ 0x47, 0x4f, 0x48, 0x50, 0x49, 0x51, 0x4d, 0x37,
+ 0x4e, 0x4f, 0x50, 0x51, 0x4b, 0x4c, 0x4d, 0x47,
+ 0x48, 0x49, 0x52, 0x53, 0x4a, 0x1c, 0x35, 0x3b,
+ 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43,
+ 0x44, 0x57, 0x58, 0x2a, 0x36, 0x38, 0x38, 0x1d,
+ 0x1d, 0x3a, 0x45, 0x46, 0x2a, 0x1d, 0x5b, 0x5c,
+ 0x5d, 0xff, 0x00, 0x00, 0x5e, 0x5f, 0x63, 0x70,
+ 0x7b, 0x79, 0x7d, 0x73, 0x5b, 0x5c, 0x5d, 0x63,
+ 0x65, 0x66, 0x68, 0x69, 0x6b, 0x56, 0x54, 0x00
+};
+
+/*
+ * The following are bit masks used to encode E0 scan codes which
+ * require special handling. However, scan codes 100 and 101 are
+ * excludable here since they each require unique multi-byte scan
+ * code translations and are therefore dealt with individually via
+ * handle_print_scr() and handle_pause() respectively below.
+ */
+
+static unsigned long int e0_codes1 = 0x030003ff; /* scan codes 53..84 */
+static unsigned long int e0_codes2 = 0x038e0a00; /* scan codes 85..116 */
+
+static void
+handle_print_scr(int up)
+{
+ if (up) {
+ input_report_key(hid->keyboard, 0xe0, 1);
+ input_report_key(hid->keyboard, 0xb7, 1);
+ input_report_key(hid->keyboard, 0xe0, 1);
+ input_report_key(hid->keyboard, 0xaa, 1);
+ } else {
+ input_report_key(hid->keyboard, 0xe0, 0);
+ input_report_key(hid->keyboard, 0x2a, 0);
+ input_report_key(hid->keyboard, 0xe0, 0);
+ input_report_key(hid->keyboard, 0x37, 0);
+ }
+}
+
+static void
+handle_pause(void)
+{
+ input_report_key(hid->keyboard, 0xe1, 0);
+ input_report_key(hid->keyboard, 0x1d, 0);
+ input_report_key(hid->keyboard, 0x45, 0);
+ input_report_key(hid->keyboard, 0xe1, 0);
+ input_report_key(hid->keyboard, 0x9d, 0);
+ input_report_key(hid->keyboard, 0xc5, 0);
+}
+
+static void
+process_keyboard_report(struct innovator_hid_dev *hid, u8 * buffer)
+{
+ unsigned char ch = buffer[1] & 0x7f;
+ int up = buffer[1] & 0x80 ? 1 : 0;
+ int is_e0 = 0;
+ hid->keyboard = input_allocate_device();
+ hid->mouse = input_allocate_device();
+
+ if ((ch == 106) || (ch == 107))
+ return; /* no code */
+
+ if (ch == 100) {
+ handle_print_scr(up);
+ return;
+ }
+
+ if (ch == 101) {
+ handle_pause();
+ return;
+ }
+
+ if ((ch >= 53) && (ch <= 84)) {
+ /* first block of e0 codes */
+ is_e0 = e0_codes1 & (1 << (ch - 53));
+ } else if ((ch >= 85) && (ch <= 116)) {
+ /* second block of e0 codes */
+ is_e0 = e0_codes2 & (1 << (ch - 85));
+ }
+
+ if (is_e0) {
+ input_report_key(hid->keyboard, 0xe0, !up);
+ }
+ input_report_key(hid->keyboard, usar2scancode[ch], !up);
+ input_sync(hid->keyboard);
+}
+
+static irqreturn_t
+innovator_hid_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ if (ATN()) {
+ disable_irq(OMAP1510_INT_FPGA_ATN);
+ tasklet_schedule(&hid_tasklet);
+ }
+ return IRQ_HANDLED;
+}
+
+static void
+do_hid_tasklet(unsigned long unused)
+{
+ int ret;
+ if ((ret = report_async(buffer, 256)) == -1) {
+ dbg("Error: Bad Juno return value: %d\n", ret);
+ } else if (ret == KEYBOARD_REPORT) {
+ process_keyboard_report(hid, buffer);
+ } else if (ret == POINTING_REPORT) {
+ process_pointing_report(hid, buffer);
+ } else {
+ dbg("ERROR: bad report\n");
+ }
+ enable_irq(OMAP1510_INT_FPGA_ATN);
+}
+
+static int
+innovator_hid_open(struct input_dev *dev)
+{
+ if (hid->open++)
+ return 0;
+
+ if (request_irq(OMAP1510_INT_FPGA_ATN, (void *) innovator_hid_interrupt,
+ IRQF_DISABLED, PFX, hid) < 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+static void
+innovator_hid_close(struct input_dev *dev)
+{
+ if (!--hid->open)
+ return;
+
+ if (hid == NULL)
+ return;
+
+ kfree(hid);
+}
+
+static int innovator_ps2_remove(struct device *dev)
+{
+ return 0;
+}
+
+static void innovator_ps2_device_release(struct device *dev)
+{
+ /* Nothing */
+}
+
+static int innovator_ps2_suspend(struct device *dev, pm_message_t state)
+{
+ u8 pmcomm = 0;
+
+ /*
+ * Set SUS_STATE in REG_PM_COMM (Page 0 R0). This will cause
+ * PM_MOD bits of REG_PM_STATUS to show suspended state,
+ * but the SUS_STAT bit of REG_PM_STATUS will continue to
+ * reflect the state of the _HSUS pin.
+ */
+
+ if (write_reg(REG_PAGENO, 0) < 0)
+ printk("ps2 suspend: write_reg REG_PAGENO error\n");
+
+ if (read_reg(REG_PM_COMM, &pmcomm) < 0)
+ printk("ps2 suspend: read_reg REG_PM_COMM error\n");
+
+ if (write_reg(REG_PM_COMM, pmcomm | SUS_STATE) < 0)
+ printk("ps2 suspend: write_reg REG_PM_COMM error\n");
+
+ return 0;
+}
+
+static int innovator_ps2_resume(struct device *dev)
+{
+ u8 pmcomm = 0;
+
+ /*
+ * Clear SUS_STATE from REG_PM_COMM (Page 0 R0).
+ */
+
+ if (write_reg(REG_PAGENO, 0) < 0)
+ printk("ps2 resume: write_reg REG_PAGENO error\n");
+
+ if (read_reg(REG_PM_COMM, &pmcomm) < 0)
+ printk("ps2 resume: read_reg REG_PM_COMM error\n");
+
+ if (write_reg(REG_PM_COMM, pmcomm & ~SUS_STATE) < 0)
+ printk("ps2 resume: write_reg REG_PM_COMM error\n");
+
+ return 0;
+}
+
+static struct device_driver innovator_ps2_driver = {
+ .name = "innovator_ps2",
+ .bus = &platform_bus_type,
+ .remove = innovator_ps2_remove,
+ .suspend = innovator_ps2_suspend,
+ .resume = innovator_ps2_resume,
+};
+
+static struct platform_device innovator_ps2_device = {
+ .name = "ps2",
+ .id = -1,
+ .dev = {
+ .driver = &innovator_ps2_driver,
+ .release = innovator_ps2_device_release,
+ },
+};
+
+static int __init
+innovator_kbd_init(void)
+{
+ int i;
+ info("Innovator PS/2 keyboard/mouse driver v1.0\n");
+
+ innovator_fpga_hid_reset();
+
+ if ((hid = kmalloc(sizeof(struct innovator_hid_dev),
+ GFP_KERNEL)) == NULL) {
+ warn("unable to allocate space for HID device\n");
+ return -ENOMEM;
+ }
+
+ /* setup the mouse */
+ memset(hid, 0, sizeof(struct innovator_hid_dev));
+ hid->mouse = input_allocate_device();
+ hid->mouse->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+ hid->mouse->keybit[BIT_WORD(BTN_MOUSE)] =
+ BIT(BTN_LEFT) | BIT(BTN_RIGHT) |
+ BIT(BTN_MIDDLE) | BIT(BTN_TOUCH);
+ hid->mouse->relbit[0] = BIT(REL_X) | BIT(REL_Y);
+ hid->mouse->private = hid;
+ hid->mouse->open = innovator_hid_open;
+ hid->mouse->close = innovator_hid_close;
+ hid->mouse->name = "innovator_mouse";
+ hid->mouse->id.bustype = 0;
+ hid->mouse->id.vendor = 0;
+ hid->mouse->id.product = 0;
+ hid->mouse->id.version = 0;
+ hid->keyboard = input_allocate_device();
+ hid->keyboard->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+ hid->keyboard->keycodesize = sizeof(unsigned char);
+ hid->keyboard->keycodemax = ARRAY_SIZE(usar2scancode);
+ for(i = 0; i < 128; i++)
+ set_bit(usar2scancode[i], hid->keyboard->keybit);
+ hid->keyboard->private = hid;
+ hid->keyboard->open = innovator_hid_open;
+ hid->keyboard->close = innovator_hid_close;
+ hid->keyboard->name = "innovator_keyboard";
+ hid->keyboard->id.bustype = 0;
+ hid->keyboard->id.vendor = 0;
+ hid->keyboard->id.product = 0;
+ hid->keyboard->id.version = 0;
+ input_register_device(hid->mouse);
+ input_register_device(hid->keyboard);
+ innovator_hid_open(hid->mouse);
+ innovator_hid_open(hid->keyboard);
+
+ if (driver_register(&innovator_ps2_driver) != 0)
+ printk(KERN_ERR "Driver register failed for innovator_ps2\n");
+
+ if (platform_device_register(&innovator_ps2_device) != 0) {
+ printk(KERN_ERR "Device register failed for ps2\n");
+ driver_unregister(&innovator_ps2_driver);
+ }
+
+#ifdef INNOVATOR_KEYB_DEBUG
+ ctrl_dump_regs();
+#endif
+ return 0;
+}
+
+static void __exit
+innovator_kbd_exit(void)
+{
+ input_unregister_device(hid->mouse);
+ input_unregister_device(hid->keyboard);
+ free_irq(OMAP1510_INT_FPGA_ATN, hid);
+ if (hid != NULL)
+ kfree(hid);
+ driver_unregister(&innovator_ps2_driver);
+ platform_device_unregister(&innovator_ps2_device);
+ return;
+}
+
+module_init(innovator_kbd_init);
+module_exit(innovator_kbd_exit);
+
+MODULE_AUTHOR("George G. Davis <gdavis@mvista.com>");
+MODULE_DESCRIPTION("Innovator PS/2 Driver");
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * drivers/i2c/chips/lm8323.c
+ *
+ * Copyright (C) 2007 Nokia Corporation
+ *
+ * Written by Daniel Stone <daniel.stone@nokia.com>
+ * Timo O. Karjalainen <timo.o.karjalainen@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 (version 2 of the License only).
+ *
+ * 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 <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/leds.h>
+#include <linux/i2c/lm8323.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/irq.h>
+
+#ifdef VERBOSE
+#define debug dev_dbg
+#else
+#define debug(...)
+#endif
+
+/* Commands to send to the chip. */
+#define LM8323_CMD_READ_ID 0x80 /* Read chip ID. */
+#define LM8323_CMD_WRITE_CFG 0x81 /* Set configuration item. */
+#define LM8323_CMD_READ_INT 0x82 /* Get interrupt status. */
+#define LM8323_CMD_RESET 0x83 /* Reset, same as external one */
+#define LM8323_CMD_WRITE_PORT_SEL 0x85 /* Set GPIO in/out. */
+#define LM8323_CMD_WRITE_PORT_STATE 0x86 /* Set GPIO pullup. */
+#define LM8323_CMD_READ_PORT_SEL 0x87 /* Get GPIO in/out. */
+#define LM8323_CMD_READ_PORT_STATE 0x88 /* Get GPIO pullup. */
+#define LM8323_CMD_READ_FIFO 0x89 /* Read byte from FIFO. */
+#define LM8323_CMD_RPT_READ_FIFO 0x8a /* Read FIFO (no increment). */
+#define LM8323_CMD_SET_ACTIVE 0x8b /* Set active time. */
+#define LM8323_CMD_READ_ERR 0x8c /* Get error status. */
+#define LM8323_CMD_READ_ROTATOR 0x8e /* Read rotator status. */
+#define LM8323_CMD_SET_DEBOUNCE 0x8f /* Set debouncing time. */
+#define LM8323_CMD_SET_KEY_SIZE 0x90 /* Set keypad size. */
+#define LM8323_CMD_READ_KEY_SIZE 0x91 /* Get keypad size. */
+#define LM8323_CMD_READ_CFG 0x92 /* Get configuration item. */
+#define LM8323_CMD_WRITE_CLOCK 0x93 /* Set clock config. */
+#define LM8323_CMD_READ_CLOCK 0x94 /* Get clock config. */
+#define LM8323_CMD_PWM_WRITE 0x95 /* Write PWM script. */
+#define LM8323_CMD_START_PWM 0x96 /* Start PWM engine. */
+#define LM8323_CMD_STOP_PWM 0x97 /* Stop PWM engine. */
+
+/* Interrupt status. */
+#define INT_KEYPAD 0x01 /* Key event. */
+#define INT_ROTATOR 0x02 /* Rotator event. */
+#define INT_ERROR 0x08 /* Error: use CMD_READ_ERR. */
+#define INT_NOINIT 0x10 /* Lost configuration. */
+#define INT_PWM1 0x20 /* PWM1 stopped. */
+#define INT_PWM2 0x40 /* PWM2 stopped. */
+#define INT_PWM3 0x80 /* PWM3 stopped. */
+
+/* Errors (signalled by INT_ERROR, read with CMD_READ_ERR). */
+#define ERR_BADPAR 0x01 /* Bad parameter. */
+#define ERR_CMDUNK 0x02 /* Unknown command. */
+#define ERR_KEYOVR 0x04 /* Too many keys pressed. */
+#define ERR_FIFOOVER 0x40 /* FIFO overflow. */
+
+/* Configuration keys (CMD_{WRITE,READ}_CFG). */
+#define CFG_MUX1SEL 0x01 /* Select MUX1_OUT input. */
+#define CFG_MUX1EN 0x02 /* Enable MUX1_OUT. */
+#define CFG_MUX2SEL 0x04 /* Select MUX2_OUT input. */
+#define CFG_MUX2EN 0x08 /* Enable MUX2_OUT. */
+#define CFG_PSIZE 0x20 /* Package size (must be 0). */
+#define CFG_ROTEN 0x40 /* Enable rotator. */
+
+/* Clock settings (CMD_{WRITE,READ}_CLOCK). */
+#define CLK_RCPWM_INTERNAL 0x00
+#define CLK_RCPWM_EXTERNAL 0x03
+#define CLK_SLOWCLKEN 0x08 /* Enable 32.768kHz clock. */
+#define CLK_SLOWCLKOUT 0x40 /* Enable slow pulse output. */
+
+/* The possible addresses corresponding to CONFIG1 and CONFIG2 pin wirings. */
+#define LM8323_I2C_ADDR00 (0x84 >> 1) /* 1000 010x */
+#define LM8323_I2C_ADDR01 (0x86 >> 1) /* 1000 011x */
+#define LM8323_I2C_ADDR10 (0x88 >> 1) /* 1000 100x */
+#define LM8323_I2C_ADDR11 (0x8A >> 1) /* 1000 101x */
+
+/* Key event fifo length */
+#define LM8323_FIFO_LEN 15
+
+/* Commands for PWM engine; feed in with PWM_WRITE. */
+/* Load ramp counter from duty cycle field (range 0 - 0xff). */
+#define PWM_SET(v) (0x4000 | ((v) & 0xff))
+/* Go to start of script. */
+#define PWM_GOTOSTART 0x0000
+/*
+ * Stop engine (generates interrupt). If reset is 1, clear the program
+ * counter, else leave it.
+ */
+#define PWM_END(reset) (0xc000 | (!!(reset) << 11))
+/*
+ * Ramp. If s is 1, divide clock by 512, else divide clock by 16.
+ * Take t clock scales (up to 63) per step, for n steps (up to 126).
+ * If u is set, ramp up, else ramp down.
+ */
+#define PWM_RAMP(s, t, n, u) ((!!(s) << 14) | ((t) & 0x3f) << 8 | \
+ ((n) & 0x7f) | ((u) ? 0 : 0x80))
+/*
+ * Loop (i.e. jump back to pos) for a given number of iterations (up to 63).
+ * If cnt is zero, execute until PWM_END is encountered.
+ */
+#define PWM_LOOP(cnt, pos) (0xa000 | (((cnt) & 0x3f) << 7) | \
+ ((pos) & 0x3f))
+/*
+ * Wait for trigger. Argument is a mask of channels, shifted by the channel
+ * number, e.g. 0xa for channels 3 and 1. Note that channels are numbered
+ * from 1, not 0.
+ */
+#define PWM_WAIT_TRIG(chans) (0xe000 | (((chans) & 0x7) << 6))
+/* Send trigger. Argument is same as PWM_WAIT_TRIG. */
+#define PWM_SEND_TRIG(chans) (0xe000 | ((chans) & 0x7))
+
+#define DRIVER_NAME "lm8323"
+
+struct lm8323_pwm {
+ int id;
+ int enabled;
+ int fade_time;
+ int brightness;
+ int desired_brightness;
+ struct work_struct work;
+ struct led_classdev cdev;
+};
+
+struct lm8323_chip {
+ struct mutex lock;
+ struct i2c_client *client;
+ struct work_struct work;
+ struct input_dev *idev;
+ int irq;
+ unsigned kp_enabled : 1;
+ unsigned pm_suspend : 1;
+ unsigned keys_down;
+ char phys[32];
+ s16 keymap[LM8323_KEYMAP_SIZE];
+ int size_x;
+ int size_y;
+ int debounce_time;
+ int active_time;
+ struct lm8323_pwm pwm1;
+ struct lm8323_pwm pwm2;
+ struct lm8323_pwm pwm3;
+};
+
+#define client_to_lm8323(c) container_of(c, struct lm8323_chip, client)
+#define dev_to_lm8323(d) container_of(d, struct lm8323_chip, client->dev)
+#define work_to_lm8323(w) container_of(w, struct lm8323_chip, work)
+#define cdev_to_pwm(c) container_of(c, struct lm8323_pwm, cdev)
+#define work_to_pwm(w) container_of(w, struct lm8323_pwm, work)
+
+static struct lm8323_chip *pwm_to_lm8323(struct lm8323_pwm *pwm)
+{
+ switch (pwm->id) {
+ case 1:
+ return container_of(pwm, struct lm8323_chip, pwm1);
+ case 2:
+ return container_of(pwm, struct lm8323_chip, pwm2);
+ case 3:
+ return container_of(pwm, struct lm8323_chip, pwm3);
+ default:
+ return NULL;
+ }
+}
+
+static struct lm8323_platform_data *lm8323_pdata;
+
+
+#define LM8323_MAX_DATA 8
+
+/*
+ * To write, we just access the chip's address in write mode, and dump the
+ * command and data out on the bus. The command byte and data are taken as
+ * sequential u8s out of varargs, to a maximum of LM8323_MAX_DATA.
+ */
+static int lm8323_write(struct lm8323_chip *lm, int len, ...)
+{
+ int ret, i;
+ va_list ap;
+ u8 data[LM8323_MAX_DATA];
+
+ va_start(ap, len);
+
+ if (unlikely(len > LM8323_MAX_DATA)) {
+ dev_err(&lm->client->dev, "tried to send %d bytes\n", len);
+ va_end(ap);
+ return 0;
+ }
+
+ for (i = 0; i < len; i++)
+ data[i] = va_arg(ap, int);
+
+ va_end(ap);
+
+ /*
+ * If the host is asleep while we send the data, we can get a NACK
+ * back while it wakes up, so try again, once.
+ */
+ ret = i2c_master_send(lm->client, data, len);
+ if (unlikely(ret == -EREMOTEIO))
+ ret = i2c_master_send(lm->client, data, len);
+ if (unlikely(ret != len))
+ dev_err(&lm->client->dev, "sent %d bytes of %d total\n",
+ len, ret);
+
+ return ret;
+}
+
+/*
+ * To read, we first send the command byte to the chip and end the transaction,
+ * then access the chip in read mode, at which point it will send the data.
+ */
+static int lm8323_read(struct lm8323_chip *lm, u8 cmd, u8 *buf, int len)
+{
+ int ret;
+
+ /*
+ * If the host is asleep while we send the byte, we can get a NACK
+ * back while it wakes up, so try again, once.
+ */
+ ret = i2c_master_send(lm->client, &cmd, 1);
+ if (unlikely(ret == -EREMOTEIO))
+ ret = i2c_master_send(lm->client, &cmd, 1);
+ if (unlikely(ret != 1)) {
+ dev_err(&lm->client->dev, "sending read cmd 0x%02x failed\n",
+ cmd);
+ return 0;
+ }
+
+ ret = i2c_master_recv(lm->client, buf, len);
+ if (unlikely(ret != len))
+ dev_err(&lm->client->dev, "wanted %d bytes, got %d\n",
+ len, ret);
+
+ return ret;
+}
+
+/*
+ * Set the chip active time (idle time before it enters halt).
+ */
+static void lm8323_set_active_time(struct lm8323_chip *lm, int time)
+{
+ lm8323_write(lm, 2, LM8323_CMD_SET_ACTIVE, time >> 2);
+}
+
+/*
+ * The signals are AT-style: the low 7 bits are the keycode, and the top
+ * bit indicates the state (1 for down, 0 for up).
+ */
+static inline u8 lm8323_whichkey(u8 event)
+{
+ return event & 0x7f;
+}
+
+static inline int lm8323_ispress(u8 event)
+{
+ return (event & 0x80) ? 1 : 0;
+}
+
+static void process_keys(struct lm8323_chip *lm)
+{
+ u8 event;
+ u8 key_fifo[LM8323_FIFO_LEN + 1];
+ int old_keys_down = lm->keys_down;
+ int ret;
+ int i = 0;
+
+ /*
+ * Read all key events from the FIFO at once. Next READ_FIFO clears the
+ * FIFO even if we didn't read all events previously.
+ */
+ ret = lm8323_read(lm, LM8323_CMD_READ_FIFO, key_fifo, LM8323_FIFO_LEN);
+
+ if (ret < 0) {
+ dev_err(&lm->client->dev, "Failed reading fifo \n");
+ return;
+ }
+ key_fifo[ret] = 0;
+
+ while ((event = key_fifo[i])) {
+ u8 key = lm8323_whichkey(event);
+ int isdown = lm8323_ispress(event);
+ s16 keycode = lm->keymap[key];
+
+ if (likely(keycode > 0)) {
+ debug(&lm->client->dev, "key 0x%02x %s\n", key,
+ isdown ? "down" : "up");
+ if (likely(lm->kp_enabled)) {
+ input_report_key(lm->idev, keycode, isdown);
+ input_sync(lm->idev);
+ }
+ if (isdown)
+ lm->keys_down++;
+ else
+ lm->keys_down--;
+ } else {
+ dev_err(&lm->client->dev, "keycode 0x%02x not mapped "
+ "to any key\n", key);
+ }
+ i++;
+ }
+
+ /*
+ * Errata: We need to ensure that the chip never enters halt mode
+ * during a keypress, so set active time to 0. When it's released,
+ * we can enter halt again, so set the active time back to normal.
+ */
+ if (!old_keys_down && lm->keys_down)
+ lm8323_set_active_time(lm, 0);
+ if (old_keys_down && !lm->keys_down)
+ lm8323_set_active_time(lm, lm->active_time);
+}
+
+static void lm8323_process_error(struct lm8323_chip *lm)
+{
+ u8 error;
+
+ if (lm8323_read(lm, LM8323_CMD_READ_ERR, &error, 1) == 1) {
+ if (error & ERR_FIFOOVER)
+ debug(&lm->client->dev, "fifo overflow!\n");
+ if (error & ERR_KEYOVR)
+ debug(&lm->client->dev, "more than two keys pressed\n");
+ if (error & ERR_CMDUNK)
+ debug(&lm->client->dev, "unknown command submitted\n");
+ if (error & ERR_BADPAR)
+ debug(&lm->client->dev, "bad command parameter\n");
+ }
+}
+
+static void lm8323_reset(struct lm8323_chip *lm)
+{
+ /* The docs say we must pass 0xAA as the data byte. */
+ lm8323_write(lm, 2, LM8323_CMD_RESET, 0xAA);
+}
+
+static int lm8323_configure(struct lm8323_chip *lm)
+{
+ int keysize = (lm->size_x << 4) | lm->size_y;
+ int clock = (CLK_SLOWCLKEN | CLK_RCPWM_EXTERNAL);
+ int debounce = lm->debounce_time >> 2;
+ int active = lm->active_time >> 2;
+
+ /*
+ * Active time must be greater than the debounce time: if it's
+ * a close-run thing, give ourselves a 12ms buffer.
+ */
+ if (debounce >= active)
+ active = debounce + 3;
+
+ lm8323_write(lm, 2, LM8323_CMD_WRITE_CFG, 0);
+ lm8323_write(lm, 2, LM8323_CMD_WRITE_CLOCK, clock);
+ lm8323_write(lm, 2, LM8323_CMD_SET_KEY_SIZE, keysize);
+ lm8323_set_active_time(lm, lm->active_time);
+ lm8323_write(lm, 2, LM8323_CMD_SET_DEBOUNCE, debounce);
+ lm8323_write(lm, 3, LM8323_CMD_WRITE_PORT_STATE, 0xff, 0xff);
+ lm8323_write(lm, 3, LM8323_CMD_WRITE_PORT_SEL, 0, 0);
+
+ /*
+ * Not much we can do about errors at this point, so just hope
+ * for the best.
+ */
+
+ return 0;
+}
+
+/*
+ * Bottom half: handle the interrupt by posting key events, or dealing with
+ * errors appropriately.
+ */
+static void lm8323_work(struct work_struct *work)
+{
+ struct lm8323_chip *lm = work_to_lm8323(work);
+ u8 ints;
+
+ mutex_lock(&lm->lock);
+
+ while ((lm8323_read(lm, LM8323_CMD_READ_INT, &ints, 1) == 1) && ints) {
+ if (likely(ints & INT_KEYPAD))
+ process_keys(lm);
+ if (ints & INT_ROTATOR) {
+ /* We don't currently support the rotator. */
+ debug(&lm->client->dev, "rotator fired\n");
+ }
+ if (ints & INT_ERROR) {
+ debug(&lm->client->dev, "error!\n");
+ lm8323_process_error(lm);
+ }
+ if (ints & INT_NOINIT) {
+ dev_err(&lm->client->dev, "chip lost config; "
+ "reinitialising\n");
+ lm8323_configure(lm);
+ }
+ if (ints & INT_PWM1)
+ debug(&lm->client->dev, "pwm1 engine completed\n");
+ if (ints & INT_PWM2)
+ debug(&lm->client->dev, "pwm2 engine completed\n");
+ if (ints & INT_PWM3)
+ debug(&lm->client->dev, "pwm3 engine completed\n");
+ }
+
+ mutex_unlock(&lm->lock);
+}
+
+/*
+ * We cannot use I2C in interrupt context, so we just schedule work.
+ */
+static irqreturn_t lm8323_irq(int irq, void *data)
+{
+ struct lm8323_chip *lm = data;
+
+ schedule_work(&lm->work);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * Read the chip ID.
+ */
+static int lm8323_read_id(struct lm8323_chip *lm, u8 *buf)
+{
+ int bytes;
+
+ bytes = lm8323_read(lm, LM8323_CMD_READ_ID, buf, 2);
+ if (unlikely(bytes != 2))
+ return -EIO;
+
+ return 0;
+}
+
+static void lm8323_write_pwm_one(struct lm8323_pwm *pwm, int pos, u16 cmd)
+{
+ struct lm8323_chip *lm = pwm_to_lm8323(pwm);
+
+ lm8323_write(lm, 4, LM8323_CMD_PWM_WRITE, (pos << 2) | pwm->id,
+ (cmd & 0xff00) >> 8, cmd & 0x00ff);
+}
+
+/*
+ * Write a script into a given PWM engine, concluding with PWM_END.
+ * If 'keepalive' is specified, the engine will be kept running
+ * indefinitely.
+ */
+static void lm8323_write_pwm(struct lm8323_pwm *pwm, int keepalive,
+ int len, ...)
+{
+ struct lm8323_chip *lm = pwm_to_lm8323(pwm);
+ int i, cmd;
+ va_list ap;
+
+ /*
+ * If there are any scripts running at the moment, terminate them
+ * and make sure the duty cycle is as if it finished.
+ */
+ lm8323_write(lm, 2, LM8323_CMD_STOP_PWM, pwm->id);
+
+ va_start(ap, len);
+ for (i = 0; i < len; i++) {
+ cmd = va_arg(ap, int);
+ lm8323_write_pwm_one(pwm, i, cmd);
+ }
+ va_end(ap);
+
+ /* Wait for a trigger from any channel. This keeps the engine alive. */
+ if (keepalive)
+ lm8323_write_pwm_one(pwm, i++, PWM_WAIT_TRIG(0xe));
+ else
+ lm8323_write_pwm_one(pwm, i++, PWM_END(1));
+
+ lm8323_write(lm, 2, LM8323_CMD_START_PWM, pwm->id);
+}
+
+static void lm8323_pwm_work(struct work_struct *work)
+{
+ struct lm8323_pwm *pwm = work_to_pwm(work);
+ int div, perstep, steps, hz, direction, keepalive;
+
+ /* Do nothing if we're already at the requested level. */
+ if (pwm->desired_brightness == pwm->brightness)
+ return;
+
+ keepalive = (pwm->desired_brightness > 0);
+ direction = (pwm->desired_brightness > pwm->brightness);
+ steps = abs(pwm->desired_brightness - pwm->brightness);
+
+ /*
+ * Convert time (in ms) into a divisor (512 or 16 on a refclk of
+ * 32768Hz), and number of ticks per step.
+ */
+ if ((pwm->fade_time / steps) > (32768 / 512))
+ div = 512;
+ else
+ div = 16;
+
+ hz = 32768 / div;
+ if (pwm->fade_time < ((steps * 1000) / hz))
+ perstep = 1;
+ else
+ perstep = (hz * pwm->fade_time) / (steps * 1000);
+
+ if (perstep == 0)
+ perstep = 1;
+ else if (perstep > 63)
+ perstep = 63;
+
+ if (steps > 252) {
+ lm8323_write_pwm(pwm, keepalive, 3,
+ PWM_RAMP((div == 512), perstep, 126,
+ direction),
+ PWM_RAMP((div == 512), perstep, 126,
+ direction),
+ PWM_RAMP((div == 512), perstep, steps - 252,
+ direction));
+ } else if (steps > 126) {
+ lm8323_write_pwm(pwm, keepalive, 2,
+ PWM_RAMP((div == 512), perstep, 126,
+ direction),
+ PWM_RAMP((div == 512), perstep, steps - 126,
+ direction));
+ } else {
+ lm8323_write_pwm(pwm, keepalive, 1,
+ PWM_RAMP((div == 512), perstep, steps,
+ direction));
+ }
+
+ pwm->brightness = pwm->desired_brightness;
+}
+
+static void lm8323_pwm_set_brightness(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ struct lm8323_pwm *pwm = cdev_to_pwm(led_cdev);
+ struct lm8323_chip *lm = pwm_to_lm8323(pwm);
+
+ pwm->desired_brightness = brightness;
+
+ if (in_interrupt()) {
+ schedule_work(&pwm->work);
+ } else {
+ /*
+ * Schedule PWM work as usual unless we are going into suspend
+ */
+ mutex_lock(&lm->lock);
+ if (likely(!lm->pm_suspend))
+ schedule_work(&pwm->work);
+ else
+ lm8323_pwm_work(&pwm->work);
+ mutex_unlock(&lm->lock);
+ }
+}
+
+static ssize_t lm8323_pwm_show_time(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ struct lm8323_pwm *pwm = cdev_to_pwm(led_cdev);
+
+ return sprintf(buf, "%d\n", pwm->fade_time);
+}
+
+static ssize_t lm8323_pwm_store_time(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ struct lm8323_pwm *pwm = cdev_to_pwm(led_cdev);
+ int ret;
+ int time;
+
+ ret = sscanf(buf, "%d", &time);
+ /* Numbers only, please. */
+ if (ret)
+ return -EINVAL;
+
+ pwm->fade_time = time;
+
+ return strlen(buf);
+}
+static DEVICE_ATTR(time, 0644, lm8323_pwm_show_time, lm8323_pwm_store_time);
+
+static int init_pwm(struct lm8323_chip *lm, int id, struct device *dev,
+ const char *name)
+{
+ struct lm8323_pwm *pwm = NULL;
+
+ BUG_ON(id > 3);
+
+ switch (id) {
+ case 1:
+ pwm = &lm->pwm1;
+ break;
+ case 2:
+ pwm = &lm->pwm2;
+ break;
+ case 3:
+ pwm = &lm->pwm3;
+ break;
+ }
+
+ pwm->id = id;
+ pwm->fade_time = 0;
+ pwm->brightness = 0;
+ pwm->desired_brightness = 0;
+ if (name) {
+ pwm->cdev.name = name;
+ pwm->cdev.brightness_set = lm8323_pwm_set_brightness;
+ if (led_classdev_register(dev, &pwm->cdev) < 0) {
+ dev_err(dev, "couldn't register PWM %d\n", id);
+ return -1;
+ }
+ if (device_create_file(pwm->cdev.dev,
+ &dev_attr_time) < 0) {
+ dev_err(dev, "couldn't register time attribute\n");
+ led_classdev_unregister(&pwm->cdev);
+ return -1;
+ }
+ INIT_WORK(&pwm->work, lm8323_pwm_work);
+ pwm->enabled = 1;
+ } else {
+ pwm->enabled = 0;
+ }
+
+ return 0;
+}
+
+static struct i2c_driver lm8323_i2c_driver;
+
+static ssize_t lm8323_show_disable(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct lm8323_chip *lm = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%u\n", !lm->kp_enabled);
+}
+
+static ssize_t lm8323_set_disable(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct lm8323_chip *lm = dev_get_drvdata(dev);
+ int ret;
+ int i;
+
+ i = sscanf(buf, "%d", &ret);
+
+ mutex_lock(&lm->lock);
+ lm->kp_enabled = !i;
+ mutex_unlock(&lm->lock);
+
+ return count;
+}
+static DEVICE_ATTR(disable_kp, 0644, lm8323_show_disable, lm8323_set_disable);
+
+static int lm8323_probe(struct i2c_client *client)
+{
+ struct input_dev *idev;
+ struct lm8323_chip *lm;
+ int i, err = 0;
+ unsigned long tmo;
+ u8 data[2];
+
+ lm = kzalloc(sizeof *lm, GFP_KERNEL);
+ if (!lm)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, lm);
+ lm->client = client;
+ lm8323_pdata = client->dev.platform_data;
+ if (!lm8323_pdata)
+ return -EINVAL; /* ? */
+
+ lm->size_x = lm8323_pdata->size_x;
+ if (lm->size_x == 0) {
+ lm->size_x = 8;
+ } else if (lm->size_x > 8) {
+ dev_err(&client->dev, "invalid x size %d specified\n",
+ lm->size_x);
+ lm->size_x = 8;
+ }
+
+ lm->size_y = lm8323_pdata->size_y;
+ if (lm->size_y == 0) {
+ lm->size_y = 12;
+ } else if (lm->size_y > 12) {
+ dev_err(&client->dev, "invalid y size %d specified\n",
+ lm->size_y);
+ lm->size_x = 12;
+ }
+
+ debug(&c->dev, "Keypad size: %d x %d\n", lm->size_x, lm->size_y);
+
+ lm->debounce_time = lm8323_pdata->debounce_time;
+ if (lm->debounce_time == 0) /* Default. */
+ lm->debounce_time = 12;
+ else if (lm->debounce_time == -1) /* Disable debounce. */
+ lm->debounce_time = 0;
+
+ lm->active_time = lm8323_pdata->active_time;
+ if (lm->active_time == 0) /* Default. */
+ lm->active_time = 500;
+ else if (lm->active_time == -1) /* Disable sleep. */
+ lm->active_time = 0;
+
+ lm8323_reset(lm);
+
+ /* Nothing's set up to service the IRQ yet, so just spin for max.
+ * 100ms until we can configure. */
+ tmo = jiffies + msecs_to_jiffies(100);
+ while (lm8323_read(lm, LM8323_CMD_READ_INT, data, 1) == 1) {
+ if (data[0] & INT_NOINIT)
+ break;
+
+ if (time_after(jiffies, tmo)) {
+ dev_err(&client->dev,
+ "timeout waiting for initialisation\n");
+ break;
+ }
+
+ msleep(1);
+ }
+ lm8323_configure(lm);
+
+ /* If a true probe check the device */
+ if (lm8323_read_id(lm, data) != 0) {
+ dev_err(&client->dev, "device not found\n");
+ err = -ENODEV;
+ goto fail2;
+ }
+
+ if (init_pwm(lm, 1, &client->dev, lm8323_pdata->pwm1_name) < 0)
+ goto fail3;
+ if (init_pwm(lm, 2, &client->dev, lm8323_pdata->pwm2_name) < 0)
+ goto fail4;
+ if (init_pwm(lm, 3, &client->dev, lm8323_pdata->pwm3_name) < 0)
+ goto fail5;
+
+ lm->irq = lm8323_pdata->irq_gpio;
+ debug(&c->dev, "IRQ: %d\n", lm->irq);
+
+ mutex_init(&lm->lock);
+ INIT_WORK(&lm->work, lm8323_work);
+
+ err = request_irq(client->irq, lm8323_irq,
+ IRQF_TRIGGER_FALLING | IRQF_DISABLED |
+ IRQF_SAMPLE_RANDOM, DRIVER_NAME, lm);
+ if (err) {
+ dev_err(&client->dev, "could not get IRQ %d\n", lm->irq);
+ goto fail6;
+ }
+
+ set_irq_wake(lm->irq, 1);
+
+ lm->kp_enabled = 1;
+ err = device_create_file(&client->dev, &dev_attr_disable_kp);
+ if (err < 0)
+ goto fail7;
+
+ idev = input_allocate_device();
+ if (idev == NULL) {
+ err = -ENOMEM;
+ goto fail8;
+ }
+
+ if (lm8323_pdata->name)
+ idev->name = lm8323_pdata->name;
+ else
+ idev->name = "LM8323 keypad";
+ snprintf(lm->phys, sizeof(lm->phys), "%s/input-kp", client->dev.bus_id);
+ idev->phys = lm->phys;
+
+ lm->keys_down = 0;
+ idev->evbit[0] = BIT(EV_KEY);
+ for (i = 0; i < LM8323_KEYMAP_SIZE; i++) {
+ if (lm8323_pdata->keymap[i] > 0)
+ set_bit(lm8323_pdata->keymap[i], idev->keybit);
+
+ lm->keymap[i] = lm8323_pdata->keymap[i];
+ }
+
+ if (lm8323_pdata->repeat)
+ set_bit(EV_REP, idev->evbit);
+
+ lm->idev = idev;
+ if (input_register_device(idev)) {
+ dev_dbg(&client->dev, "error registering input device\n");
+ goto fail8;
+ }
+
+ return 0;
+
+fail8:
+ device_remove_file(&client->dev, &dev_attr_disable_kp);
+fail7:
+ free_irq(lm->irq, lm);
+fail6:
+ if (lm->pwm3.enabled)
+ led_classdev_unregister(&lm->pwm3.cdev);
+fail5:
+ if (lm->pwm2.enabled)
+ led_classdev_unregister(&lm->pwm2.cdev);
+fail4:
+ if (lm->pwm1.enabled)
+ led_classdev_unregister(&lm->pwm1.cdev);
+fail3:
+fail2:
+ kfree(lm);
+ return err;
+}
+
+static int lm8323_remove(struct i2c_client *client)
+{
+ struct lm8323_chip *lm = i2c_get_clientdata(client);
+
+ free_irq(lm->irq, lm);
+ device_remove_file(&lm->client->dev, &dev_attr_disable_kp);
+
+ return 0;
+}
+
+/*
+ * We don't need to explicitly suspend the chip, as it already switches off
+ * when there's no activity.
+ */
+static int lm8323_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+ struct lm8323_chip *lm = i2c_get_clientdata(client);
+
+ set_irq_wake(lm->irq, 0);
+ disable_irq(lm->irq);
+
+ mutex_lock(&lm->lock);
+ lm->pm_suspend = 1;
+ mutex_unlock(&lm->lock);
+
+ if (lm->pwm1.enabled)
+ led_classdev_suspend(&lm->pwm1.cdev);
+ if (lm->pwm2.enabled)
+ led_classdev_suspend(&lm->pwm2.cdev);
+ if (lm->pwm3.enabled)
+ led_classdev_suspend(&lm->pwm3.cdev);
+
+ return 0;
+}
+
+static int lm8323_resume(struct i2c_client *client)
+{
+ struct lm8323_chip *lm = i2c_get_clientdata(client);
+
+ mutex_lock(&lm->lock);
+ lm->pm_suspend = 0;
+ mutex_unlock(&lm->lock);
+
+ if (lm->pwm1.enabled)
+ led_classdev_resume(&lm->pwm1.cdev);
+ if (lm->pwm2.enabled)
+ led_classdev_resume(&lm->pwm2.cdev);
+ if (lm->pwm3.enabled)
+ led_classdev_resume(&lm->pwm3.cdev);
+
+ enable_irq(lm->irq);
+ set_irq_wake(lm->irq, 1);
+
+ return 0;
+}
+
+static struct i2c_driver lm8323_i2c_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ },
+ .probe = lm8323_probe,
+ .remove = __exit_p(lm8323_remove),
+ .suspend = lm8323_suspend,
+ .resume = lm8323_resume,
+};
+
+static int __init lm8323_init(void)
+{
+ return i2c_add_driver(&lm8323_i2c_driver);
+}
+
+static void __exit lm8323_exit(void)
+{
+ i2c_del_driver(&lm8323_i2c_driver);
+}
+
+MODULE_AUTHOR("Daniel Stone");
+MODULE_DESCRIPTION("LM8323 keypad driver");
+MODULE_LICENSE("GPL");
+
+module_init(lm8323_init);
+module_exit(lm8323_exit);
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/mutex.h>
+#include <linux/spinlock.h>
#include <linux/errno.h>
#include <asm/arch/gpio.h>
#include <asm/arch/keypad.h>
unsigned int cols;
unsigned long delay;
unsigned int debounce;
+ int suspended;
+ spinlock_t suspend_lock;
};
DECLARE_TASKLET_DISABLED(kp_tasklet, omap_kp_tasklet, 0);
static irqreturn_t omap_kp_interrupt(int irq, void *dev_id)
{
struct omap_kp *omap_kp = dev_id;
+ unsigned long flags;
+
+ spin_lock_irqsave(&omap_kp->suspend_lock, flags);
+ if (omap_kp->suspended) {
+ spin_unlock_irqrestore(&omap_kp->suspend_lock, flags);
+ return IRQ_HANDLED;
+ }
+ spin_unlock_irqrestore(&omap_kp->suspend_lock, flags);
/* disable keyboard interrupt and schedule for handling */
if (cpu_is_omap24xx()) {
#ifdef CONFIG_PM
static int omap_kp_suspend(struct platform_device *dev, pm_message_t state)
{
- /* Nothing yet */
+ struct omap_kp *omap_kp = platform_get_drvdata(dev);
+ unsigned long flags;
+ spin_lock_irqsave(&omap_kp->suspend_lock, flags);
+
+ /*
+ * Re-enable the interrupt in case it has been masked by the
+ * handler and a key is still pressed. We need the interrupt
+ * to wake us up from suspended.
+ */
+ if (cpu_class_is_omap1())
+ omap_writew(0, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
+
+ omap_kp->suspended = 1;
+ spin_unlock_irqrestore(&omap_kp->suspend_lock, flags);
return 0;
}
static int omap_kp_resume(struct platform_device *dev)
{
- /* Nothing yet */
+ struct omap_kp *omap_kp = platform_get_drvdata(dev);
+ omap_kp->suspended = 0;
return 0;
}
#else
struct omap_kp *omap_kp;
struct input_dev *input_dev;
struct omap_kp_platform_data *pdata = pdev->dev.platform_data;
- int i, col_idx, row_idx, irq_idx, ret;
+ int i, col_idx = 0, row_idx = 0, irq_idx, ret;
if (!pdata->rows || !pdata->cols || !pdata->keymap) {
printk(KERN_ERR "No rows, cols or keymap from pdata\n");
platform_set_drvdata(pdev, omap_kp);
+ spin_lock_init(&omap_kp->suspend_lock);
omap_kp->input = input_dev;
+ omap_kp->suspended = 0;
/* Disable the interrupt for the MPUIO keyboard */
if (!cpu_is_omap24xx())
--- /dev/null
+/*
+ * drivers/input/keyboard/omap-twl4030keypad.c
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Code re-written for 2430SDP by:
+ * Syed Mohammed Khasim <x0khasim@ti.com>
+ *
+ * Initial Code:
+ * Manjunatha G K <manjugk@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/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/bitops.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/i2c/twl4030.h>
+#include <linux/irq.h>
+#include <asm/arch/keypad.h>
+#include "twl4030-keypad.h"
+
+#define PTV_PRESCALER 4
+
+#define MAX_ROWS 8 /* TWL4030 hardlimit */
+#define ROWCOL_MASK 0xFF000000
+#define KEYNUM_MASK 0x00FFFFFF
+
+/* Global variables */
+static int *keymap;
+static u16 kp_state[MAX_ROWS];
+static int n_rows, n_cols;
+
+static struct device *dbg_dev;
+static struct input_dev *omap_twl4030kp;
+
+static int twl4030_kpread(u32 module, u8 *data, u32 reg, u8 num_bytes)
+{
+ int ret;
+
+ ret = twl4030_i2c_read(module, data, reg, num_bytes);
+ if (ret < 0) {
+ dev_warn(dbg_dev, "Couldn't read TWL4030: %X - ret %d[%x]\n",
+ reg, ret, ret);
+ return ret;
+ }
+ return ret;
+}
+
+static int twl4030_kpwrite_u8(u32 module, u8 data, u32 reg)
+{
+ int ret;
+
+ ret = twl4030_i2c_write_u8(module, data, reg);
+ if (ret < 0) {
+ dev_warn(dbg_dev, "Could not write TWL4030: %X - ret %d[%x]\n",
+ reg, ret, ret);
+ return ret;
+ }
+ return ret;
+}
+
+static int omap_kp_find_key(int col, int row)
+{
+ int i, rc;
+
+ rc = KEY(col, row, 0);
+ for (i = 0; keymap[i] != 0; i++)
+ if ((keymap[i] & ROWCOL_MASK) == rc)
+ return keymap[i] & KEYNUM_MASK;
+
+ return -EINVAL;
+}
+
+static inline u16 omap_kp_col_xlate(u8 col)
+{
+ /* If all bits in a row are active for all coloumns then
+ * we have that row line connected to gnd. Mark this
+ * key on as if it was on matrix position n_cols (ie
+ * one higher than the size of the matrix).
+ */
+ if (col == 0xFF)
+ return (1 << n_cols);
+ else
+ return col & ((1 << n_cols) - 1);
+}
+
+static int omap_kp_read_kp_matrix_state(u16 *state)
+{
+ u8 new_state[MAX_ROWS];
+ int row;
+ int ret = twl4030_kpread(TWL4030_MODULE_KEYPAD,
+ new_state, KEYP_FULL_CODE_7_0, n_rows);
+ if (ret >= 0) {
+ for (row = 0; row < n_rows; row++)
+ state[row] = omap_kp_col_xlate(new_state[row]);
+ }
+ return ret;
+}
+
+static int omap_kp_is_in_ghost_state(u16 *key_state)
+{
+ int i;
+ u16 check = 0;
+
+ for (i = 0; i < n_rows; i++) {
+ u16 col = key_state[i];
+
+ if ((col & check) && hweight16(col) > 1)
+ return 1;
+ check |= col;
+ }
+
+ return 0;
+}
+
+static void twl4030_kp_scan(int release_all)
+{
+ u16 new_state[MAX_ROWS];
+ int col, row;
+
+ if (release_all)
+ memset(new_state, 0, sizeof(new_state));
+ else {
+ /* check for any changes */
+ int ret = omap_kp_read_kp_matrix_state(new_state);
+ if (ret < 0) /* panic ... */
+ return;
+
+ if (omap_kp_is_in_ghost_state(new_state))
+ return;
+ }
+
+ /* check for changes and print those */
+ for (row = 0; row < n_rows; row++) {
+ int changed = new_state[row] ^ kp_state[row];
+
+ if (!changed)
+ continue;
+
+ for (col = 0; col < n_cols + 1; col++) {
+ int key;
+
+ if (!(changed & (1 << col)))
+ continue;
+
+ dev_dbg(dbg_dev, "key [%d:%d] %s\n", row, col,
+ (new_state[row] & (1 << col)) ?
+ "press" : "release");
+
+ key = omap_kp_find_key(col, row);
+ if (key < 0)
+ dev_warn(dbg_dev, "Spurious key event %d-%d\n",
+ col, row);
+ else
+ input_report_key(omap_twl4030kp, key,
+ new_state[row] & (1 << col));
+ }
+ kp_state[row] = new_state[row];
+ }
+}
+
+/*
+ * Keypad interrupt handler
+ */
+static irqreturn_t do_kp_irq(int irq, void *dev_id)
+{
+ u8 reg;
+ int ret;
+
+ /* Read & Clear TWL4030 pending interrupt */
+ ret = twl4030_kpread(TWL4030_MODULE_KEYPAD, ®, KEYP_ISR1, 1);
+
+ /* Release all keys if I2C has gone bad or
+ * the KEYP has gone to idle state */
+ if ((ret >= 0) && (reg & KEYP_IMR1_KP))
+ twl4030_kp_scan(0);
+ else
+ twl4030_kp_scan(1);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * Registers keypad device with input sub system
+ * and configures TWL4030 keypad registers
+ */
+static int __init omap_kp_probe(struct platform_device *pdev)
+{
+ u8 reg;
+ int i;
+ int ret = 0;
+ struct omap_kp_platform_data *pdata = pdev->dev.platform_data;
+
+ /* Get the debug Device */
+ dbg_dev = &(pdev->dev);
+
+ if (!pdata->rows || !pdata->cols || !pdata->keymap) {
+ dev_err(dbg_dev, "No rows, cols or keymap from pdata\n");
+ return -EINVAL;
+ }
+
+ omap_twl4030kp = input_allocate_device();
+ if (omap_twl4030kp == NULL)
+ return -ENOMEM;
+
+ keymap = pdata->keymap;
+ n_rows = pdata->rows;
+ n_cols = pdata->cols;
+
+ /* setup input device */
+ set_bit(EV_KEY, omap_twl4030kp->evbit);
+
+ /* Enable auto repeat feature of Linux input subsystem */
+ if (pdata->rep)
+ set_bit(EV_REP, omap_twl4030kp->evbit);
+
+ for (i = 0; keymap[i] != 0; i++)
+ set_bit(keymap[i] & KEYNUM_MASK, omap_twl4030kp->keybit);
+
+ omap_twl4030kp->name = "omap_twl4030keypad";
+ omap_twl4030kp->phys = "omap_twl4030keypad/input0";
+ omap_twl4030kp->dev.parent = &pdev->dev;
+
+ omap_twl4030kp->id.bustype = BUS_HOST;
+ omap_twl4030kp->id.vendor = 0x0001;
+ omap_twl4030kp->id.product = 0x0001;
+ omap_twl4030kp->id.version = 0x0003;
+
+ omap_twl4030kp->keycode = keymap;
+ omap_twl4030kp->keycodesize = sizeof(unsigned int);
+ omap_twl4030kp->keycodemax = pdata->keymapsize;
+
+ ret = input_register_device(omap_twl4030kp);
+ if (ret < 0) {
+ dev_err(dbg_dev, "Unable to register twl4030 keypad device\n");
+ goto err2;
+ }
+
+ /* Disable auto-repeat */
+ reg = KEYP_CTRL_NOAUTORPT;
+ ret = twl4030_kpwrite_u8(TWL4030_MODULE_KEYPAD, reg, KEYP_CTRL);
+ if (ret < 0)
+ goto err3;
+
+ /* Enable TO rising and KP rising and falling edge detection */
+ reg = KEYP_EDR_KP_BOTH | KEYP_EDR_TO_RISING;
+ ret = twl4030_kpwrite_u8(TWL4030_MODULE_KEYPAD, reg, KEYP_EDR);
+ if (ret < 0)
+ goto err3;
+
+ /* Set PTV prescaler Field */
+ reg = (PTV_PRESCALER << KEYP_LK_PTV_PTV_SHIFT);
+ ret = twl4030_kpwrite_u8(TWL4030_MODULE_KEYPAD, reg, KEYP_LK_PTV);
+ if (ret < 0)
+ goto err3;
+
+ /* Set key debounce time to 20 ms */
+ i = KEYP_PERIOD_US(20000, PTV_PRESCALER);
+ ret = twl4030_kpwrite_u8(TWL4030_MODULE_KEYPAD, i, KEYP_DEB);
+ if (ret < 0)
+ goto err3;
+
+ /* Set timeout period to 100 ms */
+ i = KEYP_PERIOD_US(200000, PTV_PRESCALER);
+ ret = twl4030_kpwrite_u8(TWL4030_MODULE_KEYPAD,
+ (i & 0xFF), KEYP_TIMEOUT_L);
+ if (ret < 0)
+ goto err3;
+
+ ret = twl4030_kpwrite_u8(TWL4030_MODULE_KEYPAD,
+ (i >> 8), KEYP_TIMEOUT_H);
+ if (ret < 0)
+ goto err3;
+
+ /* Enable Clear-on-Read */
+ reg = KEYP_SIH_CTRL_COR | KEYP_SIH_CTRL_PEND_DIS;
+ ret = twl4030_kpwrite_u8(TWL4030_MODULE_KEYPAD,
+ reg, KEYP_SIH_CTRL);
+ if (ret < 0)
+ goto err3;
+
+ /*
+ * This ISR will always execute in kernel thread context because of
+ * the need to access the TWL4030 over the I2C bus.
+ */
+ ret = request_irq(TWL4030_MODIRQ_KEYPAD, do_kp_irq,
+ IRQF_DISABLED, "TWL4030 Keypad", omap_twl4030kp);
+ if (ret < 0) {
+ dev_info(dbg_dev, "request_irq failed for irq no=%d\n",
+ TWL4030_MODIRQ_KEYPAD);
+ goto err3;
+ } else {
+ /* Enable KP and TO interrupts now. */
+ reg = ~(KEYP_IMR1_KP | KEYP_IMR1_TO);
+ ret = twl4030_kpwrite_u8(TWL4030_MODULE_KEYPAD,
+ reg, KEYP_IMR1);
+ if (ret < 0)
+ goto err5;
+ }
+
+ ret = omap_kp_read_kp_matrix_state(kp_state);
+ if (ret < 0)
+ goto err4;
+
+ return ret;
+err5:
+ /* mask all events - we don't care about the result */
+ (void) twl4030_kpwrite_u8(TWL4030_MODULE_KEYPAD, 0xff, KEYP_IMR1);
+err4:
+ free_irq(TWL4030_MODIRQ_KEYPAD, NULL);
+err3:
+ input_unregister_device(omap_twl4030kp);
+err2:
+ input_free_device(omap_twl4030kp);
+ return -ENODEV;
+}
+
+static int omap_kp_remove(struct platform_device *pdev)
+{
+ free_irq(TWL4030_MODIRQ_KEYPAD, NULL);
+
+ input_unregister_device(omap_twl4030kp);
+ return 0;
+}
+
+
+static struct platform_driver omap_kp_driver = {
+ .probe = omap_kp_probe,
+ .remove = omap_kp_remove,
+ .driver = {
+ .name = "omap_twl4030keypad",
+ },
+};
+
+/*
+ * OMAP TWL4030 Keypad init
+ */
+static int __devinit omap_kp_init(void)
+{
+ 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("Texas Instruments");
+MODULE_DESCRIPTION("OMAP TWL4030 Keypad Driver");
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * TSC2301 keypad driver
+ *
+ * Copyright (C) 2005-2006 Nokia Corporation
+ *
+ * Written by Jarkko Oikarinen
+ * Rewritten by Juha Yrjola <juha.yrjola@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/spi/spi.h>
+
+#include <linux/spi/tsc2301.h>
+
+#define TSC2301_KEYBOARD_PRODUCT_ID 0x0051
+#define TSC2301_KEYBOARD_PRODUCT_VERSION 0x0001
+#define TSC2301_DEBOUNCE_TIME_2MS 0x0000
+#define TSC2301_DEBOUNCE_TIME_10MS 0x0800
+#define TSC2301_DEBOUNCE_TIME_20MS 0x1000
+#define TSC2301_DEBOUNCE_TIME_50MS 0x1800
+#define TSC2301_DEBOUNCE_TIME_60MS 0x2000
+#define TSC2301_DEBOUNCE_TIME_80MS 0x2800
+#define TSC2301_DEBOUNCE_TIME_100MS 0x3000
+#define TSC2301_DEBOUNCE_TIME_120MS 0x3800
+
+#define TSC2301_DEBOUNCE_TIME TSC2301_DEBOUNCE_TIME_20MS
+
+#define TSC2301_RELEASE_TIMEOUT 50
+
+struct tsc2301_kp {
+ struct input_dev *idev;
+ char phys[32];
+ spinlock_t lock;
+ struct mutex mutex;
+ struct timer_list timer;
+ u16 keys_pressed;
+ unsigned pending:1;
+ unsigned user_disabled:1;
+ unsigned disable_depth;
+
+ struct spi_transfer read_xfer[4];
+ struct spi_message read_msg;
+
+ u16 data;
+ u16 mask;
+
+ int irq;
+ s16 keymap[16];
+};
+
+static inline int tsc2301_kp_disabled(struct tsc2301 *tsc)
+{
+ return tsc->kp->disable_depth != 0;
+}
+
+static void tsc2301_kp_send_key_events(struct tsc2301 *tsc,
+ u16 prev_state,
+ u16 new_state)
+{
+ struct tsc2301_kp *kp = tsc->kp;
+ u16 common, released, pressed;
+ int i;
+
+ common = prev_state & new_state;
+ released = common ^ prev_state;
+ pressed = common ^ new_state;
+ if (!released && !pressed)
+ return;
+ for (i = 0; i < 16 && (released || pressed); i++) {
+ if (released & 1) {
+ dev_dbg(&tsc->spi->dev, "key %d released\n", i);
+ input_report_key(kp->idev, kp->keymap[i], 0);
+ }
+ released >>= 1;
+ if (pressed & 1) {
+ dev_dbg(&tsc->spi->dev, "key %d pressed\n", i);
+ input_report_key(kp->idev, kp->keymap[i], 1);
+ }
+ pressed >>= 1;
+ }
+ input_sync(kp->idev);
+}
+
+static inline void _filter_out(struct tsc2301 *tsc, u16 prev_state,
+ u16 *new_state, int row1, int row2, u8 rect_pat)
+{
+ u16 mask;
+
+ mask = (rect_pat << (row1 * 4)) | (rect_pat << (row2 * 4));
+ mask &= ~prev_state;
+ *new_state &= ~mask;
+ dev_dbg(&tsc->spi->dev, "filtering ghost keys %02x\n", mask);
+}
+
+static void tsc2301_filter_ghost_keys(struct tsc2301 *tsc, u16 prev_state,
+ u16 *new_state)
+{
+ int row1, row2;
+ u16 key_map;
+ u16 row1_map;
+ static const u8 rect_pat[] = {
+ 0x3, 0x5, 0x9, 0x6, 0xa, 0xc, 0,
+ };
+
+ key_map = *new_state;
+ for (row1 = 0; row1 < 4; row1++) {
+ row1_map = (key_map >> (row1 * 4)) & 0xf;
+ if (!row1_map)
+ continue;
+ for (row2 = row1 + 1; row2 < 4; row2++) {
+ u16 rect_map = (key_map >> (row2 * 4)) & 0xf;
+ const u8 *rp;
+
+ rect_map &= row1_map;
+ if (!rect_map)
+ continue;
+ for (rp = rect_pat; *rp; rp++)
+ if ((rect_map & *rp) == *rp)
+ _filter_out(tsc, prev_state, new_state,
+ row1, row2, *rp);
+ }
+ }
+}
+
+static void tsc2301_kp_timer(unsigned long arg)
+{
+ struct tsc2301 *tsc = (void *) arg;
+ struct tsc2301_kp *kp = tsc->kp;
+ unsigned long flags;
+
+ tsc2301_kp_send_key_events(tsc, kp->keys_pressed, 0);
+ spin_lock_irqsave(&kp->lock, flags);
+ kp->keys_pressed = 0;
+ spin_unlock_irqrestore(&kp->lock, flags);
+}
+
+static void tsc2301_kp_rx(void *arg)
+{
+ struct tsc2301 *tsc = arg;
+ struct tsc2301_kp *kp = tsc->kp;
+ unsigned long flags;
+ u16 kp_data;
+
+ kp_data = kp->data;
+ dev_dbg(&tsc->spi->dev, "KP data %04x\n", kp_data);
+
+ tsc2301_filter_ghost_keys(tsc, kp->keys_pressed, &kp_data);
+ tsc2301_kp_send_key_events(tsc, kp->keys_pressed, kp_data);
+ spin_lock_irqsave(&kp->lock, flags);
+ kp->keys_pressed = kp_data;
+ kp->pending = 0;
+ spin_unlock_irqrestore(&kp->lock, flags);
+}
+
+static irqreturn_t tsc2301_kp_irq_handler(int irq, void *dev_id)
+{
+ struct tsc2301 *tsc = dev_id;
+ struct tsc2301_kp *kp = tsc->kp;
+ unsigned long flags;
+ int r;
+
+ spin_lock_irqsave(&kp->lock, flags);
+ if (tsc2301_kp_disabled(tsc)) {
+ spin_unlock_irqrestore(&kp->lock, flags);
+ return IRQ_HANDLED;
+ }
+ kp->pending = 1;
+ spin_unlock_irqrestore(&kp->lock, flags);
+ mod_timer(&kp->timer,
+ jiffies + msecs_to_jiffies(TSC2301_RELEASE_TIMEOUT));
+ r = spi_async(tsc->spi, &tsc->kp->read_msg);
+ if (r)
+ dev_err(&tsc->spi->dev, "kp: spi_async() failed");
+ return IRQ_HANDLED;
+}
+
+static void tsc2301_kp_start_scan(struct tsc2301 *tsc)
+{
+ tsc2301_write_reg(tsc, TSC2301_REG_KPMASK, tsc->kp->mask);
+ tsc2301_write_reg(tsc, TSC2301_REG_KEY, TSC2301_DEBOUNCE_TIME);
+}
+
+static void tsc2301_kp_stop_scan(struct tsc2301 *tsc)
+{
+ tsc2301_write_reg(tsc, TSC2301_REG_KEY, 1 << 14);
+}
+
+/* Must be called with the mutex held */
+static void tsc2301_kp_enable(struct tsc2301 *tsc)
+{
+ struct tsc2301_kp *kp = tsc->kp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&kp->lock, flags);
+ BUG_ON(!tsc2301_kp_disabled(tsc));
+ if (--kp->disable_depth != 0) {
+ spin_unlock_irqrestore(&kp->lock, flags);
+ return;
+ }
+ spin_unlock_irqrestore(&kp->lock, flags);
+
+ set_irq_type(kp->irq, IRQT_FALLING);
+ tsc2301_kp_start_scan(tsc);
+ enable_irq(kp->irq);
+}
+
+/* Must be called with the mutex held */
+static int tsc2301_kp_disable(struct tsc2301 *tsc, int release_keys)
+{
+ struct tsc2301_kp *kp = tsc->kp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&kp->lock, flags);
+ if (kp->disable_depth++ != 0) {
+ spin_unlock_irqrestore(&kp->lock, flags);
+ goto out;
+ }
+ disable_irq_nosync(kp->irq);
+ set_irq_type(kp->irq, IRQT_NOEDGE);
+ spin_unlock_irqrestore(&kp->lock, flags);
+
+ while (kp->pending) {
+ msleep(1);
+ }
+
+ tsc2301_kp_stop_scan(tsc);
+out:
+ if (!release_keys)
+ del_timer(&kp->timer); /* let timeout release keys */
+
+ return 0;
+}
+
+/* The following workaround is needed for a HW bug triggered by the
+ * following:
+ * 1. keep any key pressed
+ * 2. disable keypad
+ * 3. release all keys
+ * 4. reenable keypad
+ * 5. disable touch screen controller
+ *
+ * After this the keypad scanner will get stuck in busy state and won't
+ * report any interrupts for further keypresses. One way to recover is to
+ * restart the keypad scanner whenever we enable / disable the
+ * touchscreen controller.
+ */
+void tsc2301_kp_restart(struct tsc2301 *tsc)
+{
+ if (!tsc2301_kp_disabled(tsc)) {
+ tsc2301_kp_start_scan(tsc);
+ }
+}
+
+static ssize_t tsc2301_kp_disable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tsc2301 *tsc = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%u\n", tsc2301_kp_disabled(tsc) ? 1 : 0);
+}
+
+static ssize_t tsc2301_kp_disable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct tsc2301 *tsc = dev_get_drvdata(dev);
+ struct tsc2301_kp *kp = tsc->kp;
+ char *endp;
+ int i;
+
+ i = simple_strtoul(buf, &endp, 10);
+ i = i ? 1 : 0;
+
+ mutex_lock(&kp->mutex);
+ if (i == kp->user_disabled) {
+ mutex_unlock(&kp->mutex);
+ return count;
+ }
+ kp->user_disabled = i;
+
+ if (i)
+ tsc2301_kp_disable(tsc, 1);
+ else
+ tsc2301_kp_enable(tsc);
+ mutex_unlock(&kp->mutex);
+
+ return count;
+}
+
+static DEVICE_ATTR(disable_kp, 0664, tsc2301_kp_disable_show,
+ tsc2301_kp_disable_store);
+
+static const u16 tsc2301_kp_read_data = 0x8000 | TSC2301_REG_KPDATA;
+
+static void tsc2301_kp_setup_spi_xfer(struct tsc2301 *tsc)
+{
+ struct tsc2301_kp *kp = tsc->kp;
+ struct spi_message *m = &kp->read_msg;
+ struct spi_transfer *x = &kp->read_xfer[0];
+
+ spi_message_init(&kp->read_msg);
+
+ x->tx_buf = &tsc2301_kp_read_data;
+ x->len = 2;
+ spi_message_add_tail(x, m);
+ x++;
+
+ x->rx_buf = &kp->data;
+ x->len = 2;
+ spi_message_add_tail(x, m);
+
+ m->complete = tsc2301_kp_rx;
+ m->context = tsc;
+}
+
+#ifdef CONFIG_PM
+int tsc2301_kp_suspend(struct tsc2301 *tsc)
+{
+ struct tsc2301_kp *kp = tsc->kp;
+
+ mutex_lock(&kp->mutex);
+ tsc2301_kp_disable(tsc, 1);
+ mutex_unlock(&kp->mutex);
+ return 0;
+}
+
+void tsc2301_kp_resume(struct tsc2301 *tsc)
+{
+ struct tsc2301_kp *kp = tsc->kp;
+
+ mutex_lock(&kp->mutex);
+ tsc2301_kp_enable(tsc);
+ mutex_unlock(&kp->mutex);
+}
+#endif
+
+int __devinit tsc2301_kp_init(struct tsc2301 *tsc,
+ struct tsc2301_platform_data *pdata)
+{
+ struct input_dev *idev;
+ struct tsc2301_kp *kp;
+ int r, i;
+ u16 mask;
+
+ if (pdata->keyb_int < 0) {
+ dev_err(&tsc->spi->dev, "need kbirq");
+ return -EINVAL;
+ }
+
+ kp = kzalloc(sizeof(*kp), GFP_KERNEL);
+ if (kp == NULL)
+ return -ENOMEM;
+ tsc->kp = kp;
+
+ kp->irq = pdata->keyb_int;
+ spin_lock_init(&kp->lock);
+ mutex_init(&kp->mutex);
+
+ init_timer(&kp->timer);
+ kp->timer.data = (unsigned long) tsc;
+ kp->timer.function = tsc2301_kp_timer;
+
+ idev = input_allocate_device();
+ if (idev == NULL) {
+ r = -ENOMEM;
+ goto err1;
+ }
+ if (pdata->keyb_name)
+ idev->name = pdata->keyb_name;
+ else
+ idev->name = "TSC2301 keypad";
+ snprintf(kp->phys, sizeof(kp->phys), "%s/input-kp", tsc->spi->dev.bus_id);
+ idev->phys = kp->phys;
+
+ mask = 0;
+ idev->evbit[0] = BIT(EV_KEY);
+ for (i = 0; i < 16; i++) {
+ if (pdata->keymap[i] > 0) {
+ set_bit(pdata->keymap[i], idev->keybit);
+ kp->keymap[i] = pdata->keymap[i];
+ } else {
+ kp->keymap[i] = -1;
+ mask |= 1 << i;
+ }
+ }
+
+ if (pdata->kp_rep)
+ set_bit(EV_REP, idev->evbit);
+
+ kp->idev = idev;
+
+ tsc2301_kp_setup_spi_xfer(tsc);
+
+ r = device_create_file(&tsc->spi->dev, &dev_attr_disable_kp);
+ if (r < 0)
+ goto err2;
+
+ tsc2301_kp_start_scan(tsc);
+
+ /* IRQ mode 0 is faulty, it can cause the KBIRQ to get stuck.
+ * Mode 2 deasserts the IRQ at:
+ * - HW or SW reset
+ * - Setting SCS flag in REG_KEY register
+ * - Releasing all keys
+ * - Reading the REG_KPDATA
+ */
+ tsc2301_write_kbc(tsc, 2);
+
+ tsc2301_write_reg(tsc, TSC2301_REG_KPMASK, mask);
+ kp->mask = mask;
+
+ set_irq_type(kp->irq, IRQT_FALLING);
+
+ r = request_irq(kp->irq, tsc2301_kp_irq_handler, IRQF_SAMPLE_RANDOM,
+ "tsc2301-kp", tsc);
+ if (r < 0) {
+ dev_err(&tsc->spi->dev, "unable to get kbirq IRQ");
+ goto err3;
+ }
+ set_irq_wake(kp->irq, 1);
+
+ /* We need to read the register once..? */
+ tsc2301_read_reg(tsc, TSC2301_REG_KPDATA);
+
+ r = input_register_device(idev);
+ if (r < 0) {
+ dev_err(&tsc->spi->dev, "can't register keypad device\n");
+ goto err4;
+ }
+
+ return 0;
+
+err4:
+ free_irq(kp->irq, tsc);
+err3:
+ tsc2301_kp_stop_scan(tsc);
+ device_remove_file(&tsc->spi->dev, &dev_attr_disable_kp);
+err2:
+ input_free_device(kp->idev);
+err1:
+ kfree(kp);
+ return r;
+}
+
+void __devexit tsc2301_kp_exit(struct tsc2301 *tsc)
+{
+ struct tsc2301_kp *kp = tsc->kp;
+
+ tsc2301_kp_disable(tsc, 1);
+ input_unregister_device(kp->idev);
+ free_irq(kp->irq, tsc);
+ device_remove_file(&tsc->spi->dev, &dev_attr_disable_kp);
+
+ kfree(kp);
+}
--- /dev/null
+/*
+ * drivers/input/keyboard/twl4030-keypad.h
+ *
+ * Copyright (C) 2006-2007 Texas Instruments, Inc.
+ *
+ * Intial Code:
+ * Syed Mohammed Khasim <x0khasim@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
+ */
+#ifndef __TWL4030_KEYPAD_H__
+#define __TWL4030_KEYPAD_H__
+
+/* Register Definitions */
+#define KEYP_CTRL 0x00
+#define KEYP_DEB 0x01
+#define KEYP_LONG_KEY 0x02
+#define KEYP_LK_PTV 0x03
+#define KEYP_TIMEOUT_L 0x04
+#define KEYP_TIMEOUT_H 0x05
+#define KEYP_FULL_CODE_7_0 0x09
+#define KEYP_ISR1 0x11
+#define KEYP_IMR1 0x12
+#define KEYP_EDR 0x16
+#define KEYP_SIH_CTRL 0x17
+
+/* KEYP_CTRL_REG Fields */
+#define KEYP_CTRL_SOFT_NRST 0x01
+#define KEYP_CTRL_SOFTMODEN 0x02
+#define KEYP_CTRL_LK_EN 0x04
+#define KEYP_CTRL_TOE_EN 0x08
+#define KEYP_CTRL_TOLE_EN 0x10
+#define KEYP_CTRL_RP_EN 0x20
+#define KEYP_CTRL_KBD_ON 0x40
+
+
+#define KEYP_CTRL_NOAUTORPT (KEYP_CTRL_SOFT_NRST | \
+ KEYP_CTRL_SOFTMODEN | \
+ KEYP_CTRL_TOE_EN | \
+ KEYP_CTRL_KBD_ON)
+
+/* KEYP_DEB, KEYP_LONG_KEY, KEYP_TIMEOUT_x*/
+#define KEYP_PERIOD_US(T, prescale) (T / (31 << (prescale + 1)) - 1)
+
+/* KEYP_LK_PTV_REG Fields */
+#define KEYP_LK_PTV_PTV_SHIFT 5
+
+/* KEYP_IMR1 Fields */
+#define KEYP_IMR1_MIS 0x08
+#define KEYP_IMR1_TO 0x04
+#define KEYP_IMR1_LK 0x02
+#define KEYP_IMR1_KP 0x01
+
+/* KEYP_EDR Fields */
+#define KEYP_EDR_KP_FALLING 0x01
+#define KEYP_EDR_KP_RISING 0x02
+#define KEYP_EDR_KP_BOTH 0x03
+#define KEYP_EDR_LK_FALLING 0x04
+#define KEYP_EDR_LK_RISING 0x08
+#define KEYP_EDR_TO_FALLING 0x10
+#define KEYP_EDR_TO_RISING 0x20
+#define KEYP_EDR_MIS_FALLING 0x40
+#define KEYP_EDR_MIS_RISING 0x80
+
+/* KEYP_SIH_CTRL Fields */
+#define KEYP_SIH_CTRL_COR 0x04
+#define KEYP_SIH_CTRL_PEND_DIS 0x02
+#define KEYP_SIH_CTRL_EXCL_EN 0x01
+
+#endif /* End of __TWL4030-KEYPAD_H__ */
To compile this driver as a module, choose M here: the
module will be called touchwin.
+config TOUCHSCREEN_TSC2005
+ tristate "TSC2005 touchscreen support"
+ help
+ Say Y here for if you are using the touchscreen features of TSC2301.
+
+config TOUCHSCREEN_TSC2102
+ tristate "TSC 2102 based touchscreens"
+ depends on SPI_MASTER
+ select SPI_TSC2102
+ help
+ Say Y here if you have a touchscreen interface using the
+ TI TSC 2102 controller, and your board-specific initialization
+ code includes that in its table of SPI devices. Also make
+ sure the proper SPI controller is selected.
+
+ If unsure, say N (but it's safe to say "Y").
+
+ To compile this driver as a module, choose M here: the
+ module will be called tsc2102_ts.
+
+config TOUCHSCREEN_TSC210X
+ tristate "TI TSC210x based touchscreens"
+ depends on SPI_MASTER
+ select SPI_TSC210X
+ help
+ Say Y here if you have a touchscreen interface using a
+ TI TSC210x controller, and your board-specific initialisation
+ code includes that in its table of SPI devices.
+
+ If unsure, say N (but it's safe to say "Y").
+
+ To compile this driver as a module, choose M here: the
+ module will be called tsc210x_ts.
+
+config TOUCHSCREEN_TSC2301
+ tristate "TSC2301 touchscreen support"
+ depends on SPI_TSC2301
+ help
+ Say Y here for if you are using the touchscreen features of TSC2301.
+
config TOUCHSCREEN_UCB1400
tristate "Philips UCB1400 touchscreen"
select AC97_BUS
obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o
obj-$(CONFIG_TOUCHSCREEN_UCB1400) += ucb1400_ts.o
+obj-$(CONFIG_TOUCHSCREEN_TSC2005) += tsc2005.o
+obj-$(CONFIG_TOUCHSCREEN_TSC2102) += tsc2102_ts.o
+obj-$(CONFIG_TOUCHSCREEN_OMAP) += omap/
+obj-$(CONFIG_TOUCHSCREEN_TSC210X) += tsc210x_ts.o
+obj-$(CONFIG_TOUCHSCREEN_TSC2301) += tsc2301_ts.o
obj-$(CONFIG_TOUCHSCREEN_WM97XX) += wm97xx-ts.o
wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9705) += wm9705.o
wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9712) += wm9712.o
return -ENODEV;
}
+ /* enable voltage */
+ if (pdata->vaux_control != NULL) {
+ err = pdata->vaux_control(VAUX_ENABLE);
+ if (err != 0) {
+ dev_dbg(&spi->dev, "TS vaux enable failed\n");
+ return err;
+ }
+ }
+
/* don't exceed max specified sample rate */
if (spi->max_speed_hz > (125000 * SAMPLE_BITS)) {
dev_dbg(&spi->dev, "f(sample) %d KHz?\n",
--- /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
+
+omapts-objs := omap_ts.o $(objs-yy)
--- /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
+};
+
+static struct omap_ts_t ts_omap;
+
+static int omap_ts_read(void)
+{
+ u16 data[4] = { 0, 0, 0, 0 };
+
+ ts_omap.dev->read(data);
+
+ input_report_abs(ts_omap.inputdevice, ABS_X, data[0]);
+ input_report_abs(ts_omap.inputdevice, ABS_Y, data[1]);
+ input_report_abs(ts_omap.inputdevice, ABS_PRESSURE, data[2]);
+ input_sync(ts_omap.inputdevice);
+
+ DEBUG_TS("omap_ts_read: read x=%d,y=%d,p=%d\n", data[0], data[1],
+ data[2]);
+
+ return 0;
+}
+
+static void omap_ts_timer(unsigned long data)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ts_omap.lock, flags);
+
+ if (!ts_omap.dev->penup()) {
+ if (!ts_omap.touched) {
+ DEBUG_TS("omap_ts_timer: pen down\n");
+ input_report_key(ts_omap.inputdevice, BTN_TOUCH, 1);
+ }
+ ts_omap.touched = 1;
+ omap_ts_read();
+ ts_omap.ts_timer.expires = jiffies + HZ / 100;
+ add_timer(&(ts_omap.ts_timer));
+ } else {
+ if (ts_omap.touched) {
+ DEBUG_TS("omap_ts_timer: pen up\n");
+ ts_omap.touched = 0;
+ input_report_abs(ts_omap.inputdevice, ABS_X, 0);
+ input_report_abs(ts_omap.inputdevice, ABS_Y, 0);
+ input_report_abs(ts_omap.inputdevice, ABS_PRESSURE,
+ 0);
+ input_sync(ts_omap.inputdevice);
+ input_report_key(ts_omap.inputdevice, BTN_TOUCH, 0);
+ }
+ if (!ts_omap.irq_enabled) {
+ ts_omap.irq_enabled = 1;
+ enable_irq(ts_omap.irq);
+ }
+ }
+
+ spin_unlock_irqrestore(&ts_omap.lock, flags);
+}
+
+static irqreturn_t omap_ts_handler(int irq, void *dev_id)
+{
+ spin_lock(&ts_omap.lock);
+
+ if (ts_omap.irq_enabled) {
+ ts_omap.irq_enabled = 0;
+ disable_irq(irq);
+ }
+ // restart acquire
+ mod_timer(&ts_omap.ts_timer, jiffies + HZ / 100);
+
+ spin_unlock(&ts_omap.lock);
+
+ return IRQ_HANDLED;
+}
+
+static int __init omap_ts_probe(struct platform_device *pdev)
+{
+ int i;
+ int status = -ENODEV;
+
+ memset(&ts_omap, 0, sizeof(ts_omap));
+
+ ts_omap.inputdevice = input_allocate_device();
+ if (!ts_omap.inputdevice) {
+ return -ENOMEM;
+ }
+
+ spin_lock_init(&ts_omap.lock);
+
+ for (i = 0; i < ARRAY_SIZE(ts_devs); i++) {
+ if (!ts_devs[i] || !ts_devs[i]->probe)
+ continue;
+ status = ts_devs[i]->probe(&ts_omap);
+ if (status == 0) {
+ ts_omap.dev = ts_devs[i];
+ break;
+ }
+ }
+
+ if (status != 0) {
+ input_free_device(ts_omap.inputdevice);
+ return status;
+ }
+
+ // Init acquisition timer function
+ init_timer(&ts_omap.ts_timer);
+ ts_omap.ts_timer.function = omap_ts_timer;
+
+ /* request irq */
+ if (ts_omap.irq != -1) {
+ if (request_irq(ts_omap.irq, omap_ts_handler,
+ IRQF_SAMPLE_RANDOM | ts_omap.irq_type,
+ OMAP_TS_NAME, &ts_omap)) {
+ printk(KERN_ERR
+ "omap_ts.c: Could not allocate touchscreen IRQ!\n");
+ ts_omap.irq = -1;
+ ts_omap.dev->remove();
+ input_free_device(ts_omap.inputdevice);
+ return -EINVAL;
+ }
+ ts_omap.irq_enabled = 1;
+ } else {
+ printk(KERN_ERR "omap_ts.c: No touchscreen IRQ assigned!\n");
+ ts_omap.dev->remove();
+ input_free_device(ts_omap.inputdevice);
+ return -EINVAL;
+ }
+
+ ts_omap.inputdevice->name = OMAP_TS_NAME;
+ ts_omap.inputdevice->dev = &pdev->dev;
+ ts_omap.inputdevice->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ ts_omap.inputdevice->keybit[BIT_WORD(BTN_TOUCH)] |= BIT(BTN_TOUCH);
+ ts_omap.inputdevice->absbit[0] =
+ BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);
+ input_register_device(ts_omap.inputdevice);
+
+ ts_omap.dev->enable();
+
+ printk("OMAP touchscreen driver initialized\n");
+
+ return 0;
+}
+
+static int omap_ts_remove(struct platform_device *pdev)
+{
+ ts_omap.dev->disable();
+ input_unregister_device(ts_omap.inputdevice);
+ if (ts_omap.irq != -1)
+ free_irq(ts_omap.irq, &ts_omap);
+
+ ts_omap.dev->remove();
+
+ return 0;
+}
+
+static int omap_ts_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ ts_omap.dev->disable();
+ return 0;
+}
+
+static int omap_ts_resume(struct platform_device *pdev)
+{
+ ts_omap.dev->enable();
+ return 0;
+}
+
+static void omap_ts_device_release(struct device *dev)
+{
+ /* Nothing */
+}
+static struct platform_driver omap_ts_driver = {
+ .probe = omap_ts_probe,
+ .remove = omap_ts_remove,
+ .suspend = omap_ts_suspend,
+ .resume = omap_ts_resume,
+ .driver = {
+ .name = OMAP_TS_NAME,
+ },
+};
+
+static struct platform_device omap_ts_device = {
+ .name = OMAP_TS_NAME,
+ .id = -1,
+ .dev = {
+ .release = omap_ts_device_release,
+ },
+};
+
+static int __init omap_ts_init(void)
+{
+ int ret;
+
+ if (machine_is_omap_osk() || machine_is_omap_innovator())
+ return -ENODEV;
+
+ ret = platform_device_register(&omap_ts_device);
+ if (ret != 0)
+ return -ENODEV;
+
+ ret = platform_driver_register(&omap_ts_driver);
+ if (ret != 0) {
+ platform_device_unregister(&omap_ts_device);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static void __exit omap_ts_exit(void)
+{
+ platform_driver_unregister(&omap_ts_driver);
+ platform_device_unregister(&omap_ts_device);
+}
+
+module_init(omap_ts_init);
+module_exit(omap_ts_exit);
+
+MODULE_LICENSE("GPL");
--- /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;
+
+#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 = IRQF_TRIGGER_FALLING;
+ return 0;
+}
+
+static void hx_ts_read(u16 * values)
+{
+ s32 t, p = 0;
+ int i;
+
+ /* Read X, Y, Z1 and Z2 */
+ omap_tsc2101_reads(TOUCHSCREEN_DATA_REGISTERS_PAGE, TSC2101_TS_X,
+ values, OMAP_TSC2101_READ_MAX);
+
+ for (i = 0; i < OMAP_TSC2101_READ_MAX; i++)
+ values[i] &= TSC2101_MASKVAL;
+
+ /* Calculate Pressure */
+ if (values[TSC2101_TS_Z1] != 0) {
+ t = ((OMAP_TSC2101_XRES * values[TSC2101_TS_X]) *
+ (values[TSC2101_TS_Z2] - values[TSC2101_TS_Z1]));
+ p = t / (u32) (TSC2101_PRESSUREVAL(values[TSC2101_TS_Z1]));
+ if (p < 0)
+ p = 0;
+ }
+
+ values[TSC2101_TS_Z1] = p;
+}
+
+static void hx_ts_enable(void)
+{
+ int ret = omap_tsc2101_enable();
+ if (ret) {
+ printk(KERN_ERR "FAILED TO INITIALIZE TSC CODEC\n");
+ return;
+ }
+
+ /* PINTDAV is data available only */
+ omap_tsc2101_write(TOUCHSCREEN_CONTROL_REGISTERS_PAGE,
+ TSC2101_TS_STATUS, TSC2101_DATA_AVAILABLE);
+ /* disable buffer mode */
+ omap_tsc2101_write(TOUCHSCREEN_CONTROL_REGISTERS_PAGE,
+ TSC2101_TS_BUFFER_CTRL, TSC2101_BUFFERMODE_DISABLE);
+ /* use internal reference, 100 usec power-up delay,
+ * * power down between conversions, 1.25V internal reference */
+ omap_tsc2101_write(TOUCHSCREEN_CONTROL_REGISTERS_PAGE,
+ TSC2101_TS_REF_CTRL, TSC2101_REF_POWERUP);
+ /* enable touch detection, 84usec precharge time, 32 usec sense time */
+ omap_tsc2101_write(TOUCHSCREEN_CONTROL_REGISTERS_PAGE,
+ TSC2101_TS_CONFIG_CTRL, TSC2101_ENABLE_TOUCHDETECT);
+ /* 3 msec conversion delays */
+ omap_tsc2101_write(TOUCHSCREEN_CONTROL_REGISTERS_PAGE,
+ TSC2101_TS_PROG_DELAY, TSC2101_PRG_DELAY);
+ /*
+ * TSC2101-controlled conversions
+ * 12-bit samples
+ * continuous X,Y,Z1,Z2 scan mode
+ * average (mean) 4 samples per coordinate
+ * 1 MHz internal conversion clock
+ * 500 usec panel voltage stabilization delay
+ */
+ omap_tsc2101_write(TOUCHSCREEN_CONTROL_REGISTERS_PAGE,
+ TSC2101_TS_ADC_CTRL, TSC2101_ADC_CONTROL);
+
+ return;
+
+}
+
+static void hx_ts_disable(void)
+{
+ /* stop conversions and power down */
+ omap_tsc2101_write(TOUCHSCREEN_CONTROL_REGISTERS_PAGE,
+ TSC2101_TS_ADC_CTRL, TSC2101_ADC_POWERDOWN);
+ omap_tsc2101_disable();
+}
+
+#ifdef MODULE
+static void __exit hx_ts_remove(void)
+{
+ if (machine_is_omap_h2())
+ omap_free_gpio(H2_GPIO_NUM);
+ else if (machine_is_omap_h3())
+ omap_free_gpio(H3_GPIO_NUM);
+}
+#endif
--- /dev/null
+/*
+ * TSC2005 touchscreen driver
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation
+ *
+ * Author: Lauri Leukkunen <lauri.leukkunen@nokia.com>
+ * based on TSC2301 driver by Klaus K. Pedersen <klaus.k.pedersen@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/spi/spi.h>
+
+#ifdef CONFIG_ARCH_OMAP
+#include <asm/arch/gpio.h>
+#endif
+
+#include <linux/spi/tsc2005.h>
+
+/**
+ * The touchscreen interface operates as follows:
+ *
+ * Initialize:
+ * Request access to GPIO103 (DAV)
+ * tsc2005_dav_irq_handler will trigger when DAV line goes down
+ *
+ * 1) Pen is pressed against touchscreeen
+ * 2) TSC2005 performs AD conversion
+ * 3) After the conversion is done TSC2005 drives DAV line down
+ * 4) GPIO IRQ is received and tsc2005_dav_irq_handler is called
+ * 5) tsc2005_ts_irq_handler queues up an spi transfer to fetch
+ * the x, y, z1, z2 values
+ * 6) tsc2005_ts_rx() reports coordinates to input layer and
+ * sets up tsc2005_ts_timer() to be called after TSC2005_TS_SCAN_TIME
+ * 7) When the penup_timer expires, there have not been DAV interrupts
+ * during the last 20ms which means the pen has been lifted.
+ */
+
+#define TSC2005_HZ (14000000)
+
+#define TSC2005_CMD (0x80)
+#define TSC2005_REG (0x00)
+
+#define TSC2005_CMD_STOP (1)
+#define TSC2005_CMD_10BIT (0 << 2)
+#define TSC2005_CMD_12BIT (1 << 2)
+
+#define TSC2005_CMD_SCAN_XYZZ (0 << 3)
+#define TSC2005_CMD_SCAN_XY (1 << 3)
+#define TSC2005_CMD_SCAN_X (2 << 3)
+#define TSC2005_CMD_SCAN_Y (3 << 3)
+#define TSC2005_CMD_SCAN_ZZ (4 << 3)
+#define TSC2005_CMD_AUX_SINGLE (5 << 3)
+#define TSC2005_CMD_TEMP1 (6 << 3)
+#define TSC2005_CMD_TEMP2 (7 << 3)
+#define TSC2005_CMD_AUX_CONT (8 << 3)
+#define TSC2005_CMD_TEST_X_CONN (9 << 3)
+#define TSC2005_CMD_TEST_Y_CONN (10 << 3)
+/* command 11 reserved */
+#define TSC2005_CMD_TEST_SHORT (12 << 3)
+#define TSC2005_CMD_DRIVE_XX (13 << 3)
+#define TSC2005_CMD_DRIVE_YY (14 << 3)
+#define TSC2005_CMD_DRIVE_YX (15 << 3)
+
+#define TSC2005_REG_X (0 << 3)
+#define TSC2005_REG_Y (1 << 3)
+#define TSC2005_REG_Z1 (2 << 3)
+#define TSC2005_REG_Z2 (3 << 3)
+#define TSC2005_REG_AUX (4 << 3)
+#define TSC2005_REG_TEMP1 (5 << 3)
+#define TSC2005_REG_TEMP2 (6 << 3)
+#define TSC2005_REG_STATUS (7 << 3)
+#define TSC2005_REG_AUX_HIGH (8 << 3)
+#define TSC2005_REG_AUX_LOW (9 << 3)
+#define TSC2005_REG_TEMP_HIGH (10 << 3)
+#define TSC2005_REG_TEMP_LOW (11 << 3)
+#define TSC2005_REG_CFR0 (12 << 3)
+#define TSC2005_REG_CFR1 (13 << 3)
+#define TSC2005_REG_CFR2 (14 << 3)
+#define TSC2005_REG_FUNCTION (15 << 3)
+
+#define TSC2005_REG_PND0 (1 << 1)
+#define TSC2005_REG_READ (0x01)
+#define TSC2005_REG_WRITE (0x00)
+
+
+#define TSC2005_CFR0_LONGSAMPLING (1)
+#define TSC2005_CFR0_DETECTINWAIT (1 << 1)
+#define TSC2005_CFR0_SENSETIME_32US (0)
+#define TSC2005_CFR0_SENSETIME_96US (1 << 2)
+#define TSC2005_CFR0_SENSETIME_544US (1 << 3)
+#define TSC2005_CFR0_SENSETIME_2080US (1 << 4)
+#define TSC2005_CFR0_SENSETIME_2656US (0x001C)
+#define TSC2005_CFR0_PRECHARGE_20US (0x0000)
+#define TSC2005_CFR0_PRECHARGE_84US (0x0020)
+#define TSC2005_CFR0_PRECHARGE_276US (0x0040)
+#define TSC2005_CFR0_PRECHARGE_1044US (0x0080)
+#define TSC2005_CFR0_PRECHARGE_1364US (0x00E0)
+#define TSC2005_CFR0_STABTIME_0US (0x0000)
+#define TSC2005_CFR0_STABTIME_100US (0x0100)
+#define TSC2005_CFR0_STABTIME_500US (0x0200)
+#define TSC2005_CFR0_STABTIME_1MS (0x0300)
+#define TSC2005_CFR0_STABTIME_5MS (0x0400)
+#define TSC2005_CFR0_STABTIME_100MS (0x0700)
+#define TSC2005_CFR0_CLOCK_4MHZ (0x0000)
+#define TSC2005_CFR0_CLOCK_2MHZ (0x0800)
+#define TSC2005_CFR0_CLOCK_1MHZ (0x1000)
+#define TSC2005_CFR0_RESOLUTION12 (0x2000)
+#define TSC2005_CFR0_STATUS (0x4000)
+#define TSC2005_CFR0_PENMODE (0x8000)
+
+#define TSC2005_CFR0_INITVALUE (TSC2005_CFR0_STABTIME_1MS | \
+ TSC2005_CFR0_CLOCK_1MHZ | \
+ TSC2005_CFR0_RESOLUTION12 | \
+ TSC2005_CFR0_PRECHARGE_276US | \
+ TSC2005_CFR0_PENMODE)
+
+#define TSC2005_CFR1_BATCHDELAY_0MS (0x0000)
+#define TSC2005_CFR1_BATCHDELAY_1MS (0x0001)
+#define TSC2005_CFR1_BATCHDELAY_2MS (0x0002)
+#define TSC2005_CFR1_BATCHDELAY_4MS (0x0003)
+#define TSC2005_CFR1_BATCHDELAY_10MS (0x0004)
+#define TSC2005_CFR1_BATCHDELAY_20MS (0x0005)
+#define TSC2005_CFR1_BATCHDELAY_40MS (0x0006)
+#define TSC2005_CFR1_BATCHDELAY_100MS (0x0007)
+
+#define TSC2005_CFR1_INITVALUE (TSC2005_CFR1_BATCHDELAY_2MS)
+
+#define TSC2005_CFR2_MAVE_TEMP (0x0001)
+#define TSC2005_CFR2_MAVE_AUX (0x0002)
+#define TSC2005_CFR2_MAVE_Z (0x0004)
+#define TSC2005_CFR2_MAVE_Y (0x0008)
+#define TSC2005_CFR2_MAVE_X (0x0010)
+#define TSC2005_CFR2_AVG_1 (0x0000)
+#define TSC2005_CFR2_AVG_3 (0x0400)
+#define TSC2005_CFR2_AVG_7 (0x0800)
+#define TSC2005_CFR2_MEDIUM_1 (0x0000)
+#define TSC2005_CFR2_MEDIUM_3 (0x1000)
+#define TSC2005_CFR2_MEDIUM_7 (0x2000)
+#define TSC2005_CFR2_MEDIUM_15 (0x3000)
+
+#define TSC2005_CFR2_IRQ_DAV (0x4000)
+#define TSC2005_CFR2_IRQ_PEN (0x8000)
+#define TSC2005_CFR2_IRQ_PENDAV (0x0000)
+
+#define TSC2005_CFR2_INITVALUE (TSC2005_CFR2_IRQ_DAV | \
+ TSC2005_CFR2_MAVE_X | \
+ TSC2005_CFR2_MAVE_Y | \
+ TSC2005_CFR2_MAVE_Z | \
+ TSC2005_CFR2_MEDIUM_15 | \
+ TSC2005_CFR2_AVG_7)
+
+#define MAX_12BIT ((1 << 12) - 1)
+#define TS_SAMPLES 4
+#define TS_RECT_SIZE 8
+#define TSC2005_TS_PENUP_TIME 20
+
+static const u32 tsc2005_read_reg[] = {
+ (TSC2005_REG | TSC2005_REG_X | TSC2005_REG_READ) << 16,
+ (TSC2005_REG | TSC2005_REG_Y | TSC2005_REG_READ) << 16,
+ (TSC2005_REG | TSC2005_REG_Z1 | TSC2005_REG_READ) << 16,
+ (TSC2005_REG | TSC2005_REG_Z2 | TSC2005_REG_READ) << 16,
+};
+#define NUM_READ_REGS (sizeof(tsc2005_read_reg)/sizeof(tsc2005_read_reg[0]))
+
+struct tsc2005 {
+ struct spi_device *spi;
+
+ struct input_dev *idev;
+ char phys[32];
+ struct timer_list penup_timer;
+ spinlock_t lock;
+ struct mutex mutex;
+
+ struct spi_message read_msg;
+ struct spi_transfer read_xfer[NUM_READ_REGS];
+ u32 data[NUM_READ_REGS];
+
+ /* previous x,y,z */
+ int x;
+ int y;
+ int p;
+ /* average accumulators for each component */
+ int sample_cnt;
+ int avg_x;
+ int avg_y;
+ int avg_z1;
+ int avg_z2;
+ /* configuration */
+ int x_plate_ohm;
+ int hw_avg_max;
+ int stab_time;
+ int p_max;
+ int touch_pressure;
+ int irq;
+ s16 dav_gpio;
+ /* status */
+ u8 sample_sent;
+ u8 pen_down;
+ u8 disabled;
+ u8 disable_depth;
+ u8 spi_active;
+};
+
+static void tsc2005_cmd(struct tsc2005 *ts, u8 cmd)
+{
+ u16 data = TSC2005_CMD | TSC2005_CMD_12BIT | cmd;
+ struct spi_message msg;
+ struct spi_transfer xfer = { 0 };
+
+ spi_message_init(&msg);
+ msg.spi = ts->spi;
+ xfer.tx_buf = &data;
+ xfer.rx_buf = NULL;
+ xfer.len = 2;
+ xfer.bits_per_word = 8;
+
+ spi_message_add_tail(&xfer, &msg);
+ spi_sync(ts->spi, &msg);
+}
+
+static void tsc2005_write(struct tsc2005 *ts, u8 reg, u16 value)
+{
+ u32 tx;
+ struct spi_message msg;
+ struct spi_transfer xfer = { 0 };
+
+ tx = (TSC2005_REG | reg | TSC2005_REG_PND0 |
+ TSC2005_REG_WRITE) << (2 * 8);
+ tx |= value;
+
+ spi_message_init(&msg);
+ msg.spi = ts->spi;
+ xfer.tx_buf = &tx;
+ xfer.rx_buf = NULL;
+ xfer.len = 4;
+ xfer.bits_per_word = 3 * 8;
+
+ spi_message_add_tail(&xfer, &msg);
+ spi_sync(ts->spi, &msg);
+}
+
+static void tsc2005_ts_update_pen_state(struct tsc2005 *ts,
+ int x, int y, int pressure)
+{
+ if (pressure) {
+ input_report_abs(ts->idev, ABS_X, x);
+ input_report_abs(ts->idev, ABS_Y, y);
+ input_report_abs(ts->idev, ABS_PRESSURE, pressure);
+ if (!ts->pen_down) {
+ input_report_key(ts->idev, BTN_TOUCH, 1);
+ ts->pen_down = 1;
+ }
+ } else {
+ input_report_abs(ts->idev, ABS_PRESSURE, 0);
+ if (ts->pen_down)
+ input_report_key(ts->idev, BTN_TOUCH, 0);
+
+ ts->pen_down = 0;
+ }
+
+ input_sync(ts->idev);
+}
+
+/*
+ * This function is called by the SPI framework after the coordinates
+ * have been read from TSC2005
+ */
+static void tsc2005_ts_rx(void *arg)
+{
+ struct tsc2005 *ts = arg;
+ unsigned long flags;
+ int inside_rect, pressure_limit;
+ int x, y, z1, z2, pressure;
+
+ spin_lock_irqsave(&ts->lock, flags);
+
+ x = ts->data[0];
+ y = ts->data[1];
+ z1 = ts->data[2];
+ z2 = ts->data[3];
+
+ /* validate pressure and position */
+ if (x > MAX_12BIT || y > MAX_12BIT)
+ goto out;
+
+ /* skip coords if the pressure-components are out of range */
+ if (z1 < 100 || z2 > 4000)
+ goto out;
+
+ /* don't run average on the "pen down" event */
+ if (ts->sample_sent) {
+ ts->avg_x += x;
+ ts->avg_y += y;
+ ts->avg_z1 += z1;
+ ts->avg_z2 += z2;
+
+ if (++ts->sample_cnt < TS_SAMPLES)
+ goto out;
+
+ x = ts->avg_x / TS_SAMPLES;
+ y = ts->avg_y / TS_SAMPLES;
+ z1 = ts->avg_z1 / TS_SAMPLES;
+ z2 = ts->avg_z2 / TS_SAMPLES;
+ }
+
+ ts->sample_cnt = 0;
+ ts->avg_x = 0;
+ ts->avg_y = 0;
+ ts->avg_z1 = 0;
+ ts->avg_z2 = 0;
+
+ if (z1) {
+ pressure = x * (z2 - z1) / z1;
+ pressure = pressure * ts->x_plate_ohm / 4096;
+ } else
+ goto out;
+
+ pressure_limit = ts->sample_sent? ts->p_max: ts->touch_pressure;
+ if (pressure > pressure_limit)
+ goto out;
+
+ /* discard the event if it still is within the previous rect - unless
+ * if the pressure is harder, but then use previous x,y position */
+ inside_rect = (ts->sample_sent &&
+ x > (int)ts->x - TS_RECT_SIZE &&
+ x < (int)ts->x + TS_RECT_SIZE &&
+ y > (int)ts->y - TS_RECT_SIZE &&
+ y < (int)ts->y + TS_RECT_SIZE);
+ if (inside_rect)
+ x = ts->x, y = ts->y;
+
+ if (!inside_rect || pressure < ts->p) {
+ tsc2005_ts_update_pen_state(ts, x, y, pressure);
+ ts->sample_sent = 1;
+ ts->x = x;
+ ts->y = y;
+ ts->p = pressure;
+ }
+out:
+ ts->spi_active = 0;
+ spin_unlock_irqrestore(&ts->lock, flags);
+
+ /* kick pen up timer - to make sure it expires again(!) */
+ if (ts->sample_sent)
+ mod_timer(&ts->penup_timer,
+ jiffies + msecs_to_jiffies(TSC2005_TS_PENUP_TIME));
+}
+
+static void tsc2005_ts_penup_timer_handler(unsigned long data)
+{
+ struct tsc2005 *ts = (struct tsc2005 *)data;
+
+ if (ts->sample_sent) {
+ tsc2005_ts_update_pen_state(ts, 0, 0, 0);
+ ts->sample_sent = 0;
+ }
+}
+
+/*
+ * This interrupt is called when pen is down and coordinates are
+ * available. That is indicated by a falling edge on DEV line.
+ */
+static irqreturn_t tsc2005_ts_irq_handler(int irq, void *dev_id)
+{
+ struct tsc2005 *ts = dev_id;
+ int r;
+
+ if (ts->spi_active)
+ return IRQ_HANDLED;
+
+ ts->spi_active = 1;
+ r = spi_async(ts->spi, &ts->read_msg);
+ if (r)
+ dev_err(&ts->spi->dev, "ts: spi_async() failed");
+
+ /* kick pen up timer */
+ mod_timer(&ts->penup_timer,
+ jiffies + msecs_to_jiffies(TSC2005_TS_PENUP_TIME));
+
+ return IRQ_HANDLED;
+}
+
+static void tsc2005_ts_setup_spi_xfer(struct tsc2005 *ts)
+{
+ struct spi_message *m = &ts->read_msg;
+ struct spi_transfer *x = &ts->read_xfer[0];
+ int i;
+
+ spi_message_init(m);
+ m->spi = ts->spi;
+
+ for (i = 0; i < NUM_READ_REGS; i++, x++) {
+ x->tx_buf = &tsc2005_read_reg[i];
+ x->rx_buf = &ts->data[i];
+ x->len = 4;
+ x->bits_per_word = 24;
+ x->cs_change = i < (NUM_READ_REGS - 1);
+ spi_message_add_tail(x, m);
+ }
+
+ m->complete = tsc2005_ts_rx;
+ m->context = ts;
+}
+
+static ssize_t tsc2005_ts_pen_down_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct tsc2005 *tsc = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%u\n", tsc->pen_down);
+}
+
+static DEVICE_ATTR(pen_down, S_IRUGO, tsc2005_ts_pen_down_show, NULL);
+
+static int tsc2005_configure(struct tsc2005 *tsc, int flags)
+{
+ tsc2005_write(tsc, TSC2005_REG_CFR0, TSC2005_CFR0_INITVALUE);
+ tsc2005_write(tsc, TSC2005_REG_CFR1, TSC2005_CFR1_INITVALUE);
+ tsc2005_write(tsc, TSC2005_REG_CFR2, TSC2005_CFR2_INITVALUE);
+ tsc2005_cmd(tsc, flags);
+
+ return 0;
+}
+
+static void tsc2005_start_scan(struct tsc2005 *tsc)
+{
+ tsc2005_configure(tsc, TSC2005_CMD_SCAN_XYZZ);
+}
+
+static void tsc2005_stop_scan(struct tsc2005 *tsc)
+{
+ tsc2005_cmd(tsc, TSC2005_CMD_STOP);
+}
+
+/* Must be called with mutex held */
+static void tsc2005_disable(struct tsc2005 *ts)
+{
+ if (ts->disable_depth++ != 0)
+ return;
+
+ disable_irq(ts->irq);
+
+ /* wait until penup timer expire normally */
+ do {
+ msleep(4);
+ } while (ts->sample_sent);
+
+ tsc2005_stop_scan(ts);
+}
+
+static void tsc2005_enable(struct tsc2005 *ts)
+{
+ if (--ts->disable_depth != 0)
+ return;
+
+ enable_irq(ts->irq);
+
+ tsc2005_start_scan(ts);
+}
+
+static ssize_t tsc2005_disable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tsc2005 *ts = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%u\n", ts->disabled);
+}
+
+static ssize_t tsc2005_disable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct tsc2005 *tsc = dev_get_drvdata(dev);
+ unsigned long res;
+ int i;
+
+ i = strict_strtoul(buf, 10, &res);
+ i = i ? 1 : 0;
+
+ mutex_lock(&tsc->mutex);
+ if (i == tsc->disabled)
+ goto out;
+ tsc->disabled = i;
+
+ if (i)
+ tsc2005_disable(tsc);
+ else
+ tsc2005_enable(tsc);
+out:
+ mutex_unlock(&tsc->mutex);
+ return count;
+}
+
+static DEVICE_ATTR(disable_ts, 0664, tsc2005_disable_show,
+ tsc2005_disable_store);
+
+
+static int __devinit tsc2005_ts_init(struct tsc2005 *ts,
+ struct tsc2005_platform_data *pdata)
+{
+ struct input_dev *idev;
+ int dav_gpio, r;
+ int x_max, y_max;
+ int x_fudge, y_fudge, p_fudge;
+
+ if (pdata->dav_gpio < 0) {
+ dev_err(&ts->spi->dev, "need DAV GPIO");
+ return -EINVAL;
+ }
+ dav_gpio = pdata->dav_gpio;
+ ts->dav_gpio = dav_gpio;
+ dev_dbg(&ts->spi->dev, "TSC2005: DAV GPIO = %d\n", dav_gpio);
+
+#ifdef CONFIG_ARCH_OMAP
+ r = omap_request_gpio(dav_gpio);
+ if (r < 0) {
+ dev_err(&ts->spi->dev, "unable to get DAV GPIO");
+ goto err1;
+ }
+ omap_set_gpio_direction(dav_gpio, 1);
+ ts->irq = OMAP_GPIO_IRQ(dav_gpio);
+ dev_dbg(&ts->spi->dev, "TSC2005: DAV IRQ = %d\n", ts->irq);
+#endif
+ init_timer(&ts->penup_timer);
+ setup_timer(&ts->penup_timer, tsc2005_ts_penup_timer_handler,
+ (unsigned long)ts);
+
+ spin_lock_init(&ts->lock);
+ mutex_init(&ts->mutex);
+
+ ts->x_plate_ohm = pdata->ts_x_plate_ohm ? : 280;
+ ts->hw_avg_max = pdata->ts_hw_avg;
+ ts->stab_time = pdata->ts_stab_time;
+ x_max = pdata->ts_x_max ? : 4096;
+ x_fudge = pdata->ts_x_fudge ? : 4;
+ y_max = pdata->ts_y_max ? : 4096;
+ y_fudge = pdata->ts_y_fudge ? : 8;
+ ts->p_max = pdata->ts_pressure_max ? : MAX_12BIT;
+ ts->touch_pressure = pdata->ts_touch_pressure ? : ts->p_max;
+ p_fudge = pdata->ts_pressure_fudge ? : 2;
+
+ idev = input_allocate_device();
+ if (idev == NULL) {
+ r = -ENOMEM;
+ goto err2;
+ }
+
+ /*
+ * TODO: should be "TSC2005 touchscreen", but X has hardcoded these
+ * strings and doesn't accept TSC2005 yet...
+ */
+ idev->name = "TSC2301 touchscreen";
+ snprintf(ts->phys, sizeof(ts->phys), "%s/input-ts",
+ ts->spi->dev.bus_id);
+ idev->phys = ts->phys;
+
+ idev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY);
+ idev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);
+ ts->idev = idev;
+
+ tsc2005_ts_setup_spi_xfer(ts);
+
+ input_set_abs_params(idev, ABS_X, 0, x_max, x_fudge, 0);
+ input_set_abs_params(idev, ABS_Y, 0, y_max, y_fudge, 0);
+ input_set_abs_params(idev, ABS_PRESSURE, 0, ts->p_max, p_fudge, 0);
+
+ tsc2005_start_scan(ts);
+
+ r = request_irq(ts->irq, tsc2005_ts_irq_handler,
+ IRQF_TRIGGER_FALLING | IRQF_DISABLED |
+ IRQF_SAMPLE_RANDOM, "tsc2005", ts);
+ if (r < 0) {
+ dev_err(&ts->spi->dev, "unable to get DAV IRQ");
+ goto err3;
+ }
+
+ set_irq_wake(ts->irq, 1);
+
+ r = input_register_device(idev);
+ if (r < 0) {
+ dev_err(&ts->spi->dev, "can't register touchscreen device\n");
+ goto err4;
+ }
+
+ /* We can tolerate these failing */
+ if (device_create_file(&ts->spi->dev, &dev_attr_pen_down));
+ if (device_create_file(&ts->spi->dev, &dev_attr_disable_ts));
+
+ return 0;
+err4:
+ free_irq(ts->irq, ts);
+err3:
+ tsc2005_stop_scan(ts);
+ input_free_device(idev);
+err2:
+#ifdef CONFIG_ARCH_OMAP
+ omap_free_gpio(dav_gpio);
+#endif
+err1:
+ return r;
+}
+
+static int __devinit tsc2005_probe(struct spi_device *spi)
+{
+ struct tsc2005 *tsc;
+ struct tsc2005_platform_data *pdata = spi->dev.platform_data;
+ int r;
+
+ if (!pdata) {
+ dev_dbg(&spi->dev, "no platform data?\n");
+ return -ENODEV;
+ }
+
+ tsc = kzalloc(sizeof(*tsc), GFP_KERNEL);
+ if (tsc == NULL)
+ return -ENOMEM;
+
+ dev_set_drvdata(&spi->dev, tsc);
+ tsc->spi = spi;
+ spi->dev.power.power_state = PMSG_ON;
+
+ spi->mode = SPI_MODE_0;
+ spi->bits_per_word = 8;
+ /* The max speed might've been defined by the board-specific
+ * struct */
+ if (!spi->max_speed_hz)
+ spi->max_speed_hz = TSC2005_HZ;
+
+ spi_setup(spi);
+
+ r = tsc2005_ts_init(tsc, pdata);
+ if (r)
+ goto err1;
+
+ return 0;
+
+err1:
+ kfree(tsc);
+ return r;
+}
+
+static int __devexit tsc2005_remove(struct spi_device *spi)
+{
+ struct tsc2005 *ts = dev_get_drvdata(&spi->dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&ts->lock, flags);
+ tsc2005_disable(ts);
+ spin_unlock_irqrestore(&ts->lock, flags);
+
+ device_remove_file(&ts->spi->dev, &dev_attr_disable_ts);
+ device_remove_file(&ts->spi->dev, &dev_attr_pen_down);
+
+ free_irq(ts->irq, ts);
+ input_unregister_device(ts->idev);
+
+#ifdef CONFIG_ARCH_OMAP
+ omap_free_gpio(ts->dav_gpio);
+#endif
+ kfree(ts);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int tsc2005_suspend(struct spi_device *spi, pm_message_t mesg)
+{
+ struct tsc2005 *ts = dev_get_drvdata(&spi->dev);
+
+ mutex_lock(&ts->mutex);
+ tsc2005_disable(ts);
+ mutex_unlock(&ts->mutex);
+
+ return 0;
+}
+
+static int tsc2005_resume(struct spi_device *spi)
+{
+ struct tsc2005 *ts = dev_get_drvdata(&spi->dev);
+
+ mutex_lock(&ts->mutex);
+ tsc2005_enable(ts);
+ mutex_unlock(&ts->mutex);
+
+ return 0;
+}
+#endif
+
+static struct spi_driver tsc2005_driver = {
+ .driver = {
+ .name = "tsc2005",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+#ifdef CONFIG_PM
+ .suspend = tsc2005_suspend,
+ .resume = tsc2005_resume,
+#endif
+ .probe = tsc2005_probe,
+ .remove = __devexit_p(tsc2005_remove),
+};
+
+static int __init tsc2005_init(void)
+{
+ printk(KERN_INFO "TSC2005 driver initializing\n");
+
+ return spi_register_driver(&tsc2005_driver);
+}
+module_init(tsc2005_init);
+
+static void __exit tsc2005_exit(void)
+{
+ spi_unregister_driver(&tsc2005_driver);
+}
+module_exit(tsc2005_exit);
+
+MODULE_AUTHOR("Lauri Leukkunen <lauri.leukkunen@nokia.com>");
+MODULE_LICENSE("GPL");
+
--- /dev/null
+/*
+ * input/touchscreen/tsc2102_ts.c
+ *
+ * Touchscreen input device driver for the TSC 2102 chip.
+ *
+ * Copyright (c) 2006 Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this package; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <linux/spi/tsc2102.h>
+
+struct input_dev *dev;
+
+static void tsc2102_touch(int touching)
+{
+ if (!touching) {
+ input_report_abs(dev, ABS_X, 0);
+ input_report_abs(dev, ABS_Y, 0);
+ input_report_abs(dev, ABS_PRESSURE, 0);
+ input_sync(dev);
+ }
+
+ input_report_key(dev, BTN_TOUCH, touching);
+}
+
+static void tsc2102_coords(int x, int y, int z1, int z2)
+{
+ int p;
+
+ /* Calculate the touch resistance a la equation #1 */
+ if (z1 != 0)
+ p = x * (z2 - z1) / (z1 << 4);
+ else
+ p = 1;
+
+ input_report_abs(dev, ABS_X, x);
+ input_report_abs(dev, ABS_Y, y);
+ input_report_abs(dev, ABS_PRESSURE, p);
+ input_sync(dev);
+}
+
+static int tsc2102_ts_probe(struct platform_device *pdev)
+{
+ int status;
+
+ dev = input_allocate_device();
+ if (!dev)
+ return -ENOMEM;
+
+ status = tsc2102_touch_cb(tsc2102_touch);
+ if (status) {
+ input_free_device(dev);
+ return status;
+ }
+
+ status = tsc2102_coords_cb(tsc2102_coords);
+ if (status) {
+ tsc2102_touch_cb(0);
+ input_free_device(dev);
+ return status;
+ }
+
+ dev->name = "TSC2102 Touchscreen";
+ dev->cdev.dev = &pdev->dev;
+ dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ dev->keybit[LONG(BTN_TOUCH)] |= BIT(BTN_TOUCH);
+ dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);
+ dev->phys = "tsc2102/input0";
+ dev->id.bustype = BUS_HOST;
+ dev->id.vendor = 0x0001;
+ dev->id.product = 0x2102;
+ dev->id.version = 0x0001;
+
+ status = input_register_device(dev);
+ if (status) {
+ tsc2102_coords_cb(0);
+ tsc2102_touch_cb(0);
+ input_free_device(dev);
+ return status;
+ }
+
+ printk(KERN_INFO "TSC2102 touchscreen driver initialized\n");
+ return 0;
+}
+
+static int tsc2102_ts_remove(struct platform_device *pdev)
+{
+ tsc2102_touch_cb(0);
+ tsc2102_coords_cb(0);
+ input_unregister_device(dev);
+ input_free_device(dev);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int
+tsc2102_ts_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ return 0;
+}
+
+static int tsc2102_ts_resume(struct platform_device *pdev)
+{
+ return 0;
+}
+#else
+#define tsc2102_ts_suspend NULL
+#define tsc2102_ts_resume NULL
+#endif
+
+static struct platform_driver tsc2102_ts_driver = {
+ .probe = tsc2102_ts_probe,
+ .remove = tsc2102_ts_remove,
+ .suspend = tsc2102_ts_suspend,
+ .resume = tsc2102_ts_resume,
+ .driver = {
+ .name = "tsc2102-ts",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init tsc2102_ts_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&tsc2102_ts_driver);
+ if (ret)
+ return -ENODEV;
+
+ return 0;
+}
+
+static void __exit tsc2102_ts_exit(void)
+{
+ platform_driver_unregister(&tsc2102_ts_driver);
+}
+
+module_init(tsc2102_ts_init);
+module_exit(tsc2102_ts_exit);
+
+MODULE_AUTHOR("Andrzej Zaborowski");
+MODULE_DESCRIPTION("Touchscreen input driver for TI TSC2102.");
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * tsc210x_ts.c - touchscreen input device for TI TSC210x chips
+ *
+ * Copyright (c) 2006-2007 Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this package; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <linux/spi/tsc210x.h>
+
+
+/*
+ * The sensor ADC on tsc210x chips is most often used with the smart
+ * touchscreen controller. Those controllers can be made to improve
+ * sample quality directly by multi-sampling and by taking the mean or
+ * median of various numbers of samples. They also take X, Y, and
+ * pressure measurements automatically, so this driver has relatively
+ * little to do.
+ *
+ * There are a few chips in this family that don't have quite the same
+ * touchscreen interface, e.g. no "median" mode.
+ */
+
+static void tsc210x_touch(void *context, int touching)
+{
+ struct input_dev *dev = context;
+
+ if (!touching) {
+ input_report_abs(dev, ABS_X, 0);
+ input_report_abs(dev, ABS_Y, 0);
+ input_report_abs(dev, ABS_PRESSURE, 0);
+ input_sync(dev);
+ }
+
+ input_report_key(dev, BTN_TOUCH, touching);
+}
+
+static void tsc210x_coords(void *context, int x, int y, int z1, int z2)
+{
+ struct input_dev *dev = context;
+ int p;
+
+ /* Calculate the touch resistance a la equation #1 */
+ if (z1 != 0)
+ p = x * (z2 - z1) / (z1 << 4);
+ else
+ p = 1;
+
+ input_report_abs(dev, ABS_X, x);
+ input_report_abs(dev, ABS_Y, y);
+ input_report_abs(dev, ABS_PRESSURE, p);
+ input_sync(dev);
+}
+
+static int tsc210x_ts_probe(struct platform_device *pdev)
+{
+ int status;
+ struct input_dev *dev;
+
+ dev = input_allocate_device();
+ if (!dev)
+ return -ENOMEM;
+
+ status = tsc210x_touch_cb(pdev->dev.parent, tsc210x_touch, dev);
+ if (status) {
+ input_free_device(dev);
+ return status;
+ }
+
+ status = tsc210x_coords_cb(pdev->dev.parent, tsc210x_coords, dev);
+ if (status) {
+ tsc210x_touch_cb(pdev->dev.parent, NULL, NULL);
+ input_free_device(dev);
+ return status;
+ }
+
+ dev->name = "TSC210x Touchscreen";
+ dev->dev.parent = &pdev->dev;
+ dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ dev->keybit[BIT_WORD(BTN_TOUCH)] |= BIT_MASK(BTN_TOUCH);
+ dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);
+ dev->phys = "tsc210x/input0";
+ dev->id.bustype = BUS_HOST;
+ dev->id.vendor = 0x0001;
+ dev->id.product = 0x2100;
+ dev->id.version = 0x0001;
+
+ status = input_register_device(dev);
+ if (status) {
+ tsc210x_coords_cb(pdev->dev.parent, NULL, NULL);
+ tsc210x_touch_cb(pdev->dev.parent, NULL, NULL);
+ input_free_device(dev);
+ return status;
+ }
+
+ platform_set_drvdata(pdev, dev);
+ printk(KERN_INFO "TSC210x touchscreen initialised\n");
+ return 0;
+}
+
+static int __exit tsc210x_ts_remove(struct platform_device *pdev)
+{
+ struct input_dev *dev = platform_get_drvdata(pdev);
+
+ tsc210x_touch_cb(pdev->dev.parent, NULL, NULL);
+ tsc210x_coords_cb(pdev->dev.parent, NULL, NULL);
+ platform_set_drvdata(pdev, NULL);
+ input_unregister_device(dev);
+ input_free_device(dev);
+
+ return 0;
+}
+
+static struct platform_driver tsc210x_ts_driver = {
+ .probe = tsc210x_ts_probe,
+ .remove = __exit_p(tsc210x_ts_remove),
+ /* Nothing to do on suspend/resume */
+ .driver = {
+ .name = "tsc210x-ts",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init tsc210x_ts_init(void)
+{
+ /* can't use driver_probe() here since the parent device
+ * gets registered "late"
+ */
+ return platform_driver_register(&tsc210x_ts_driver);
+}
+module_init(tsc210x_ts_init);
+
+static void __exit tsc210x_ts_exit(void)
+{
+ platform_driver_unregister(&tsc210x_ts_driver);
+}
+module_exit(tsc210x_ts_exit);
+
+MODULE_AUTHOR("Andrzej Zaborowski");
+MODULE_DESCRIPTION("Touchscreen input driver for TI TSC2101/2102.");
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * TSC2301 touchscreen driver
+ *
+ * Copyright (C) 2005-2008 Nokia Corporation
+ *
+ * Written by Jarkko Oikarinen, Imre Deak and Juha Yrjola
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/spi/spi.h>
+
+#include <linux/spi/tsc2301.h>
+
+/**
+ * The touchscreen interface operates as follows:
+ *
+ * Initialize:
+ * Request access to GPIO103 (DAV)
+ * tsc2301_ts_irq_handler will trigger when DAV line goes down
+ *
+ * 1) Pen is pressed against touchscreeen
+ * 2) TSC2301 performs AD conversion
+ * 3) After the conversion is done TSC2301 drives DAV line down
+ * 4) GPIO IRQ is received and tsc2301_ts_irq_handler is called
+ * 5) tsc2301_ts_irq_handler queues up an spi transfer to fetch
+ * the x, y, z1, z2 values
+ * 6) SPI framework calls tsc2301_ts_rx after the coordinates are read
+ * 7) When the penup_timer expires, there have not been DAV interrupts
+ * during the last 20ms which means the pen has been lifted.
+ */
+
+
+#define TSC2301_TOUCHSCREEN_PRODUCT_ID 0x0052
+#define TSC2301_TOUCHSCREEN_PRODUCT_VERSION 0x0001
+
+#define TSC2301_TS_PENUP_TIME 20
+
+#define TSC2301_ADCREG_CONVERSION_CTRL_BY_TSC2301 0x8000
+#define TSC2301_ADCREG_CONVERSION_CTRL_BY_HOST 0x0000
+
+#define TSC2301_ADCREG_FUNCTION_NONE 0x0000
+#define TSC2301_ADCREG_FUNCTION_XY 0x0400
+#define TSC2301_ADCREG_FUNCTION_XYZ 0x0800
+#define TSC2301_ADCREG_FUNCTION_X 0x0C00
+#define TSC2301_ADCREG_FUNCTION_Y 0x1000
+#define TSC2301_ADCREG_FUNCTION_Z 0x1400
+#define TSC2301_ADCREG_FUNCTION_DAT1 0x1800
+#define TSC2301_ADCREG_FUNCTION_DAT2 0x1C00
+#define TSC2301_ADCREG_FUNCTION_AUX1 0x2000
+#define TSC2301_ADCREG_FUNCTION_AUX2 0x2400
+#define TSC2301_ADCREG_FUNCTION_TEMP 0x2800
+
+#define TSC2301_ADCREG_RESOLUTION_8BIT 0x0100
+#define TSC2301_ADCREG_RESOLUTION_10BIT 0x0200
+#define TSC2301_ADCREG_RESOLUTION_12BIT 0x0300
+
+#define TSC2301_ADCREG_AVERAGING_NONE 0x0000
+#define TSC2301_ADCREG_AVERAGING_4AVG 0x0040
+#define TSC2301_ADCREG_AVERAGING_8AVG 0x0080
+#define TSC2301_ADCREG_AVERAGING_16AVG 0x00C0
+
+#define TSC2301_ADCREG_CLOCK_8MHZ 0x0000
+#define TSC2301_ADCREG_CLOCK_4MHZ 0x0010
+#define TSC2301_ADCREG_CLOCK_2MHZ 0x0020
+#define TSC2301_ADCREG_CLOCK_1MHZ 0x0030
+
+#define TSC2301_ADCREG_VOLTAGE_STAB_0US 0x0000
+#define TSC2301_ADCREG_VOLTAGE_STAB_100US 0x0002
+#define TSC2301_ADCREG_VOLTAGE_STAB_500US 0x0004
+#define TSC2301_ADCREG_VOLTAGE_STAB_1MS 0x0006
+#define TSC2301_ADCREG_VOLTAGE_STAB_5MS 0x0008
+#define TSC2301_ADCREG_VOLTAGE_STAB_10MS 0x000A
+#define TSC2301_ADCREG_VOLTAGE_STAB_50MS 0x000C
+#define TSC2301_ADCREG_VOLTAGE_STAB_100MS 0x000E
+
+#define TSC2301_ADCREG_STOP_CONVERSION 0x4000
+
+#define MAX_12BIT ((1 << 12) - 1)
+
+#define TS_RECT_SIZE 8
+#define TSF_MIN_Z1 100
+#define TSF_MAX_Z2 4000
+
+#define TSF_SAMPLES 4
+
+struct ts_filter {
+ int sample_cnt;
+
+ int avg_x;
+ int avg_y;
+ int avg_z1;
+ int avg_z2;
+};
+
+struct ts_coords {
+ u16 x;
+ u16 y;
+ u16 z1;
+ u16 z2;
+};
+
+struct tsc2301_ts {
+ struct input_dev *idev;
+ char phys[32];
+ struct timer_list penup_timer;
+ struct mutex mutex;
+
+ struct spi_transfer read_xfer[2];
+ struct spi_message read_msg;
+ struct ts_coords *coords;
+
+ struct ts_filter filter;
+
+ int hw_avg_max;
+ u16 x;
+ u16 y;
+ u16 p;
+
+ u16 x_plate_ohm;
+ int stab_time;
+ int max_pressure;
+ int touch_pressure;
+
+ u8 event_sent;
+ u8 pen_down;
+ u8 disabled;
+ u8 disable_depth;
+
+ int hw_flags;
+ int irq;
+};
+
+
+static const u16 tsc2301_ts_read_data = 0x8000 | TSC2301_REG_X;
+
+static int tsc2301_ts_check_config(struct tsc2301_ts *ts, int *hw_flags)
+{
+ int flags;
+
+ flags = 0;
+ switch (ts->hw_avg_max) {
+ case 0:
+ flags |= TSC2301_ADCREG_AVERAGING_NONE;
+ break;
+ case 4:
+ flags |= TSC2301_ADCREG_AVERAGING_4AVG;
+ break;
+ case 8:
+ flags |= TSC2301_ADCREG_AVERAGING_8AVG;
+ break;
+ case 16:
+ flags |= TSC2301_ADCREG_AVERAGING_16AVG;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (ts->stab_time) {
+ case 0:
+ flags |= TSC2301_ADCREG_VOLTAGE_STAB_0US;
+ break;
+ case 100:
+ flags |= TSC2301_ADCREG_VOLTAGE_STAB_100US;
+ break;
+ case 500:
+ flags |= TSC2301_ADCREG_VOLTAGE_STAB_500US;
+ break;
+ case 1000:
+ flags |= TSC2301_ADCREG_VOLTAGE_STAB_1MS;
+ break;
+ case 5000:
+ flags |= TSC2301_ADCREG_VOLTAGE_STAB_5MS;
+ break;
+ case 10000:
+ flags |= TSC2301_ADCREG_VOLTAGE_STAB_10MS;
+ break;
+ case 50000:
+ flags |= TSC2301_ADCREG_VOLTAGE_STAB_50MS;
+ break;
+ case 100000:
+ flags |= TSC2301_ADCREG_VOLTAGE_STAB_100MS;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ *hw_flags = flags;
+ return 0;
+}
+
+/*
+ * This odd three-time initialization is to work around a bug in TSC2301.
+ * See TSC2301 errata for details.
+ */
+static int tsc2301_ts_configure(struct tsc2301 *tsc, int flags)
+{
+ struct spi_transfer xfer[5];
+ struct spi_transfer *x;
+ struct spi_message m;
+ int i;
+ u16 val1, val2, val3;
+ u16 data[10];
+
+ val1 = TSC2301_ADCREG_CONVERSION_CTRL_BY_HOST |
+ TSC2301_ADCREG_STOP_CONVERSION |
+ TSC2301_ADCREG_FUNCTION_NONE |
+ TSC2301_ADCREG_RESOLUTION_12BIT |
+ TSC2301_ADCREG_AVERAGING_NONE |
+ TSC2301_ADCREG_CLOCK_2MHZ |
+ TSC2301_ADCREG_VOLTAGE_STAB_100MS;
+
+ val2 = TSC2301_ADCREG_CONVERSION_CTRL_BY_HOST |
+ TSC2301_ADCREG_FUNCTION_XYZ |
+ TSC2301_ADCREG_RESOLUTION_12BIT |
+ TSC2301_ADCREG_AVERAGING_16AVG |
+ TSC2301_ADCREG_CLOCK_1MHZ |
+ TSC2301_ADCREG_VOLTAGE_STAB_100MS;
+
+ /* Averaging and voltage stabilization settings in flags */
+ val3 = TSC2301_ADCREG_CONVERSION_CTRL_BY_TSC2301 |
+ TSC2301_ADCREG_FUNCTION_XYZ |
+ TSC2301_ADCREG_RESOLUTION_12BIT |
+ TSC2301_ADCREG_CLOCK_2MHZ |
+ flags;
+
+ /* Now we prepare the command for transferring */
+ data[0] = TSC2301_REG_ADC;
+ data[1] = val1;
+ data[2] = TSC2301_REG_ADC;
+ data[3] = val2;
+ data[4] = TSC2301_REG_ADC;
+ data[5] = val3;
+ data[6] = TSC2301_REG_REF;
+ data[7] = 1 << 4 | 1 << 2 | 1; /* intref, 100uS settl, 2.5V ref */
+ data[8] = TSC2301_REG_CONFIG;
+ data[9] = 3 << 3 | 2 << 0; /* 340uS pre-chrg, 544us delay */
+
+ spi_message_init(&m);
+ m.spi = tsc->spi;
+
+ memset(xfer, 0, sizeof(xfer));
+ x = &xfer[0];
+
+ for (i = 0; i < 10; i += 2) {
+ x->tx_buf = &data[i];
+ x->len = 4;
+ if (i != 8)
+ x->cs_change = 1;
+ spi_message_add_tail(x, &m);
+ x++;
+ }
+ spi_sync(m.spi, &m);
+
+ return 0;
+}
+
+static void tsc2301_ts_start_scan(struct tsc2301 *tsc)
+{
+ tsc2301_ts_configure(tsc, tsc->ts->hw_flags);
+ tsc2301_kp_restart(tsc);
+}
+
+static void tsc2301_ts_stop_scan(struct tsc2301 *tsc)
+{
+ tsc2301_write_reg(tsc, TSC2301_REG_ADC, TSC2301_ADCREG_STOP_CONVERSION);
+ tsc2301_kp_restart(tsc);
+}
+
+static void update_pen_state(struct tsc2301_ts *ts, int x, int y, int pressure)
+{
+ if (pressure) {
+ input_report_abs(ts->idev, ABS_X, x);
+ input_report_abs(ts->idev, ABS_Y, y);
+ input_report_abs(ts->idev, ABS_PRESSURE, pressure);
+ if (!ts->pen_down)
+ input_report_key(ts->idev, BTN_TOUCH, 1);
+ ts->pen_down = 1;
+ } else {
+ input_report_abs(ts->idev, ABS_PRESSURE, 0);
+ if (ts->pen_down)
+ input_report_key(ts->idev, BTN_TOUCH, 0);
+ ts->pen_down = 0;
+ }
+
+ input_sync(ts->idev);
+
+#ifdef VERBOSE
+ dev_dbg(&tsc->spi->dev, "x %4d y %4d p %4d\n", x, y, pressure);
+#endif
+}
+
+static int filter(struct tsc2301_ts *ts, int x, int y, int z1, int z2)
+{
+ int inside_rect, pressure_limit, Rt;
+ struct ts_filter *tsf = &ts->filter;
+
+ /* validate pressure and position */
+ if (x > MAX_12BIT || y > MAX_12BIT)
+ return 0;
+
+ /* skip coords if the pressure-components are out of range */
+ if (z1 < TSF_MIN_Z1 || z2 > TSF_MAX_Z2)
+ return 0;
+
+ /* Use the x,y,z1,z2 directly on the first "pen down" event */
+ if (ts->event_sent) {
+ tsf->avg_x += x;
+ tsf->avg_y += y;
+ tsf->avg_z1 += z1;
+ tsf->avg_z2 += z2;
+
+ if (++tsf->sample_cnt < TSF_SAMPLES)
+ return 0;
+ x = tsf->avg_x / TSF_SAMPLES;
+ y = tsf->avg_y / TSF_SAMPLES;
+ z1 = tsf->avg_z1 / TSF_SAMPLES;
+ z2 = tsf->avg_z2 / TSF_SAMPLES;
+ }
+ tsf->sample_cnt = 0;
+ tsf->avg_x = 0;
+ tsf->avg_y = 0;
+ tsf->avg_z1 = 0;
+ tsf->avg_z2 = 0;
+
+ pressure_limit = ts->event_sent? ts->max_pressure: ts->touch_pressure;
+
+ /* z1 is always at least 100: */
+ Rt = x * (z2 - z1) / z1;
+ Rt = Rt * ts->x_plate_ohm / 4096;
+ if (Rt > pressure_limit)
+ return 0;
+
+ /* discard the event if it still is within the previous rect - unless
+ * if the pressure is harder, but then use previous x,y position */
+ inside_rect = (
+ x > (int)ts->x - TS_RECT_SIZE && x < (int)ts->x + TS_RECT_SIZE &&
+ y > (int)ts->y - TS_RECT_SIZE && y < (int)ts->y + TS_RECT_SIZE);
+
+ if (!ts->event_sent || !inside_rect) {
+ ts->x = x;
+ ts->y = y;
+ ts->p = Rt;
+ return 1;
+ } else if (Rt < ts->p) {
+ ts->p = Rt;
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * This procedure is called by the SPI framework after the coordinates
+ * have been read from TSC2301
+ */
+static void tsc2301_ts_rx(void *arg)
+{
+ struct tsc2301 *tsc = arg;
+ struct tsc2301_ts *ts = tsc->ts;
+ int send_event;
+ int x, y, z1, z2;
+
+ x = ts->coords->x;
+ y = ts->coords->y;
+ z1 = ts->coords->z1;
+ z2 = ts->coords->z2;
+
+ send_event = filter(ts, x, y, z1, z2);
+ if (send_event) {
+ update_pen_state(ts, ts->x, ts->y, ts->p);
+ ts->event_sent = 1;
+ }
+
+ mod_timer(&ts->penup_timer,
+ jiffies + msecs_to_jiffies(TSC2301_TS_PENUP_TIME));
+}
+
+/*
+ * Timer is called TSC2301_TS_PENUP_TIME after pen is up
+ */
+static void tsc2301_ts_timer_handler(unsigned long data)
+{
+ struct tsc2301 *tsc = (struct tsc2301 *)data;
+ struct tsc2301_ts *ts = tsc->ts;
+
+ if (ts->event_sent) {
+ ts->event_sent = 0;
+ update_pen_state(ts, 0, 0, 0);
+ }
+}
+
+/*
+ * This interrupt is called when pen is down and coordinates are
+ * available. That is indicated by a falling edge on DEV line.
+ */
+static irqreturn_t tsc2301_ts_irq_handler(int irq, void *dev_id)
+{
+ struct tsc2301 *tsc = dev_id;
+ struct tsc2301_ts *ts = tsc->ts;
+ int r;
+
+ r = spi_async(tsc->spi, &ts->read_msg);
+ if (r)
+ dev_err(&tsc->spi->dev, "ts: spi_async() failed");
+
+ mod_timer(&ts->penup_timer,
+ jiffies + msecs_to_jiffies(TSC2301_TS_PENUP_TIME));
+
+ return IRQ_HANDLED;
+}
+
+static void tsc2301_ts_disable(struct tsc2301 *tsc)
+{
+ struct tsc2301_ts *ts = tsc->ts;
+
+ if (ts->disable_depth++ != 0)
+ return;
+
+ disable_irq(ts->irq);
+
+ /* wait until penup timer expire normally */
+ do {
+ msleep(1);
+ } while (ts->event_sent);
+
+ tsc2301_ts_stop_scan(tsc);
+}
+
+static void tsc2301_ts_enable(struct tsc2301 *tsc)
+{
+ struct tsc2301_ts *ts = tsc->ts;
+
+ if (--ts->disable_depth != 0)
+ return;
+
+ enable_irq(ts->irq);
+
+ tsc2301_ts_start_scan(tsc);
+}
+
+#ifdef CONFIG_PM
+int tsc2301_ts_suspend(struct tsc2301 *tsc)
+{
+ struct tsc2301_ts *ts = tsc->ts;
+
+ mutex_lock(&ts->mutex);
+ tsc2301_ts_disable(tsc);
+ mutex_unlock(&ts->mutex);
+
+ return 0;
+}
+
+void tsc2301_ts_resume(struct tsc2301 *tsc)
+{
+ struct tsc2301_ts *ts = tsc->ts;
+
+ mutex_lock(&ts->mutex);
+ tsc2301_ts_enable(tsc);
+ mutex_unlock(&ts->mutex);
+}
+#endif
+
+static void tsc2301_ts_setup_spi_xfer(struct tsc2301 *tsc)
+{
+ struct tsc2301_ts *ts = tsc->ts;
+ struct spi_message *m = &ts->read_msg;
+ struct spi_transfer *x = &ts->read_xfer[0];
+
+ spi_message_init(m);
+
+ x->tx_buf = &tsc2301_ts_read_data;
+ x->len = 2;
+ spi_message_add_tail(x, m);
+
+ x++;
+ x->rx_buf = ts->coords;
+ x->len = 8;
+ spi_message_add_tail(x, m);
+
+ m->complete = tsc2301_ts_rx;
+ m->context = tsc;
+}
+
+static ssize_t tsc2301_ts_pen_down_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct tsc2301 *tsc = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%u\n", tsc->ts->pen_down);
+}
+
+static DEVICE_ATTR(pen_down, S_IRUGO, tsc2301_ts_pen_down_show, NULL);
+
+static ssize_t tsc2301_ts_disable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tsc2301 *tsc = dev_get_drvdata(dev);
+ struct tsc2301_ts *ts = tsc->ts;
+
+ return sprintf(buf, "%u\n", ts->disabled);
+}
+
+static ssize_t tsc2301_ts_disable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct tsc2301 *tsc = dev_get_drvdata(dev);
+ struct tsc2301_ts *ts = tsc->ts;
+ char *endp;
+ int i;
+
+ i = simple_strtoul(buf, &endp, 10);
+ i = i ? 1 : 0;
+ mutex_lock(&ts->mutex);
+ if (i == ts->disabled) goto out;
+ ts->disabled = i;
+
+ if (i)
+ tsc2301_ts_disable(tsc);
+ else
+ tsc2301_ts_enable(tsc);
+out:
+ mutex_unlock(&ts->mutex);
+ return count;
+}
+
+static DEVICE_ATTR(disable_ts, 0664, tsc2301_ts_disable_show,
+ tsc2301_ts_disable_store);
+
+int __devinit tsc2301_ts_init(struct tsc2301 *tsc,
+ struct tsc2301_platform_data *pdata)
+{
+ struct tsc2301_ts *ts;
+ struct input_dev *idev;
+ int r;
+ int x_max, y_max;
+ int x_fudge, y_fudge, p_fudge;
+
+ if (pdata->dav_int <= 0) {
+ dev_err(&tsc->spi->dev, "need DAV IRQ");
+ return -EINVAL;
+ }
+
+ ts = kzalloc(sizeof(*ts), GFP_KERNEL);
+ if (ts == NULL)
+ return -ENOMEM;
+ tsc->ts = ts;
+
+ ts->coords = kzalloc(sizeof(*ts->coords), GFP_KERNEL);
+ if (ts->coords == NULL) {
+ kfree(ts);
+ return -ENOMEM;
+ }
+
+ ts->irq = pdata->dav_int;
+
+ init_timer(&ts->penup_timer);
+ setup_timer(&ts->penup_timer, tsc2301_ts_timer_handler,
+ (unsigned long)tsc);
+
+ mutex_init(&ts->mutex);
+
+ ts->x_plate_ohm = pdata->ts_x_plate_ohm ? : 280;
+ ts->hw_avg_max = pdata->ts_hw_avg;
+ ts->max_pressure = pdata->ts_max_pressure ? : MAX_12BIT;
+ ts->touch_pressure = pdata->ts_touch_pressure ? : ts->max_pressure;
+ ts->stab_time = pdata->ts_stab_time;
+
+ x_max = pdata->ts_x_max ? : 4096;
+ y_max = pdata->ts_y_max ? : 4096;
+ x_fudge = pdata->ts_x_fudge ? : 4;
+ y_fudge = pdata->ts_y_fudge ? : 8;
+ p_fudge = pdata->ts_pressure_fudge ? : 2;
+
+ if ((r = tsc2301_ts_check_config(ts, &ts->hw_flags))) {
+ dev_err(&tsc->spi->dev, "invalid configuration\n");
+ goto err2;
+ }
+
+ idev = input_allocate_device();
+ if (idev == NULL) {
+ r = -ENOMEM;
+ goto err2;
+ }
+ idev->name = "TSC2301 touchscreen";
+ snprintf(ts->phys, sizeof(ts->phys),
+ "%s/input-ts", tsc->spi->dev.bus_id);
+ idev->phys = ts->phys;
+ idev->dev.parent = &tsc->spi->dev;
+
+ idev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY);
+ idev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);
+ ts->idev = idev;
+
+ tsc2301_ts_setup_spi_xfer(tsc);
+
+ /* These parameters should perhaps be configurable? */
+ input_set_abs_params(idev, ABS_X, 0, x_max, x_fudge, 0);
+ input_set_abs_params(idev, ABS_Y, 0, y_max, y_fudge, 0);
+ input_set_abs_params(idev, ABS_PRESSURE, 0, ts->max_pressure,
+ p_fudge, 0);
+
+ tsc2301_ts_start_scan(tsc);
+
+ r = request_irq(ts->irq, tsc2301_ts_irq_handler,
+ IRQF_SAMPLE_RANDOM | IRQF_TRIGGER_FALLING,
+ "tsc2301-ts", tsc);
+ if (r < 0) {
+ dev_err(&tsc->spi->dev, "unable to get DAV IRQ");
+ goto err3;
+ }
+ set_irq_wake(ts->irq, 1);
+
+ if (device_create_file(&tsc->spi->dev, &dev_attr_pen_down) < 0)
+ goto err4;
+ if (device_create_file(&tsc->spi->dev, &dev_attr_disable_ts) < 0)
+ goto err5;
+
+ r = input_register_device(idev);
+ if (r < 0) {
+ dev_err(&tsc->spi->dev, "can't register touchscreen device\n");
+ goto err6;
+ }
+
+ return 0;
+err6:
+ device_remove_file(&tsc->spi->dev, &dev_attr_disable_ts);
+err5:
+ device_remove_file(&tsc->spi->dev, &dev_attr_pen_down);
+err4:
+ free_irq(ts->irq, tsc);
+err3:
+ tsc2301_ts_stop_scan(tsc);
+ input_free_device(idev);
+err2:
+ kfree(ts->coords);
+ kfree(ts);
+ return r;
+}
+
+void __devexit tsc2301_ts_exit(struct tsc2301 *tsc)
+{
+ struct tsc2301_ts *ts = tsc->ts;
+
+ tsc2301_ts_disable(tsc);
+
+ device_remove_file(&tsc->spi->dev, &dev_attr_disable_ts);
+ device_remove_file(&tsc->spi->dev, &dev_attr_pen_down);
+
+ free_irq(ts->irq, tsc);
+ input_unregister_device(ts->idev);
+
+ kfree(ts->coords);
+ kfree(ts);
+}
+MODULE_AUTHOR("Jarkko Oikarinen <jarkko.oikarinen@nokia.com>");
+MODULE_LICENSE("GPL");
help
This option enables support for the PCEngines WRAP programmable LEDs.
+config LEDS_OMAP_DEBUG
+ boolean "LED Support for OMAP debug board LEDs"
+ depends on LEDS_CLASS=y && ARCH_OMAP
+ help
+ Enables support for the LEDs on the debug board used with OMAP
+ reference boards like H2/H3/H4 and Perseus2. Up to six of these
+ may be claimed by the original ARM debug LED API.
+
+config LEDS_OMAP
+ tristate "LED Support for OMAP GPIO LEDs"
+ depends on LEDS_CLASS && ARCH_OMAP
+ help
+ This option enables support for the LEDs on OMAP processors.
+
+config LEDS_OMAP_PWM
+ tristate "LED Support for OMAP PWM-controlled LEDs"
+ depends on LEDS_CLASS && ARCH_OMAP && OMAP_DM_TIMER
+ help
+ This options enables support for LEDs connected to GPIO lines
+ controlled by a PWM timer on OMAP CPUs.
+
config LEDS_H1940
tristate "LED Support for iPAQ H1940 device"
depends on LEDS_CLASS && ARCH_H1940
obj-$(CONFIG_LEDS_AMS_DELTA) += leds-ams-delta.o
obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o
obj-$(CONFIG_LEDS_WRAP) += leds-wrap.o
+obj-$(CONFIG_LEDS_OMAP) += leds-omap.o
+obj-$(CONFIG_LEDS_OMAP_PWM) += leds-omap-pwm.o
obj-$(CONFIG_LEDS_H1940) += leds-h1940.o
obj-$(CONFIG_LEDS_COBALT_QUBE) += leds-cobalt-qube.o
obj-$(CONFIG_LEDS_COBALT_RAQ) += leds-cobalt-raq.o
--- /dev/null
+/* drivers/leds/leds-omap_pwm.c
+ *
+ * Driver to blink LEDs using OMAP PWM timers
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Author: Timo Teras
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/ctype.h>
+#include <linux/sched.h>
+#include <asm/delay.h>
+#include <asm/arch/board.h>
+#include <asm/arch/dmtimer.h>
+
+struct omap_pwm_led {
+ struct led_classdev cdev;
+ struct work_struct work;
+ struct omap_pwm_led_platform_data *pdata;
+ struct omap_dm_timer *intensity_timer;
+ struct omap_dm_timer *blink_timer;
+ int powered;
+ unsigned int on_period, off_period;
+ enum led_brightness brightness;
+};
+
+static inline struct omap_pwm_led *pdev_to_omap_pwm_led(struct platform_device *pdev)
+{
+ return platform_get_drvdata(pdev);
+}
+
+static inline struct omap_pwm_led *cdev_to_omap_pwm_led(struct led_classdev *led_cdev)
+{
+ return container_of(led_cdev, struct omap_pwm_led, cdev);
+}
+
+static inline struct omap_pwm_led *work_to_omap_pwm_led(struct work_struct *work)
+{
+ return container_of(work, struct omap_pwm_led, work);
+}
+
+static void omap_pwm_led_set_blink(struct omap_pwm_led *led)
+{
+ if (!led->powered)
+ return;
+
+ if (led->on_period != 0 && led->off_period != 0) {
+ unsigned long load_reg, cmp_reg;
+
+ load_reg = 32768 * (led->on_period + led->off_period) / 1000;
+ cmp_reg = 32768 * led->on_period / 1000;
+
+ omap_dm_timer_stop(led->blink_timer);
+ omap_dm_timer_set_load(led->blink_timer, 1, -load_reg);
+ omap_dm_timer_set_match(led->blink_timer, 1, -cmp_reg);
+ omap_dm_timer_set_pwm(led->blink_timer, 1, 1,
+ OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE);
+ omap_dm_timer_write_counter(led->blink_timer, -2);
+ omap_dm_timer_start(led->blink_timer);
+ } else {
+ omap_dm_timer_set_pwm(led->blink_timer, 1, 1,
+ OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE);
+ omap_dm_timer_stop(led->blink_timer);
+ }
+}
+
+static void omap_pwm_led_power_on(struct omap_pwm_led *led)
+{
+ if (led->powered)
+ return;
+ led->powered = 1;
+
+ /* Select clock */
+ omap_dm_timer_enable(led->intensity_timer);
+ omap_dm_timer_set_source(led->intensity_timer, OMAP_TIMER_SRC_32_KHZ);
+
+ /* Turn voltage on */
+ if (led->pdata->set_power != NULL)
+ led->pdata->set_power(led->pdata, 1);
+
+ /* Enable PWM timers */
+ if (led->blink_timer != NULL) {
+ omap_dm_timer_enable(led->blink_timer);
+ omap_dm_timer_set_source(led->blink_timer,
+ OMAP_TIMER_SRC_32_KHZ);
+ omap_pwm_led_set_blink(led);
+ }
+
+ omap_dm_timer_set_load(led->intensity_timer, 1, 0xffffff00);
+}
+
+static void omap_pwm_led_power_off(struct omap_pwm_led *led)
+{
+ if (!led->powered)
+ return;
+ led->powered = 0;
+
+ /* Everything off */
+ omap_dm_timer_stop(led->intensity_timer);
+ omap_dm_timer_disable(led->intensity_timer);
+
+ if (led->blink_timer != NULL) {
+ omap_dm_timer_stop(led->blink_timer);
+ omap_dm_timer_disable(led->blink_timer);
+ }
+
+ if (led->pdata->set_power != NULL)
+ led->pdata->set_power(led->pdata, 0);
+}
+
+static void omap_pwm_led_set_pwm_cycle(struct omap_pwm_led *led, int cycle)
+{
+ int n;
+
+ if (cycle == 0)
+ n = 0xff;
+ else n = cycle - 1;
+
+ if (cycle == LED_FULL) {
+ omap_dm_timer_set_pwm(led->intensity_timer, 1, 1,
+ OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE);
+ omap_dm_timer_stop(led->intensity_timer);
+ } else {
+ omap_dm_timer_set_pwm(led->intensity_timer, 0, 1,
+ OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE);
+ omap_dm_timer_set_match(led->intensity_timer, 1,
+ (0xffffff00) | cycle);
+ omap_dm_timer_start(led->intensity_timer);
+ }
+}
+
+static void omap_pwm_led_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ struct omap_pwm_led *led = cdev_to_omap_pwm_led(led_cdev);
+
+ led->brightness = value;
+ schedule_work(&led->work);
+}
+
+static void omap_pwm_led_work(struct work_struct *work)
+{
+ struct omap_pwm_led *led = work_to_omap_pwm_led(work);
+
+ if (led->brightness != LED_OFF) {
+ omap_pwm_led_power_on(led);
+ omap_pwm_led_set_pwm_cycle(led, led->brightness);
+ } else {
+ omap_pwm_led_power_off(led);
+ }
+}
+
+static ssize_t omap_pwm_led_on_period_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ struct omap_pwm_led *led = cdev_to_omap_pwm_led(led_cdev);
+
+ return sprintf(buf, "%u\n", led->on_period) + 1;
+}
+
+static ssize_t omap_pwm_led_on_period_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ struct omap_pwm_led *led = cdev_to_omap_pwm_led(led_cdev);
+ int ret = -EINVAL;
+ unsigned long val;
+ char *after;
+ size_t count;
+
+ val = simple_strtoul(buf, &after, 10);
+ count = after - buf;
+ if (*after && isspace(*after))
+ count++;
+
+ if (count == size) {
+ led->on_period = val;
+ omap_pwm_led_set_blink(led);
+ ret = count;
+ }
+
+ return ret;
+}
+
+static ssize_t omap_pwm_led_off_period_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ struct omap_pwm_led *led = cdev_to_omap_pwm_led(led_cdev);
+
+ return sprintf(buf, "%u\n", led->off_period) + 1;
+}
+
+static ssize_t omap_pwm_led_off_period_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ struct omap_pwm_led *led = cdev_to_omap_pwm_led(led_cdev);
+ int ret = -EINVAL;
+ unsigned long val;
+ char *after;
+ size_t count;
+
+ val = simple_strtoul(buf, &after, 10);
+ count = after - buf;
+ if (*after && isspace(*after))
+ count++;
+
+ if (count == size) {
+ led->off_period = val;
+ omap_pwm_led_set_blink(led);
+ ret = count;
+ }
+
+ return ret;
+}
+
+static DEVICE_ATTR(on_period, 0644, omap_pwm_led_on_period_show,
+ omap_pwm_led_on_period_store);
+static DEVICE_ATTR(off_period, 0644, omap_pwm_led_off_period_show,
+ omap_pwm_led_off_period_store);
+
+static int omap_pwm_led_probe(struct platform_device *pdev)
+{
+ struct omap_pwm_led_platform_data *pdata = pdev->dev.platform_data;
+ struct omap_pwm_led *led;
+ int ret;
+
+ led = kzalloc(sizeof(struct omap_pwm_led), GFP_KERNEL);
+ if (led == NULL) {
+ dev_err(&pdev->dev, "No memory for device\n");
+ return -ENOMEM;
+ }
+
+ platform_set_drvdata(pdev, led);
+ led->cdev.brightness_set = omap_pwm_led_set;
+ led->cdev.default_trigger = NULL;
+ led->cdev.name = pdata->name;
+ led->pdata = pdata;
+ led->brightness = LED_OFF;
+ INIT_WORK(&led->work, omap_pwm_led_work);
+
+ dev_info(&pdev->dev, "OMAP PWM LED (%s) at GP timer %d/%d\n",
+ pdata->name, pdata->intensity_timer, pdata->blink_timer);
+
+ /* register our new led device */
+ ret = led_classdev_register(&pdev->dev, &led->cdev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "led_classdev_register failed\n");
+ goto error_classdev;
+ }
+
+ /* get related dm timers */
+ led->intensity_timer = omap_dm_timer_request_specific(pdata->intensity_timer);
+ if (led->intensity_timer == NULL) {
+ dev_err(&pdev->dev, "failed to request intensity pwm timer\n");
+ ret = -ENODEV;
+ goto error_intensity;
+ }
+ omap_dm_timer_disable(led->intensity_timer);
+
+ if (pdata->blink_timer != 0) {
+ led->blink_timer = omap_dm_timer_request_specific(pdata->blink_timer);
+ if (led->blink_timer == NULL) {
+ dev_err(&pdev->dev, "failed to request blinking pwm timer\n");
+ ret = -ENODEV;
+ goto error_blink1;
+ }
+ omap_dm_timer_disable(led->blink_timer);
+
+ ret = device_create_file(led->cdev.dev,
+ &dev_attr_on_period);
+ if(ret)
+ goto error_blink2;
+
+ ret = device_create_file(led->cdev.dev,
+ &dev_attr_off_period);
+ if(ret)
+ goto error_blink3;
+
+ }
+
+ return 0;
+
+error_blink3:
+ device_remove_file(led->cdev.dev,
+ &dev_attr_on_period);
+error_blink2:
+ dev_err(&pdev->dev, "failed to create device file(s)\n");
+error_blink1:
+ omap_dm_timer_free(led->intensity_timer);
+error_intensity:
+ led_classdev_unregister(&led->cdev);
+error_classdev:
+ kfree(led);
+ return ret;
+}
+
+static int omap_pwm_led_remove(struct platform_device *pdev)
+{
+ struct omap_pwm_led *led = pdev_to_omap_pwm_led(pdev);
+
+ device_remove_file(led->cdev.dev,
+ &dev_attr_on_period);
+ device_remove_file(led->cdev.dev,
+ &dev_attr_off_period);
+ led_classdev_unregister(&led->cdev);
+
+ omap_pwm_led_set(&led->cdev, LED_OFF);
+ if (led->blink_timer != NULL)
+ omap_dm_timer_free(led->blink_timer);
+ omap_dm_timer_free(led->intensity_timer);
+ kfree(led);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int omap_pwm_led_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct omap_pwm_led *led = pdev_to_omap_pwm_led(pdev);
+
+ led_classdev_suspend(&led->cdev);
+ return 0;
+}
+
+static int omap_pwm_led_resume(struct platform_device *pdev)
+{
+ struct omap_pwm_led *led = pdev_to_omap_pwm_led(pdev);
+
+ led_classdev_resume(&led->cdev);
+ return 0;
+}
+#else
+#define omap_pwm_led_suspend NULL
+#define omap_pwm_led_resume NULL
+#endif
+
+static struct platform_driver omap_pwm_led_driver = {
+ .probe = omap_pwm_led_probe,
+ .remove = omap_pwm_led_remove,
+ .suspend = omap_pwm_led_suspend,
+ .resume = omap_pwm_led_resume,
+ .driver = {
+ .name = "omap_pwm_led",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init omap_pwm_led_init(void)
+{
+ return platform_driver_register(&omap_pwm_led_driver);
+}
+
+static void __exit omap_pwm_led_exit(void)
+{
+ platform_driver_unregister(&omap_pwm_led_driver);
+}
+
+module_init(omap_pwm_led_init);
+module_exit(omap_pwm_led_exit);
+
+MODULE_AUTHOR("Timo Teras");
+MODULE_DESCRIPTION("OMAP PWM LED driver");
+MODULE_LICENSE("GPL");
--- /dev/null
+/* drivers/leds/leds-omap.c
+ *
+ * (C) 2006 Samsung Electronics
+ * Kyungmin Park <kyungmin.park@samsung.com>
+ *
+ * OMAP - LEDs GPIO driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/led.h>
+
+/* our context */
+
+static void omap_set_led_gpio(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ struct omap_led_config *led_dev;
+
+ led_dev = container_of(led_cdev, struct omap_led_config, cdev);
+
+ if (value)
+ omap_set_gpio_dataout(led_dev->gpio, 1);
+ else
+ omap_set_gpio_dataout(led_dev->gpio, 0);
+}
+
+static void omap_configure_led_gpio(int gpio)
+{
+ if (omap_request_gpio(gpio) < 0) {
+ printk(KERN_ERR "Failed to request GPIO%d for LEDs\n", gpio);
+ return;
+ }
+ omap_set_gpio_direction(gpio, 0); /* OUT */
+}
+
+static int omap_led_probe(struct platform_device *dev)
+{
+ struct omap_led_platform_data *pdata = dev->dev.platform_data;
+ struct omap_led_config *leds = pdata->leds;
+ int i, ret = 0;
+
+ for (i = 0; ret >= 0 && i < pdata->nr_leds; i++) {
+ omap_configure_led_gpio(leds[i].gpio);
+ if (!leds[i].cdev.brightness_set)
+ leds[i].cdev.brightness_set = omap_set_led_gpio;
+
+ ret = led_classdev_register(&dev->dev, &leds[i].cdev);
+ }
+
+ if (ret < 0 && i > 1) {
+ for (i = i - 2; i >= 0; i--)
+ led_classdev_unregister(&leds[i].cdev);
+ }
+
+ return ret;
+}
+
+static int omap_led_remove(struct platform_device *dev)
+{
+ struct omap_led_platform_data *pdata = dev->dev.platform_data;
+ struct omap_led_config *leds = pdata->leds;
+ int i;
+
+ for (i = 0; i < pdata->nr_leds; i++)
+ led_classdev_unregister(&leds[i].cdev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int omap_led_suspend(struct platform_device *dev, pm_message_t state)
+{
+ struct omap_led_platform_data *pdata = dev->dev.platform_data;
+ struct omap_led_config *leds = pdata->leds;
+ int i;
+
+ for (i = 0; i < pdata->nr_leds; i++)
+ led_classdev_suspend(&leds[i].cdev);
+
+ return 0;
+}
+
+static int omap_led_resume(struct platform_device *dev)
+{
+ struct omap_led_platform_data *pdata = dev->dev.platform_data;
+ struct omap_led_config *leds = pdata->leds;
+ int i;
+
+ for (i = 0; i < pdata->nr_leds; i++)
+ led_classdev_resume(&leds[i].cdev);
+
+ return 0;
+}
+#else
+#define omap_led_suspend NULL
+#define omap_led_resume NULL
+#endif
+
+static struct platform_driver omap_led_driver = {
+ .probe = omap_led_probe,
+ .remove = omap_led_remove,
+ .suspend = omap_led_suspend,
+ .resume = omap_led_resume,
+ .driver = {
+ .name = "omap-led",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init omap_led_init(void)
+{
+ return platform_driver_register(&omap_led_driver);
+}
+
+static void __exit omap_led_exit(void)
+{
+ platform_driver_unregister(&omap_led_driver);
+}
+
+module_init(omap_led_init);
+module_exit(omap_led_exit);
+
+MODULE_AUTHOR("Kyungmin Park<kyungmin.park@samsung.com>");
+MODULE_DESCRIPTION("OMAP LED driver");
+MODULE_LICENSE("GPL");
help
Enter the I/O port of your Zoltrix radio card.
+config RADIO_TEA5761
+ tristate "Philips Semiconductors TEA5761 I2C FM Radio"
+ help
+ Choose Y here if you have one of these AM/FM radio cards.
+
+ In order to control your radio card, you will need to use programs
+ that are compatible with the Video For Linux 2 API. Information on
+ this API and pointers to "v4l" programs may be found at
+ <file:Documentation/video4linux/API.html>.
+
+ To compile this driver as a module, choose M here: the
+ module will be called radio-tea5761.
+
config USB_DSBR
tristate "D-Link/GemTek USB FM radio support"
depends on USB && VIDEO_V4L2
obj-$(CONFIG_RADIO_GEMTEK_PCI) += radio-gemtek-pci.o
obj-$(CONFIG_RADIO_TRUST) += radio-trust.o
obj-$(CONFIG_RADIO_MAESTRO) += radio-maestro.o
+obj-$(CONFIG_RADIO_TEA5761) += radio-tea5761.o
obj-$(CONFIG_USB_DSBR) += dsbr100.o
obj-$(CONFIG_USB_SI470X) += radio-si470x.o
--- /dev/null
+/*
+ * drivers/media/radio/radio-tea5761.c
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <media/v4l2-common.h>
+
+#define DRIVER_NAME "tea5761"
+
+#define TEA5761_VERSION KERNEL_VERSION(0, 0, 1)
+
+#define TEA5761_I2C_ADDR 0x10
+
+#define TEA5761_MANID 0x002b
+#define TEA5761_CHIPID 0x5761
+
+#define TEA5761_INTREG_BLMSK 0x0001
+#define TEA5761_INTREG_FRRMSK 0x0002
+#define TEA5761_INTREG_LEVMSK 0x0008
+#define TEA5761_INTREG_IFMSK 0x0010
+#define TEA5761_INTREG_BLMFLAG 0x0100
+#define TEA5761_INTREG_FRRFLAG 0x0200
+#define TEA5761_INTREG_LEVFLAG 0x0800
+#define TEA5761_INTREG_IFFLAG 0x1000
+
+#define TEA5761_FRQSET_SUD 0x8000
+#define TEA5761_FRQSET_SM 0x4000
+
+#define TEA5761_TNCTRL_PUPD0 0x4000
+#define TEA5761_TNCTRL_BLIM 0x2000
+#define TEA5761_TNCTRL_SWPM 0x1000
+#define TEA5761_TNCTRL_IFCTC 0x0800
+#define TEA5761_TNCTRL_AFM 0x0400
+#define TEA5761_TNCTRL_SMUTE 0x0200
+#define TEA5761_TNCTRL_SNC 0x0100
+#define TEA5761_TNCTRL_MU 0x0080
+#define TEA5761_TNCTRL_SSL1 0x0040
+#define TEA5761_TNCTRL_SSL0 0x0020
+#define TEA5761_TNCTRL_HLSI 0x0010
+#define TEA5761_TNCTRL_MST 0x0008
+#define TEA5761_TNCTRL_SWP 0x0004
+#define TEA5761_TNCTRL_DTC 0x0002
+#define TEA5761_TNCTRL_AHLSI 0x0001
+
+#define TEA5761_TUNCHK_LEVEL(x) (((x) & 0x00F0) >> 4)
+#define TEA5761_TUNCHK_IFCNT(x) (((x) & 0xFE00) >> 9)
+#define TEA5761_TUNCHK_TUNTO 0x0100
+#define TEA5761_TUNCHK_LD 0x0008
+#define TEA5761_TUNCHK_STEREO 0x0004
+
+#define TEA5761_TESTREG_TRIGFR 0x0800
+
+#define TEA5761_FREQ_LOW 87500
+#define TEA5761_FREQ_HIGH 108000
+
+struct tea5761_regs {
+ u16 intreg;
+ u16 frqset;
+ u16 tnctrl;
+ u16 frqchk;
+ u16 tunchk;
+ u16 testreg;
+ u16 manid;
+ u16 chipid;
+} __attribute__ ((packed));
+
+struct tea5761_write_regs {
+ u8 intreg;
+ u16 frqset;
+ u16 tnctrl;
+ u16 testreg;
+} __attribute__ ((packed));
+
+struct tea5761_device {
+ struct video_device *video_dev;
+ struct i2c_client *i2c_dev;
+ struct tea5761_regs regs;
+ struct mutex mutex;
+ int users;
+};
+
+static struct tea5761_device tea5761;
+
+static struct i2c_driver tea5761_driver;
+static int radio_nr = -1;
+
+static int tea5761_read_regs(struct tea5761_device *tea)
+{
+ int rc, i;
+ u16 *p = (u16 *) &tea->regs;
+ struct i2c_client *client = tea->i2c_dev;
+
+ rc = i2c_master_recv(client, (void*) &tea->regs, sizeof(tea->regs));
+ for (i = 0; i < 8; i++) {
+ p[i] = __be16_to_cpu(p[i]);
+ }
+
+ dev_dbg(&client->dev,
+ "chip state: %04x %04x %04x %04x %04x %04x %04x %04x\n",
+ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
+
+ if (rc < 0)
+ dev_err(&client->dev, "read\n");
+
+ return rc;
+}
+
+static void tea5761_write_regs(struct tea5761_device *tea)
+{
+ struct tea5761_write_regs wr;
+ struct tea5761_regs *r = &tea->regs;
+ struct i2c_client *client = tea->i2c_dev;
+ u8 *p = (u8 *) r;
+
+ wr.intreg = r->intreg & 0xff;
+ wr.frqset = __cpu_to_be16(r->frqset);
+ wr.tnctrl = __cpu_to_be16(r->tnctrl);
+ wr.testreg = __cpu_to_be16(r->testreg);
+
+ dev_dbg(&client->dev,
+ "writing state: %02x %02x %02x %02x %02x %02x %02x\n",
+ p[0], p[1], p[2], p[3], p[4], p[5], p[6]);
+ if (i2c_master_send(client, (void *) &wr, sizeof(wr)) < 0)
+ dev_err(&client->dev, "write\n");
+}
+
+static void tea5761_power_up(struct tea5761_device *tea)
+{
+ struct tea5761_regs *r = &tea->regs;
+
+ if (!(r->tnctrl & TEA5761_TNCTRL_PUPD0)) {
+ r->tnctrl &= ~(TEA5761_TNCTRL_AFM | TEA5761_TNCTRL_MU |
+ TEA5761_TNCTRL_HLSI);
+ r->testreg |= TEA5761_TESTREG_TRIGFR;
+ r->tnctrl |= TEA5761_TNCTRL_PUPD0;
+ return tea5761_write_regs(tea);
+ }
+}
+
+static void tea5761_power_down(struct tea5761_device *tea)
+{
+ struct tea5761_regs *r = &tea->regs;
+
+ if (r->tnctrl & TEA5761_TNCTRL_PUPD0) {
+ r->tnctrl &= ~TEA5761_TNCTRL_PUPD0;
+ return tea5761_write_regs(tea);
+ }
+}
+
+static void tea5761_set_freq(struct tea5761_device *tea, int freq)
+{
+ struct tea5761_regs *r = &tea->regs;
+
+ if (r->tnctrl & TEA5761_TNCTRL_HLSI)
+ r->frqset = (freq + 225000) / 8192;
+ else
+ r->frqset = (freq - 225000) / 8192;
+}
+
+static int tea5761_get_freq(struct tea5761_device *tea)
+{
+ struct tea5761_regs *r = &tea->regs;
+
+ if (r->tnctrl & TEA5761_TNCTRL_HLSI)
+ return (r->frqchk * 8192) - 225000;
+ else
+ return (r->frqchk * 8192) + 225000;
+}
+
+static void tea5761_tune(struct tea5761_device *tea, int freq)
+{
+ tea5761_set_freq(tea, freq);
+ tea5761_write_regs(tea);
+}
+
+static void tea5761_set_audout_mode(struct tea5761_device *tea, int audmode)
+{
+ struct tea5761_regs *r = &tea->regs;
+ int tnctrl = r->tnctrl;
+
+ if (audmode == V4L2_TUNER_MODE_MONO)
+ r->tnctrl |= TEA5761_TNCTRL_MST;
+ else
+ r->tnctrl &= ~TEA5761_TNCTRL_MST;
+ if (tnctrl != r->tnctrl)
+ tea5761_write_regs(tea);
+}
+
+static int tea5761_get_audout_mode(struct tea5761_device *tea)
+{
+ struct tea5761_regs *r = &tea->regs;
+
+ if (r->tnctrl & TEA5761_TNCTRL_MST)
+ return V4L2_TUNER_MODE_MONO;
+ else
+ return V4L2_TUNER_MODE_STEREO;
+}
+
+static void tea5761_mute(struct tea5761_device *tea, int on)
+{
+ struct tea5761_regs *r = &tea->regs;
+ int tnctrl = r->tnctrl;
+
+ if (on)
+ r->tnctrl |= TEA5761_TNCTRL_MU;
+ else
+ r->tnctrl &= ~TEA5761_TNCTRL_MU;
+ if (tnctrl != r->tnctrl)
+ tea5761_write_regs(tea);
+}
+
+static int tea5761_is_muted(struct tea5761_device *tea)
+{
+ return tea->regs.tnctrl & TEA5761_TNCTRL_MU;
+}
+
+static int tea5761_do_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, void *arg)
+{
+ struct tea5761_device *tea = file->private_data;
+ struct video_device *dev = tea->video_dev;
+ struct i2c_client *client = tea->i2c_dev;
+ struct tea5761_regs *r = &tea->regs;
+
+ union {
+ struct v4l2_capability c;
+ struct v4l2_tuner t;
+ struct v4l2_frequency f;
+ struct v4l2_queryctrl qc;
+ struct v4l2_control ct;
+ } *u = arg;
+
+ tea5761_read_regs(tea);
+
+ switch (cmd) {
+ case VIDIOC_QUERYCAP:
+ dev_dbg(&client->dev, "VIDIOC_QUERYCAP\n");
+ memset(&u->c, 0, sizeof(u->c));
+ strlcpy(u->c.driver, dev->dev->driver->name,
+ sizeof(u->c.driver));
+ strlcpy(u->c.card, dev->name, sizeof(u->c.card));
+ snprintf(u->c.bus_info, sizeof(u->c.bus_info), "I2C:%s",
+ dev->dev->bus_id);
+ u->c.version = TEA5761_VERSION;
+ u->c.capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+ break;
+
+ case VIDIOC_G_TUNER:
+ /* Only one tuner chip */
+ dev_dbg(&client->dev, "VIDIOC_G_TUNER\n");
+ if (u->t.index != 0)
+ return -EINVAL;
+
+ memset(&u->t, 0, sizeof(u->t));
+ u->t.type = V4L2_TUNER_RADIO;
+ strlcpy(u->t.name, "FM", sizeof(u->t.name));
+ /* Freq in 62.5Hz units */
+ u->t.rangelow = TEA5761_FREQ_LOW * 16;
+ u->t.rangehigh = TEA5761_FREQ_HIGH * 16;
+ u->t.capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
+ if (r->tunchk & TEA5761_TUNCHK_STEREO)
+ u->t.rxsubchans = V4L2_TUNER_SUB_STEREO;
+ u->t.audmode = tea5761_get_audout_mode(tea);
+ u->t.signal = TEA5761_TUNCHK_LEVEL(r->tunchk) * 0xffff / 0xf;
+ u->t.afc = TEA5761_TUNCHK_IFCNT(r->tunchk);
+ break;
+
+ case VIDIOC_S_TUNER:
+ /* Only tuner nro 0 can be selected. */
+ dev_dbg(&client->dev, "VIDIOC_S_TUNER\n");
+ if (u->t.index != 0)
+ return -EINVAL;
+ tea5761_set_audout_mode(tea, u->t.audmode);
+ break;
+
+ case VIDIOC_G_FREQUENCY:
+ dev_dbg(&client->dev, "VIDIOC_G_FREQUENCY\n");
+ memset(&u->f, 0, sizeof(u->f));
+ u->f.type = V4L2_TUNER_RADIO;
+ if (r->tnctrl & TEA5761_TNCTRL_PUPD0)
+ u->f.frequency = (tea5761_get_freq(tea) * 2) / 125;
+ else
+ u->f.frequency = 0;
+ break;
+
+ case VIDIOC_S_FREQUENCY:
+ dev_dbg(&client->dev, "VIDIOC_S_FREQUENCY %u\n",
+ u->f.frequency);
+ if (u->f.tuner != 0)
+ return -EINVAL;
+ if (u->f.frequency == 0) {
+ /* We special case this as a power down
+ * control. */
+ tea5761_power_down(tea);
+ break;
+ }
+ if (u->f.frequency < 16 * TEA5761_FREQ_LOW)
+ return -EINVAL;
+ if (u->f.frequency > 16 * TEA5761_FREQ_HIGH)
+ return -EINVAL;
+
+ tea5761_power_up(tea);
+ tea5761_tune(tea, (u->f.frequency * 125) / 2);
+ break;
+
+ case VIDIOC_QUERYCTRL:
+ dev_dbg(&client->dev, "VIDIOC_QUERYCTRL %d\n", u->qc.id);
+ if (u->qc.id != V4L2_CID_AUDIO_MUTE)
+ return -EINVAL;
+ strlcpy(u->qc.name, "Mute", sizeof(u->qc.name));
+ u->qc.minimum = 0;
+ u->qc.maximum = 1;
+ u->qc.step = 1;
+ u->qc.default_value = 0;
+ u->qc.type = V4L2_CTRL_TYPE_BOOLEAN;
+ break;
+
+ case VIDIOC_G_CTRL:
+ dev_dbg(&client->dev, "VIDIOC_G_CTRL %d\n", u->ct.id);
+ if (u->ct.id != V4L2_CID_AUDIO_MUTE)
+ return -EINVAL;
+ if (r->tnctrl & TEA5761_TNCTRL_PUPD0)
+ u->ct.value = tea5761_is_muted(tea) ? 1 : 0;
+ else
+ u->ct.value = 0;
+ break;
+
+ case VIDIOC_S_CTRL:
+ dev_dbg(&client->dev, "VIDIOC_S_CTRL %d\n", u->ct.id);
+ if (u->ct.id != V4L2_CID_AUDIO_MUTE)
+ return -EINVAL;
+ tea5761_mute(tea, u->ct.value);
+ break;
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+
+ return 0;
+}
+
+static int tea5761_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ return video_usercopy(inode, file, cmd, arg, tea5761_do_ioctl);
+}
+
+static int tea5761_open(struct inode *inode, struct file *file)
+{
+ int minor = iminor(file->f_dentry->d_inode);
+ /* Currently we support only one device */
+ struct tea5761_device *tea = &tea5761;
+
+ if (tea->video_dev->minor != minor)
+ return -ENODEV;
+
+ mutex_lock(&tea->mutex);
+ /* Only exclusive access */
+ if (tea->users) {
+ mutex_unlock(&tea->mutex);
+ return -EBUSY;
+ }
+ tea->users++;
+ mutex_unlock(&tea->mutex);
+
+ file->private_data = tea;
+ return 0;
+}
+
+static int tea5761_release(struct inode *inode, struct file *file)
+{
+ struct tea5761_device *tea = file->private_data;
+
+ mutex_lock(&tea->mutex);
+ tea->users--;
+ mutex_unlock(&tea->mutex);
+
+ return 0;
+}
+
+static struct file_operations tea5761_fops = {
+ .owner = THIS_MODULE,
+ .open = tea5761_open,
+ .release = tea5761_release,
+ .ioctl = tea5761_ioctl,
+ .llseek = no_llseek,
+};
+
+static struct video_device tea5761_video_device = {
+ .owner = THIS_MODULE,
+ .name = "TEA5761 FM-Radio",
+ .type = VID_TYPE_TUNER,
+ .fops = &tea5761_fops,
+ .release = video_device_release
+};
+
+static int tea5761_i2c_driver_probe(struct i2c_client *client)
+{
+ struct video_device *video_dev;
+ int err = 0;
+ struct tea5761_device *tea = &tea5761;
+
+ mutex_init(&tea->mutex);
+
+ tea->i2c_dev = client;
+
+ /* V4L initialization */
+ video_dev = video_device_alloc();
+ if (video_dev == NULL) {
+ dev_err(&client->dev, "couldn't allocate memory\n");
+ err = -ENOMEM;
+ goto exit;
+ }
+ tea->video_dev = video_dev;
+
+ *video_dev = tea5761_video_device;
+ video_dev->dev = &client->dev;
+ i2c_set_clientdata(client, video_dev);
+
+ /* initialize and power off the chip */
+ tea5761_read_regs(tea);
+ tea5761_set_audout_mode(tea, V4L2_TUNER_MODE_STEREO);
+ tea5761_mute(tea, 0);
+ tea5761_power_down(tea);
+
+ tea5761.video_dev = video_dev;
+ tea5761.i2c_dev = client;
+
+ err = video_register_device(video_dev, VFL_TYPE_RADIO, radio_nr);
+ if (err) {
+ dev_err(&client->dev, "couldn't register video device\n");
+ goto err_video_alloc;
+ }
+
+ dev_info(&client->dev, "tea5761 (version %d) detected\n",
+ (tea->regs.manid >> 12) & 0xf);
+
+ return 0;
+
+err_video_alloc:
+ video_device_release(video_dev);
+exit:
+ kfree(client);
+ return err;
+}
+
+static int tea5761_i2c_driver_remove(struct i2c_client *client)
+{
+ struct video_device *vd = i2c_get_clientdata(client);
+
+ video_unregister_device(vd);
+
+ return 0;
+}
+
+static struct i2c_driver tea5761_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ },
+ .probe = tea5761_i2c_driver_probe,
+ .remove = tea5761_i2c_driver_remove,
+};
+
+static int __init tea5761_init(void)
+{
+ int res;
+
+ if ((res = i2c_add_driver(&tea5761_driver))) {
+ printk(KERN_ERR DRIVER_NAME ": driver registration failed\n");
+ return res;
+ }
+
+ return 0;
+}
+
+static void __exit tea5761_exit(void)
+{
+ i2c_del_driver(&tea5761_driver);
+}
+
+MODULE_AUTHOR("Timo Teräs");
+MODULE_DESCRIPTION("I2C interface for TEA5761.");
+MODULE_LICENSE("GPL");
+
+module_param(radio_nr, int, 0);
+MODULE_PARM_DESC(nr_radio, "video4linux device number to use");
+
+module_init(tea5761_init)
+module_exit(tea5761_exit)
This is a driver for the Toshiba TCM825x VGA camera sensor.
It is used for example in Nokia N800.
+config VIDEO_OV9640
+ tristate "OmniVision OV9640 sensor support"
+ depends on I2C && VIDEO_V4L2
+ ---help---
+ This is a Video4Linux2 sensor-level driver for the OmniVision
+ OV9640 camera. It is currently working with the TI OMAP2
+ camera controller.
+
config VIDEO_SAA7110
tristate "Philips SAA7110 video decoder"
depends on VIDEO_V4L1 && I2C
source "drivers/media/video/ivtv/Kconfig"
+source drivers/media/video/omap/Kconfig
+
source "drivers/media/video/cx18/Kconfig"
config VIDEO_M32R_AR
CMOS camera controller. This is the controller found on first-
generation OLPC systems.
+config VIDEO_OMAP2
+ tristate "OMAP 2 Camera support (EXPERIMENTAL)"
+ select VIDEOBUF_GEN
+ select VIDEOBUF_DMA_SG
+ depends on VIDEO_V4L2 && ARCH_OMAP24XX
+ ---help---
+ Driver for an OMAP 2 camera controller.
+
+
#
# USB Multimedia device configuration
#
obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o
+obj-$(CONFIG_VIDEO_OMAP_CAMERA) += omap/
obj-$(CONFIG_VIDEO_CX25840) += cx25840/
obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o
obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o
obj-$(CONFIG_VIDEO_OV7670) += ov7670.o
+obj-$(CONFIG_VIDEO_OMAP2) += omap24xxcam.o omap24xxcam-dma.o
obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
+obj-$(CONFIG_VIDEO_OV9640) += ov9640.o
obj-$(CONFIG_USB_DABUSB) += dabusb.o
obj-$(CONFIG_USB_OV511) += ov511.o
--- /dev/null
+config VIDEO_OMAP_CAMERA
+ tristate "OMAP Camera support (EXPERIMENTAL)"
+ select VIDEOBUF_GEN
+ select VIDEOBUF_DMA_SG
+ depends on VIDEO_DEV && (ARCH_OMAP16XX || ARCH_OMAP24XX)
+ help
+ V4L2 camera driver support for OMAP1/2 based boards.
--- /dev/null
+# Makefile for OMAP1/2 camera driver
+
+obj-$(CONFIG_VIDEO_OMAP_CAMERA) += omapcamera.o
+
+objs-y$(CONFIG_ARCH_OMAP16XX) += omap16xxcam.o camera_core.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/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/version.h>
+#include <linux/dma-mapping.h>
+#include <linux/fb.h>
+
+#include <media/v4l2-common.h>
+
+#include <asm/io.h>
+
+#include "camera_hw_if.h"
+#include "camera_core.h"
+
+#define OMAP1CAM_VERSION KERNEL_VERSION(0, 0, 0)
+
+static struct camera_device *camera_dev;
+static void camera_core_sgdma_process(struct camera_device *cam);
+
+/* Module parameters */
+static int video_nr = -1; /* Video device minor (-1 ==> auto assign) */
+
+/* Maximum amount of memory to use for capture buffers.
+ * Default is 4800KB, enough to double-buffer SXGA.
+ */
+static int capture_mem = 1280 * 960 * 2 * 2;
+
+/* Size of video overlay framebuffer. This determines the maximum image size
+ * that can be previewed. Default is 600KB, enough for sxga.
+ */
+static int overlay_mem = 640 * 480 * 2;
+
+/* Enable the external sensor interface. Try to negotiate interface
+ * parameters with the sensor and start using the new ones. The calls
+ * to sensor_if_enable and sensor_if_disable do not need to be balanced.
+ */
+static int camera_sensor_if_enable(struct camera_device *cam)
+{
+ int rval;
+ struct v4l2_ifparm p;
+
+ rval = vidioc_int_g_ifparm(cam->sdev, &p);
+ if (rval) {
+ dev_err(cam->dev, "vidioc_int_g_ifparm failed with %d\n", rval);
+ return rval;
+ }
+
+ cam->if_type = p.if_type;
+
+ switch (p.if_type) {
+ case V4L2_IF_TYPE_BT656:
+ cam->if_u.bt656.xclk =
+ cam->cam_hardware->set_xclk(cam->if_u.bt656.xclk,
+ cam->hardware_data);
+ break;
+ default:
+ /* FIXME: how about other interfaces? */
+ dev_err(cam->dev, "interface type %d not supported\n",
+ p.if_type);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void camera_sensor_if_disable(const struct camera_device *cam)
+{
+ switch (cam->if_type) {
+ case V4L2_IF_TYPE_BT656:
+ break;
+ }
+}
+
+/* Initialize the sensor hardware. */
+static int camera_sensor_init(struct camera_device *cam)
+{
+ int err = 0;
+ struct v4l2_int_device *sdev = cam->sdev;
+
+ /* 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.
+ */
+
+ /* Choose an arbitrary xclk frequency */
+ cam->if_u.bt656.xclk = 21000000;
+
+ cam->if_u.bt656.xclk = cam->cam_hardware->set_xclk(cam->if_u.bt656.xclk,
+ cam->hardware_data);
+
+ err = camera_sensor_if_enable(cam);
+ if (err) {
+ dev_err(cam->dev, "sensor interface could not be enabled at "
+ "initialization, %d\n", err);
+ cam->sdev = NULL;
+ goto out;
+ }
+
+ /* Power up sensor during sensor initialization */
+ vidioc_int_s_power(sdev, 1);
+
+ err = vidioc_int_dev_init(sdev);
+ if (err) {
+ dev_err(cam->dev, "cannot initialize sensor, error %d\n", err);
+ /* Sensor initialization failed --- it's nonexistent to us! */
+ cam->sdev = NULL;
+ goto out;
+ }
+
+ dev_info(cam->dev, "sensor is %s\n", sdev->name);
+
+out:
+ camera_sensor_if_disable(cam);
+
+ vidioc_int_s_power(sdev, 0);
+
+ return err;
+}
+
+static void camera_sensor_exit(struct camera_device *cam)
+{
+ if (cam->sdev)
+ vidioc_int_dev_exit(cam->sdev);
+}
+
+/* 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);
+ dev_err(cam->dev, "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)
+{
+ struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
+ videobuf_waiton(vb, 0, 0);
+ videobuf_dma_unmap(q, dma);
+ videobuf_dma_free(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_fh *fh = q->priv_data;
+ struct camera_device *cam = fh->cam;
+
+ 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_fh *fh = q->priv_data;
+ struct camera_device *cam = fh->cam;
+ int err = 0;
+
+ spin_lock(&cam->img_lock);
+ if (cam->pix.sizeimage > vb->bsize) {
+ spin_unlock(&cam->img_lock);
+ return -EINVAL;
+ }
+ vb->size = cam->pix.sizeimage;
+ vb->width = cam->pix.width;
+ vb->height = cam->pix.height;
+ vb->field = field;
+ spin_unlock(&cam->img_lock);
+
+ if (vb->state == STATE_NEEDS_INIT)
+ err = videobuf_iolock(q, vb, NULL);
+
+ if (!err)
+ vb->state = STATE_PREPARED;
+ else
+ camera_core_vbq_release(q, vb);
+
+ return err;
+}
+
+static void camera_core_vbq_queue(struct videobuf_queue *q,
+ struct videobuf_buffer *vb)
+{
+ struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
+ struct camera_fh *fh = q->priv_data;
+ struct camera_device *cam = fh->cam;
+ enum videobuf_state state = vb->state;
+ int err;
+
+ vb->state = STATE_QUEUED;
+ err = camera_core_sgdma_queue(cam, dma->sglist, 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.
+ */
+ dev_dbg(cam->dev, "Failed to queue a video buffer for SGDMA\n");
+ vb->state = state;
+ }
+}
+
+/* IOCTL interface. */
+static int vidioc_querycap(struct file *file, void *fh,
+ struct v4l2_capability *cap)
+{
+ struct camera_fh *ofh = fh;
+ struct camera_device *cam = ofh->cam;
+
+ strlcpy(cap->driver, CAM_NAME, sizeof(cap->driver));
+ strlcpy(cap->card, cam->vfd->name, sizeof(cap->card));
+ cap->version = OMAP1CAM_VERSION;
+ cap->capabilities =
+ V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+
+ return 0;
+}
+
+static int vidioc_enum_fmt_cap(struct file *file, void *fh,
+ struct v4l2_fmtdesc *f)
+{
+ struct camera_fh *ofh = fh;
+ struct camera_device *cam = ofh->cam;
+
+ return vidioc_int_enum_fmt_cap(cam->sdev, f);
+}
+
+static int vidioc_g_fmt_cap(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct camera_fh *ofh = fh;
+ struct camera_device *cam = ofh->cam;
+
+ /* Get the current format */
+ memset(&f->fmt.pix, 0, sizeof(f->fmt.pix));
+ f->fmt.pix = cam->pix;
+
+ return 0;
+}
+
+static int vidioc_s_fmt_cap(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct camera_fh *ofh = fh;
+ struct camera_device *cam = ofh->cam;
+ int rval = 0;
+
+ vidioc_int_try_fmt_cap(cam->sdev, f);
+
+ cam->pix = f->fmt.pix;
+
+ rval = vidioc_int_s_fmt_cap(cam->sdev, f);
+ camera_sensor_if_enable(cam);
+
+ return rval;
+}
+
+static int vidioc_try_fmt_cap(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct camera_fh *ofh = fh;
+ struct camera_device *cam = ofh->cam;
+
+ return vidioc_int_try_fmt_cap(cam->sdev, f);
+}
+
+static int vidioc_reqbufs(struct file *file, void *fh,
+ struct v4l2_requestbuffers *b)
+{
+ struct camera_fh *ofh = fh;
+
+ return videobuf_reqbufs(&ofh->vbq, b);
+}
+
+static int vidioc_querybuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+ struct camera_fh *ofh = fh;
+
+ return videobuf_querybuf(&ofh->vbq, b);
+}
+
+static int vidioc_qbuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+ struct camera_fh *ofh = fh;
+
+ return videobuf_qbuf(&ofh->vbq, b);
+}
+
+static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+ struct camera_fh *ofh = fh;
+
+ return videobuf_dqbuf(&ofh->vbq, b, file->f_flags & O_NONBLOCK);
+}
+
+static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
+{
+ struct camera_fh *ofh = fh;
+ struct camera_device *cam = ofh->cam;
+
+ spin_lock(&cam->img_lock);
+
+ if (cam->streaming || cam->reading) {
+ spin_unlock(&cam->img_lock);
+ return -EBUSY;
+ } else
+ cam->streaming = ofh;
+ /* FIXME: start camera interface */
+
+ spin_unlock(&cam->img_lock);
+
+ return videobuf_streamon(&ofh->vbq);
+}
+
+static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
+{
+ struct camera_fh *ofh = fh;
+ struct camera_device *cam = ofh->cam;
+ int err;
+
+ err = videobuf_streamoff(&ofh->vbq);
+ if (err < 0)
+ return err;
+
+ spin_lock(&cam->img_lock);
+ if (cam->streaming == ofh)
+ cam->streaming = NULL;
+ /* FIXME: stop camera interface */
+
+ spin_unlock(&cam->img_lock);
+ return 0;
+}
+
+static int vidioc_enum_input(struct file *file, void *fh,
+ struct v4l2_input *inp)
+{
+ if (inp->index > 0)
+ return -EINVAL;
+
+ strlcpy(inp->name, "camera", sizeof(inp->name));
+ inp->type = V4L2_INPUT_TYPE_CAMERA;
+
+ return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
+{
+ *i = 0;
+
+ return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *fh, unsigned int i)
+{
+ if (i > 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int vidioc_queryctrl(struct file *file, void *fh,
+ struct v4l2_queryctrl *a)
+{
+ struct camera_fh *ofh = fh;
+ struct camera_device *cam = ofh->cam;
+
+ return vidioc_int_queryctrl(cam->sdev, a);
+}
+
+static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *a)
+{
+ struct camera_fh *ofh = fh;
+ struct camera_device *cam = ofh->cam;
+
+ return vidioc_int_g_ctrl(cam->sdev, a);
+}
+
+static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *a)
+{
+ struct camera_fh *ofh = fh;
+ struct camera_device *cam = ofh->cam;
+
+ return vidioc_int_s_ctrl(cam->sdev, a);
+}
+
+static int vidioc_g_fbuf(struct file *file, void *fh,
+ struct v4l2_framebuffer *a)
+{
+ struct camera_fh *ofh = fh;
+ struct camera_device *cam = ofh->cam;
+
+ spin_lock(&cam->img_lock);
+ *a = cam->fbuf;
+ spin_unlock(&cam->img_lock);
+
+ return 0;
+}
+
+static int vidioc_s_fbuf(struct file *file, void *fh,
+ struct v4l2_framebuffer *a)
+{
+ struct camera_fh *ofh = fh;
+ struct camera_device *cam = ofh->cam;
+
+ spin_lock(&cam->img_lock);
+ if (cam->previewing) {
+ spin_unlock(&cam->img_lock);
+ return -EBUSY;
+ }
+ cam->fbuf.base = a->base;
+ cam->fbuf.fmt = a->fmt;
+
+ spin_unlock(&cam->img_lock);
+ return 0;
+}
+
+static int vidioc_overlay(struct file *file, void *fh, unsigned int i)
+{
+ struct camera_fh *ofh = fh;
+ struct camera_device *cam = ofh->cam;
+ int enable = i;
+
+ /* 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;
+}
+
+/* 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) {
+ dev_err(cam->dev, "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) {
+ dev_err(cam->dev, "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_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);
+ }
+
+ module_put(cam->sdev->module);
+
+ 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;
+ struct v4l2_format format;
+ int rval;
+
+ 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) {
+ dev_err(cam->dev, "Camera device Active\n");
+ spin_unlock(&cam->img_lock);
+ rval = -EPERM;
+ goto err;
+ }
+ cam->active = 1;
+
+ if (cam->sdev == NULL || !try_module_get(cam->sdev->module)) {
+ spin_unlock(&cam->img_lock);
+ rval = -ENODEV;
+ goto err;
+ }
+
+ vidioc_int_g_fmt_cap(cam->sdev, &format);
+ spin_unlock(&cam->img_lock);
+
+ videobuf_queue_sg_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)) {
+ dev_err(cam->dev, "Camera IF configuration failed\n");
+ cam->active = 0;
+ rval = -ENODEV;
+ goto err;
+ }
+ rval = vidioc_s_fmt_cap(file, fh, &format);
+ if (rval) {
+ dev_err(cam->dev, "Camera sensor configuration failed (%d)\n",
+ rval);
+ cam->cam_hardware->close(cam->hardware_data);
+ cam->active = 0;
+ rval = -ENODEV;
+ goto err;
+ }
+
+ return 0;
+
+err:
+ module_put(cam->sdev->module);
+ kfree(fh);
+ return rval;
+}
+
+#ifdef CONFIG_PM
+static int camera_core_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct camera_device *cam = platform_get_drvdata(pdev);
+
+ spin_lock(&cam->img_lock);
+ if (cam->active)
+ cam->cam_hardware->close(cam->hardware_data);
+
+ vidioc_int_s_power(cam->sdev, 0);
+ spin_unlock(&cam->img_lock);
+
+ return 0;
+}
+
+static int camera_core_resume(struct platform_device *pdev)
+{
+ struct camera_device *cam = platform_get_drvdata(pdev);
+
+ spin_lock(&cam->img_lock);
+ vidioc_int_s_power(cam->sdev, 1);
+ if (cam->active) {
+ struct v4l2_format format;
+
+ cam->capture_completed = 1;
+ cam->cam_hardware->open(cam->hardware_data);
+
+ vidioc_int_g_fmt_cap(cam->sdev, &format);
+ vidioc_int_s_fmt_cap(cam->sdev, &format);
+ camera_sensor_if_enable(cam);
+
+ camera_core_sgdma_process(cam);
+ }
+ spin_unlock(&cam->img_lock);
+
+ return 0;
+}
+#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 = video_ioctl2,
+ .mmap = camera_core_mmap,
+ .open = camera_core_open,
+ .release = camera_core_release,
+};
+static ssize_t camera_streaming_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct camera_device *cam = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%s\n", cam->streaming ? "active" : "inactive");
+}
+
+static DEVICE_ATTR(streaming, S_IRUGO, camera_streaming_show, NULL);
+
+static void camera_device_unregister(struct v4l2_int_device *s)
+{
+ struct camera_device *cam = s->u.slave->master->priv;
+
+ camera_sensor_exit(cam);
+}
+
+static int camera_device_register(struct v4l2_int_device *s)
+{
+ struct camera_device *cam = s->u.slave->master->priv;
+ struct video_device *vfd;
+ int rval;
+
+ /* We already have a slave. */
+ if (cam->sdev)
+ return -EBUSY;
+
+ cam->sdev = s;
+
+ if (device_create_file(cam->dev, &dev_attr_streaming) != 0) {
+ dev_err(cam->dev, "could not register sysfs entry\n");
+ rval = -EBUSY;
+ goto err;
+ }
+
+ /* Initialize the video_device struct */
+ vfd = cam->vfd = video_device_alloc();
+ if (!vfd) {
+ dev_err(cam->dev, " could not allocate video device struct\n");
+ rval = -ENOMEM;
+ goto err;
+ }
+
+ 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->fops = &camera_core_fops;
+ video_set_drvdata(vfd, cam);
+ vfd->minor = -1;
+
+ vfd->vidioc_querycap = vidioc_querycap;
+ vfd->vidioc_enum_fmt_cap = vidioc_enum_fmt_cap;
+ vfd->vidioc_g_fmt_cap = vidioc_g_fmt_cap;
+ vfd->vidioc_s_fmt_cap = vidioc_s_fmt_cap;
+ vfd->vidioc_try_fmt_cap = vidioc_try_fmt_cap;
+ vfd->vidioc_reqbufs = vidioc_reqbufs;
+ vfd->vidioc_querybuf = vidioc_querybuf;
+ vfd->vidioc_qbuf = vidioc_qbuf;
+ vfd->vidioc_dqbuf = vidioc_dqbuf;
+ vfd->vidioc_streamon = vidioc_streamon;
+ vfd->vidioc_streamoff = vidioc_streamoff;
+ vfd->vidioc_enum_input = vidioc_enum_input;
+ vfd->vidioc_g_input = vidioc_g_input;
+ vfd->vidioc_s_input = vidioc_s_input;
+ vfd->vidioc_queryctrl = vidioc_queryctrl;
+ vfd->vidioc_g_ctrl = vidioc_g_ctrl;
+ vfd->vidioc_s_ctrl = vidioc_s_ctrl;
+ vfd->vidioc_g_fbuf = vidioc_g_fbuf;
+ vfd->vidioc_s_fbuf = vidioc_s_fbuf;
+ vfd->vidioc_overlay = vidioc_overlay;
+
+ dev_info(cam->dev, "%s interface with %s sensor\n",
+ cam->cam_hardware->name, cam->sdev->name);
+
+ if (video_register_device(vfd, VFL_TYPE_GRABBER, video_nr) < 0) {
+ dev_err(cam->dev,
+ "could not register Video for Linux device\n");
+ rval = -ENODEV;
+ goto err;
+ }
+
+ rval = camera_sensor_init(cam);
+ if (rval)
+ goto err;
+
+ /* Disable the Camera after detection */
+ cam->cam_hardware->disable(cam->hardware_data);
+
+ return 0;
+
+err:
+ camera_device_unregister(s);
+
+ return rval;
+}
+
+static struct v4l2_int_master camera_master = {
+ .attach = camera_device_register,
+ .detach = camera_device_unregister,
+};
+
+static struct v4l2_int_device camera = {
+ .module = THIS_MODULE,
+ .name = CAM_NAME,
+ .type = v4l2_int_type_master,
+ .u = {
+ .master = &camera_master
+ },
+};
+
+static int __init camera_core_probe(struct platform_device *pdev)
+{
+ struct camera_device *cam;
+ int status = 0;
+
+ cam = kzalloc(sizeof(struct camera_device), GFP_KERNEL);
+ if (!cam) {
+ dev_err(&pdev->dev, "could not allocate memory\n");
+ status = -ENOMEM;
+ goto err;
+ }
+
+ platform_set_drvdata(pdev, cam);
+
+ cam->dev = &pdev->dev;
+
+ /* Initialize the camera interface */
+ cam->cam_hardware = &camera_hardware_if;
+ cam->hardware_data = cam->cam_hardware->init();
+ if (!cam->hardware_data) {
+ dev_err(cam->dev, "cannot initialize interface hardware\n");
+ status = -ENODEV;
+ goto err;
+ }
+
+ /* Save the pointer to camera device in a global variable */
+ camera_dev = cam;
+
+ /* 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;
+
+ /* Initialize 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) {
+ dev_err(cam->dev,
+ "cannot allocate overlay framebuffer\n");
+ status = -ENOMEM;
+ goto err;
+ }
+ }
+ memset((void *)cam->overlay_base, 0, cam->overlay_size);
+ spin_lock_init(&cam->overlay_lock);
+ spin_lock_init(&cam->capture_lock);
+
+ /* Initialize the spinlock used to serialize access to the image
+ * parameters
+ */
+ spin_lock_init(&cam->img_lock);
+
+ /* Initialize the wait queue */
+ init_waitqueue_head(&cam->new_video_frame);
+
+ /* Initialize the DMA structures */
+ camera_core_sgdma_init(cam);
+
+ platform_set_drvdata(pdev, cam);
+
+ camera.priv = cam;
+
+ if (v4l2_int_device_register(&camera))
+ goto err;
+
+ return 0;
+
+err:
+ vidioc_int_dev_exit(cam->sdev);
+ cam->overlay_base = 0;
+ return status;
+}
+
+static int camera_core_remove(struct platform_device *pdev)
+{
+ struct camera_device *cam = platform_get_drvdata(pdev);
+ struct video_device *vfd;
+
+ vfd = cam->vfd;
+ if (vfd) {
+ if (vfd->minor == -1) {
+ /* The device never got registered, so release the
+ * video_device struct directly
+ */
+ video_device_release(vfd);
+ } else {
+ /* The unregister function will release the
+ * video_device struct as well as unregistering it.
+ */
+ video_unregister_device(vfd);
+ }
+ cam->vfd = NULL;
+ }
+ if (cam->overlay_base) {
+ dma_free_coherent(NULL, cam->overlay_size,
+ (void *)cam->overlay_base,
+ cam->overlay_base_phys);
+ cam->overlay_base = 0;
+ }
+ cam->overlay_base_phys = 0;
+
+ vidioc_int_dev_exit(cam->sdev);
+ cam->cam_hardware->cleanup(cam->hardware_data);
+ kfree(cam);
+ camera_dev = NULL;
+
+ return 0;
+}
+
+static struct platform_driver camera_core_driver = {
+ .driver = {
+ .name = CAM_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = camera_core_probe,
+ .remove = camera_core_remove,
+#ifdef CONFIG_PM
+ .suspend = camera_core_suspend,
+ .resume = camera_core_resume,
+#endif
+};
+
+/* FIXME register omap16xx or omap24xx camera device in arch/arm/...
+ * system initialization code, with its resources and mux setup, NOT here.
+ * Then MODULE_ALIAS(CAM_NAME) so it hotplugs and coldplugs; this
+ * "legacy" driver style is trouble.
+ */
+static struct platform_device *cam;
+
+static void __exit camera_core_cleanup(void)
+{
+ platform_driver_unregister(&camera_core_driver);
+ platform_device_unregister(cam);
+}
+
+static char banner[] __initdata = KERN_INFO "OMAP Camera driver initializing\n";
+
+static int __init camera_core_init(void)
+{
+
+ printk(banner);
+ platform_driver_register(&camera_core_driver);
+
+ cam = platform_device_register_simple(CAM_NAME, -1, NULL, 0);
+
+ return 0;
+}
+
+MODULE_AUTHOR("Texas Instruments.");
+MODULE_DESCRIPTION("OMAP Video for Linux camera driver");
+MODULE_LICENSE("GPL");
+
+module_param(video_nr, int, 0);
+MODULE_PARM_DESC(video_nr,
+ "Minor number for video device (-1 ==> auto assign)");
+module_param(capture_mem, int, 0);
+MODULE_PARM_DESC(capture_mem,
+ "Maximum amount of memory for capture buffers "
+ "(default 4800KB)");
+
+module_init(camera_core_init);
+module_exit(camera_core_cleanup);
--- /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 <asm/scatterlist.h>
+#include <media/videobuf-dma-sg.h>
+#include <media/v4l2-int-device.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;
+
+ /*
+ * Sensor interface parameters: interface type, CC_CTRL
+ * register value and interface specific data.
+ */
+ int if_type;
+ union {
+ struct parallel {
+ u32 xclk;
+ } bt656;
+ } if_u;
+ /* Pointer to the sensor interface ops */
+ struct v4l2_int_device *sdev;
+
+ /* 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 *);
+};
+
+extern struct camera_hardware camera_hardware_if;
+
+#endif /* OMAP_CAMERA_HW_IF_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/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;
+
+ /* Frequency (in Hz) of camera interface functional clock (ocp_clk) */
+ unsigned long ocp_clk;
+
+ struct clk *func_clk;
+
+ /* DMA related stuff */
+ spinlock_t dma_lock;
+ int free_dmach;
+ int next_dmach;
+ struct camdma_state camdma[NUM_CAMDMA_CHANNELS];
+ int dma_channel_number1;
+ int dma_channel_number2;
+
+ wait_queue_head_t vsync_wait;
+
+ int new;
+};
+static struct omap16xxcam hardware_data;
+
+static int omap16xxcam_set_xclk(int, void *);
+static void omap16xx_cam_dma_link_callback(int, unsigned short, void *);
+
+/* Clears the camera data FIFO by setting RAZ_FIFO bit in MODE configuration
+ * register.
+ */
+static void omap16xx_cam_clear_fifo(struct omap16xxcam *data)
+{
+ data->camera_regs->mode |= RAZ_FIFO;
+ udelay(10);
+ data->camera_regs->mode &= ~RAZ_FIFO;
+}
+
+static void omap16xx_cam_reset(struct omap16xxcam *data, int yes)
+{
+ if (machine_is_omap_h3())
+ data->camera_regs->gpio = yes ? 0 : 1;
+ else
+ data->camera_regs->gpio = yes ? 1 : 0;
+}
+
+static void omap16xx_cam_init(void)
+{
+ /*
+ * FIXME - Use mux API's instead of directly writing in to MUX registers
+ */
+ omap_writel(omap_readl(FUNC_MUX_CTRL_4) & ~(0x1ff << 21),
+ FUNC_MUX_CTRL_4);
+ omap_writel(0, FUNC_MUX_CTRL_5);
+ omap_writel(omap_readl(PULL_DWN_CTRL_0) & ~(0x1FFF << 17),
+ PULL_DWN_CTRL_0);
+ omap_writel(omap_readl(PU_PD_SEL_0) & ~(0x1FFF << 17), PU_PD_SEL_0);
+
+ omap_writel(0xeaef, COMP_MODE_CTRL_0);
+ omap_writel(omap_readl(OMAP1610_RESET_CONTROL) &
+ ~(1 << CONF_CAMERAIF_RESET_R), OMAP1610_RESET_CONTROL);
+ omap_writel(omap_readl(OMAP1610_RESET_CONTROL) |
+ (1 << CONF_CAMERAIF_RESET_R), OMAP1610_RESET_CONTROL);
+
+ /* Enable peripheral reset */
+ omap_writew(omap_readw(ARM_RSTCT2) | (1 << EN_PER), ARM_RSTCT2);
+
+ /* Enable peripheral clock */
+ clk_enable(hardware_data.func_clk);
+}
+
+static void omap16xx_cam_waitfor_syncedge(struct omap16xxcam *data,
+ u32 edge_mask)
+{
+ data->camera_regs->mode =
+ (FIFO_TRIGGER_LVL << THRESHOLD_BIT) | edge_mask;
+ do {
+ interruptible_sleep_on(&data->vsync_wait);
+ } while (signal_pending(current));
+}
+
+static void omap16xx_cam_configure_dma(struct omap16xxcam *data)
+{
+
+ data->camera_regs->mode = (FIFO_TRIGGER_LVL << THRESHOLD_BIT)
+ | EN_DMA | EN_FIFO_FULL;
+ data->camera_regs->ctrlclock |= LCLK_EN;
+}
+
+/* Acquire h/w resources DMA */
+static int omap16xx_cam_link_open(struct omap16xxcam *data)
+{
+ int ret;
+
+ /* Acquire first DMA channel */
+ ret = omap_request_dma(OMAP_DMA_CAMERA_IF_RX,
+ "camera dma 1",
+ omap16xx_cam_dma_link_callback,
+ (void *)data, &data->dma_channel_number1);
+ if (ret)
+ return ret;
+
+ /* Acquire second DMA channel */
+ ret = omap_request_dma(OMAP_DMA_CAMERA_IF_RX,
+ "camera dma 2",
+ omap16xx_cam_dma_link_callback,
+ (void *)data, &data->dma_channel_number2);
+ if (ret) {
+ printk(KERN_ERR "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(KERN_ERR "callback all CHANNELS WERE IDLE \n");
+ spin_unlock(&cam->dma_lock);
+ return;
+ }
+ if (cam->free_dmach == 0) {
+ lch = cam->next_dmach;
+ } else {
+ lch = cam->next_dmach == cam->dma_channel_number1 ?
+ cam->dma_channel_number2 : cam->dma_channel_number1;
+ }
+
+ while (cam->free_dmach < 2) {
+ if (OMAP_DMA_CCR_REG(lch) & (1 << 7))
+ break;
+
+ count = (lch == cam->dma_channel_number2) ? 1 : 0;
+
+ callback = cam->camdma[count].callback;
+ arg1 = cam->camdma[count].arg1;
+ arg2 = cam->camdma[count].arg2;
+ cam->free_dmach++;
+
+ spin_unlock(&cam->dma_lock);
+ callback(arg1, arg2);
+ spin_lock(&cam->dma_lock);
+
+ lch =
+ (lch ==
+ cam->dma_channel_number2) ? cam->
+ dma_channel_number1 : cam->dma_channel_number2;
+ }
+ spin_unlock(&cam->dma_lock);
+
+}
+
+static irqreturn_t omap16xx_cam_isr(int irq, void *client_data)
+{
+ struct omap16xxcam *data = (struct omap16xxcam *)client_data;
+ unsigned int itstat = data->camera_regs->it_status;
+
+ /* VSYNC UP interrupt, start filling FIFO and enabling DMA */
+ if (itstat & V_UP) {
+ data->camera_regs->mode &= ~EN_V_UP;
+ omap16xx_cam_clear_fifo(data);
+ omap16xx_cam_configure_dma(data);
+ omap_start_dma(data->next_dmach);
+ wake_up_interruptible(&data->vsync_wait);
+ }
+
+ if (itstat & V_DOWN) {
+ data->camera_regs->mode &= ~EN_V_DOWN;
+ wake_up_interruptible(&data->vsync_wait);
+ }
+
+ if (itstat & H_UP)
+ printk(KERN_INFO "H_UP\n");
+
+ if (itstat & H_DOWN)
+ printk(KERN_INFO "H_DOWN\n");
+
+ if (itstat & FIFO_FULL) {
+ omap16xx_cam_clear_fifo(data);
+ printk(KERN_INFO "FIFO_FULL\n");
+ }
+
+ if (itstat & DATA_XFER)
+ printk(KERN_INFO "DATA_TRANS\n");
+
+ return IRQ_HANDLED;
+}
+
+/* ------------- Below are interface functions -----------------
+ * ------------- These functions are named omap16xxcam_<name> --
+ */
+static int omap16xxcam_init_dma(void *priv)
+{
+ int ch;
+ struct omap16xxcam *data = (struct omap16xxcam *)priv;
+
+ data->free_dmach = 2;
+ for (ch = 0; ch < 2; ++ch) {
+ data->camdma[ch].callback = NULL;
+ data->camdma[ch].arg1 = NULL;
+ data->camdma[ch].arg2 = NULL;
+ }
+
+ return 0;
+}
+
+/* Start the DMA of chains */
+static int omap16xxcam_start_dma(struct sgdma_state *sgdma,
+ dma_callback_t callback, void *arg1,
+ void *arg2, void *priv)
+{
+ struct omap16xxcam *data = (struct omap16xxcam *)priv;
+ struct scatterlist *sglist;
+ unsigned long irqflags;
+ int dmach;
+ int prev_dmach;
+ int count;
+
+ spin_lock_irqsave(&data->dma_lock, irqflags);
+ sglist = (struct scatterlist *)(sgdma->sglist + sgdma->next_sglist);
+
+ if (!data->free_dmach) {
+ spin_unlock_irqrestore(&data->dma_lock, irqflags);
+ return -EBUSY;
+ }
+ dmach = data->next_dmach;
+ count = (dmach == data->dma_channel_number2) ? 1 : 0;
+ data->camdma[count].callback = callback;
+ data->camdma[count].arg1 = arg1;
+ data->camdma[count].arg2 = arg2;
+
+ if (cpu_is_omap1710())
+ omap_set_dma_src_params(dmach, OMAP_DMA_PORT_OCP_T1,
+ OMAP_DMA_AMODE_CONSTANT,
+ CAM_CAMDATA_REG, 0, 0);
+ else
+ omap_set_dma_src_params(dmach, OMAP_DMA_PORT_TIPB,
+ OMAP_DMA_AMODE_CONSTANT,
+ CAM_CAMDATA_REG, 0, 0);
+
+ omap_set_dma_dest_params(dmach, OMAP_DMA_PORT_EMIFF,
+ OMAP_DMA_AMODE_POST_INC,
+ sg_dma_address(sglist), 0, 0);
+
+ omap_set_dma_transfer_params(dmach, OMAP_DMA_DATA_TYPE_S32,
+ FIFO_TRIGGER_LVL,
+ sg_dma_len(sglist) / (4 *
+ FIFO_TRIGGER_LVL),
+ OMAP_DMA_SYNC_FRAME, 0, 0);
+
+ OMAP_DMA_CLNK_CTRL_REG(dmach) &= ~(1 << 15);
+
+ prev_dmach = (dmach == data->dma_channel_number2) ?
+ data->dma_channel_number1 : data->dma_channel_number2;
+
+ if (data->new) {
+ data->new = 0;
+ omap16xx_cam_waitfor_syncedge(data, EN_V_UP);
+ } else {
+ if (OMAP_DMA_CCR_REG(prev_dmach) & (1 << 7))
+ OMAP_DMA_CLNK_CTRL_REG(prev_dmach) |= (1 << 15);
+ else {
+ /* No transfer is in progress */
+ omap_start_dma(dmach);
+ }
+ }
+
+ data->next_dmach = prev_dmach;
+ data->free_dmach--;
+ spin_unlock_irqrestore(&data->dma_lock, irqflags);
+ return 0;
+}
+
+int static omap16xxcam_finish_dma(void *priv)
+{
+ struct omap16xxcam *data = (struct omap16xxcam *)priv;
+
+ while (data->free_dmach < 2)
+ mdelay(1);
+
+ return 0;
+}
+
+/* Enables the camera. Takes camera out of reset. Enables the clocks. */
+static int omap16xxcam_enable(void *priv)
+{
+ struct omap16xxcam *data = (struct omap16xxcam *)priv;
+
+ omap16xx_cam_reset(data, 1);
+
+ /* Give clock to camera_module */
+ data->camera_regs->mode = (FIFO_TRIGGER_LVL << THRESHOLD_BIT);
+ data->camera_regs->ctrlclock = MCLK_EN | CAMEXCLK_EN;
+
+ omap16xx_cam_clear_fifo(data);
+
+ /* Wait for camera to settle down */
+ mdelay(5);
+
+ return 0;
+}
+
+/* Disables all the camera clocks. Put the camera interface in reset. */
+static int omap16xxcam_disable(void *priv)
+{
+ struct omap16xxcam *data = (struct omap16xxcam *)priv;
+
+ omap16xx_cam_clear_fifo(data);
+
+ data->camera_regs->ctrlclock = 0x00000000;
+ data->camera_regs->mode = 0x00000000;
+
+ omap16xx_cam_reset(data, 0);
+
+ return 0;
+}
+
+/* Abort the data transfer */
+static int omap16xxcam_abort(void *priv)
+{
+ return omap16xxcam_disable(priv);
+}
+
+static int omap16xxcam_set_xclk(int xclk, void *priv)
+{
+ struct omap16xxcam *data = (struct omap16xxcam *)priv;
+ int xclk_val;
+ int divisor = 1;
+ divisor = data->ocp_clk / xclk;
+ if (divisor * xclk < data->ocp_clk)
+ ++divisor;
+
+ switch (divisor) {
+ case 1:
+ case 2:
+ xclk_val = FOSCMOD_TC2_CK2;
+ break;
+ case 3:
+ xclk_val = FOSCMOD_TC2_CK3;
+ break;
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ xclk_val = FOSCMOD_TC2_CK4;
+ break;
+ case 8:
+ case 9:
+ xclk_val = FOSCMOD_TC2_CK8;
+ break;
+ case 10:
+ case 11:
+ xclk_val = FOSCMOD_TC2_CK10;
+ break;
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ xclk_val = FOSCMOD_TC2_CK12;
+ break;
+ case 16:
+ xclk_val = FOSCMOD_TC2_CK16;
+ break;
+ default:
+ xclk_val = FOSCMOD_TC2_CK16;
+ }
+
+ /* Follow the protocol to change the XCLK clock */
+ data->camera_regs->ctrlclock &= ~CAMEXCLK_EN;
+ data->camera_regs->ctrlclock |= xclk_val;
+ data->camera_regs->ctrlclock |= CAMEXCLK_EN;
+
+ return (data->ocp_clk / divisor);
+}
+
+static int omap16xxcam_open(void *priv)
+{
+ struct omap16xxcam *data = (struct omap16xxcam *)priv;
+ int ret;
+
+ ret = request_irq(INT_CAMERA, omap16xx_cam_isr, IRQF_DISABLED,
+ "camera", data);
+ if (ret) {
+ printk(KERN_ERR "FAILED to acquire IRQ\n");
+ return ret;
+ }
+
+ data->new = 1;
+ omap16xxcam_enable(data);
+ omap16xxcam_init_dma(data);
+
+ return omap16xx_cam_link_open(data);
+}
+
+static int omap16xxcam_close(void *priv)
+{
+ struct omap16xxcam *data = (struct omap16xxcam *)priv;
+
+ omap16xxcam_disable(priv);
+
+ free_irq(INT_CAMERA, data);
+
+ return omap16xx_cam_link_close(data);
+}
+
+static int omap16xxcam_cleanup(void *priv)
+{
+ struct omap16xxcam *data = (struct omap16xxcam *)priv;
+
+ if (!data->camera_regs)
+ return -EINVAL;
+
+ omap16xxcam_disable(data);
+ if (cpu_is_omap1710())
+ iounmap((void *)data->camera_regs);
+ data->camera_regs = NULL;
+
+ if (data->iobase_phys) {
+ release_mem_region(data->iobase_phys, CAMERA_IOSIZE);
+ data->iobase_phys = 0;
+ }
+
+ if (hardware_data.func_clk) {
+ clk_disable(hardware_data.func_clk);
+ clk_put(hardware_data.func_clk);
+ hardware_data.func_clk = NULL;
+ }
+
+ return 0;
+}
+
+/* Initialize the OMAP camera interface */
+static void *omap16xxcam_init(void)
+{
+ unsigned long cam_iobase;
+
+ if (!request_mem_region(CAMERA_BASE, CAMERA_IOSIZE,
+ camera_hardware_if.name)) {
+ pr_debug("%s is already in use\n", camera_hardware_if.name);
+ return NULL;
+ }
+
+ if (cpu_is_omap1710()) {
+ cam_iobase = (unsigned long)ioremap(CAMERA_BASE, CAMERA_IOSIZE);
+ if (!cam_iobase) {
+ printk(KERN_ERR "CANNOT MAP CAMERA REGISTER\n");
+ return NULL;
+ }
+ } else
+ cam_iobase = io_p2v(CAMERA_BASE);
+
+ /* Set the base address of the camera registers */
+ hardware_data.camera_regs = (camera_regs_t *) cam_iobase;
+ hardware_data.iobase_phys = (unsigned long)CAMERA_BASE;
+
+ /* Get the input clock value to camera interface and store it */
+ if (cpu_is_omap1710())
+ hardware_data.func_clk = clk_get(0, "tc2_ck");
+ else
+ hardware_data.func_clk = clk_get(0, "armper_ck");
+ hardware_data.ocp_clk = clk_get_rate(hardware_data.func_clk);
+
+ /* Initialize the camera IF */
+ omap16xx_cam_init();
+ /* Enable it. This is needed for sensor detection */
+ omap16xxcam_enable((void *)&hardware_data);
+ /* Initialize DMA data */
+ spin_lock_init(&hardware_data.dma_lock);
+
+ init_waitqueue_head(&hardware_data.vsync_wait);
+ return (void *)&hardware_data;
+}
+
+struct camera_hardware camera_hardware_if = {
+ .version = 0x01,
+ .name = "OMAP16xx Parallel Camera",
+ .init = omap16xxcam_init,
+ .cleanup = omap16xxcam_cleanup,
+ .open = omap16xxcam_open,
+ .close = omap16xxcam_close,
+ .enable = omap16xxcam_enable,
+ .disable = omap16xxcam_disable,
+ .abort = omap16xxcam_abort,
+ .set_xclk = omap16xxcam_set_xclk,
+ .init_dma = omap16xxcam_init_dma,
+ .start_dma = omap16xxcam_start_dma,
+ .finish_dma = omap16xxcam_finish_dma,
+};
--- /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/omap24xxcam-dma.c
+ *
+ * Copyright (C) 2004 MontaVista Software, Inc.
+ * Copyright (C) 2004 Texas Instruments.
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Sakari Ailus <sakari.ailus@nokia.com>
+ *
+ * Based on code from Andy Lowe <source@mvista.com> and
+ * David Cohen <david.cohen@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
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/scatterlist.h>
+
+#include "omap24xxcam.h"
+
+/*
+ *
+ * DMA hardware.
+ *
+ */
+
+/* Ack all interrupt on CSR and IRQSTATUS_L0 */
+static void omap24xxcam_dmahw_ack_all(unsigned long base)
+{
+ u32 csr;
+ int i;
+
+ for (i = 0; i < NUM_CAMDMA_CHANNELS; ++i) {
+ csr = omap24xxcam_reg_in(base, CAMDMA_CSR(i));
+ /* ack interrupt in CSR */
+ omap24xxcam_reg_out(base, CAMDMA_CSR(i), csr);
+ }
+ omap24xxcam_reg_out(base, CAMDMA_IRQSTATUS_L0, 0xf);
+}
+
+/* Ack dmach on CSR and IRQSTATUS_L0 */
+static u32 omap24xxcam_dmahw_ack_ch(unsigned long base, int dmach)
+{
+ u32 csr;
+
+ csr = omap24xxcam_reg_in(base, CAMDMA_CSR(dmach));
+ /* ack interrupt in CSR */
+ omap24xxcam_reg_out(base, CAMDMA_CSR(dmach), csr);
+ /* ack interrupt in IRQSTATUS */
+ omap24xxcam_reg_out(base, CAMDMA_IRQSTATUS_L0, (1 << dmach));
+
+ return csr;
+}
+
+static int omap24xxcam_dmahw_running(unsigned long base, int dmach)
+{
+ return omap24xxcam_reg_in(base, CAMDMA_CCR(dmach)) & CAMDMA_CCR_ENABLE;
+}
+
+static void omap24xxcam_dmahw_transfer_setup(unsigned long base, int dmach,
+ dma_addr_t start, u32 len)
+{
+ omap24xxcam_reg_out(base, CAMDMA_CCR(dmach),
+ CAMDMA_CCR_SEL_SRC_DST_SYNC
+ | CAMDMA_CCR_BS
+ | CAMDMA_CCR_DST_AMODE_POST_INC
+ | CAMDMA_CCR_SRC_AMODE_POST_INC
+ | CAMDMA_CCR_FS
+ | CAMDMA_CCR_WR_ACTIVE
+ | CAMDMA_CCR_RD_ACTIVE
+ | CAMDMA_CCR_SYNCHRO_CAMERA);
+ omap24xxcam_reg_out(base, CAMDMA_CLNK_CTRL(dmach), 0);
+ omap24xxcam_reg_out(base, CAMDMA_CEN(dmach), len);
+ omap24xxcam_reg_out(base, CAMDMA_CFN(dmach), 1);
+ omap24xxcam_reg_out(base, CAMDMA_CSDP(dmach),
+ CAMDMA_CSDP_WRITE_MODE_POSTED
+ | CAMDMA_CSDP_DST_BURST_EN_32
+ | CAMDMA_CSDP_DST_PACKED
+ | CAMDMA_CSDP_SRC_BURST_EN_32
+ | CAMDMA_CSDP_SRC_PACKED
+ | CAMDMA_CSDP_DATA_TYPE_8BITS);
+ omap24xxcam_reg_out(base, CAMDMA_CSSA(dmach), 0);
+ omap24xxcam_reg_out(base, CAMDMA_CDSA(dmach), start);
+ omap24xxcam_reg_out(base, CAMDMA_CSEI(dmach), 0);
+ omap24xxcam_reg_out(base, CAMDMA_CSFI(dmach), DMA_THRESHOLD);
+ omap24xxcam_reg_out(base, CAMDMA_CDEI(dmach), 0);
+ omap24xxcam_reg_out(base, CAMDMA_CDFI(dmach), 0);
+ omap24xxcam_reg_out(base, CAMDMA_CSR(dmach),
+ CAMDMA_CSR_MISALIGNED_ERR
+ | CAMDMA_CSR_SECURE_ERR
+ | CAMDMA_CSR_TRANS_ERR
+ | CAMDMA_CSR_BLOCK
+ | CAMDMA_CSR_DROP);
+ omap24xxcam_reg_out(base, CAMDMA_CICR(dmach),
+ CAMDMA_CICR_MISALIGNED_ERR_IE
+ | CAMDMA_CICR_SECURE_ERR_IE
+ | CAMDMA_CICR_TRANS_ERR_IE
+ | CAMDMA_CICR_BLOCK_IE
+ | CAMDMA_CICR_DROP_IE);
+}
+
+static void omap24xxcam_dmahw_transfer_start(unsigned long base, int dmach)
+{
+ omap24xxcam_reg_out(base, CAMDMA_CCR(dmach),
+ CAMDMA_CCR_SEL_SRC_DST_SYNC
+ | CAMDMA_CCR_BS
+ | CAMDMA_CCR_DST_AMODE_POST_INC
+ | CAMDMA_CCR_SRC_AMODE_POST_INC
+ | CAMDMA_CCR_ENABLE
+ | CAMDMA_CCR_FS
+ | CAMDMA_CCR_SYNCHRO_CAMERA);
+}
+
+static void omap24xxcam_dmahw_transfer_chain(unsigned long base, int dmach,
+ int free_dmach)
+{
+ int prev_dmach, ch;
+
+ if (dmach == 0)
+ prev_dmach = NUM_CAMDMA_CHANNELS - 1;
+ else
+ prev_dmach = dmach - 1;
+ omap24xxcam_reg_out(base, CAMDMA_CLNK_CTRL(prev_dmach),
+ CAMDMA_CLNK_CTRL_ENABLE_LNK | dmach);
+ /* Did we chain the DMA transfer before the previous one
+ * finished?
+ */
+ ch = (dmach + free_dmach) % NUM_CAMDMA_CHANNELS;
+ while (!(omap24xxcam_reg_in(base, CAMDMA_CCR(ch))
+ & CAMDMA_CCR_ENABLE)) {
+ if (ch == dmach) {
+ /* The previous transfer has ended and this one
+ * hasn't started, so we must not have chained
+ * to the previous one in time. We'll have to
+ * start it now.
+ */
+ omap24xxcam_dmahw_transfer_start(base, dmach);
+ break;
+ } else
+ ch = (ch + 1) % NUM_CAMDMA_CHANNELS;
+ }
+}
+
+/* Abort all chained DMA transfers. After all transfers have been
+ * aborted and the DMA controller is idle, the completion routines for
+ * any aborted transfers will be called in sequence. The DMA
+ * controller may not be idle after this routine completes, because
+ * the completion routines might start new transfers.
+ */
+static void omap24xxcam_dmahw_abort_ch(unsigned long base, int dmach)
+{
+ /* mask all interrupts from this channel */
+ omap24xxcam_reg_out(base, CAMDMA_CICR(dmach), 0);
+ /* unlink this channel */
+ omap24xxcam_reg_merge(base, CAMDMA_CLNK_CTRL(dmach), 0,
+ CAMDMA_CLNK_CTRL_ENABLE_LNK);
+ /* disable this channel */
+ omap24xxcam_reg_merge(base, CAMDMA_CCR(dmach), 0, CAMDMA_CCR_ENABLE);
+}
+
+static void omap24xxcam_dmahw_init(unsigned long base)
+{
+ omap24xxcam_reg_out(base, CAMDMA_OCP_SYSCONFIG,
+ CAMDMA_OCP_SYSCONFIG_MIDLEMODE_FSTANDBY
+ | CAMDMA_OCP_SYSCONFIG_SIDLEMODE_FIDLE
+ | CAMDMA_OCP_SYSCONFIG_AUTOIDLE);
+
+ omap24xxcam_reg_merge(base, CAMDMA_GCR, 0x10,
+ CAMDMA_GCR_MAX_CHANNEL_FIFO_DEPTH);
+
+ omap24xxcam_reg_out(base, CAMDMA_IRQENABLE_L0, 0xf);
+}
+
+/*
+ *
+ * Individual DMA channel handling.
+ *
+ */
+
+/* Start a DMA transfer from the camera to memory.
+ * Returns zero if the transfer was successfully started, or non-zero if all
+ * DMA channels are already in use or starting is currently inhibited.
+ */
+static int omap24xxcam_dma_start(struct omap24xxcam_dma *dma, dma_addr_t start,
+ u32 len, dma_callback_t callback, void *arg)
+{
+ unsigned long flags;
+ int dmach;
+
+ spin_lock_irqsave(&dma->lock, flags);
+
+ if (!dma->free_dmach || atomic_read(&dma->dma_stop)) {
+ spin_unlock_irqrestore(&dma->lock, flags);
+ return -EBUSY;
+ }
+
+ dmach = dma->next_dmach;
+
+ dma->ch_state[dmach].callback = callback;
+ dma->ch_state[dmach].arg = arg;
+
+ omap24xxcam_dmahw_transfer_setup(dma->base, dmach, start, len);
+
+ /* We're ready to start the DMA transfer. */
+
+ if (dma->free_dmach < NUM_CAMDMA_CHANNELS) {
+ /* A transfer is already in progress, so try to chain to it. */
+ omap24xxcam_dmahw_transfer_chain(dma->base, dmach,
+ dma->free_dmach);
+ } else {
+ /* No transfer is in progress, so we'll just start this one
+ * now.
+ */
+ omap24xxcam_dmahw_transfer_start(dma->base, dmach);
+ }
+
+ dma->next_dmach = (dma->next_dmach + 1) % NUM_CAMDMA_CHANNELS;
+ dma->free_dmach--;
+
+ spin_unlock_irqrestore(&dma->lock, flags);
+
+ return 0;
+}
+
+/* Abort all chained DMA transfers. After all transfers have been
+ * aborted and the DMA controller is idle, the completion routines for
+ * any aborted transfers will be called in sequence. The DMA
+ * controller may not be idle after this routine completes, because
+ * the completion routines might start new transfers.
+ */
+static void omap24xxcam_dma_abort(struct omap24xxcam_dma *dma, u32 csr)
+{
+ unsigned long flags;
+ int dmach, i, free_dmach;
+ dma_callback_t callback;
+ void *arg;
+
+ spin_lock_irqsave(&dma->lock, flags);
+
+ /* stop any DMA transfers in progress */
+ dmach = (dma->next_dmach + dma->free_dmach) % NUM_CAMDMA_CHANNELS;
+ for (i = 0; i < NUM_CAMDMA_CHANNELS; i++) {
+ omap24xxcam_dmahw_abort_ch(dma->base, dmach);
+ dmach = (dmach + 1) % NUM_CAMDMA_CHANNELS;
+ }
+
+ /* We have to be careful here because the callback routine
+ * might start a new DMA transfer, and we only want to abort
+ * transfers that were started before this routine was called.
+ */
+ free_dmach = dma->free_dmach;
+ while ((dma->free_dmach < NUM_CAMDMA_CHANNELS) &&
+ (free_dmach < NUM_CAMDMA_CHANNELS)) {
+ dmach = (dma->next_dmach + dma->free_dmach)
+ % NUM_CAMDMA_CHANNELS;
+ callback = dma->ch_state[dmach].callback;
+ arg = dma->ch_state[dmach].arg;
+ dma->free_dmach++;
+ free_dmach++;
+ if (callback) {
+ /* leave interrupts disabled during callback */
+ spin_unlock(&dma->lock);
+ (*callback) (dma, csr, arg);
+ spin_lock(&dma->lock);
+ }
+ }
+
+ spin_unlock_irqrestore(&dma->lock, flags);
+}
+
+/* Abort all chained DMA transfers. After all transfers have been
+ * aborted and the DMA controller is idle, the completion routines for
+ * any aborted transfers will be called in sequence. If the completion
+ * routines attempt to start a new DMA transfer it will fail, so the
+ * DMA controller will be idle after this routine completes.
+ */
+static void omap24xxcam_dma_stop(struct omap24xxcam_dma *dma, u32 csr)
+{
+ atomic_inc(&dma->dma_stop);
+ omap24xxcam_dma_abort(dma, csr);
+ atomic_dec(&dma->dma_stop);
+}
+
+/* Camera DMA interrupt service routine. */
+void omap24xxcam_dma_isr(struct omap24xxcam_dma *dma)
+{
+ int dmach;
+ dma_callback_t callback;
+ void *arg;
+ u32 csr;
+ const u32 csr_error = CAMDMA_CSR_MISALIGNED_ERR
+ | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR
+ | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP;
+
+ spin_lock(&dma->lock);
+
+ if (dma->free_dmach == NUM_CAMDMA_CHANNELS) {
+ /* A camera DMA interrupt occurred while all channels
+ * are idle, so we'll acknowledge the interrupt in the
+ * IRQSTATUS register and exit.
+ */
+ omap24xxcam_dmahw_ack_all(dma->base);
+ spin_unlock(&dma->lock);
+ return;
+ }
+
+ while (dma->free_dmach < NUM_CAMDMA_CHANNELS) {
+ dmach = (dma->next_dmach + dma->free_dmach)
+ % NUM_CAMDMA_CHANNELS;
+ if (omap24xxcam_dmahw_running(dma->base, dmach)) {
+ /* This buffer hasn't finished yet, so we're done. */
+ break;
+ }
+ csr = omap24xxcam_dmahw_ack_ch(dma->base, dmach);
+ if (csr & csr_error) {
+ /* A DMA error occurred, so stop all DMA
+ * transfers in progress.
+ */
+ spin_unlock(&dma->lock);
+ omap24xxcam_dma_stop(dma, csr);
+ return;
+ } else {
+ callback = dma->ch_state[dmach].callback;
+ arg = dma->ch_state[dmach].arg;
+ dma->free_dmach++;
+ if (callback) {
+ spin_unlock(&dma->lock);
+ (*callback) (dma, csr, arg);
+ spin_lock(&dma->lock);
+ }
+ }
+ }
+
+ spin_unlock(&dma->lock);
+
+ omap24xxcam_sgdma_process(
+ container_of(dma, struct omap24xxcam_sgdma, dma));
+}
+
+void omap24xxcam_dma_hwinit(const struct omap24xxcam_dma *dma)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dma->lock, flags);
+
+ omap24xxcam_dmahw_init(dma->base);
+
+ spin_unlock_irqrestore(&dma->lock, flags);
+}
+
+static void omap24xxcam_dma_init(struct omap24xxcam_dma *dma,
+ unsigned long base)
+{
+ int ch;
+
+ /* group all channels on DMA IRQ0 and unmask irq */
+ spin_lock_init(&dma->lock);
+ dma->base = base;
+ dma->free_dmach = NUM_CAMDMA_CHANNELS;
+ dma->next_dmach = 0;
+ for (ch = 0; ch < NUM_CAMDMA_CHANNELS; ch++) {
+ dma->ch_state[ch].callback = NULL;
+ dma->ch_state[ch].arg = NULL;
+ }
+}
+
+/*
+ *
+ * Scatter-gather DMA.
+ *
+ * High-level DMA construct for transferring whole picture frames to
+ * memory that is discontinuous.
+ *
+ */
+
+/* DMA completion routine for the scatter-gather DMA fragments. */
+static void omap24xxcam_sgdma_callback(struct omap24xxcam_dma *dma, u32 csr,
+ void *arg)
+{
+ struct omap24xxcam_sgdma *sgdma =
+ container_of(dma, struct omap24xxcam_sgdma, dma);
+ int sgslot = (int)arg;
+ struct sgdma_state *sg_state;
+ const u32 csr_error = CAMDMA_CSR_MISALIGNED_ERR
+ | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR
+ | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP;
+
+ spin_lock(&sgdma->lock);
+
+ /* We got an interrupt, we can remove the timer */
+ del_timer(&sgdma->reset_timer);
+
+ sg_state = sgdma->sg_state + sgslot;
+ if (!sg_state->queued_sglist) {
+ spin_unlock(&sgdma->lock);
+ printk(KERN_ERR "%s: sgdma completed when none queued!\n",
+ __FUNCTION__);
+ return;
+ }
+
+ sg_state->csr |= csr;
+ if (!--sg_state->queued_sglist) {
+ /* Queue for this sglist is empty, so check to see if we're
+ * done.
+ */
+ if ((sg_state->next_sglist == sg_state->sglen)
+ || (sg_state->csr & csr_error)) {
+ sgdma_callback_t callback = sg_state->callback;
+ void *arg = sg_state->arg;
+ u32 sg_csr = sg_state->csr;
+ /* All done with this sglist */
+ sgdma->free_sgdma++;
+ if (callback) {
+ spin_unlock(&sgdma->lock);
+ (*callback) (sgdma, sg_csr, arg);
+ return;
+ }
+ }
+ }
+
+ spin_unlock(&sgdma->lock);
+}
+
+/* Start queued scatter-gather DMA transfers. */
+void omap24xxcam_sgdma_process(struct omap24xxcam_sgdma *sgdma)
+{
+ unsigned long flags;
+ int queued_sgdma, sgslot;
+ struct sgdma_state *sg_state;
+ const u32 csr_error = CAMDMA_CSR_MISALIGNED_ERR
+ | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR
+ | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP;
+
+ spin_lock_irqsave(&sgdma->lock, flags);
+
+ queued_sgdma = NUM_SG_DMA - sgdma->free_sgdma;
+ sgslot = (sgdma->next_sgdma + sgdma->free_sgdma) % NUM_SG_DMA;
+ while (queued_sgdma > 0) {
+ sg_state = sgdma->sg_state + sgslot;
+ while ((sg_state->next_sglist < sg_state->sglen) &&
+ !(sg_state->csr & csr_error)) {
+ const struct scatterlist *sglist;
+ unsigned int len;
+
+ sglist = sg_state->sglist + sg_state->next_sglist;
+ /* try to start the next DMA transfer */
+ if (sg_state->next_sglist + 1 == sg_state->sglen) {
+ /*
+ * On the last sg, we handle the case where
+ * cam->img.pix.sizeimage % PAGE_ALIGN != 0
+ */
+ len = sg_state->len - sg_state->bytes_read;
+ } else {
+ len = sg_dma_len(sglist);
+ }
+
+ if (omap24xxcam_dma_start(&sgdma->dma,
+ sg_dma_address(sglist),
+ len,
+ omap24xxcam_sgdma_callback,
+ (void *)sgslot)) {
+ /* DMA start failed */
+ spin_unlock_irqrestore(&sgdma->lock, flags);
+ return;
+ } else {
+ unsigned long expires;
+ /* DMA start was successful */
+ sg_state->next_sglist++;
+ sg_state->bytes_read += len;
+ sg_state->queued_sglist++;
+
+ /* We start the reset timer */
+ expires = jiffies + HZ;
+ mod_timer(&sgdma->reset_timer, expires);
+ }
+ }
+ queued_sgdma--;
+ sgslot = (sgslot + 1) % NUM_SG_DMA;
+ }
+
+ spin_unlock_irqrestore(&sgdma->lock, flags);
+}
+
+/*
+ * 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.
+ */
+int omap24xxcam_sgdma_queue(struct omap24xxcam_sgdma *sgdma,
+ const struct scatterlist *sglist, int sglen,
+ int len, sgdma_callback_t callback, void *arg)
+{
+ unsigned long flags;
+ struct sgdma_state *sg_state;
+
+ if ((sglen < 0) || ((sglen > 0) & !sglist))
+ return -EINVAL;
+
+ spin_lock_irqsave(&sgdma->lock, flags);
+
+ if (!sgdma->free_sgdma) {
+ spin_unlock_irqrestore(&sgdma->lock, flags);
+ return -EBUSY;
+ }
+
+ sg_state = sgdma->sg_state + sgdma->next_sgdma;
+
+ sg_state->sglist = sglist;
+ sg_state->sglen = sglen;
+ sg_state->next_sglist = 0;
+ sg_state->bytes_read = 0;
+ sg_state->len = len;
+ sg_state->queued_sglist = 0;
+ sg_state->csr = 0;
+ sg_state->callback = callback;
+ sg_state->arg = arg;
+
+ sgdma->next_sgdma = (sgdma->next_sgdma + 1) % NUM_SG_DMA;
+ sgdma->free_sgdma--;
+
+ spin_unlock_irqrestore(&sgdma->lock, flags);
+
+ omap24xxcam_sgdma_process(sgdma);
+
+ return 0;
+}
+
+/* Sync scatter-gather DMA by aborting any DMA transfers currently in progress.
+ * Any queued scatter-gather DMA transactions that have not yet been started
+ * will remain queued. The DMA controller will be idle after this routine
+ * completes. When the scatter-gather queue is restarted, the next
+ * scatter-gather DMA transfer will begin at the start of a new transaction.
+ */
+void omap24xxcam_sgdma_sync(struct omap24xxcam_sgdma *sgdma)
+{
+ unsigned long flags;
+ int sgslot;
+ struct sgdma_state *sg_state;
+ u32 csr = CAMDMA_CSR_TRANS_ERR;
+
+ /* stop any DMA transfers in progress */
+ omap24xxcam_dma_stop(&sgdma->dma, csr);
+
+ spin_lock_irqsave(&sgdma->lock, flags);
+
+ if (sgdma->free_sgdma < NUM_SG_DMA) {
+ sgslot = (sgdma->next_sgdma + sgdma->free_sgdma) % NUM_SG_DMA;
+ sg_state = sgdma->sg_state + sgslot;
+ if (sg_state->next_sglist != 0) {
+ /* This DMA transfer was in progress, so abort it. */
+ sgdma_callback_t callback = sg_state->callback;
+ void *arg = sg_state->arg;
+ sgdma->free_sgdma++;
+ if (callback) {
+ /* leave interrupts masked */
+ spin_unlock(&sgdma->lock);
+ (*callback) (sgdma, csr, arg);
+ spin_lock(&sgdma->lock);
+ }
+ }
+ }
+
+ spin_unlock_irqrestore(&sgdma->lock, flags);
+}
+
+void omap24xxcam_sgdma_init(struct omap24xxcam_sgdma *sgdma,
+ unsigned long base,
+ void (*reset_callback)(unsigned long data),
+ unsigned long reset_callback_data)
+{
+ int sg;
+
+ spin_lock_init(&sgdma->lock);
+ sgdma->free_sgdma = NUM_SG_DMA;
+ sgdma->next_sgdma = 0;
+ for (sg = 0; sg < NUM_SG_DMA; sg++) {
+ sgdma->sg_state[sg].sglen = 0;
+ sgdma->sg_state[sg].next_sglist = 0;
+ sgdma->sg_state[sg].bytes_read = 0;
+ sgdma->sg_state[sg].queued_sglist = 0;
+ sgdma->sg_state[sg].csr = 0;
+ sgdma->sg_state[sg].callback = NULL;
+ sgdma->sg_state[sg].arg = NULL;
+ }
+
+ omap24xxcam_dma_init(&sgdma->dma, base);
+ setup_timer(&sgdma->reset_timer, reset_callback, reset_callback_data);
+}
--- /dev/null
+/*
+ * drivers/media/video/omap24xxcam.c
+ *
+ * OMAP 2 camera block driver.
+ *
+ * Copyright (C) 2004 MontaVista Software, Inc.
+ * Copyright (C) 2004 Texas Instruments.
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Sakari Ailus <sakari.ailus@nokia.com>
+ *
+ * Based on code from Andy Lowe <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
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/videodev2.h>
+#include <linux/pci.h> /* needed for videobufs */
+#include <linux/version.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <media/v4l2-common.h>
+
+#include "omap24xxcam.h"
+
+#define OMAP24XXCAM_VERSION KERNEL_VERSION(0, 0, 0)
+
+#define RESET_TIMEOUT_NS 10000
+
+static void omap24xxcam_reset(struct omap24xxcam_device *cam);
+static int omap24xxcam_sensor_if_enable(struct omap24xxcam_device *cam);
+static void omap24xxcam_device_unregister(struct v4l2_int_device *s);
+static int omap24xxcam_remove(struct platform_device *pdev);
+
+/* 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;
+
+static struct v4l2_int_device omap24xxcam;
+
+/*
+ *
+ * Clocks.
+ *
+ */
+
+static void omap24xxcam_clock_put(struct omap24xxcam_device *cam)
+{
+ if (cam->ick != NULL && !IS_ERR(cam->ick))
+ clk_put(cam->ick);
+ if (cam->fck != NULL && !IS_ERR(cam->fck))
+ clk_put(cam->fck);
+
+ cam->ick = cam->fck = NULL;
+}
+
+static int omap24xxcam_clock_get(struct omap24xxcam_device *cam)
+{
+ int rval = 0;
+
+ cam->fck = clk_get(cam->dev, "cam_fck");
+ if (IS_ERR(cam->fck)) {
+ dev_err(cam->dev, "can't get cam_fck");
+ rval = PTR_ERR(cam->fck);
+ omap24xxcam_clock_put(cam);
+ return rval;
+ }
+
+ cam->ick = clk_get(cam->dev, "cam_ick");
+ if (IS_ERR(cam->ick)) {
+ dev_err(cam->dev, "can't get cam_ick");
+ rval = PTR_ERR(cam->ick);
+ omap24xxcam_clock_put(cam);
+ }
+
+ return rval;
+}
+
+static void omap24xxcam_clock_on(struct omap24xxcam_device *cam)
+{
+ clk_enable(cam->fck);
+ clk_enable(cam->ick);
+}
+
+static void omap24xxcam_clock_off(struct omap24xxcam_device *cam)
+{
+ clk_disable(cam->fck);
+ clk_disable(cam->ick);
+}
+
+/*
+ *
+ * Camera core
+ *
+ */
+
+/*
+ * Set xclk.
+ *
+ * To disable xclk, use value zero.
+ */
+static void omap24xxcam_core_xclk_set(const struct omap24xxcam_device *cam,
+ u32 xclk)
+{
+ if (xclk) {
+ u32 divisor = CAM_MCLK / xclk;
+
+ if (divisor == 1)
+ omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET,
+ CC_CTRL_XCLK,
+ CC_CTRL_XCLK_DIV_BYPASS);
+ else
+ omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET,
+ CC_CTRL_XCLK, divisor);
+ } else
+ omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET,
+ CC_CTRL_XCLK, CC_CTRL_XCLK_DIV_STABLE_LOW);
+}
+
+static void omap24xxcam_core_hwinit(const struct omap24xxcam_device *cam)
+{
+ /*
+ * Setting the camera core AUTOIDLE bit causes problems with frame
+ * synchronization, so we will clear the AUTOIDLE bit instead.
+ */
+ omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_SYSCONFIG,
+ CC_SYSCONFIG_AUTOIDLE);
+
+ /* program the camera interface DMA packet size */
+ omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_CTRL_DMA,
+ CC_CTRL_DMA_EN | (DMA_THRESHOLD / 4 - 1));
+
+ /* enable camera core error interrupts */
+ omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_IRQENABLE,
+ CC_IRQENABLE_FW_ERR_IRQ
+ | CC_IRQENABLE_FSC_ERR_IRQ
+ | CC_IRQENABLE_SSC_ERR_IRQ
+ | CC_IRQENABLE_FIFO_OF_IRQ);
+}
+
+/*
+ * Enable the camera core.
+ *
+ * Data transfer to the camera DMA starts from next starting frame.
+ */
+static void omap24xxcam_core_enable(const struct omap24xxcam_device *cam)
+{
+
+ omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_CTRL,
+ cam->cc_ctrl);
+}
+
+/*
+ * Disable camera core.
+ *
+ * The data transfer will be stopped immediately (CC_CTRL_CC_RST). The
+ * core internal state machines will be reset. Use
+ * CC_CTRL_CC_FRAME_TRIG instead if you want to transfer the current
+ * frame completely.
+ */
+static void omap24xxcam_core_disable(const struct omap24xxcam_device *cam)
+{
+ omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_CTRL,
+ CC_CTRL_CC_RST);
+}
+
+/* Interrupt service routine for camera core interrupts. */
+static void omap24xxcam_core_isr(struct omap24xxcam_device *cam)
+{
+ u32 cc_irqstatus;
+ const u32 cc_irqstatus_err =
+ CC_IRQSTATUS_FW_ERR_IRQ
+ | CC_IRQSTATUS_FSC_ERR_IRQ
+ | CC_IRQSTATUS_SSC_ERR_IRQ
+ | CC_IRQSTATUS_FIFO_UF_IRQ
+ | CC_IRQSTATUS_FIFO_OF_IRQ;
+
+ cc_irqstatus = omap24xxcam_reg_in(cam->mmio_base + CC_REG_OFFSET,
+ CC_IRQSTATUS);
+ omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_IRQSTATUS,
+ cc_irqstatus);
+
+ if (cc_irqstatus & cc_irqstatus_err
+ && !atomic_read(&cam->in_reset)) {
+ dev_dbg(cam->dev, "resetting camera, cc_irqstatus 0x%x\n",
+ cc_irqstatus);
+ omap24xxcam_reset(cam);
+ }
+}
+
+/*
+ *
+ * videobuf_buffer handling.
+ *
+ * Memory for mmapped videobuf_buffers is not allocated
+ * conventionally, but by several kmalloc allocations and then
+ * creating the scatterlist on our own. User-space buffers are handled
+ * normally.
+ *
+ */
+
+/*
+ * Free the memory-mapped buffer memory allocated for a
+ * videobuf_buffer and the associated scatterlist.
+ */
+static void omap24xxcam_vbq_free_mmap_buffer(struct videobuf_buffer *vb)
+{
+ struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
+ size_t alloc_size;
+ struct page *page;
+ int i;
+
+ if (dma->sglist == NULL)
+ return;
+
+ i = dma->sglen;
+ while (i) {
+ i--;
+ alloc_size = sg_dma_len(&dma->sglist[i]);
+ page = sg_page(&dma->sglist[i]);
+ do {
+ ClearPageReserved(page++);
+ } while (alloc_size -= PAGE_SIZE);
+ __free_pages(sg_page(&dma->sglist[i]),
+ get_order(sg_dma_len(&dma->sglist[i])));
+ }
+
+ kfree(dma->sglist);
+ dma->sglist = NULL;
+}
+
+/* Release all memory related to the videobuf_queue. */
+static void omap24xxcam_vbq_free_mmap_buffers(struct videobuf_queue *vbq)
+{
+ int i;
+
+ mutex_lock(&vbq->vb_lock);
+
+ for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+ if (NULL == vbq->bufs[i])
+ continue;
+ if (V4L2_MEMORY_MMAP != vbq->bufs[i]->memory)
+ continue;
+ vbq->ops->buf_release(vbq, vbq->bufs[i]);
+ omap24xxcam_vbq_free_mmap_buffer(vbq->bufs[i]);
+ kfree(vbq->bufs[i]);
+ vbq->bufs[i] = NULL;
+ }
+
+ mutex_unlock(&vbq->vb_lock);
+
+ videobuf_mmap_free(vbq);
+}
+
+/*
+ * Allocate physically as contiguous as possible buffer for video
+ * frame and allocate and build DMA scatter-gather list for it.
+ */
+static int omap24xxcam_vbq_alloc_mmap_buffer(struct videobuf_buffer *vb)
+{
+ unsigned int order;
+ size_t alloc_size, size = vb->bsize; /* vb->bsize is page aligned */
+ struct page *page;
+ int max_pages, err = 0, i = 0;
+ struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
+
+ /*
+ * allocate maximum size scatter-gather list. Note this is
+ * overhead. We may not use as many entries as we allocate
+ */
+ max_pages = vb->bsize >> PAGE_SHIFT;
+ dma->sglist = kcalloc(max_pages, sizeof(*dma->sglist), GFP_KERNEL);
+ if (dma->sglist == NULL) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ while (size) {
+ order = get_order(size);
+ /*
+ * do not over-allocate even if we would get larger
+ * contiguous chunk that way
+ */
+ if ((PAGE_SIZE << order) > size)
+ order--;
+
+ /* try to allocate as many contiguous pages as possible */
+ page = alloc_pages(GFP_KERNEL | GFP_DMA, order);
+ /* if allocation fails, try to allocate smaller amount */
+ while (page == NULL) {
+ order--;
+ page = alloc_pages(GFP_KERNEL | GFP_DMA, order);
+ if (page == NULL && !order) {
+ err = -ENOMEM;
+ goto out;
+ }
+ }
+ size -= (PAGE_SIZE << order);
+
+ /* append allocated chunk of pages into scatter-gather list */
+ sg_set_page(&dma->sglist[i], page, PAGE_SIZE << order, 0);
+ dma->sglen++;
+ i++;
+
+ alloc_size = (PAGE_SIZE << order);
+
+ /* clear pages before giving them to user space */
+ memset(page_address(page), 0, alloc_size);
+
+ /* mark allocated pages reserved */
+ do {
+ SetPageReserved(page++);
+ } while (alloc_size -= PAGE_SIZE);
+ }
+ /*
+ * REVISIT: not fully correct to assign nr_pages == sglen but
+ * video-buf is passing nr_pages for e.g. unmap_sg calls
+ */
+ dma->nr_pages = dma->sglen;
+ dma->direction = PCI_DMA_FROMDEVICE;
+
+ return 0;
+
+out:
+ omap24xxcam_vbq_free_mmap_buffer(vb);
+ return err;
+}
+
+static int omap24xxcam_vbq_alloc_mmap_buffers(struct videobuf_queue *vbq,
+ unsigned int count)
+{
+ int i, err = 0;
+ struct omap24xxcam_fh *fh =
+ container_of(vbq, struct omap24xxcam_fh, vbq);
+
+ mutex_lock(&vbq->vb_lock);
+
+ for (i = 0; i < count; i++) {
+ err = omap24xxcam_vbq_alloc_mmap_buffer(vbq->bufs[i]);
+ if (err)
+ goto out;
+ dev_dbg(fh->cam->dev, "sglen is %d for buffer %d\n",
+ videobuf_to_dma(vbq->bufs[i])->sglen, i);
+ }
+
+ mutex_unlock(&vbq->vb_lock);
+
+ return 0;
+out:
+ while (i) {
+ i--;
+ omap24xxcam_vbq_free_mmap_buffer(vbq->bufs[i]);
+ }
+
+ mutex_unlock(&vbq->vb_lock);
+
+ return err;
+}
+
+/*
+ * This routine is called from interrupt context when a scatter-gather DMA
+ * transfer of a videobuf_buffer completes.
+ */
+static void omap24xxcam_vbq_complete(struct omap24xxcam_sgdma *sgdma,
+ u32 csr, void *arg)
+{
+ struct omap24xxcam_device *cam =
+ container_of(sgdma, struct omap24xxcam_device, sgdma);
+ struct omap24xxcam_fh *fh = cam->streaming->private_data;
+ struct videobuf_buffer *vb = (struct videobuf_buffer *)arg;
+ const u32 csr_error = CAMDMA_CSR_MISALIGNED_ERR
+ | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR
+ | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cam->core_enable_disable_lock, flags);
+ if (--cam->sgdma_in_queue == 0)
+ omap24xxcam_core_disable(cam);
+ spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags);
+
+ do_gettimeofday(&vb->ts);
+ vb->field_count = atomic_add_return(2, &fh->field_count);
+ if (csr & csr_error) {
+ vb->state = VIDEOBUF_ERROR;
+ if (!atomic_read(&fh->cam->in_reset)) {
+ dev_dbg(cam->dev, "resetting camera, csr 0x%x\n", csr);
+ omap24xxcam_reset(cam);
+ }
+ } else
+ vb->state = VIDEOBUF_DONE;
+ wake_up(&vb->done);
+}
+
+static void omap24xxcam_vbq_release(struct videobuf_queue *vbq,
+ struct videobuf_buffer *vb)
+{
+ struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
+
+ /* wait for buffer, especially to get out of the sgdma queue */
+ videobuf_waiton(vb, 0, 0);
+ if (vb->memory == V4L2_MEMORY_MMAP) {
+ dma_unmap_sg(vbq->dev, dma->sglist, dma->sglen,
+ dma->direction);
+ dma->direction = DMA_NONE;
+ } else {
+ videobuf_dma_unmap(vbq, videobuf_to_dma(vb));
+ videobuf_dma_free(videobuf_to_dma(vb));
+ }
+
+ vb->state = VIDEOBUF_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 omap24xxcam_vbq_setup(struct videobuf_queue *vbq, unsigned int *cnt,
+ unsigned int *size)
+{
+ struct omap24xxcam_fh *fh = vbq->priv_data;
+
+ if (*cnt <= 0)
+ *cnt = VIDEO_MAX_FRAME; /* supply a default number of buffers */
+
+ if (*cnt > VIDEO_MAX_FRAME)
+ *cnt = VIDEO_MAX_FRAME;
+
+ *size = fh->pix.sizeimage;
+
+ /* accessing fh->cam->capture_mem is ok, it's constant */
+ while (*size * *cnt > fh->cam->capture_mem)
+ (*cnt)--;
+
+ return 0;
+}
+
+static int omap24xxcam_dma_iolock(struct videobuf_queue *vbq,
+ struct videobuf_dmabuf *dma)
+{
+ int err = 0;
+
+ dma->direction = PCI_DMA_FROMDEVICE;
+ if (!dma_map_sg(vbq->dev, dma->sglist, dma->sglen, dma->direction)) {
+ kfree(dma->sglist);
+ dma->sglist = NULL;
+ dma->sglen = 0;
+ err = -EIO;
+ }
+
+ return err;
+}
+
+static int omap24xxcam_vbq_prepare(struct videobuf_queue *vbq,
+ struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct omap24xxcam_fh *fh = vbq->priv_data;
+ int err = 0;
+
+ /*
+ * Accessing pix here is okay since it's constant while
+ * streaming is on (and we only get called then).
+ */
+ if (vb->baddr) {
+ /* This is a userspace buffer. */
+ if (fh->pix.sizeimage > vb->bsize) {
+ /* The buffer isn't big enough. */
+ err = -EINVAL;
+ } else
+ vb->size = fh->pix.sizeimage;
+ } else {
+ if (vb->state != VIDEOBUF_NEEDS_INIT) {
+ /*
+ * We have a kernel bounce buffer that has
+ * already been allocated.
+ */
+ if (fh->pix.sizeimage > vb->size) {
+ /*
+ * The image size has been changed to
+ * a larger size since this buffer was
+ * allocated, so we need to free and
+ * reallocate it.
+ */
+ omap24xxcam_vbq_release(vbq, vb);
+ vb->size = fh->pix.sizeimage;
+ }
+ } else {
+ /* We need to allocate a new kernel bounce buffer. */
+ vb->size = fh->pix.sizeimage;
+ }
+ }
+
+ if (err)
+ return err;
+
+ vb->width = fh->pix.width;
+ vb->height = fh->pix.height;
+ vb->field = field;
+
+ if (vb->state == VIDEOBUF_NEEDS_INIT) {
+ if (vb->memory == V4L2_MEMORY_MMAP)
+ /*
+ * we have built the scatter-gather list by ourself so
+ * do the scatter-gather mapping as well
+ */
+ err = omap24xxcam_dma_iolock(vbq, videobuf_to_dma(vb));
+ else
+ err = videobuf_iolock(vbq, vb, NULL);
+ }
+
+ if (!err)
+ vb->state = VIDEOBUF_PREPARED;
+ else
+ omap24xxcam_vbq_release(vbq, vb);
+
+ return err;
+}
+
+static void omap24xxcam_vbq_queue(struct videobuf_queue *vbq,
+ struct videobuf_buffer *vb)
+{
+ struct omap24xxcam_fh *fh = vbq->priv_data;
+ struct omap24xxcam_device *cam = fh->cam;
+ enum videobuf_state state = vb->state;
+ unsigned long flags;
+ int err;
+
+ /*
+ * FIXME: We're marking the buffer active since we have no
+ * pretty way of marking it active exactly when the
+ * scatter-gather transfer starts.
+ */
+ vb->state = VIDEOBUF_ACTIVE;
+
+ err = omap24xxcam_sgdma_queue(&fh->cam->sgdma,
+ videobuf_to_dma(vb)->sglist,
+ videobuf_to_dma(vb)->sglen, vb->size,
+ omap24xxcam_vbq_complete, vb);
+
+ if (!err) {
+ spin_lock_irqsave(&cam->core_enable_disable_lock, flags);
+ if (++cam->sgdma_in_queue == 1
+ && !atomic_read(&cam->in_reset))
+ omap24xxcam_core_enable(cam);
+ spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags);
+ } else {
+ /*
+ * 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.
+ */
+ dev_err(cam->dev, "failed to queue a video buffer for dma!\n");
+ dev_err(cam->dev, "likely a bug in the driver!\n");
+ vb->state = state;
+ }
+}
+
+static struct videobuf_queue_ops omap24xxcam_vbq_ops = {
+ .buf_setup = omap24xxcam_vbq_setup,
+ .buf_prepare = omap24xxcam_vbq_prepare,
+ .buf_queue = omap24xxcam_vbq_queue,
+ .buf_release = omap24xxcam_vbq_release,
+};
+
+/*
+ *
+ * OMAP main camera system
+ *
+ */
+
+/*
+ * Reset camera block to power-on state.
+ */
+static void omap24xxcam_poweron_reset(const struct omap24xxcam_device *cam)
+{
+ int max_loop = RESET_TIMEOUT_NS;
+
+ /* Reset whole camera subsystem */
+ omap24xxcam_reg_out(cam->mmio_base,
+ CAM_SYSCONFIG,
+ CAM_SYSCONFIG_SOFTRESET);
+
+ /* Wait till it's finished */
+ while (!(omap24xxcam_reg_in(cam->mmio_base, CAM_SYSSTATUS)
+ & CAM_SYSSTATUS_RESETDONE)
+ && --max_loop) {
+ ndelay(1);
+ }
+
+ if (!(omap24xxcam_reg_in(cam->mmio_base, CAM_SYSSTATUS)
+ & CAM_SYSSTATUS_RESETDONE))
+ dev_err(cam->dev, "camera soft reset timeout\n");
+}
+
+/*
+ * (Re)initialise the camera block.
+ */
+static void omap24xxcam_hwinit(const struct omap24xxcam_device *cam)
+{
+ omap24xxcam_poweron_reset(cam);
+
+ /* set the camera subsystem autoidle bit */
+ omap24xxcam_reg_out(cam->mmio_base, CAM_SYSCONFIG,
+ CAM_SYSCONFIG_AUTOIDLE);
+
+ /* set the camera MMU autoidle bit */
+ omap24xxcam_reg_out(cam->mmio_base,
+ CAMMMU_REG_OFFSET + CAMMMU_SYSCONFIG,
+ CAMMMU_SYSCONFIG_AUTOIDLE);
+
+ omap24xxcam_core_hwinit(cam);
+
+ omap24xxcam_dma_hwinit(&cam->sgdma.dma);
+}
+
+/*
+ * Callback for dma transfer stalling.
+ */
+static void omap24xxcam_stalled_dma_reset(unsigned long data)
+{
+ struct omap24xxcam_device *cam = (struct omap24xxcam_device *)data;
+
+ if (!atomic_read(&cam->in_reset)) {
+ dev_dbg(cam->dev, "dma stalled, resetting camera\n");
+ omap24xxcam_reset(cam);
+ }
+}
+
+/*
+ * Stop capture. Mark we're doing a reset, stop DMA transfers and
+ * core. (No new scatter-gather transfers will be queued whilst
+ * in_reset is non-zero.)
+ *
+ * If omap24xxcam_capture_stop is called from several places at
+ * once, only the first call will have an effect. Similarly, the last
+ * call omap24xxcam_streaming_cont will have effect.
+ *
+ * Serialisation is ensured by using cam->core_enable_disable_lock.
+ */
+static void omap24xxcam_capture_stop(struct omap24xxcam_device *cam)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&cam->core_enable_disable_lock, flags);
+
+ if (atomic_inc_return(&cam->in_reset) != 1) {
+ spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags);
+ return;
+ }
+
+ omap24xxcam_core_disable(cam);
+
+ spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags);
+
+ omap24xxcam_sgdma_sync(&cam->sgdma);
+}
+
+/*
+ * Reset and continue streaming.
+ *
+ * Note: Resetting the camera FIFO via the CC_RST bit in the CC_CTRL
+ * register is supposed to be sufficient to recover from a camera
+ * interface error, but it doesn't seem to be enough. If we only do
+ * that then subsequent image captures are out of sync by either one
+ * or two times DMA_THRESHOLD bytes. Resetting and re-initializing the
+ * entire camera subsystem prevents the problem with frame
+ * synchronization.
+ */
+static void omap24xxcam_capture_cont(struct omap24xxcam_device *cam)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&cam->core_enable_disable_lock, flags);
+
+ if (atomic_read(&cam->in_reset) != 1)
+ goto out;
+
+ omap24xxcam_hwinit(cam);
+
+ omap24xxcam_sensor_if_enable(cam);
+
+ omap24xxcam_sgdma_process(&cam->sgdma);
+
+ if (cam->sgdma_in_queue)
+ omap24xxcam_core_enable(cam);
+
+out:
+ atomic_dec(&cam->in_reset);
+ spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags);
+}
+
+static ssize_t
+omap24xxcam_streaming_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct omap24xxcam_device *cam = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%s\n", cam->streaming ? "active" : "inactive");
+}
+static DEVICE_ATTR(streaming, S_IRUGO, omap24xxcam_streaming_show, NULL);
+
+/*
+ * Stop capture and restart it. I.e. reset the camera during use.
+ */
+static void omap24xxcam_reset(struct omap24xxcam_device *cam)
+{
+ omap24xxcam_capture_stop(cam);
+ omap24xxcam_capture_cont(cam);
+}
+
+/*
+ * The main interrupt handler.
+ */
+static irqreturn_t omap24xxcam_isr(int irq, void *arg)
+{
+ struct omap24xxcam_device *cam = (struct omap24xxcam_device *)arg;
+ u32 irqstatus;
+ unsigned int irqhandled = 0;
+
+ irqstatus = omap24xxcam_reg_in(cam->mmio_base, CAM_IRQSTATUS);
+
+ if (irqstatus &
+ (CAM_IRQSTATUS_DMA_IRQ2 | CAM_IRQSTATUS_DMA_IRQ1
+ | CAM_IRQSTATUS_DMA_IRQ0)) {
+ omap24xxcam_dma_isr(&cam->sgdma.dma);
+ irqhandled = 1;
+ }
+ if (irqstatus & CAM_IRQSTATUS_CC_IRQ) {
+ omap24xxcam_core_isr(cam);
+ irqhandled = 1;
+ }
+ if (irqstatus & CAM_IRQSTATUS_MMU_IRQ)
+ dev_err(cam->dev, "unhandled camera MMU interrupt!\n");
+
+ return IRQ_RETVAL(irqhandled);
+}
+
+/*
+ *
+ * Sensor handling.
+ *
+ */
+
+/*
+ * Enable the external sensor interface. Try to negotiate interface
+ * parameters with the sensor and start using the new ones. The calls
+ * to sensor_if_enable and sensor_if_disable need not to be balanced.
+ */
+static int omap24xxcam_sensor_if_enable(struct omap24xxcam_device *cam)
+{
+ int rval;
+ struct v4l2_ifparm p;
+
+ rval = vidioc_int_g_ifparm(cam->sdev, &p);
+ if (rval) {
+ dev_err(cam->dev, "vidioc_int_g_ifparm failed with %d\n", rval);
+ return rval;
+ }
+
+ cam->if_type = p.if_type;
+
+ cam->cc_ctrl = CC_CTRL_CC_EN;
+
+ switch (p.if_type) {
+ case V4L2_IF_TYPE_BT656:
+ if (p.u.bt656.frame_start_on_rising_vs)
+ cam->cc_ctrl |= CC_CTRL_NOBT_SYNCHRO;
+ if (p.u.bt656.bt_sync_correct)
+ cam->cc_ctrl |= CC_CTRL_BT_CORRECT;
+ if (p.u.bt656.swap)
+ cam->cc_ctrl |= CC_CTRL_PAR_ORDERCAM;
+ if (p.u.bt656.latch_clk_inv)
+ cam->cc_ctrl |= CC_CTRL_PAR_CLK_POL;
+ if (p.u.bt656.nobt_hs_inv)
+ cam->cc_ctrl |= CC_CTRL_NOBT_HS_POL;
+ if (p.u.bt656.nobt_vs_inv)
+ cam->cc_ctrl |= CC_CTRL_NOBT_VS_POL;
+
+ switch (p.u.bt656.mode) {
+ case V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT:
+ cam->cc_ctrl |= CC_CTRL_PAR_MODE_NOBT8;
+ break;
+ case V4L2_IF_TYPE_BT656_MODE_NOBT_10BIT:
+ cam->cc_ctrl |= CC_CTRL_PAR_MODE_NOBT10;
+ break;
+ case V4L2_IF_TYPE_BT656_MODE_NOBT_12BIT:
+ cam->cc_ctrl |= CC_CTRL_PAR_MODE_NOBT12;
+ break;
+ case V4L2_IF_TYPE_BT656_MODE_BT_8BIT:
+ cam->cc_ctrl |= CC_CTRL_PAR_MODE_BT8;
+ break;
+ case V4L2_IF_TYPE_BT656_MODE_BT_10BIT:
+ cam->cc_ctrl |= CC_CTRL_PAR_MODE_BT10;
+ break;
+ default:
+ dev_err(cam->dev,
+ "bt656 interface mode %d not supported\n",
+ p.u.bt656.mode);
+ return -EINVAL;
+ }
+ /*
+ * The clock rate that the sensor wants has changed.
+ * We have to adjust the xclk from OMAP 2 side to
+ * match the sensor's wish as closely as possible.
+ */
+ if (p.u.bt656.clock_curr != cam->if_u.bt656.xclk) {
+ u32 xclk = p.u.bt656.clock_curr;
+ u32 divisor;
+
+ if (xclk == 0)
+ return -EINVAL;
+
+ if (xclk > CAM_MCLK)
+ xclk = CAM_MCLK;
+
+ divisor = CAM_MCLK / xclk;
+ if (divisor * xclk < CAM_MCLK)
+ divisor++;
+ if (CAM_MCLK / divisor < p.u.bt656.clock_min
+ && divisor > 1)
+ divisor--;
+ if (divisor > 30)
+ divisor = 30;
+
+ xclk = CAM_MCLK / divisor;
+
+ if (xclk < p.u.bt656.clock_min
+ || xclk > p.u.bt656.clock_max)
+ return -EINVAL;
+
+ cam->if_u.bt656.xclk = xclk;
+ }
+ omap24xxcam_core_xclk_set(cam, cam->if_u.bt656.xclk);
+ break;
+ default:
+ /* FIXME: how about other interfaces? */
+ dev_err(cam->dev, "interface type %d not supported\n",
+ p.if_type);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void omap24xxcam_sensor_if_disable(const struct omap24xxcam_device *cam)
+{
+ switch (cam->if_type) {
+ case V4L2_IF_TYPE_BT656:
+ omap24xxcam_core_xclk_set(cam, 0);
+ break;
+ }
+}
+
+/*
+ * Initialise the sensor hardware.
+ */
+static int omap24xxcam_sensor_init(struct omap24xxcam_device *cam)
+{
+ int err = 0;
+ struct v4l2_int_device *sdev = cam->sdev;
+
+ omap24xxcam_clock_on(cam);
+ err = omap24xxcam_sensor_if_enable(cam);
+ if (err) {
+ dev_err(cam->dev, "sensor interface could not be enabled at "
+ "initialisation, %d\n", err);
+ cam->sdev = NULL;
+ goto out;
+ }
+
+ /* power up sensor during sensor initialization */
+ vidioc_int_s_power(sdev, 1);
+
+ err = vidioc_int_dev_init(sdev);
+ if (err) {
+ dev_err(cam->dev, "cannot initialize sensor, error %d\n", err);
+ /* Sensor init failed --- it's nonexistent to us! */
+ cam->sdev = NULL;
+ goto out;
+ }
+
+ dev_info(cam->dev, "sensor is %s\n", sdev->name);
+
+out:
+ omap24xxcam_sensor_if_disable(cam);
+ omap24xxcam_clock_off(cam);
+
+ vidioc_int_s_power(sdev, 0);
+
+ return err;
+}
+
+static void omap24xxcam_sensor_exit(struct omap24xxcam_device *cam)
+{
+ if (cam->sdev)
+ vidioc_int_dev_exit(cam->sdev);
+}
+
+static void omap24xxcam_sensor_disable(struct omap24xxcam_device *cam)
+{
+ omap24xxcam_sensor_if_disable(cam);
+ omap24xxcam_clock_off(cam);
+ vidioc_int_s_power(cam->sdev, 0);
+}
+
+/*
+ * Power-up and configure camera sensor. It's ready for capturing now.
+ */
+static int omap24xxcam_sensor_enable(struct omap24xxcam_device *cam)
+{
+ int rval;
+
+ omap24xxcam_clock_on(cam);
+
+ omap24xxcam_sensor_if_enable(cam);
+
+ rval = vidioc_int_s_power(cam->sdev, 1);
+ if (rval)
+ goto out;
+
+ rval = vidioc_int_init(cam->sdev);
+ if (rval)
+ goto out;
+
+ return 0;
+
+out:
+ omap24xxcam_sensor_disable(cam);
+
+ return rval;
+}
+
+static void omap24xxcam_sensor_reset_work(struct work_struct *work)
+{
+ struct omap24xxcam_device *cam =
+ container_of(work, struct omap24xxcam_device,
+ sensor_reset_work);
+
+ if (atomic_read(&cam->reset_disable))
+ return;
+
+ omap24xxcam_capture_stop(cam);
+
+ if (vidioc_int_reset(cam->sdev) == 0) {
+ vidioc_int_init(cam->sdev);
+ } else {
+ /* Can't reset it by vidioc_int_reset. */
+ omap24xxcam_sensor_disable(cam);
+ omap24xxcam_sensor_enable(cam);
+ }
+
+ omap24xxcam_capture_cont(cam);
+}
+
+/*
+ *
+ * IOCTL interface.
+ *
+ */
+
+static int vidioc_querycap(struct file *file, void *fh,
+ struct v4l2_capability *cap)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+
+ strlcpy(cap->driver, CAM_NAME, sizeof(cap->driver));
+ strlcpy(cap->card, cam->vfd->name, sizeof(cap->card));
+ cap->version = OMAP24XXCAM_VERSION;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+
+ return 0;
+}
+
+static int vidioc_enum_fmt_cap(struct file *file, void *fh,
+ struct v4l2_fmtdesc *f)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ int rval;
+
+ rval = vidioc_int_enum_fmt_cap(cam->sdev, f);
+
+ return rval;
+}
+
+static int vidioc_g_fmt_cap(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ int rval;
+
+ mutex_lock(&cam->mutex);
+ rval = vidioc_int_g_fmt_cap(cam->sdev, f);
+ mutex_unlock(&cam->mutex);
+
+ return rval;
+}
+
+static int vidioc_s_fmt_cap(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ int rval;
+
+ mutex_lock(&cam->mutex);
+ if (cam->streaming) {
+ rval = -EBUSY;
+ goto out;
+ }
+
+ rval = vidioc_int_s_fmt_cap(cam->sdev, f);
+
+out:
+ mutex_unlock(&cam->mutex);
+
+ if (!rval) {
+ mutex_lock(&ofh->vbq.vb_lock);
+ ofh->pix = f->fmt.pix;
+ mutex_unlock(&ofh->vbq.vb_lock);
+ }
+
+ memset(f, 0, sizeof(*f));
+ vidioc_g_fmt_cap(file, fh, f);
+
+ return rval;
+}
+
+static int vidioc_try_fmt_cap(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ int rval;
+
+ mutex_lock(&cam->mutex);
+ rval = vidioc_int_try_fmt_cap(cam->sdev, f);
+ mutex_unlock(&cam->mutex);
+
+ return rval;
+}
+
+static int vidioc_reqbufs(struct file *file, void *fh,
+ struct v4l2_requestbuffers *b)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ int rval;
+
+ mutex_lock(&cam->mutex);
+ if (cam->streaming) {
+ mutex_unlock(&cam->mutex);
+ return -EBUSY;
+ }
+
+ omap24xxcam_vbq_free_mmap_buffers(&ofh->vbq);
+ mutex_unlock(&cam->mutex);
+
+ rval = videobuf_reqbufs(&ofh->vbq, b);
+
+ /*
+ * Either videobuf_reqbufs failed or the buffers are not
+ * memory-mapped (which would need special attention).
+ */
+ if (rval < 0 || b->memory != V4L2_MEMORY_MMAP)
+ goto out;
+
+ rval = omap24xxcam_vbq_alloc_mmap_buffers(&ofh->vbq, rval);
+ if (rval)
+ omap24xxcam_vbq_free_mmap_buffers(&ofh->vbq);
+
+out:
+ return rval;
+}
+
+static int vidioc_querybuf(struct file *file, void *fh,
+ struct v4l2_buffer *b)
+{
+ struct omap24xxcam_fh *ofh = fh;
+
+ return videobuf_querybuf(&ofh->vbq, b);
+}
+
+static int vidioc_qbuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+ struct omap24xxcam_fh *ofh = fh;
+
+ return videobuf_qbuf(&ofh->vbq, b);
+}
+
+static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ struct videobuf_buffer *vb;
+ int rval;
+
+videobuf_dqbuf_again:
+ rval = videobuf_dqbuf(&ofh->vbq, b, file->f_flags & O_NONBLOCK);
+ if (rval)
+ goto out;
+
+ vb = ofh->vbq.bufs[b->index];
+
+ mutex_lock(&cam->mutex);
+ /* _needs_reset returns -EIO if reset is required. */
+ rval = vidioc_int_g_needs_reset(cam->sdev, (void *)vb->baddr);
+ mutex_unlock(&cam->mutex);
+ if (rval == -EIO)
+ schedule_work(&cam->sensor_reset_work);
+ else
+ rval = 0;
+
+out:
+ /*
+ * This is a hack. We don't want to show -EIO to the user
+ * space. Requeue the buffer and try again if we're not doing
+ * this in non-blocking mode.
+ */
+ if (rval == -EIO) {
+ videobuf_qbuf(&ofh->vbq, b);
+ if (!(file->f_flags & O_NONBLOCK))
+ goto videobuf_dqbuf_again;
+ /*
+ * We don't have a videobuf_buffer now --- maybe next
+ * time...
+ */
+ rval = -EAGAIN;
+ }
+
+ return rval;
+}
+
+static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ int rval;
+
+ mutex_lock(&cam->mutex);
+ if (cam->streaming) {
+ rval = -EBUSY;
+ goto out;
+ }
+
+ rval = omap24xxcam_sensor_if_enable(cam);
+ if (rval) {
+ dev_dbg(cam->dev, "vidioc_int_g_ifparm failed\n");
+ goto out;
+ }
+
+ rval = videobuf_streamon(&ofh->vbq);
+ if (!rval) {
+ cam->streaming = file;
+ sysfs_notify(&cam->dev->kobj, NULL, "streaming");
+ }
+
+out:
+ mutex_unlock(&cam->mutex);
+
+ return rval;
+}
+
+static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ struct videobuf_queue *q = &ofh->vbq;
+ int rval;
+
+ atomic_inc(&cam->reset_disable);
+
+ flush_scheduled_work();
+
+ rval = videobuf_streamoff(q);
+ if (!rval) {
+ mutex_lock(&cam->mutex);
+ cam->streaming = NULL;
+ mutex_unlock(&cam->mutex);
+ sysfs_notify(&cam->dev->kobj, NULL, "streaming");
+ }
+
+ atomic_dec(&cam->reset_disable);
+
+ return rval;
+}
+
+static int vidioc_enum_input(struct file *file, void *fh,
+ struct v4l2_input *inp)
+{
+ if (inp->index > 0)
+ return -EINVAL;
+
+ strlcpy(inp->name, "camera", sizeof(inp->name));
+ inp->type = V4L2_INPUT_TYPE_CAMERA;
+
+ return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
+{
+ *i = 0;
+
+ return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *fh, unsigned int i)
+{
+ if (i > 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int vidioc_queryctrl(struct file *file, void *fh,
+ struct v4l2_queryctrl *a)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ int rval;
+
+ rval = vidioc_int_queryctrl(cam->sdev, a);
+
+ return rval;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *fh,
+ struct v4l2_control *a)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ int rval;
+
+ mutex_lock(&cam->mutex);
+ rval = vidioc_int_g_ctrl(cam->sdev, a);
+ mutex_unlock(&cam->mutex);
+
+ return rval;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *fh,
+ struct v4l2_control *a)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ int rval;
+
+ mutex_lock(&cam->mutex);
+ rval = vidioc_int_s_ctrl(cam->sdev, a);
+ mutex_unlock(&cam->mutex);
+
+ return rval;
+}
+
+static int vidioc_g_parm(struct file *file, void *fh,
+ struct v4l2_streamparm *a) {
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ int rval;
+
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ mutex_lock(&cam->mutex);
+ rval = vidioc_int_g_parm(cam->sdev, a);
+ mutex_unlock(&cam->mutex);
+
+ return rval;
+}
+
+static int vidioc_s_parm(struct file *file, void *fh,
+ struct v4l2_streamparm *a)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ struct v4l2_streamparm old_streamparm;
+ int rval;
+
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ mutex_lock(&cam->mutex);
+ if (cam->streaming) {
+ rval = -EBUSY;
+ goto out;
+ }
+
+ old_streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ rval = vidioc_int_g_parm(cam->sdev, &old_streamparm);
+ if (rval)
+ goto out;
+
+ rval = vidioc_int_s_parm(cam->sdev, a);
+ if (rval)
+ goto out;
+
+ rval = omap24xxcam_sensor_if_enable(cam);
+ /*
+ * Revert to old streaming parameters if enabling sensor
+ * interface with the new ones failed.
+ */
+ if (rval)
+ vidioc_int_s_parm(cam->sdev, &old_streamparm);
+
+out:
+ mutex_unlock(&cam->mutex);
+
+ return rval;
+}
+
+/*
+ *
+ * File operations.
+ *
+ */
+
+static unsigned int omap24xxcam_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct omap24xxcam_fh *fh = file->private_data;
+ struct omap24xxcam_device *cam = fh->cam;
+ struct videobuf_buffer *vb;
+
+ mutex_lock(&cam->mutex);
+ if (cam->streaming != file) {
+ mutex_unlock(&cam->mutex);
+ return POLLERR;
+ }
+ mutex_unlock(&cam->mutex);
+
+ mutex_lock(&fh->vbq.vb_lock);
+ if (list_empty(&fh->vbq.stream)) {
+ mutex_unlock(&fh->vbq.vb_lock);
+ return POLLERR;
+ }
+ vb = list_entry(fh->vbq.stream.next, struct videobuf_buffer, stream);
+ mutex_unlock(&fh->vbq.vb_lock);
+
+ poll_wait(file, &vb->done, wait);
+
+ if (vb->state == VIDEOBUF_DONE || vb->state == VIDEOBUF_ERROR)
+ return POLLIN | POLLRDNORM;
+
+ return 0;
+}
+
+static int omap24xxcam_mmap_buffers(struct file *file,
+ struct vm_area_struct *vma)
+{
+ struct omap24xxcam_fh *fh = file->private_data;
+ struct omap24xxcam_device *cam = fh->cam;
+ struct videobuf_queue *vbq = &fh->vbq;
+ unsigned int first, last, size, i, j;
+ int err = 0;
+
+ mutex_lock(&cam->mutex);
+ if (cam->streaming) {
+ mutex_unlock(&cam->mutex);
+ return -EBUSY;
+ }
+ mutex_unlock(&cam->mutex);
+ mutex_lock(&vbq->vb_lock);
+
+ /* look for first buffer to map */
+ for (first = 0; first < VIDEO_MAX_FRAME; first++) {
+ if (NULL == vbq->bufs[first])
+ continue;
+ if (V4L2_MEMORY_MMAP != vbq->bufs[first]->memory)
+ continue;
+ if (vbq->bufs[first]->boff == (vma->vm_pgoff << PAGE_SHIFT))
+ break;
+ }
+
+ /* look for last buffer to map */
+ for (size = 0, last = first; last < VIDEO_MAX_FRAME; last++) {
+ if (NULL == vbq->bufs[last])
+ continue;
+ if (V4L2_MEMORY_MMAP != vbq->bufs[last]->memory)
+ continue;
+ size += vbq->bufs[last]->bsize;
+ if (size == (vma->vm_end - vma->vm_start))
+ break;
+ }
+
+ size = 0;
+ for (i = first; i <= last; i++) {
+ struct videobuf_dmabuf *dma = videobuf_to_dma(vbq->bufs[i]);
+
+ for (j = 0; j < dma->sglen; j++) {
+ err = remap_pfn_range(
+ vma, vma->vm_start + size,
+ page_to_pfn(sg_page(&dma->sglist[j])),
+ sg_dma_len(&dma->sglist[j]), vma->vm_page_prot);
+ if (err)
+ goto out;
+ size += sg_dma_len(&dma->sglist[j]);
+ }
+ }
+
+out:
+ mutex_unlock(&vbq->vb_lock);
+
+ return err;
+}
+
+static int omap24xxcam_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct omap24xxcam_fh *fh = file->private_data;
+ int rval;
+
+ /* let the video-buf mapper check arguments and set-up structures */
+ rval = videobuf_mmap_mapper(&fh->vbq, vma);
+ if (rval)
+ return rval;
+
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+ /* do mapping to our allocated buffers */
+ rval = omap24xxcam_mmap_buffers(file, vma);
+ /*
+ * In case of error, free vma->vm_private_data allocated by
+ * videobuf_mmap_mapper.
+ */
+ if (rval)
+ kfree(vma->vm_private_data);
+
+ return rval;
+}
+
+static int omap24xxcam_open(struct inode *inode, struct file *file)
+{
+ int minor = iminor(inode);
+ struct omap24xxcam_device *cam = omap24xxcam.priv;
+ struct omap24xxcam_fh *fh;
+ struct v4l2_format format;
+
+ if (!cam || !cam->vfd || (cam->vfd->minor != minor))
+ return -ENODEV;
+
+ fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+ if (fh == NULL)
+ return -ENOMEM;
+
+ mutex_lock(&cam->mutex);
+ if (cam->sdev == NULL || !try_module_get(cam->sdev->module)) {
+ mutex_unlock(&cam->mutex);
+ goto out_try_module_get;
+ }
+
+ if (atomic_inc_return(&cam->users) == 1) {
+ omap24xxcam_hwinit(cam);
+ if (omap24xxcam_sensor_enable(cam)) {
+ mutex_unlock(&cam->mutex);
+ goto out_omap24xxcam_sensor_enable;
+ }
+ }
+ mutex_unlock(&cam->mutex);
+
+ fh->cam = cam;
+ mutex_lock(&cam->mutex);
+ vidioc_int_g_fmt_cap(cam->sdev, &format);
+ mutex_unlock(&cam->mutex);
+ /* FIXME: how about fh->pix when there are more users? */
+ fh->pix = format.fmt.pix;
+
+ file->private_data = fh;
+
+ spin_lock_init(&fh->vbq_lock);
+
+ videobuf_queue_sg_init(&fh->vbq, &omap24xxcam_vbq_ops, NULL,
+ &fh->vbq_lock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ V4L2_FIELD_NONE,
+ sizeof(struct videobuf_buffer), fh);
+
+ return 0;
+
+out_omap24xxcam_sensor_enable:
+ omap24xxcam_poweron_reset(cam);
+ module_put(cam->sdev->module);
+
+out_try_module_get:
+ kfree(fh);
+
+ return -ENODEV;
+}
+
+static int omap24xxcam_release(struct inode *inode, struct file *file)
+{
+ struct omap24xxcam_fh *fh = file->private_data;
+ struct omap24xxcam_device *cam = fh->cam;
+
+ atomic_inc(&cam->reset_disable);
+
+ flush_scheduled_work();
+
+ /* stop streaming capture */
+ videobuf_streamoff(&fh->vbq);
+
+ mutex_lock(&cam->mutex);
+ if (cam->streaming == file) {
+ cam->streaming = NULL;
+ mutex_unlock(&cam->mutex);
+ sysfs_notify(&cam->dev->kobj, NULL, "streaming");
+ } else {
+ mutex_unlock(&cam->mutex);
+ }
+
+ atomic_dec(&cam->reset_disable);
+
+ omap24xxcam_vbq_free_mmap_buffers(&fh->vbq);
+
+ /*
+ * Make sure the reset work we might have scheduled is not
+ * pending! It may be run *only* if we have users. (And it may
+ * not be scheduled anymore since streaming is already
+ * disabled.)
+ */
+ flush_scheduled_work();
+
+ mutex_lock(&cam->mutex);
+ if (atomic_dec_return(&cam->users) == 0) {
+ omap24xxcam_sensor_disable(cam);
+ omap24xxcam_poweron_reset(cam);
+ }
+ mutex_unlock(&cam->mutex);
+
+ file->private_data = NULL;
+
+ module_put(cam->sdev->module);
+ kfree(fh);
+
+ return 0;
+}
+
+static struct file_operations omap24xxcam_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .ioctl = video_ioctl2,
+ .poll = omap24xxcam_poll,
+ .mmap = omap24xxcam_mmap,
+ .open = omap24xxcam_open,
+ .release = omap24xxcam_release,
+};
+
+/*
+ *
+ * Power management.
+ *
+ */
+
+#ifdef CONFIG_PM
+static int omap24xxcam_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct omap24xxcam_device *cam = platform_get_drvdata(pdev);
+
+ if (atomic_read(&cam->users) == 0)
+ return 0;
+
+ if (!atomic_read(&cam->reset_disable))
+ omap24xxcam_capture_stop(cam);
+
+ omap24xxcam_sensor_disable(cam);
+ omap24xxcam_poweron_reset(cam);
+
+ return 0;
+}
+
+static int omap24xxcam_resume(struct platform_device *pdev)
+{
+ struct omap24xxcam_device *cam = platform_get_drvdata(pdev);
+
+ if (atomic_read(&cam->users) == 0)
+ return 0;
+
+ omap24xxcam_hwinit(cam);
+ omap24xxcam_sensor_enable(cam);
+
+ if (!atomic_read(&cam->reset_disable))
+ omap24xxcam_capture_cont(cam);
+
+ return 0;
+}
+#endif /* CONFIG_PM */
+
+/*
+ *
+ * Camera device (i.e. /dev/video).
+ *
+ */
+
+static int omap24xxcam_device_register(struct v4l2_int_device *s)
+{
+ struct omap24xxcam_device *cam = s->u.slave->master->priv;
+ struct video_device *vfd;
+ int rval;
+
+ /* We already have a slave. */
+ if (cam->sdev)
+ return -EBUSY;
+
+ cam->sdev = s;
+
+ if (device_create_file(cam->dev, &dev_attr_streaming) != 0) {
+ dev_err(cam->dev, "could not register sysfs entry\n");
+ rval = -EBUSY;
+ goto err;
+ }
+
+ /* initialize the video_device struct */
+ vfd = cam->vfd = video_device_alloc();
+ if (!vfd) {
+ dev_err(cam->dev, "could not allocate video device struct\n");
+ rval = -ENOMEM;
+ goto err;
+ }
+ vfd->release = video_device_release;
+
+ vfd->dev = cam->dev;
+
+ strlcpy(vfd->name, CAM_NAME, sizeof(vfd->name));
+ vfd->type = VID_TYPE_CAPTURE | VID_TYPE_CHROMAKEY;
+ vfd->fops = &omap24xxcam_fops;
+ vfd->priv = cam;
+ vfd->minor = -1;
+
+ vfd->vidioc_querycap = vidioc_querycap;
+ vfd->vidioc_enum_fmt_cap = vidioc_enum_fmt_cap;
+ vfd->vidioc_g_fmt_cap = vidioc_g_fmt_cap;
+ vfd->vidioc_s_fmt_cap = vidioc_s_fmt_cap;
+ vfd->vidioc_try_fmt_cap = vidioc_try_fmt_cap;
+ vfd->vidioc_reqbufs = vidioc_reqbufs;
+ vfd->vidioc_querybuf = vidioc_querybuf;
+ vfd->vidioc_qbuf = vidioc_qbuf;
+ vfd->vidioc_dqbuf = vidioc_dqbuf;
+ vfd->vidioc_streamon = vidioc_streamon;
+ vfd->vidioc_streamoff = vidioc_streamoff;
+ vfd->vidioc_enum_input = vidioc_enum_input;
+ vfd->vidioc_g_input = vidioc_g_input;
+ vfd->vidioc_s_input = vidioc_s_input;
+ vfd->vidioc_queryctrl = vidioc_queryctrl;
+ vfd->vidioc_g_ctrl = vidioc_g_ctrl;
+ vfd->vidioc_s_ctrl = vidioc_s_ctrl;
+ vfd->vidioc_g_parm = vidioc_g_parm;
+ vfd->vidioc_s_parm = vidioc_s_parm;
+
+ omap24xxcam_hwinit(cam);
+
+ rval = omap24xxcam_sensor_init(cam);
+ if (rval)
+ goto err;
+
+ if (video_register_device(vfd, VFL_TYPE_GRABBER, video_nr) < 0) {
+ dev_err(cam->dev, "could not register V4L device\n");
+ vfd->minor = -1;
+ rval = -EBUSY;
+ goto err;
+ }
+
+ omap24xxcam_poweron_reset(cam);
+
+ dev_info(cam->dev, "registered device video%d\n", vfd->minor);
+
+ return 0;
+
+err:
+ omap24xxcam_device_unregister(s);
+
+ return rval;
+}
+
+static void omap24xxcam_device_unregister(struct v4l2_int_device *s)
+{
+ struct omap24xxcam_device *cam = s->u.slave->master->priv;
+
+ omap24xxcam_sensor_exit(cam);
+
+ if (cam->vfd) {
+ if (cam->vfd->minor == -1) {
+ /*
+ * The device was never registered, so release the
+ * video_device struct directly.
+ */
+ video_device_release(cam->vfd);
+ } else {
+ /*
+ * The unregister function will release the
+ * video_device struct as well as
+ * unregistering it.
+ */
+ video_unregister_device(cam->vfd);
+ }
+ cam->vfd = NULL;
+ }
+
+ device_remove_file(cam->dev, &dev_attr_streaming);
+
+ cam->sdev = NULL;
+}
+
+static struct v4l2_int_master omap24xxcam_master = {
+ .attach = omap24xxcam_device_register,
+ .detach = omap24xxcam_device_unregister,
+};
+
+static struct v4l2_int_device omap24xxcam = {
+ .module = THIS_MODULE,
+ .name = CAM_NAME,
+ .type = v4l2_int_type_master,
+ .u = {
+ .master = &omap24xxcam_master
+ },
+};
+
+/*
+ *
+ * Driver initialisation and deinitialisation.
+ *
+ */
+
+static int __init omap24xxcam_probe(struct platform_device *pdev)
+{
+ struct omap24xxcam_device *cam;
+ struct resource *mem;
+ int irq;
+
+ cam = kzalloc(sizeof(*cam), GFP_KERNEL);
+ if (!cam) {
+ dev_err(&pdev->dev, "could not allocate memory\n");
+ goto err;
+ }
+
+ platform_set_drvdata(pdev, cam);
+
+ cam->dev = &pdev->dev;
+
+ /*
+ * Impose a lower limit on the amount of memory allocated for
+ * capture. We require at least enough memory to double-buffer
+ * QVGA (300KB).
+ */
+ if (capture_mem < 320 * 240 * 2 * 2)
+ capture_mem = 320 * 240 * 2 * 2;
+ cam->capture_mem = capture_mem;
+
+ /* request the mem region for the camera registers */
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ dev_err(cam->dev, "no mem resource?\n");
+ goto err;
+ }
+ if (!request_mem_region(mem->start, (mem->end - mem->start) + 1,
+ pdev->name)) {
+ dev_err(cam->dev,
+ "cannot reserve camera register I/O region\n");
+ goto err;
+ }
+ cam->mmio_base_phys = mem->start;
+ cam->mmio_size = (mem->end - mem->start) + 1;
+
+ /* map the region */
+ cam->mmio_base = (unsigned long)
+ ioremap_nocache(cam->mmio_base_phys, cam->mmio_size);
+ if (!cam->mmio_base) {
+ dev_err(cam->dev, "cannot map camera register I/O region\n");
+ goto err;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq <= 0) {
+ dev_err(cam->dev, "no irq for camera?\n");
+ goto err;
+ }
+
+ /* install the interrupt service routine */
+ if (request_irq(irq, omap24xxcam_isr, 0, CAM_NAME, cam)) {
+ dev_err(cam->dev,
+ "could not install interrupt service routine\n");
+ goto err;
+ }
+ cam->irq = irq;
+
+ if (omap24xxcam_clock_get(cam))
+ goto err;
+
+ INIT_WORK(&cam->sensor_reset_work, omap24xxcam_sensor_reset_work);
+
+ mutex_init(&cam->mutex);
+ spin_lock_init(&cam->core_enable_disable_lock);
+
+ omap24xxcam_sgdma_init(&cam->sgdma,
+ cam->mmio_base + CAMDMA_REG_OFFSET,
+ omap24xxcam_stalled_dma_reset,
+ (unsigned long)cam);
+
+ omap24xxcam.priv = cam;
+
+ if (v4l2_int_device_register(&omap24xxcam))
+ goto err;
+
+ return 0;
+
+err:
+ omap24xxcam_remove(pdev);
+ return -ENODEV;
+}
+
+static int omap24xxcam_remove(struct platform_device *pdev)
+{
+ struct omap24xxcam_device *cam = platform_get_drvdata(pdev);
+
+ if (!cam)
+ return 0;
+
+ if (omap24xxcam.priv != NULL)
+ v4l2_int_device_unregister(&omap24xxcam);
+ omap24xxcam.priv = NULL;
+
+ omap24xxcam_clock_put(cam);
+
+ if (cam->irq) {
+ free_irq(cam->irq, cam);
+ cam->irq = 0;
+ }
+
+ if (cam->mmio_base) {
+ iounmap((void *)cam->mmio_base);
+ cam->mmio_base = 0;
+ }
+
+ if (cam->mmio_base_phys) {
+ release_mem_region(cam->mmio_base_phys, cam->mmio_size);
+ cam->mmio_base_phys = 0;
+ }
+
+ kfree(cam);
+
+ return 0;
+}
+
+static struct platform_driver omap24xxcam_driver = {
+ .probe = omap24xxcam_probe,
+ .remove = omap24xxcam_remove,
+#ifdef CONFIG_PM
+ .suspend = omap24xxcam_suspend,
+ .resume = omap24xxcam_resume,
+#endif
+ .driver = {
+ .name = CAM_NAME,
+ },
+};
+
+/*
+ *
+ * Module initialisation and deinitialisation
+ *
+ */
+
+static int __init omap24xxcam_init(void)
+{
+ return platform_driver_register(&omap24xxcam_driver);
+}
+
+static void __exit omap24xxcam_cleanup(void)
+{
+ platform_driver_unregister(&omap24xxcam_driver);
+}
+
+MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com>");
+MODULE_DESCRIPTION("OMAP24xx 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 4800kiB)");
+
+module_init(omap24xxcam_init);
+module_exit(omap24xxcam_cleanup);
--- /dev/null
+/*
+ * drivers/media/video/omap24xxcam.h
+ *
+ * Copyright (C) 2004 MontaVista Software, Inc.
+ * Copyright (C) 2004 Texas Instruments.
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Sakari Ailus <sakari.ailus@nokia.com>
+ *
+ * Based on code from Andy Lowe <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
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef OMAP24XXCAM_H
+#define OMAP24XXCAM_H
+
+#include <media/videobuf-dma-sg.h>
+#include <media/v4l2-int-device.h>
+
+/*
+ *
+ * General driver related definitions.
+ *
+ */
+
+#define CAM_NAME "omap24xxcam"
+
+#define CAM_MCLK 96000000
+
+/* number of bytes transferred per DMA request */
+#define DMA_THRESHOLD 32
+
+/*
+ * NUM_CAMDMA_CHANNELS is the number of logical channels provided by
+ * the camera DMA controller.
+ */
+#define NUM_CAMDMA_CHANNELS 4
+
+/*
+ * NUM_SG_DMA is the number of scatter-gather DMA transfers that can
+ * be queued. (We don't have any overlay sglists now.)
+ */
+#define NUM_SG_DMA (VIDEO_MAX_FRAME)
+
+/*
+ *
+ * Register definitions.
+ *
+ */
+
+/* subsystem register block offsets */
+#define CC_REG_OFFSET 0x00000400
+#define CAMDMA_REG_OFFSET 0x00000800
+#define CAMMMU_REG_OFFSET 0x00000C00
+
+/* define camera subsystem register offsets */
+#define CAM_REVISION 0x000
+#define CAM_SYSCONFIG 0x010
+#define CAM_SYSSTATUS 0x014
+#define CAM_IRQSTATUS 0x018
+#define CAM_GPO 0x040
+#define CAM_GPI 0x050
+
+/* define camera core register offsets */
+#define CC_REVISION 0x000
+#define CC_SYSCONFIG 0x010
+#define CC_SYSSTATUS 0x014
+#define CC_IRQSTATUS 0x018
+#define CC_IRQENABLE 0x01C
+#define CC_CTRL 0x040
+#define CC_CTRL_DMA 0x044
+#define CC_CTRL_XCLK 0x048
+#define CC_FIFODATA 0x04C
+#define CC_TEST 0x050
+#define CC_GENPAR 0x054
+#define CC_CCPFSCR 0x058
+#define CC_CCPFECR 0x05C
+#define CC_CCPLSCR 0x060
+#define CC_CCPLECR 0x064
+#define CC_CCPDFR 0x068
+
+/* define camera dma register offsets */
+#define CAMDMA_REVISION 0x000
+#define CAMDMA_IRQSTATUS_L0 0x008
+#define CAMDMA_IRQSTATUS_L1 0x00C
+#define CAMDMA_IRQSTATUS_L2 0x010
+#define CAMDMA_IRQSTATUS_L3 0x014
+#define CAMDMA_IRQENABLE_L0 0x018
+#define CAMDMA_IRQENABLE_L1 0x01C
+#define CAMDMA_IRQENABLE_L2 0x020
+#define CAMDMA_IRQENABLE_L3 0x024
+#define CAMDMA_SYSSTATUS 0x028
+#define CAMDMA_OCP_SYSCONFIG 0x02C
+#define CAMDMA_CAPS_0 0x064
+#define CAMDMA_CAPS_2 0x06C
+#define CAMDMA_CAPS_3 0x070
+#define CAMDMA_CAPS_4 0x074
+#define CAMDMA_GCR 0x078
+#define CAMDMA_CCR(n) (0x080 + (n)*0x60)
+#define CAMDMA_CLNK_CTRL(n) (0x084 + (n)*0x60)
+#define CAMDMA_CICR(n) (0x088 + (n)*0x60)
+#define CAMDMA_CSR(n) (0x08C + (n)*0x60)
+#define CAMDMA_CSDP(n) (0x090 + (n)*0x60)
+#define CAMDMA_CEN(n) (0x094 + (n)*0x60)
+#define CAMDMA_CFN(n) (0x098 + (n)*0x60)
+#define CAMDMA_CSSA(n) (0x09C + (n)*0x60)
+#define CAMDMA_CDSA(n) (0x0A0 + (n)*0x60)
+#define CAMDMA_CSEI(n) (0x0A4 + (n)*0x60)
+#define CAMDMA_CSFI(n) (0x0A8 + (n)*0x60)
+#define CAMDMA_CDEI(n) (0x0AC + (n)*0x60)
+#define CAMDMA_CDFI(n) (0x0B0 + (n)*0x60)
+#define CAMDMA_CSAC(n) (0x0B4 + (n)*0x60)
+#define CAMDMA_CDAC(n) (0x0B8 + (n)*0x60)
+#define CAMDMA_CCEN(n) (0x0BC + (n)*0x60)
+#define CAMDMA_CCFN(n) (0x0C0 + (n)*0x60)
+#define CAMDMA_COLOR(n) (0x0C4 + (n)*0x60)
+
+/* define camera mmu register offsets */
+#define CAMMMU_REVISION 0x000
+#define CAMMMU_SYSCONFIG 0x010
+#define CAMMMU_SYSSTATUS 0x014
+#define CAMMMU_IRQSTATUS 0x018
+#define CAMMMU_IRQENABLE 0x01C
+#define CAMMMU_WALKING_ST 0x040
+#define CAMMMU_CNTL 0x044
+#define CAMMMU_FAULT_AD 0x048
+#define CAMMMU_TTB 0x04C
+#define CAMMMU_LOCK 0x050
+#define CAMMMU_LD_TLB 0x054
+#define CAMMMU_CAM 0x058
+#define CAMMMU_RAM 0x05C
+#define CAMMMU_GFLUSH 0x060
+#define CAMMMU_FLUSH_ENTRY 0x064
+#define CAMMMU_READ_CAM 0x068
+#define CAMMMU_READ_RAM 0x06C
+#define CAMMMU_EMU_FAULT_AD 0x070
+
+/* Define bit fields within selected registers */
+#define CAM_REVISION_MAJOR (15 << 4)
+#define CAM_REVISION_MAJOR_SHIFT 4
+#define CAM_REVISION_MINOR (15 << 0)
+#define CAM_REVISION_MINOR_SHIFT 0
+
+#define CAM_SYSCONFIG_SOFTRESET (1 << 1)
+#define CAM_SYSCONFIG_AUTOIDLE (1 << 0)
+
+#define CAM_SYSSTATUS_RESETDONE (1 << 0)
+
+#define CAM_IRQSTATUS_CC_IRQ (1 << 4)
+#define CAM_IRQSTATUS_MMU_IRQ (1 << 3)
+#define CAM_IRQSTATUS_DMA_IRQ2 (1 << 2)
+#define CAM_IRQSTATUS_DMA_IRQ1 (1 << 1)
+#define CAM_IRQSTATUS_DMA_IRQ0 (1 << 0)
+
+#define CAM_GPO_CAM_S_P_EN (1 << 1)
+#define CAM_GPO_CAM_CCP_MODE (1 << 0)
+
+#define CAM_GPI_CC_DMA_REQ1 (1 << 24)
+#define CAP_GPI_CC_DMA_REQ0 (1 << 23)
+#define CAP_GPI_CAM_MSTANDBY (1 << 21)
+#define CAP_GPI_CAM_WAIT (1 << 20)
+#define CAP_GPI_CAM_S_DATA (1 << 17)
+#define CAP_GPI_CAM_S_CLK (1 << 16)
+#define CAP_GPI_CAM_P_DATA (0xFFF << 3)
+#define CAP_GPI_CAM_P_DATA_SHIFT 3
+#define CAP_GPI_CAM_P_VS (1 << 2)
+#define CAP_GPI_CAM_P_HS (1 << 1)
+#define CAP_GPI_CAM_P_CLK (1 << 0)
+
+#define CC_REVISION_MAJOR (15 << 4)
+#define CC_REVISION_MAJOR_SHIFT 4
+#define CC_REVISION_MINOR (15 << 0)
+#define CC_REVISION_MINOR_SHIFT 0
+
+#define CC_SYSCONFIG_SIDLEMODE (3 << 3)
+#define CC_SYSCONFIG_SIDLEMODE_FIDLE (0 << 3)
+#define CC_SYSCONFIG_SIDLEMODE_NIDLE (1 << 3)
+#define CC_SYSCONFIG_SOFTRESET (1 << 1)
+#define CC_SYSCONFIG_AUTOIDLE (1 << 0)
+
+#define CC_SYSSTATUS_RESETDONE (1 << 0)
+
+#define CC_IRQSTATUS_FS_IRQ (1 << 19)
+#define CC_IRQSTATUS_LE_IRQ (1 << 18)
+#define CC_IRQSTATUS_LS_IRQ (1 << 17)
+#define CC_IRQSTATUS_FE_IRQ (1 << 16)
+#define CC_IRQSTATUS_FW_ERR_IRQ (1 << 10)
+#define CC_IRQSTATUS_FSC_ERR_IRQ (1 << 9)
+#define CC_IRQSTATUS_SSC_ERR_IRQ (1 << 8)
+#define CC_IRQSTATUS_FIFO_NOEMPTY_IRQ (1 << 4)
+#define CC_IRQSTATUS_FIFO_FULL_IRQ (1 << 3)
+#define CC_IRQSTATUS_FIFO_THR_IRQ (1 << 2)
+#define CC_IRQSTATUS_FIFO_OF_IRQ (1 << 1)
+#define CC_IRQSTATUS_FIFO_UF_IRQ (1 << 0)
+
+#define CC_IRQENABLE_FS_IRQ (1 << 19)
+#define CC_IRQENABLE_LE_IRQ (1 << 18)
+#define CC_IRQENABLE_LS_IRQ (1 << 17)
+#define CC_IRQENABLE_FE_IRQ (1 << 16)
+#define CC_IRQENABLE_FW_ERR_IRQ (1 << 10)
+#define CC_IRQENABLE_FSC_ERR_IRQ (1 << 9)
+#define CC_IRQENABLE_SSC_ERR_IRQ (1 << 8)
+#define CC_IRQENABLE_FIFO_NOEMPTY_IRQ (1 << 4)
+#define CC_IRQENABLE_FIFO_FULL_IRQ (1 << 3)
+#define CC_IRQENABLE_FIFO_THR_IRQ (1 << 2)
+#define CC_IRQENABLE_FIFO_OF_IRQ (1 << 1)
+#define CC_IRQENABLE_FIFO_UF_IRQ (1 << 0)
+
+#define CC_CTRL_CC_ONE_SHOT (1 << 20)
+#define CC_CTRL_CC_IF_SYNCHRO (1 << 19)
+#define CC_CTRL_CC_RST (1 << 18)
+#define CC_CTRL_CC_FRAME_TRIG (1 << 17)
+#define CC_CTRL_CC_EN (1 << 16)
+#define CC_CTRL_NOBT_SYNCHRO (1 << 13)
+#define CC_CTRL_BT_CORRECT (1 << 12)
+#define CC_CTRL_PAR_ORDERCAM (1 << 11)
+#define CC_CTRL_PAR_CLK_POL (1 << 10)
+#define CC_CTRL_NOBT_HS_POL (1 << 9)
+#define CC_CTRL_NOBT_VS_POL (1 << 8)
+#define CC_CTRL_PAR_MODE (7 << 1)
+#define CC_CTRL_PAR_MODE_SHIFT 1
+#define CC_CTRL_PAR_MODE_NOBT8 (0 << 1)
+#define CC_CTRL_PAR_MODE_NOBT10 (1 << 1)
+#define CC_CTRL_PAR_MODE_NOBT12 (2 << 1)
+#define CC_CTRL_PAR_MODE_BT8 (4 << 1)
+#define CC_CTRL_PAR_MODE_BT10 (5 << 1)
+#define CC_CTRL_PAR_MODE_FIFOTEST (7 << 1)
+#define CC_CTRL_CCP_MODE (1 << 0)
+
+#define CC_CTRL_DMA_EN (1 << 8)
+#define CC_CTRL_DMA_FIFO_THRESHOLD (0x7F << 0)
+#define CC_CTRL_DMA_FIFO_THRESHOLD_SHIFT 0
+
+#define CC_CTRL_XCLK_DIV (0x1F << 0)
+#define CC_CTRL_XCLK_DIV_SHIFT 0
+#define CC_CTRL_XCLK_DIV_STABLE_LOW (0 << 0)
+#define CC_CTRL_XCLK_DIV_STABLE_HIGH (1 << 0)
+#define CC_CTRL_XCLK_DIV_BYPASS (31 << 0)
+
+#define CC_TEST_FIFO_RD_POINTER (0xFF << 24)
+#define CC_TEST_FIFO_RD_POINTER_SHIFT 24
+#define CC_TEST_FIFO_WR_POINTER (0xFF << 16)
+#define CC_TEST_FIFO_WR_POINTER_SHIFT 16
+#define CC_TEST_FIFO_LEVEL (0xFF << 8)
+#define CC_TEST_FIFO_LEVEL_SHIFT 8
+#define CC_TEST_FIFO_LEVEL_PEAK (0xFF << 0)
+#define CC_TEST_FIFO_LEVEL_PEAK_SHIFT 0
+
+#define CC_GENPAR_FIFO_DEPTH (7 << 0)
+#define CC_GENPAR_FIFO_DEPTH_SHIFT 0
+
+#define CC_CCPDFR_ALPHA (0xFF << 8)
+#define CC_CCPDFR_ALPHA_SHIFT 8
+#define CC_CCPDFR_DATAFORMAT (15 << 0)
+#define CC_CCPDFR_DATAFORMAT_SHIFT 0
+#define CC_CCPDFR_DATAFORMAT_YUV422BE ( 0 << 0)
+#define CC_CCPDFR_DATAFORMAT_YUV422 ( 1 << 0)
+#define CC_CCPDFR_DATAFORMAT_YUV420 ( 2 << 0)
+#define CC_CCPDFR_DATAFORMAT_RGB444 ( 4 << 0)
+#define CC_CCPDFR_DATAFORMAT_RGB565 ( 5 << 0)
+#define CC_CCPDFR_DATAFORMAT_RGB888NDE ( 6 << 0)
+#define CC_CCPDFR_DATAFORMAT_RGB888 ( 7 << 0)
+#define CC_CCPDFR_DATAFORMAT_RAW8NDE ( 8 << 0)
+#define CC_CCPDFR_DATAFORMAT_RAW8 ( 9 << 0)
+#define CC_CCPDFR_DATAFORMAT_RAW10NDE (10 << 0)
+#define CC_CCPDFR_DATAFORMAT_RAW10 (11 << 0)
+#define CC_CCPDFR_DATAFORMAT_RAW12NDE (12 << 0)
+#define CC_CCPDFR_DATAFORMAT_RAW12 (13 << 0)
+#define CC_CCPDFR_DATAFORMAT_JPEG8 (15 << 0)
+
+#define CAMDMA_REVISION_MAJOR (15 << 4)
+#define CAMDMA_REVISION_MAJOR_SHIFT 4
+#define CAMDMA_REVISION_MINOR (15 << 0)
+#define CAMDMA_REVISION_MINOR_SHIFT 0
+
+#define CAMDMA_OCP_SYSCONFIG_MIDLEMODE (3 << 12)
+#define CAMDMA_OCP_SYSCONFIG_MIDLEMODE_FSTANDBY (0 << 12)
+#define CAMDMA_OCP_SYSCONFIG_MIDLEMODE_NSTANDBY (1 << 12)
+#define CAMDMA_OCP_SYSCONFIG_MIDLEMODE_SSTANDBY (2 << 12)
+#define CAMDMA_OCP_SYSCONFIG_FUNC_CLOCK (1 << 9)
+#define CAMDMA_OCP_SYSCONFIG_OCP_CLOCK (1 << 8)
+#define CAMDMA_OCP_SYSCONFIG_EMUFREE (1 << 5)
+#define CAMDMA_OCP_SYSCONFIG_SIDLEMODE (3 << 3)
+#define CAMDMA_OCP_SYSCONFIG_SIDLEMODE_FIDLE (0 << 3)
+#define CAMDMA_OCP_SYSCONFIG_SIDLEMODE_NIDLE (1 << 3)
+#define CAMDMA_OCP_SYSCONFIG_SIDLEMODE_SIDLE (2 << 3)
+#define CAMDMA_OCP_SYSCONFIG_SOFTRESET (1 << 1)
+#define CAMDMA_OCP_SYSCONFIG_AUTOIDLE (1 << 0)
+
+#define CAMDMA_SYSSTATUS_RESETDONE (1 << 0)
+
+#define CAMDMA_GCR_ARBITRATION_RATE (0xFF << 16)
+#define CAMDMA_GCR_ARBITRATION_RATE_SHIFT 16
+#define CAMDMA_GCR_MAX_CHANNEL_FIFO_DEPTH (0xFF << 0)
+#define CAMDMA_GCR_MAX_CHANNEL_FIFO_DEPTH_SHIFT 0
+
+#define CAMDMA_CCR_SEL_SRC_DST_SYNC (1 << 24)
+#define CAMDMA_CCR_PREFETCH (1 << 23)
+#define CAMDMA_CCR_SUPERVISOR (1 << 22)
+#define CAMDMA_CCR_SECURE (1 << 21)
+#define CAMDMA_CCR_BS (1 << 18)
+#define CAMDMA_CCR_TRANSPARENT_COPY_ENABLE (1 << 17)
+#define CAMDMA_CCR_CONSTANT_FILL_ENABLE (1 << 16)
+#define CAMDMA_CCR_DST_AMODE (3 << 14)
+#define CAMDMA_CCR_DST_AMODE_CONST_ADDR (0 << 14)
+#define CAMDMA_CCR_DST_AMODE_POST_INC (1 << 14)
+#define CAMDMA_CCR_DST_AMODE_SGL_IDX (2 << 14)
+#define CAMDMA_CCR_DST_AMODE_DBL_IDX (3 << 14)
+#define CAMDMA_CCR_SRC_AMODE (3 << 12)
+#define CAMDMA_CCR_SRC_AMODE_CONST_ADDR (0 << 12)
+#define CAMDMA_CCR_SRC_AMODE_POST_INC (1 << 12)
+#define CAMDMA_CCR_SRC_AMODE_SGL_IDX (2 << 12)
+#define CAMDMA_CCR_SRC_AMODE_DBL_IDX (3 << 12)
+#define CAMDMA_CCR_WR_ACTIVE (1 << 10)
+#define CAMDMA_CCR_RD_ACTIVE (1 << 9)
+#define CAMDMA_CCR_SUSPEND_SENSITIVE (1 << 8)
+#define CAMDMA_CCR_ENABLE (1 << 7)
+#define CAMDMA_CCR_PRIO (1 << 6)
+#define CAMDMA_CCR_FS (1 << 5)
+#define CAMDMA_CCR_SYNCHRO ((3 << 19) | (31 << 0))
+#define CAMDMA_CCR_SYNCHRO_CAMERA 0x01
+
+#define CAMDMA_CLNK_CTRL_ENABLE_LNK (1 << 15)
+#define CAMDMA_CLNK_CTRL_NEXTLCH_ID (0x1F << 0)
+#define CAMDMA_CLNK_CTRL_NEXTLCH_ID_SHIFT 0
+
+#define CAMDMA_CICR_MISALIGNED_ERR_IE (1 << 11)
+#define CAMDMA_CICR_SUPERVISOR_ERR_IE (1 << 10)
+#define CAMDMA_CICR_SECURE_ERR_IE (1 << 9)
+#define CAMDMA_CICR_TRANS_ERR_IE (1 << 8)
+#define CAMDMA_CICR_PACKET_IE (1 << 7)
+#define CAMDMA_CICR_BLOCK_IE (1 << 5)
+#define CAMDMA_CICR_LAST_IE (1 << 4)
+#define CAMDMA_CICR_FRAME_IE (1 << 3)
+#define CAMDMA_CICR_HALF_IE (1 << 2)
+#define CAMDMA_CICR_DROP_IE (1 << 1)
+
+#define CAMDMA_CSR_MISALIGNED_ERR (1 << 11)
+#define CAMDMA_CSR_SUPERVISOR_ERR (1 << 10)
+#define CAMDMA_CSR_SECURE_ERR (1 << 9)
+#define CAMDMA_CSR_TRANS_ERR (1 << 8)
+#define CAMDMA_CSR_PACKET (1 << 7)
+#define CAMDMA_CSR_SYNC (1 << 6)
+#define CAMDMA_CSR_BLOCK (1 << 5)
+#define CAMDMA_CSR_LAST (1 << 4)
+#define CAMDMA_CSR_FRAME (1 << 3)
+#define CAMDMA_CSR_HALF (1 << 2)
+#define CAMDMA_CSR_DROP (1 << 1)
+
+#define CAMDMA_CSDP_SRC_ENDIANNESS (1 << 21)
+#define CAMDMA_CSDP_SRC_ENDIANNESS_LOCK (1 << 20)
+#define CAMDMA_CSDP_DST_ENDIANNESS (1 << 19)
+#define CAMDMA_CSDP_DST_ENDIANNESS_LOCK (1 << 18)
+#define CAMDMA_CSDP_WRITE_MODE (3 << 16)
+#define CAMDMA_CSDP_WRITE_MODE_WRNP (0 << 16)
+#define CAMDMA_CSDP_WRITE_MODE_POSTED (1 << 16)
+#define CAMDMA_CSDP_WRITE_MODE_POSTED_LAST_WRNP (2 << 16)
+#define CAMDMA_CSDP_DST_BURST_EN (3 << 14)
+#define CAMDMA_CSDP_DST_BURST_EN_1 (0 << 14)
+#define CAMDMA_CSDP_DST_BURST_EN_16 (1 << 14)
+#define CAMDMA_CSDP_DST_BURST_EN_32 (2 << 14)
+#define CAMDMA_CSDP_DST_BURST_EN_64 (3 << 14)
+#define CAMDMA_CSDP_DST_PACKED (1 << 13)
+#define CAMDMA_CSDP_WR_ADD_TRSLT (15 << 9)
+#define CAMDMA_CSDP_WR_ADD_TRSLT_ENABLE_MREQADD (3 << 9)
+#define CAMDMA_CSDP_SRC_BURST_EN (3 << 7)
+#define CAMDMA_CSDP_SRC_BURST_EN_1 (0 << 7)
+#define CAMDMA_CSDP_SRC_BURST_EN_16 (1 << 7)
+#define CAMDMA_CSDP_SRC_BURST_EN_32 (2 << 7)
+#define CAMDMA_CSDP_SRC_BURST_EN_64 (3 << 7)
+#define CAMDMA_CSDP_SRC_PACKED (1 << 6)
+#define CAMDMA_CSDP_RD_ADD_TRSLT (15 << 2)
+#define CAMDMA_CSDP_RD_ADD_TRSLT_ENABLE_MREQADD (3 << 2)
+#define CAMDMA_CSDP_DATA_TYPE (3 << 0)
+#define CAMDMA_CSDP_DATA_TYPE_8BITS (0 << 0)
+#define CAMDMA_CSDP_DATA_TYPE_16BITS (1 << 0)
+#define CAMDMA_CSDP_DATA_TYPE_32BITS (2 << 0)
+
+#define CAMMMU_SYSCONFIG_AUTOIDLE (1 << 0)
+
+/*
+ *
+ * Declarations.
+ *
+ */
+
+/* forward declarations */
+struct omap24xxcam_sgdma;
+struct omap24xxcam_dma;
+
+typedef void (*sgdma_callback_t)(struct omap24xxcam_sgdma *cam,
+ u32 status, void *arg);
+typedef void (*dma_callback_t)(struct omap24xxcam_dma *cam,
+ u32 status, void *arg);
+
+struct channel_state {
+ dma_callback_t callback;
+ void *arg;
+};
+
+/* sgdma state for each of the possible videobuf_buffers + 2 overlays */
+struct sgdma_state {
+ const struct scatterlist *sglist;
+ int sglen; /* number of sglist entries */
+ int next_sglist; /* index of next sglist entry to process */
+ unsigned int bytes_read; /* number of bytes read */
+ unsigned int len; /* total length of sglist (excluding
+ * bytes due to page alignment) */
+ int queued_sglist; /* number of sglist entries queued for DMA */
+ u32 csr; /* DMA return code */
+ sgdma_callback_t callback;
+ void *arg;
+};
+
+/* physical DMA channel management */
+struct omap24xxcam_dma {
+ spinlock_t lock; /* Lock for the whole structure. */
+
+ unsigned long base; /* base address for dma controller */
+
+ /* While dma_stop!=0, an attempt to start a new DMA transfer will
+ * fail.
+ */
+ atomic_t dma_stop;
+ int free_dmach; /* number of dma channels free */
+ int next_dmach; /* index of next dma channel to use */
+ struct channel_state ch_state[NUM_CAMDMA_CHANNELS];
+};
+
+/* scatter-gather DMA (scatterlist stuff) management */
+struct omap24xxcam_sgdma {
+ struct omap24xxcam_dma dma;
+
+ spinlock_t lock; /* Lock for the fields below. */
+ int free_sgdma; /* number of free sg dma slots */
+ int next_sgdma; /* index of next sg dma slot to use */
+ struct sgdma_state sg_state[NUM_SG_DMA];
+
+ /* Reset timer data */
+ struct timer_list reset_timer;
+};
+
+/* per-device data structure */
+struct omap24xxcam_device {
+ /*** mutex ***/
+ /*
+ * mutex serialises access to this structure. Also camera
+ * opening and releasing is synchronised by this.
+ */
+ struct mutex mutex;
+
+ /*** general driver state information ***/
+ atomic_t users;
+ /*
+ * Lock to serialise core enabling and disabling and access to
+ * sgdma_in_queue.
+ */
+ spinlock_t core_enable_disable_lock;
+ /*
+ * Number or sgdma requests in scatter-gather queue, protected
+ * by the lock above.
+ */
+ int sgdma_in_queue;
+ /*
+ * Sensor interface parameters: interface type, CC_CTRL
+ * register value and interface specific data.
+ */
+ int if_type;
+ union {
+ struct parallel {
+ u32 xclk;
+ } bt656;
+ } if_u;
+ u32 cc_ctrl;
+
+ /*** subsystem structures ***/
+ struct omap24xxcam_sgdma sgdma;
+
+ /*** hardware resources ***/
+ unsigned int irq;
+ unsigned long mmio_base;
+ unsigned long mmio_base_phys;
+ unsigned long mmio_size;
+
+ /*** interfaces and device ***/
+ struct v4l2_int_device *sdev;
+ struct device *dev;
+ struct video_device *vfd;
+
+ /*** camera and sensor reset related stuff ***/
+ struct work_struct sensor_reset_work;
+ /*
+ * We're in the middle of a reset. Don't enable core if this
+ * is non-zero! This exists to help decisionmaking in a case
+ * where videobuf_qbuf is called while we are in the middle of
+ * a reset.
+ */
+ atomic_t in_reset;
+ /*
+ * Non-zero if we don't want any resets for now. Used to
+ * prevent reset work to run when we're about to stop
+ * streaming.
+ */
+ atomic_t reset_disable;
+
+ /*** video device parameters ***/
+ int capture_mem;
+
+ /*** camera module clocks ***/
+ struct clk *fck;
+ struct clk *ick;
+
+ /*** capture data ***/
+ /* file handle, if streaming is on */
+ struct file *streaming;
+};
+
+/* Per-file handle data. */
+struct omap24xxcam_fh {
+ spinlock_t vbq_lock; /* spinlock for the videobuf queue */
+ struct videobuf_queue vbq;
+ struct v4l2_pix_format pix; /* serialise pix by vbq->lock */
+ atomic_t field_count; /* field counter for videobuf_buffer */
+ /* accessing cam here doesn't need serialisation: it's constant */
+ struct omap24xxcam_device *cam;
+};
+
+/*
+ *
+ * Register I/O functions.
+ *
+ */
+
+static __inline__ u32 omap24xxcam_reg_in(unsigned long base, u32 offset)
+{
+ return readl(base + offset);
+}
+
+static __inline__ u32 omap24xxcam_reg_out(unsigned long base, u32 offset,
+ u32 val)
+{
+ writel(val, base + offset);
+ return val;
+}
+
+static __inline__ u32 omap24xxcam_reg_merge(unsigned long base, u32 offset,
+ u32 val, u32 mask)
+{
+ u32 addr = base + offset;
+ u32 new_val = (readl(addr) & ~mask) | (val & mask);
+
+ writel(new_val, addr);
+ return new_val;
+}
+
+/*
+ *
+ * Function prototypes.
+ *
+ */
+
+/* dma prototypes */
+
+void omap24xxcam_dma_hwinit(const struct omap24xxcam_dma *dma);
+void omap24xxcam_dma_isr(struct omap24xxcam_dma *dma);
+
+/* sgdma prototypes */
+
+void omap24xxcam_sgdma_process(struct omap24xxcam_sgdma *sgdma);
+int omap24xxcam_sgdma_queue(struct omap24xxcam_sgdma *sgdma,
+ const struct scatterlist *sglist, int sglen,
+ int len, sgdma_callback_t callback, void *arg);
+void omap24xxcam_sgdma_sync(struct omap24xxcam_sgdma *sgdma);
+void omap24xxcam_sgdma_init(struct omap24xxcam_sgdma *sgdma,
+ unsigned long base,
+ void (*reset_callback)(unsigned long data),
+ unsigned long reset_callback_data);
+void omap24xxcam_sgdma_exit(struct omap24xxcam_sgdma *sgdma);
+
+#endif
--- /dev/null
+/*
+ * drivers/media/video/ov9640.c
+ *
+ * OV9640 sensor driver
+ *
+ * Author: Andy Lowe (source@mvista.com)
+ * Contact: Trilok Soni <soni.trilok@gmail.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/i2c.h>
+#include <linux/delay.h>
+#include <media/v4l2-int-device.h>
+
+#include "ov9640.h"
+
+#define DRIVER_NAME "ov9640"
+
+struct ov9640_sensor {
+ const struct ov9640_platform_data *pdata;
+ struct v4l2_int_device *v4l2_int_device;
+ struct i2c_client *i2c_client;
+ struct v4l2_pix_format pix;
+ struct v4l2_fract timeperframe;
+ int ver; /*ov9640 chip version*/
+};
+
+static struct ov9640_sensor ov9640;
+static struct i2c_driver ov9640sensor_i2c_driver;
+
+/* list of image formats supported by OV9640 sensor */
+const static struct v4l2_fmtdesc ov9640_formats[] = {
+ {
+ /* Note: V4L2 defines RGB565 as:
+ *
+ * Byte 0 Byte 1
+ * g2 g1 g0 r4 r3 r2 r1 r0 b4 b3 b2 b1 b0 g5 g4 g3
+ *
+ * We interpret RGB565 as:
+ *
+ * Byte 0 Byte 1
+ * g2 g1 g0 b4 b3 b2 b1 b0 r4 r3 r2 r1 r0 g5 g4 g3
+ */
+ .description = "RGB565, le",
+ .pixelformat = V4L2_PIX_FMT_RGB565,
+ },
+ {
+ /* Note: V4L2 defines RGB565X as:
+ *
+ * Byte 0 Byte 1
+ * b4 b3 b2 b1 b0 g5 g4 g3 g2 g1 g0 r4 r3 r2 r1 r0
+ *
+ * We interpret RGB565X as:
+ *
+ * Byte 0 Byte 1
+ * r4 r3 r2 r1 r0 g5 g4 g3 g2 g1 g0 b4 b3 b2 b1 b0
+ */
+ .description = "RGB565, be",
+ .pixelformat = V4L2_PIX_FMT_RGB565X,
+ },
+ {
+ .description = "YUYV (YUV 4:2:2), packed",
+ .pixelformat = V4L2_PIX_FMT_YUYV,
+ },
+ {
+ .description = "UYVY, packed",
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ },
+ {
+ /* Note: V4L2 defines RGB555 as:
+ *
+ * Byte 0 Byte 1
+ * g2 g1 g0 r4 r3 r2 r1 r0 x b4 b3 b2 b1 b0 g4 g3
+ *
+ * We interpret RGB555 as:
+ *
+ * Byte 0 Byte 1
+ * g2 g1 g0 b4 b3 b2 b1 b0 x r4 r3 r2 r1 r0 g4 g3
+ */
+ .description = "RGB555, le",
+ .pixelformat = V4L2_PIX_FMT_RGB555,
+ },
+ {
+ /* Note: V4L2 defines RGB555X as:
+ *
+ * Byte 0 Byte 1
+ * x b4 b3 b2 b1 b0 g4 g3 g2 g1 g0 r4 r3 r2 r1 r0
+ *
+ * We interpret RGB555X as:
+ *
+ * Byte 0 Byte 1
+ * x r4 r3 r2 r1 r0 g4 g3 g2 g1 g0 b4 b3 b2 b1 b0
+ */
+ .description = "RGB555, be",
+ .pixelformat = V4L2_PIX_FMT_RGB555X,
+ },
+};
+
+#define NUM_CAPTURE_FORMATS ARRAY_SIZE(ov9640_formats)
+
+/*
+ * 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
+#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;
+} video_control[] = {
+ {
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gain",
+ .minimum = 0,
+ .maximum = 63,
+ .step = 1,
+ .default_value = DEF_GAIN,
+ },
+ .current_value = 0,
+ .reg = OV9640_GAIN,
+ .mask = 0x3f,
+ .start_bit = 0,
+ },
+ {
+ {
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto Gain",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 0,
+ .default_value = DEF_AUTOGAIN,
+ },
+ .current_value = 0,
+ .reg = OV9640_COM8,
+ .mask = 0x04,
+ .start_bit = 2,
+ },
+ {
+ {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Exposure",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = DEF_EXPOSURE,
+ },
+ .current_value = 0,
+ .reg = OV9640_AECH,
+ .mask = 0xff,
+ .start_bit = 0,
+ },
+ {
+ {
+ .id = V4L2_CID_AUTOEXPOSURE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto Exposure",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 0,
+ .default_value = DEF_AEC,
+ },
+ .current_value = 0,
+ .reg = OV9640_COM8,
+ .mask = 0x01,
+ .start_bit = 0,
+ },
+ {
+ {
+ .id = V4L2_CID_FREEZE_AGCAEC,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Freeze AGC/AEC",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 0,
+ .default_value = DEF_FREEZE_AGCAEC,
+ },
+ .current_value = 0,
+ .reg = OV9640_COM9,
+ .mask = 0x01,
+ .start_bit = 0,
+ },
+ {
+ {
+ .id = V4L2_CID_RED_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Red Balance",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = DEF_RED,
+ },
+ .current_value = 0,
+ .reg = OV9640_RED,
+ .mask = 0xff,
+ .start_bit = 0,
+ },
+ {
+ {
+ .id = V4L2_CID_BLUE_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Blue Balance",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = DEF_BLUE,
+ },
+ .current_value = 0,
+ .reg = OV9640_BLUE,
+ .mask = 0xff,
+ .start_bit = 0,
+ },
+ {
+ {
+ .id = V4L2_CID_AUTO_WHITE_BALANCE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto White Balance",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 0,
+ .default_value = DEF_AWB,
+ },
+ .current_value = 0,
+ .reg = OV9640_COM8,
+ .mask = 0x02,
+ .start_bit = 1,
+ },
+ {
+ {
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Mirror Image",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 0,
+ .default_value = DEF_HFLIP,
+ },
+ .current_value = 0,
+ .reg = OV9640_MVFP,
+ .mask = 0x20,
+ .start_bit = 5,
+ },
+ {
+ {
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Vertical Flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 0,
+ .default_value = DEF_VFLIP,
+ },
+ .current_value = 0,
+ .reg = OV9640_MVFP,
+ .mask = 0x10,
+ .start_bit = 4,
+ },
+};
+
+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 */
+ rc = ov9640_read_reg(client, reg, &oldval);
+ if (rc)
+ 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 */
+ rc = ov9640_write_reg(client, reg, newval);
+ if (rc)
+ return rc;
+
+ rc = ov9640_read_reg(client, reg, &newval);
+ if (rc)
+ 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;
+
+ rc = ov9640_read_reg(client, reg, val);
+ if (rc)
+ 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 = (ARRAY_SIZE(video_control) - 1); i >= 0; i--)
+ if (video_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;
+ /* FIXME
+ * clks_per_frame should come from platform data
+ */
+#ifdef CONFIG_ARCH_OMAP24XX
+ const static unsigned long clks_per_frame[] =
+ { 200000, 400000, 200000, 400000, 400000, 800000, 3200000 };
+ /* QQCIF QQVGA QCIF QVGA CIF VGA SXGA
+ * 199680,400000, 199680, 400000, 399360, 800000, 3200000
+ */
+#else
+ const static unsigned long clks_per_frame[] =
+ { 200000, 200000, 200000, 200000, 400000, 800000, 3200000 };
+#endif
+
+ if (fper->numerator > 0)
+ fpm = (fper->denominator*60)/fper->numerator;
+ else
+ fpm = 0xffffffff;
+ fpm_max = (xclk*60)/clks_per_frame[isize];
+ if (fpm_max == 0)
+ fpm_max = 1;
+ if (fpm > fpm_max)
+ fpm = fpm_max;
+ if (fpm == 0)
+ fpm = 1;
+ divisor = fpm_max/fpm;
+ if (divisor > divisor_max)
+ divisor = divisor_max;
+ fper->numerator = divisor*60;
+ fper->denominator = fpm_max;
+
+ /* try to reduce the fraction */
+ while (!(fper->denominator % 5) && !(fper->numerator % 5)) {
+ fper->numerator /= 5;
+ fper->denominator /= 5;
+ }
+ while (!(fper->denominator % 3) && !(fper->numerator % 3)) {
+ fper->numerator /= 3;
+ fper->denominator /= 3;
+ }
+ while (!(fper->denominator % 2) && !(fper->numerator % 2)) {
+ fper->numerator /= 2;
+ fper->denominator /= 2;
+ }
+ if (fper->numerator < fper->denominator) {
+ if (!(fper->denominator % fper->numerator)) {
+ fper->denominator /= fper->numerator;
+ fper->numerator = 1;
+ }
+ } else {
+ if (!(fper->numerator % fper->denominator)) {
+ fper->numerator /= fper->denominator;
+ fper->denominator = 1;
+ }
+ }
+
+ /* we set bit 7 in CLKRC to enable the digital PLL */
+ return (0x80 | (divisor - 1));
+}
+
+/*
+ * 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;
+}
+
+/*
+ * Given the image capture format in pix, the nominal frame period in
+ * timeperframe, calculate the required xclk frequency
+ */
+static unsigned long
+ov9640sensor_calc_xclk(struct i2c_client *c)
+{
+ struct ov9640_sensor *sensor = i2c_get_clientdata(c);
+ struct v4l2_fract *timeperframe = &sensor->timeperframe;
+ struct v4l2_pix_format *pix = &sensor->pix;
+
+ 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.
+ */
+ tgt_fpm = (timeperframe->denominator*60)
+ / timeperframe->numerator;
+ tgt_xclk = OV9640_XCLK_NOM;
+ isize = ov9640_find_size(pix->width, pix->height);
+ switch (isize) {
+ case SXGA:
+ if (tgt_fpm > 450)
+ tgt_xclk = OV9640_XCLK_MAX;
+ break;
+ case VGA:
+ if (tgt_fpm > 900)
+ tgt_xclk = OV9640_XCLK_MAX;
+ break;
+ default:
+ break;
+ }
+ return tgt_xclk;
+}
+
+/*
+ * 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 v4l2_int_device *s)
+{
+ struct ov9640_sensor *sensor = s->priv;
+ struct v4l2_pix_format *pix = &sensor->pix;
+ struct v4l2_fract *fper = &sensor->timeperframe;
+ struct i2c_client *client = sensor->i2c_client;
+ enum image_size isize;
+ unsigned long xclk;
+
+ int err;
+ unsigned char clkrc;
+ 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;
+ }
+
+ xclk = ov9640sensor_calc_xclk(client);
+
+ isize = ov9640_find_size(pix->width, pix->height);
+
+ /* common register initialization */
+ err = ov9640_write_regs(client, sensor->pdata->default_regs);
+ 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;
+}
+
+/*
+ * 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;
+}
+
+/*
+ * following are sensor interface functions implemented by
+ * OV9640 sensor driver.
+ */
+static int ioctl_queryctrl(struct v4l2_int_device *s,
+ struct v4l2_queryctrl *qc)
+{
+ int i;
+
+ i = find_vctrl(qc->id);
+ if (i == -EINVAL) {
+ qc->flags = V4L2_CTRL_FLAG_DISABLED;
+ return 0;
+ }
+ if (i < 0)
+ return -EINVAL;
+
+ *qc = video_control[i].qc;
+ return 0;
+}
+
+static int ioctl_g_ctrl(struct v4l2_int_device *s,
+ struct v4l2_control *vc)
+{
+ struct ov9640_sensor *sensor = s->priv;
+ struct i2c_client *client = sensor->i2c_client;
+ int i, val;
+ struct vcontrol *lvc;
+
+ i = find_vctrl(vc->id);
+ if (i < 0)
+ return -EINVAL;
+
+ lvc = &video_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 ioctl_s_ctrl(struct v4l2_int_device *s,
+ struct v4l2_control *vc)
+{
+ struct ov9640_sensor *sensor = s->priv;
+ struct i2c_client *client = sensor->i2c_client;
+ struct vcontrol *lvc;
+ int val = vc->value;
+ int i;
+
+ i = find_vctrl(vc->id);
+ if (i < 0)
+ return -EINVAL;
+
+ lvc = &video_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 ioctl_enum_fmt_cap(struct v4l2_int_device *s,
+ struct v4l2_fmtdesc *fmt)
+{
+ 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;
+ 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 ioctl_try_fmt_cap(struct v4l2_int_device *s,
+ struct v4l2_format *f)
+{
+ enum image_size isize;
+ int ifmt;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+
+ 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;
+}
+
+static int ioctl_s_fmt_cap(struct v4l2_int_device *s,
+ struct v4l2_format *f)
+{
+ struct ov9640_sensor *sensor = s->priv;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ int rval;
+
+ rval = ioctl_try_fmt_cap(s, f);
+ if (rval)
+ return rval;
+
+ rval = ov9640_configure(s);
+
+ if (!rval)
+ sensor->pix = *pix;
+
+ return rval;
+}
+
+static int ioctl_g_fmt_cap(struct v4l2_int_device *s,
+ struct v4l2_format *f)
+{
+ struct ov9640_sensor *sensor = s->priv;
+
+ f->fmt.pix = sensor->pix;
+
+ return 0;
+}
+
+static int ioctl_g_parm(struct v4l2_int_device *s,
+ struct v4l2_streamparm *a)
+{
+ struct ov9640_sensor *sensor = s->priv;
+ struct v4l2_captureparm *cparm = &a->parm.capture;
+
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ memset(a, 0, sizeof(*a));
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ cparm->capability = V4L2_CAP_TIMEPERFRAME;
+ cparm->timeperframe = sensor->timeperframe;
+
+ return 0;
+}
+
+static int ioctl_s_parm(struct v4l2_int_device *s,
+ struct v4l2_streamparm *a)
+{
+ struct ov9640_sensor *sensor = s->priv;
+ struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe;
+ struct v4l2_fract timeperframe_old;
+ int rval;
+
+ timeperframe_old = sensor->timeperframe;
+ sensor->timeperframe = *timeperframe;
+
+ rval = ov9640_configure(s);
+
+ if (rval)
+ sensor->timeperframe = timeperframe_old;
+ else
+ *timeperframe = sensor->timeperframe;
+
+ return rval;
+}
+
+static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p)
+{
+ struct ov9640_sensor *sensor = s->priv;
+ struct i2c_client *client = sensor->i2c_client;
+ u32 xclk; /* target xclk */
+ int rval;
+
+ rval = sensor->pdata->ifparm(p);
+ if (rval)
+ return rval;
+
+ xclk = ov9640sensor_calc_xclk(client);
+
+ p->u.bt656.clock_curr = xclk;
+
+ return 0;
+}
+
+static int ioctl_s_power(struct v4l2_int_device *s, int on)
+{
+ struct ov9640_sensor *sensor = s->priv;
+
+ return sensor->pdata->power_set(on);
+}
+
+static int ioctl_init(struct v4l2_int_device *s)
+{
+ return ov9640_configure(s);
+}
+
+static int ioctl_dev_exit(struct v4l2_int_device *s)
+{
+ return 0;
+}
+
+static int ioctl_dev_init(struct v4l2_int_device *s)
+{
+ struct ov9640_sensor *sensor = s->priv;
+ struct i2c_client *c = sensor->i2c_client;
+ int err;
+
+ err = ov9640_detect(c);
+ if (err < 0) {
+ dev_err(&c->dev, "Unable to detect " DRIVER_NAME " sensor\n");
+ return err;
+ }
+
+ sensor->ver = err;
+ pr_info(DRIVER_NAME " chip version 0x%02x detected\n", sensor->ver);
+
+ return 0;
+}
+
+static struct v4l2_int_ioctl_desc ov9640_ioctl_desc[] = {
+ { vidioc_int_dev_init_num,
+ (v4l2_int_ioctl_func *)ioctl_dev_init },
+ { vidioc_int_dev_exit_num,
+ (v4l2_int_ioctl_func *)ioctl_dev_exit },
+ { vidioc_int_s_power_num,
+ (v4l2_int_ioctl_func *)ioctl_s_power },
+ { vidioc_int_g_ifparm_num,
+ (v4l2_int_ioctl_func *)ioctl_g_ifparm },
+ { vidioc_int_init_num,
+ (v4l2_int_ioctl_func *)ioctl_init },
+ { vidioc_int_enum_fmt_cap_num,
+ (v4l2_int_ioctl_func *)ioctl_enum_fmt_cap },
+ { vidioc_int_try_fmt_cap_num,
+ (v4l2_int_ioctl_func *)ioctl_try_fmt_cap },
+ { vidioc_int_g_fmt_cap_num,
+ (v4l2_int_ioctl_func *)ioctl_g_fmt_cap },
+ { vidioc_int_s_fmt_cap_num,
+ (v4l2_int_ioctl_func *)ioctl_s_fmt_cap },
+ { vidioc_int_g_parm_num,
+ (v4l2_int_ioctl_func *)ioctl_g_parm },
+ { vidioc_int_s_parm_num,
+ (v4l2_int_ioctl_func *)ioctl_s_parm },
+ { vidioc_int_queryctrl_num,
+ (v4l2_int_ioctl_func *)ioctl_queryctrl },
+ { vidioc_int_g_ctrl_num,
+ (v4l2_int_ioctl_func *)ioctl_g_ctrl },
+ { vidioc_int_s_ctrl_num,
+ (v4l2_int_ioctl_func *)ioctl_s_ctrl },
+};
+
+static struct v4l2_int_slave ov9640_slave = {
+ .ioctls = ov9640_ioctl_desc,
+ .num_ioctls = ARRAY_SIZE(ov9640_ioctl_desc),
+};
+
+static struct v4l2_int_device ov9640_int_device = {
+ .module = THIS_MODULE,
+ .name = DRIVER_NAME,
+ .priv = &ov9640,
+ .type = v4l2_int_type_slave,
+ .u = {
+ .slave = &ov9640_slave,
+ },
+};
+
+static int __init
+ov9640_probe(struct i2c_client *client)
+{
+ struct ov9640_sensor *sensor = &ov9640;
+ int err;
+
+ if (i2c_get_clientdata(client))
+ return -EBUSY;
+
+ sensor->pdata = client->dev.platform_data;
+
+ if (!sensor->pdata || !sensor->pdata->default_regs) {
+ dev_err(&client->dev, "no platform data?\n");
+ return -ENODEV;
+ }
+
+ sensor->v4l2_int_device = &ov9640_int_device;
+ sensor->i2c_client = client;
+
+ i2c_set_clientdata(client, sensor);
+
+ /* Make the default capture format QCIF RGB565 */
+ sensor->pix.width = ov9640_sizes[QCIF].width;
+ sensor->pix.height = ov9640_sizes[QCIF].height;
+ sensor->pix.pixelformat = V4L2_PIX_FMT_RGB565;
+
+ err = v4l2_int_device_register(sensor->v4l2_int_device);
+ if (err)
+ i2c_set_clientdata(client, NULL);
+
+ return 0;
+}
+
+static int __exit
+ov9640_remove(struct i2c_client *client)
+{
+ struct ov9640_sensor *sensor = i2c_get_clientdata(client);
+
+ if (!client->adapter)
+ return -ENODEV; /* our client isn't attached */
+
+ v4l2_int_device_unregister(sensor->v4l2_int_device);
+ i2c_set_clientdata(client, NULL);
+
+ return 0;
+}
+
+static struct i2c_driver ov9640sensor_i2c_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ },
+ .probe = ov9640_probe,
+ .remove = __exit_p(ov9640_remove),
+};
+
+static struct ov9640_sensor ov9640 = {
+ .timeperframe = {
+ .numerator = 1,
+ .denominator = 15,
+ },
+};
+
+static int ov9640sensor_init(void)
+{
+ int err;
+
+ err = i2c_add_driver(&ov9640sensor_i2c_driver);
+ if (err) {
+ printk(KERN_ERR "Failed to register" DRIVER_NAME ".\n");
+ return err;
+ }
+ return 0;
+}
+module_init(ov9640sensor_init);
+
+static void __exit ov9640sensor_cleanup(void)
+{
+ i2c_del_driver(&ov9640sensor_i2c_driver);
+}
+module_exit(ov9640sensor_cleanup);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("OV9640 camera sensor driver");
--- /dev/null
+/*
+ * drivers/media/video/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
+
+#define OV9640_I2C_ADDR 0x30
+
+/* 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 OV9640_REG_TERM 0xFF /* terminating list entry for reg */
+#define OV9640_VAL_TERM 0xFF /* terminating list entry for val */
+
+/*
+ * The nominal xclk input frequency of the OV9640 is 24MHz, maximum
+ * frequency is 48MHz, and minimum frequency is 10MHz.
+ */
+#define OV9640_XCLK_MIN 10000000
+#define OV9640_XCLK_MAX 48000000
+#define OV9640_XCLK_NOM 24000000
+
+/* 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;
+};
+
+struct ov9640_platform_data {
+ /* Set power state, zero is off, non-zero is on. */
+ int (*power_set)(int power);
+ /* Default registers written after power-on or reset. */
+ const struct ov9640_reg *default_regs;
+ int (*ifparm)(struct v4l2_ifparm *p);
+};
+
+/*
+ * 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 */
depends on BACKLIGHT_CLASS_DEVICE
depends on HWMON
depends on EXPERIMENTAL
+
---help---
This driver supports the Fn-Fx keys on Eee PC laptops.
It also adds the ability to switch camera/wlan on/off.
- If you have an Eee PC laptop, say Y or M here.
+config OMAP_STI
+ bool "Serial Trace Interface support"
+ depends on ARCH_OMAP16XX || ARCH_OMAP24XX || ARCH_OMAP34XX
+ default n
+ help
+ Serial Trace Interface. The protocols suported for OMAP1/2/3 are
+ STI/CSTI/XTIv2 correspondingly.
+
+config OMAP_STI_CONSOLE
+ bool "STI console support"
+ depends on OMAP_STI
+ help
+ This enables a console driver by way of STI/XTI.
config ENCLOSURE_SERVICES
tristate "Enclosure Services"
obj-$(CONFIG_IBM_ASM) += ibmasm/
obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/
+obj-$(CONFIG_OMAP_STI) += sti/
obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o
obj-$(CONFIG_ACER_WMI) += acer-wmi.o
obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o
--- /dev/null
+ifeq ($(CONFIG_ARCH_OMAP3),y)
+obj-$(CONFIG_OMAP_STI) += sdti.o
+else
+obj-$(CONFIG_OMAP_STI) += sti.o sti-fifo.o
+obj-$(CONFIG_NET) += sti-netlink.o
+endif
+
+obj-$(CONFIG_OMAP_STI_CONSOLE) += sti-console.o
--- /dev/null
+/*
+ * Support functions for OMAP3 SDTI (Serial Debug Tracing Interface)
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Written by: Roman Tereshonkov <roman.tereshonkov@nokia.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <asm/arch/sti.h>
+#include <asm/byteorder.h>
+#include <asm/io.h>
+
+#define SDTI_REVISION 0x000
+#define SDTI_SYSCONFIG 0x010
+#define SDTI_SYSSTATUS 0x014
+#define SDTI_WINCTRL 0x024
+#define SDTI_SCONFIG 0x028
+#define SDTI_TESTCTRL 0x02C
+#define SDTI_LOCK_ACCESS 0xFB0
+
+#define CPU1_TRACE_EN 0x01
+#define CPU2_TRACE_EN 0x02
+
+#define EPM_BASE 0x5401D000
+#define EPM_CONTROL_0 0x50
+#define EPM_CONTROL_1 0x54
+#define EPM_CONTROL_2 0x58
+
+static struct clk *sdti_ck;
+unsigned long sti_base, sti_channel_base, epm_base;
+static DEFINE_SPINLOCK(sdti_lock);
+
+void omap_sti_channel_write_trace(int len, int id, void *data,
+ unsigned int channel)
+{
+ const u8 *tpntr = data;
+
+ spin_lock_irq(&sdti_lock);
+
+ sti_channel_writeb(id, channel);
+ while (len--)
+ sti_channel_writeb(*tpntr++, channel);
+ sti_channel_flush(channel);
+
+ spin_unlock_irq(&sdti_lock);
+}
+EXPORT_SYMBOL(omap_sti_channel_write_trace);
+
+static void omap_sdti_reset(void)
+{
+ int i;
+
+ sti_writel(0x02, SDTI_SYSCONFIG);
+
+ for (i = 0; i < 10000; i++)
+ if (sti_readl(SDTI_SYSSTATUS) & 1)
+ break;
+ if (i == 10000)
+ printk(KERN_WARNING "XTI: no real reset\n");
+}
+
+void init_epm(void)
+{
+ epm_base = (unsigned long)ioremap(EPM_BASE, 256);
+ if (unlikely(!epm_base)) {
+ printk(KERN_ERR "EPM cannot be ioremapped\n");
+ return;
+ }
+
+ __raw_writel(1<<30, epm_base + EPM_CONTROL_2);
+ __raw_writel(0x78, epm_base + EPM_CONTROL_0);
+ __raw_writel(0x80000000, epm_base + EPM_CONTROL_1);
+ __raw_writel(1<<31 | 0x00007770, epm_base + EPM_CONTROL_2);
+}
+
+static int __init omap_sdti_init(void)
+{
+ char buf[64];
+ int i;
+
+ sdti_ck = clk_get(NULL, "emu_per_alwon_ck");
+ if (IS_ERR(sdti_ck)) {
+ printk(KERN_ERR "Cannot get clk emu_per_alwon_ck\n");
+ return PTR_ERR(sdti_ck);
+ }
+ clk_enable(sdti_ck);
+
+ /* Init emulation pin manager */
+ init_epm();
+
+ omap_sdti_reset();
+ sti_writel(0xC5ACCE55, SDTI_LOCK_ACCESS);
+
+ /* Claim SDTI */
+ sti_writel(1 << 30, SDTI_WINCTRL);
+ i = sti_readl(SDTI_WINCTRL);
+ if (!(i & (1 << 30)))
+ printk(KERN_WARNING "SDTI: cannot claim SDTI\n");
+
+ /* 4 bits dual, fclk/3 */
+ sti_writel(0x43, SDTI_SCONFIG);
+
+ /* CPU1 trace enable */
+ sti_writel(i | CPU2_TRACE_EN, SDTI_WINCTRL);
+ i = sti_readl(SDTI_WINCTRL);
+
+ /* Enable SDTI */
+ sti_writel((1 << 31) | (i & 0x3FFFFFFF), SDTI_WINCTRL);
+
+ i = sti_readl(SDTI_REVISION);
+ snprintf(buf, sizeof(buf), "OMAP SDTI support loaded (HW v%u.%u)\n",
+ (i >> 4) & 0x0f, i & 0x0f);
+ printk(KERN_INFO "%s", buf);
+ omap_sti_channel_write_trace(strlen(buf), 0xc3, buf, 239);
+
+ return 0;
+}
+
+static void omap_sdti_exit(void)
+{
+ sti_writel(0, SDTI_WINCTRL);
+ clk_disable(sdti_ck);
+ clk_put(sdti_ck);
+}
+
+static int __devinit omap_sdti_probe(struct platform_device *pdev)
+{
+ struct resource *res, *cres;
+ unsigned int size;
+
+ if (pdev->num_resources != 2) {
+ dev_err(&pdev->dev, "invalid number of resources: %d\n",
+ pdev->num_resources);
+ return -ENODEV;
+ }
+
+ /* SDTI 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;
+ }
+
+ size = res->end - res->start;
+ sti_base = (unsigned long)ioremap(res->start, size);
+ if (unlikely(!sti_base))
+ return -ENODEV;
+
+ size = cres->end - cres->start;
+ sti_channel_base = (unsigned long)ioremap(cres->start, size);
+ if (unlikely(!sti_channel_base)) {
+ iounmap((void *)sti_base);
+ return -ENODEV;
+ }
+
+ return omap_sdti_init();
+}
+
+static int __devexit omap_sdti_remove(struct platform_device *pdev)
+{
+ iounmap((void *)sti_channel_base);
+ iounmap((void *)sti_base);
+ iounmap((void *)epm_base);
+ omap_sdti_exit();
+
+ return 0;
+}
+
+static struct platform_driver omap_sdti_driver = {
+ .probe = omap_sdti_probe,
+ .remove = __devexit_p(omap_sdti_remove),
+ .driver = {
+ .name = "sti",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init omap_sdti_module_init(void)
+{
+ return platform_driver_register(&omap_sdti_driver);
+}
+
+static void __exit omap_sdti_module_exit(void)
+{
+ platform_driver_unregister(&omap_sdti_driver);
+}
+subsys_initcall(omap_sdti_module_init);
+module_exit(omap_sdti_module_exit);
+
+MODULE_AUTHOR("Roman Tereshonkov");
+MODULE_LICENSE("GPL");
--- /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 = -1;
+static int sti_line_done = -1;
+
+/*
+ * Write a string to any channel (including terminating NULL)
+ * Returns number of characters written.
+ */
+static int sti_channel_puts(const char *string, unsigned int channel, int len)
+{
+ int count = 0;
+
+ /*
+ * sti_line_done is needed to determine when we have reached the
+ * end of the line. write() has a tendency to hand us small
+ * strings which otherwise end up creating newlines.. we need to
+ * keep the channel open and in append mode until the line has
+ * been terminated.
+ */
+ if (sti_line_done != 0) {
+#ifdef __LITTLE_ENDIAN
+ sti_channel_writeb(0xc3, channel);
+#else
+ sti_channel_writeb(0xc0, channel);
+#endif
+ xchg(&sti_line_done, 0);
+ }
+
+ while (*string && count != len) {
+ char c = *string++;
+
+ count++;
+
+ if (c == '\n') {
+ xchg(&sti_line_done, 1);
+ sti_channel_writeb(0, channel);
+ break;
+ } else
+ sti_channel_writeb(c, channel);
+ }
+
+ if (sti_line_done)
+ sti_channel_flush(channel);
+
+ return count;
+}
+
+static int sti_tty_open(struct tty_struct *tty, struct file *filp)
+{
+ return 0;
+}
+
+static int sti_tty_write(struct tty_struct *tty,
+ const unsigned char *buf, int len)
+{
+ unsigned long flags;
+ int bytes;
+
+ spin_lock_irqsave(&sti_console_lock, flags);
+ bytes = sti_channel_puts(buf, sti_console_channel, len);
+ spin_unlock_irqrestore(&sti_console_lock, flags);
+
+ return bytes;
+}
+
+static int sti_tty_write_room(struct tty_struct *tty)
+{
+ return 0x100000;
+}
+
+static int sti_tty_chars_in_buffer(struct tty_struct *tty)
+{
+ return 0;
+}
+
+static struct tty_operations sti_tty_ops = {
+ .open = sti_tty_open,
+ .write = sti_tty_write,
+ .write_room = sti_tty_write_room,
+ .chars_in_buffer = sti_tty_chars_in_buffer,
+};
+
+static void sti_console_write(struct console *c, const char *s, unsigned n)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&sti_console_lock, flags);
+ sti_channel_puts(s, sti_console_channel, n);
+ spin_unlock_irqrestore(&sti_console_lock, flags);
+}
+
+static struct tty_driver *sti_console_device(struct console *c, int *index)
+{
+ *index = c->index;
+ return tty_driver;
+}
+
+static int sti_console_setup(struct console *c, char *opts)
+{
+ return 0;
+}
+
+static struct console sti_console = {
+ .name = DRV_NAME,
+ .write = sti_console_write,
+ .device = sti_console_device,
+ .setup = sti_console_setup,
+ .flags = CON_PRINTBUFFER | CON_ENABLED,
+ .index = -1,
+};
+
+static int __init sti_console_init(void)
+{
+ const struct omap_sti_console_config *info;
+
+ info = omap_get_config(OMAP_TAG_STI_CONSOLE,
+ struct omap_sti_console_config);
+ if (info && info->enable) {
+ add_preferred_console(DRV_NAME, 0, NULL);
+
+ sti_console_channel = info->channel;
+ }
+
+ if (unlikely(sti_console_channel == -1))
+ return -EINVAL;
+
+ register_console(&sti_console);
+
+ return 0;
+}
+__initcall(sti_console_init);
+
+static int __init sti_tty_init(void)
+{
+ struct tty_driver *tty;
+ int ret;
+
+ tty = alloc_tty_driver(1);
+ if (!tty)
+ return -ENOMEM;
+
+ tty->name = DRV_NAME;
+ tty->driver_name = DRV_NAME;
+ tty->major = 0; /* dynamic major */
+ tty->minor_start = 0;
+ tty->type = TTY_DRIVER_TYPE_SYSTEM;
+ tty->subtype = SYSTEM_TYPE_SYSCONS;
+ tty->init_termios = tty_std_termios;
+
+ tty_set_operations(tty, &sti_tty_ops);
+
+ ret = tty_register_driver(tty);
+ if (ret) {
+ put_tty_driver(tty);
+ return ret;
+ }
+
+ tty_driver = tty;
+ return 0;
+}
+late_initcall(sti_tty_init);
+
+module_param(sti_console_channel, uint, 0);
+MODULE_PARM_DESC(sti_console_channel, "STI console channel");
+MODULE_AUTHOR("Paul Mundt");
+MODULE_DESCRIPTION("OMAP STI console support");
+MODULE_LICENSE("GPL");
--- /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, 2006 Nokia Corporation
+ * Written by: Paul Mundt <paul.mundt@nokia.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/netlink.h>
+#include <linux/socket.h>
+#include <linux/skbuff.h>
+#include <linux/mutex.h>
+#include <net/sock.h>
+#include <asm/arch/sti.h>
+
+static struct sock *sti_sock;
+static DEFINE_MUTEX(sti_netlink_mutex);
+
+enum {
+ STI_READ,
+ STI_WRITE,
+};
+
+static int sti_netlink_read(int pid, int seq, void *payload, int size)
+{
+ struct sk_buff *skb;
+ struct nlmsghdr *nlh;
+ int ret, len = NLMSG_SPACE(size);
+ unsigned char *tail;
+
+ skb = alloc_skb(len, GFP_KERNEL);
+ if (!skb)
+ return -ENOMEM;
+
+ tail = skb->tail;
+ nlh = NLMSG_PUT(skb, pid, seq, STI_READ,
+ len - (sizeof(struct nlmsghdr)));
+ nlh->nlmsg_flags = 0;
+ memcpy(NLMSG_DATA(nlh), payload, size);
+ nlh->nlmsg_len = skb->tail - tail;
+
+ ret = netlink_unicast(sti_sock, skb, pid, MSG_DONTWAIT);
+ if (ret > 0)
+ ret = 0;
+
+ return ret;
+
+nlmsg_failure:
+ if (skb)
+ kfree_skb(skb);
+
+ return -EINVAL;
+}
+
+/*
+ * We abuse nlmsg_type and nlmsg_flags for our purposes.
+ *
+ * The ID is encoded into the upper 8 bits of the nlmsg_type, while the
+ * channel number is encoded into the upper 8 bits of the nlmsg_flags.
+ */
+static int sti_netlink_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+{
+ void *data;
+ u8 chan, id;
+ int size, ret = 0, len = 0;
+
+ data = NLMSG_DATA(nlh);
+ chan = (nlh->nlmsg_flags >> 8) & 0xff;
+ id = (nlh->nlmsg_type >> 8) & 0xff;
+ size = (int)(nlh->nlmsg_len - ((char *)data - (char *)nlh));
+
+ switch (nlh->nlmsg_type & 0xff) {
+ case STI_WRITE:
+ sti_channel_write_trace(size, id, data, chan);
+ break;
+ case STI_READ:
+ data = kmalloc(size, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+ memset(data, 0, size);
+
+ len = sti_read_packet(data, size);
+ ret = sti_netlink_read(NETLINK_CB(skb).pid, nlh->nlmsg_seq,
+ data, len);
+ kfree(data);
+ break;
+ default:
+ return -ENOTTY;
+ }
+
+ return ret;
+}
+
+static int sti_netlink_receive_skb(struct sk_buff *skb)
+{
+ while (skb->len >= NLMSG_SPACE(0)) {
+ struct nlmsghdr *nlh;
+ u32 rlen;
+ int ret;
+
+ nlh = (struct nlmsghdr *)skb->data;
+ if (nlh->nlmsg_len < sizeof(struct nlmsghdr) ||
+ skb->len < nlh->nlmsg_len)
+ break;
+
+ rlen = NLMSG_ALIGN(nlh->nlmsg_len);
+ if (rlen > skb->len)
+ rlen = skb->len;
+
+ ret = sti_netlink_receive_msg(skb, nlh);
+ if (ret)
+ netlink_ack(skb, nlh, -ret);
+ else if (nlh->nlmsg_flags & NLM_F_ACK)
+ netlink_ack(skb, nlh, 0);
+
+ skb_pull(skb, rlen);
+ }
+
+ return 0;
+}
+
+static void sti_netlink_receive(struct sk_buff *skb)
+{
+ if (!mutex_trylock(&sti_netlink_mutex))
+ return;
+
+ sti_netlink_receive_skb(skb);
+ mutex_unlock(&sti_netlink_mutex);
+}
+
+static int __init sti_netlink_init(void)
+{
+ sti_sock = netlink_kernel_create(&init_net, NETLINK_USERSOCK, 0,
+ sti_netlink_receive, NULL,
+ THIS_MODULE);
+ if (!sti_sock) {
+ printk(KERN_ERR "STI: Failed to create netlink socket\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+module_init(sti_netlink_init);
+
+MODULE_AUTHOR("Paul Mundt");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("STI netlink-driven communications interface");
--- /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/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <asm/arch/sti.h>
+#include <asm/byteorder.h>
+
+static struct clk *sti_ck;
+unsigned long sti_base, sti_channel_base;
+static unsigned long sti_kern_mask = STIEn;
+static unsigned long sti_irq_mask = STI_IRQSTATUS_MASK;
+static DEFINE_SPINLOCK(sti_lock);
+
+static struct sti_irqdesc {
+ irqreturn_t (*func)(unsigned long);
+ unsigned long data;
+} ____cacheline_aligned sti_irq_desc[STI_NR_IRQS];
+
+void sti_channel_write_trace(int len, int id, void *data, unsigned int channel)
+{
+ const u8 *tpntr = data;
+
+ sti_channel_writeb(id, channel);
+
+ if (cpu_is_omap16xx())
+ /* Check u32 boundary */
+ if (!((u32)data & (STI_PERCHANNEL_SIZE - 1)) &&
+ (len >= STI_PERCHANNEL_SIZE)) {
+ const u32 *asrc = data;
+
+ do {
+ sti_channel_writel(cpu_to_be32(*asrc++),
+ channel);
+ len -= STI_PERCHANNEL_SIZE;
+ } while (len >= STI_PERCHANNEL_SIZE);
+
+ tpntr = (const u8 *)asrc;
+ }
+
+ while (len--)
+ sti_channel_writeb(*tpntr++, channel);
+
+ sti_channel_flush(channel);
+}
+EXPORT_SYMBOL(sti_channel_write_trace);
+
+void sti_enable_irq(unsigned int id)
+{
+ spin_lock_irq(&sti_lock);
+ sti_writel(1 << id, STI_IRQSETEN);
+ spin_unlock_irq(&sti_lock);
+}
+EXPORT_SYMBOL(sti_enable_irq);
+
+void sti_disable_irq(unsigned int id)
+{
+ spin_lock_irq(&sti_lock);
+
+ if (cpu_is_omap16xx())
+ sti_writel(1 << id, STI_IRQCLREN);
+ else if (cpu_is_omap24xx())
+ sti_writel(sti_readl(STI_IRQSETEN) & ~(1 << id), STI_IRQSETEN);
+ else
+ BUG();
+
+ spin_unlock_irq(&sti_lock);
+}
+EXPORT_SYMBOL(sti_disable_irq);
+
+void sti_ack_irq(unsigned int id)
+{
+ /* Even though the clear state is 0, we have to write 1 to clear */
+ sti_writel(1 << id, STI_IRQSTATUS);
+}
+EXPORT_SYMBOL(sti_ack_irq);
+
+int sti_request_irq(unsigned int irq, void *handler, unsigned long arg)
+{
+ struct sti_irqdesc *desc;
+
+ if (unlikely(!handler || irq > STI_NR_IRQS))
+ return -EINVAL;
+
+ desc = sti_irq_desc + irq;
+ if (unlikely(desc->func)) {
+ printk(KERN_WARNING "STI: Attempting to request in-use IRQ "
+ "%d, consider fixing your code..\n", irq);
+ return -EBUSY;
+ }
+
+ desc->func = handler;
+ desc->data = arg;
+
+ sti_enable_irq(irq);
+ return 0;
+}
+EXPORT_SYMBOL(sti_request_irq);
+
+void sti_free_irq(unsigned int irq)
+{
+ struct sti_irqdesc *desc = sti_irq_desc + irq;
+
+ if (unlikely(irq > STI_NR_IRQS))
+ return;
+
+ sti_disable_irq(irq);
+
+ desc->func = NULL;
+ desc->data = 0;
+}
+EXPORT_SYMBOL(sti_free_irq);
+
+/*
+ * This is a bit heavy, so normally we would defer this to a tasklet.
+ * Unfortunately tasklets are too slow for the RX FIFO interrupt (and
+ * possibly some others), so we just do the irqdesc walking here.
+ */
+static irqreturn_t sti_interrupt(int irq, void *dev_id)
+{
+ int ret = IRQ_NONE;
+ u16 status;
+ int i;
+
+ status = sti_readl(STI_IRQSTATUS) & sti_irq_mask;
+
+ for (i = 0; status; i++) {
+ struct sti_irqdesc *desc = sti_irq_desc + i;
+ u16 id = 1 << i;
+
+ if (!(status & id))
+ continue;
+
+ if (likely(desc && desc->func))
+ ret |= desc->func(desc->data);
+ if (unlikely(ret == IRQ_NONE)) {
+ printk("STI: spurious interrupt (id %d)\n", id);
+ sti_disable_irq(i);
+ sti_ack_irq(i);
+ ret = IRQ_HANDLED;
+ }
+
+ status &= ~id;
+ }
+
+ return IRQ_RETVAL(ret);
+}
+
+static void omap_sti_reset(void)
+{
+ int i;
+
+ /* Reset STI module */
+ sti_writel(0x02, STI_SYSCONFIG);
+
+ /* Wait a while for the STI module to complete its reset */
+ for (i = 0; i < 10000; i++)
+ if (sti_readl(STI_SYSSTATUS) & 1)
+ break;
+}
+
+static int __init sti_init(void)
+{
+ char buf[64];
+ int i;
+
+ if (cpu_is_omap16xx()) {
+ /* Release ARM Rhea buses peripherals enable */
+ sti_writel(sti_readl(ARM_RSTCT2) | 0x0001, ARM_RSTCT2);
+
+ /* Enable TC1_CK (functional clock) */
+ sti_ck = clk_get(NULL, "tc1_ck");
+ } else if (cpu_is_omap24xx())
+ /* Enable emulation tools clock */
+ sti_ck = clk_get(NULL, "emul_ck");
+
+ if (IS_ERR(sti_ck))
+ return PTR_ERR(sti_ck);
+
+ clk_enable(sti_ck);
+
+ /* Reset STI module */
+ omap_sti_reset();
+
+ /* Enable STI */
+ sti_trace_enable(MPUCmdEn);
+
+ /* Change to custom serial protocol */
+ sti_writel(0x01, STI_SERIAL_CFG);
+
+ /* Set STI clock control register to normal mode */
+ sti_writel(0x00, STI_CLK_CTRL);
+
+ i = sti_readl(STI_REVISION);
+ snprintf(buf, sizeof(buf), "OMAP STI support loaded (HW v%u.%u)\n",
+ (i >> 4) & 0x0f, i & 0x0f);
+ printk(KERN_INFO "%s", buf);
+
+ sti_channel_write_trace(strlen(buf), 0xc3, buf, 239);
+
+ return 0;
+}
+
+static void sti_exit(void)
+{
+ u32 tmp;
+
+ /*
+ * This should have already been done by reset, but we switch off
+ * STI entirely just for added sanity..
+ */
+ tmp = sti_readl(STI_ER);
+ tmp &= ~STIEn;
+ sti_writel(tmp, STI_ER);
+
+ clk_disable(sti_ck);
+ clk_put(sti_ck);
+}
+
+static void __sti_trace_enable(int event)
+{
+ u32 tmp;
+
+ tmp = sti_readl(STI_ER);
+ tmp |= sti_kern_mask | event;
+ sti_writel(tmp, STI_ER);
+}
+
+int sti_trace_enable(int event)
+{
+ spin_lock_irq(&sti_lock);
+ sti_kern_mask |= event;
+ __sti_trace_enable(event);
+ spin_unlock_irq(&sti_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(sti_trace_enable);
+
+static void __sti_trace_disable(int event)
+{
+ u32 tmp;
+
+ tmp = sti_readl(STI_DR);
+
+ if (cpu_is_omap16xx()) {
+ tmp |= event;
+ tmp &= ~sti_kern_mask;
+ } else if (cpu_is_omap24xx()) {
+ tmp &= ~event;
+ tmp |= sti_kern_mask;
+ } else
+ BUG();
+
+ sti_writel(tmp, STI_DR);
+}
+
+void sti_trace_disable(int event)
+{
+ spin_lock_irq(&sti_lock);
+ sti_kern_mask &= ~event;
+ __sti_trace_disable(event);
+ spin_unlock_irq(&sti_lock);
+}
+EXPORT_SYMBOL(sti_trace_disable);
+
+static ssize_t
+sti_trace_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "0x%08lx\n", sti_readl(STI_ER));
+}
+
+static ssize_t
+sti_trace_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int evt = simple_strtoul(buf, NULL, 0);
+ int mask = ~evt;
+
+ spin_lock_irq(&sti_lock);
+ __sti_trace_disable(mask);
+ __sti_trace_enable(evt);
+ spin_unlock_irq(&sti_lock);
+
+ return count;
+}
+static DEVICE_ATTR(trace, S_IRUGO | S_IWUSR, sti_trace_show, sti_trace_store);
+
+static ssize_t
+sti_imask_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "0x%04lx\n", sti_irq_mask);
+}
+
+static ssize_t
+sti_imask_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ spin_lock_irq(&sti_lock);
+ sti_irq_mask = simple_strtoul(buf, NULL, 0);
+ spin_unlock_irq(&sti_lock);
+
+ return count;
+}
+static DEVICE_ATTR(imask, S_IRUGO | S_IWUSR, sti_imask_show, sti_imask_store);
+
+static int __devinit sti_probe(struct platform_device *pdev)
+{
+ struct resource *res, *cres;
+ int ret;
+
+ if (pdev->num_resources != 3) {
+ dev_err(&pdev->dev, "invalid number of resources: %d\n",
+ pdev->num_resources);
+ return -ENODEV;
+ }
+
+ /* STI base */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (unlikely(!res)) {
+ dev_err(&pdev->dev, "invalid mem resource\n");
+ return -ENODEV;
+ }
+
+ /* Channel base */
+ cres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (unlikely(!cres)) {
+ dev_err(&pdev->dev, "invalid channel mem resource\n");
+ return -ENODEV;
+ }
+
+ ret = device_create_file(&pdev->dev, &dev_attr_trace);
+ if (unlikely(ret != 0))
+ return ret;
+
+ ret = device_create_file(&pdev->dev, &dev_attr_imask);
+ if (unlikely(ret != 0))
+ goto err;
+
+ sti_base = res->start;
+
+ /*
+ * OMAP 16xx keeps channels in a relatively sane location,
+ * whereas 24xx maps them much further out, and so they must be
+ * remapped.
+ */
+ if (cpu_is_omap16xx())
+ sti_channel_base = cres->start;
+ else if (cpu_is_omap24xx()) {
+ unsigned int size = cres->end - cres->start;
+
+ sti_channel_base = (unsigned long)ioremap(cres->start, size);
+ if (unlikely(!sti_channel_base)) {
+ ret = -ENODEV;
+ goto err_badremap;
+ }
+ }
+
+ ret = request_irq(platform_get_irq(pdev, 0), sti_interrupt,
+ IRQF_DISABLED, "sti", NULL);
+ if (unlikely(ret != 0))
+ goto err_badirq;
+
+ return sti_init();
+
+err_badirq:
+ iounmap((void *)sti_channel_base);
+err_badremap:
+ device_remove_file(&pdev->dev, &dev_attr_imask);
+err:
+ device_remove_file(&pdev->dev, &dev_attr_trace);
+
+ return ret;
+}
+
+static int __devexit sti_remove(struct platform_device *pdev)
+{
+ unsigned int irq = platform_get_irq(pdev, 0);
+
+ if (cpu_is_omap24xx())
+ iounmap((void *)sti_channel_base);
+
+ device_remove_file(&pdev->dev, &dev_attr_trace);
+ device_remove_file(&pdev->dev, &dev_attr_imask);
+ free_irq(irq, NULL);
+ sti_exit();
+
+ return 0;
+}
+
+static struct platform_driver sti_driver = {
+ .probe = sti_probe,
+ .remove = __devexit_p(sti_remove),
+ .driver = {
+ .name = "sti",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init sti_module_init(void)
+{
+ return platform_driver_register(&sti_driver);
+}
+
+static void __exit sti_module_exit(void)
+{
+ platform_driver_unregister(&sti_driver);
+}
+subsys_initcall(sti_module_init);
+module_exit(sti_module_exit);
+
+MODULE_AUTHOR("Paul Mundt, Juha Yrjölä, Roman Tereshonkov");
+MODULE_LICENSE("GPL");
config MMC_OMAP
tristate "TI OMAP Multimedia Card Interface support"
- depends on ARCH_OMAP
+ depends on ARCH_OMAP1 || (ARCH_OMAP2 && ARCH_OMAP2420)
select TPS65010 if MACH_OMAP_H2
+ select OMAP_GPIO_SWITCH if MACH_NOKIA_N800
help
This selects the TI OMAP Multimedia card Interface.
If you have an OMAP board with a Multimedia Card slot,
If unsure, say N.
+config MMC_OMAP_HS
+ tristate "TI OMAP High Speed Multimedia Card Interface support"
+ depends on (ARCH_OMAP2 && ARCH_OMAP2430) || ARCH_OMAP3
+ select TWL4030_CORE if MACH_OMAP_2430SDP || MACH_OMAP_3430SDP
+ help
+ This selects the TI OMAP High Speed Multimedia card Interface.
+ If you have an OMAP2(2430) or OMAP3 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 ISA_DMA_API
obj-$(CONFIG_MMC_WBSD) += wbsd.o
obj-$(CONFIG_MMC_AU1X) += au1xmmc.o
obj-$(CONFIG_MMC_OMAP) += omap.o
+obj-$(CONFIG_MMC_OMAP_HS) += omap_hsmmc.o
obj-$(CONFIG_MMC_AT91) += at91_mci.o
obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o
obj-$(CONFIG_MMC_SPI) += mmc_spi.o
static int mmc_omap_get_dma_channel(struct mmc_omap_host *host, struct mmc_data *data)
{
- const char *dev_name;
+ const char *dma_dev_name;
int sync_dev, dma_ch, is_read, r;
is_read = !(data->flags & MMC_DATA_WRITE);
if (is_read) {
if (host->id == 1) {
sync_dev = OMAP_DMA_MMC_RX;
- dev_name = "MMC1 read";
+ dma_dev_name = "MMC1 read";
} else {
sync_dev = OMAP_DMA_MMC2_RX;
- dev_name = "MMC2 read";
+ dma_dev_name = "MMC2 read";
}
} else {
if (host->id == 1) {
sync_dev = OMAP_DMA_MMC_TX;
- dev_name = "MMC1 write";
+ dma_dev_name = "MMC1 write";
} else {
sync_dev = OMAP_DMA_MMC2_TX;
- dev_name = "MMC2 write";
+ dma_dev_name = "MMC2 write";
}
}
- r = omap_request_dma(sync_dev, dev_name, mmc_omap_dma_cb,
+ r = omap_request_dma(sync_dev, dma_dev_name, mmc_omap_dma_cb,
host, &dma_ch);
if (r != 0) {
dev_dbg(mmc_dev(host->mmc), "omap_request_dma() failed with %d\n", r);
--- /dev/null
+/*
+ * drivers/mmc/host/omap_hsmmc.c
+ *
+ * Driver for OMAP2430/3430 MMC controller.
+ *
+ * Copyright (C) 2007 Texas Instruments.
+ *
+ * Authors:
+ * Syed Mohammed Khasim <x0khasim@ti.com>
+ * Madhusudhan <madhu.cr@ti.com>
+ * Mohit Jalori <mjalori@ti.com>
+ *
+ * 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/init.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+#include <linux/timer.h>
+#include <linux/clk.h>
+#include <linux/mmc/host.h>
+#include <linux/io.h>
+#include <asm/semaphore.h>
+#include <asm/dma.h>
+#include <asm/hardware.h>
+#include <asm/arch/board.h>
+#include <asm/arch/mmc.h>
+#include <asm/arch/cpu.h>
+
+/* OMAP HSMMC Host Controller Registers */
+#define OMAP_HSMMC_SYSCONFIG 0x0010
+#define OMAP_HSMMC_CON 0x002C
+#define OMAP_HSMMC_BLK 0x0104
+#define OMAP_HSMMC_ARG 0x0108
+#define OMAP_HSMMC_CMD 0x010C
+#define OMAP_HSMMC_RSP10 0x0110
+#define OMAP_HSMMC_RSP32 0x0114
+#define OMAP_HSMMC_RSP54 0x0118
+#define OMAP_HSMMC_RSP76 0x011C
+#define OMAP_HSMMC_DATA 0x0120
+#define OMAP_HSMMC_HCTL 0x0128
+#define OMAP_HSMMC_SYSCTL 0x012C
+#define OMAP_HSMMC_STAT 0x0130
+#define OMAP_HSMMC_IE 0x0134
+#define OMAP_HSMMC_ISE 0x0138
+#define OMAP_HSMMC_CAPA 0x0140
+
+#define VS18 (1<<26)
+#define VS30 (1<<25)
+#define SDVS18 (0x5<<9)
+#define SDVS30 (0x6<<9)
+#define SDVSCLR 0xFFFFF1FF
+#define SDVSDET 0x00000400
+#define AUTOIDLE 0x1
+#define SDBP (1<<8)
+#define DTO 0xe
+#define ICE 0x1
+#define ICS 0x2
+#define CEN (1<<2)
+#define CLKD_MASK 0x0000FFC0
+#define INT_EN_MASK 0x307F0033
+#define INIT_STREAM (1<<1)
+#define DP_SELECT (1<<21)
+#define DDIR (1<<4)
+#define DMA_EN 0x1
+#define MSBS 1<<5
+#define BCE 1<<1
+#define FOUR_BIT 1 << 1
+#define CC 0x1
+#define TC 0x02
+#define OD 0x1
+#define ERR (1 << 15)
+#define CMD_TIMEOUT (1 << 16)
+#define DATA_TIMEOUT (1 << 20)
+#define CMD_CRC (1 << 17)
+#define DATA_CRC (1 << 21)
+#define CARD_ERR (1 << 28)
+#define STAT_CLEAR 0xFFFFFFFF
+#define INIT_STREAM_CMD 0x00000000
+#define DUAL_VOLT_OCR_BIT 7
+
+#define OMAP_MMC1_DEVID 1
+#define OMAP_MMC2_DEVID 2
+#define OMAP_MMC_DATADIR_NONE 0
+#define OMAP_MMC_DATADIR_READ 1
+#define OMAP_MMC_DATADIR_WRITE 2
+#define MMC_TIMEOUT_MS 20
+#define OMAP_MMC_MASTER_CLOCK 96000000
+#define DRIVER_NAME "mmci-omap"
+/*
+ * slot_id is device id - 1, device id is a static value
+ * of 1 to represent device 1 etc..
+ */
+#define mmc_slot(host) (host->pdata->slots[host->slot_id])
+
+/*
+ * MMC Host controller read/write API's
+ */
+#define OMAP_HSMMC_READ(base, reg) \
+ __raw_readl((base) + OMAP_HSMMC_##reg)
+
+#define OMAP_HSMMC_WRITE(base, reg, val) \
+ __raw_writel((val), (base) + OMAP_HSMMC_##reg)
+
+struct mmc_omap_host {
+ struct device *dev;
+ struct mmc_host *mmc;
+ struct mmc_request *mrq;
+ struct mmc_command *cmd;
+ struct mmc_data *data;
+ struct clk *fclk;
+ struct clk *iclk;
+ struct clk *dbclk;
+ struct semaphore sem;
+ struct work_struct mmc_carddetect_work;
+ void __iomem *base;
+ resource_size_t mapbase;
+ unsigned int id;
+ unsigned int dma_len;
+ unsigned int dma_dir;
+ unsigned char bus_mode;
+ unsigned char datadir;
+ u32 *buffer;
+ u32 bytesleft;
+ int suspended;
+ int irq;
+ int carddetect;
+ int use_dma, dma_ch;
+ int initstr;
+ int slot_id;
+ int dbclk_enabled;
+ struct omap_mmc_platform_data *pdata;
+};
+
+/*
+ * Stop clock to the card
+ */
+static void omap_mmc_stop_clock(struct mmc_omap_host *host)
+{
+ OMAP_HSMMC_WRITE(host->base, SYSCTL,
+ OMAP_HSMMC_READ(host->base, SYSCTL) & ~CEN);
+ if ((OMAP_HSMMC_READ(host->base, SYSCTL) & CEN) != 0x0)
+ dev_dbg(mmc_dev(host->mmc), "MMC Clock is not stoped\n");
+}
+
+/*
+ * Send init stream sequence to card
+ * before sending IDLE command
+ */
+static void send_init_stream(struct mmc_omap_host *host)
+{
+ int reg = 0;
+ unsigned long timeout;
+
+ disable_irq(host->irq);
+ OMAP_HSMMC_WRITE(host->base, CON,
+ OMAP_HSMMC_READ(host->base, CON) | INIT_STREAM);
+ OMAP_HSMMC_WRITE(host->base, CMD, INIT_STREAM_CMD);
+
+ timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
+ while ((reg != CC) && time_before(jiffies, timeout))
+ reg = OMAP_HSMMC_READ(host->base, STAT) & CC;
+
+ OMAP_HSMMC_WRITE(host->base, CON,
+ OMAP_HSMMC_READ(host->base, CON) & ~INIT_STREAM);
+ enable_irq(host->irq);
+}
+
+/*
+ * Configure the response type and send the cmd.
+ */
+static void
+mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd,
+ struct mmc_data *data)
+{
+ int cmdreg = 0, resptype = 0, cmdtype = 0;
+
+ dev_dbg(mmc_dev(host->mmc), "%s: CMD%d, argument 0x%08x\n",
+ mmc_hostname(host->mmc), cmd->opcode, cmd->arg);
+ host->cmd = cmd;
+
+ /*
+ * Clear status bits and enable interrupts
+ */
+ OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
+ OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
+ OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
+
+ if (cmd->flags & MMC_RSP_PRESENT) {
+ if (cmd->flags & MMC_RSP_136)
+ resptype = 1;
+ else
+ resptype = 2;
+ }
+
+ /*
+ * Unlike OMAP1 controller, the cmdtype does not seem to be based on
+ * ac, bc, adtc, bcr. Only CMD12 needs a val of 0x3, rest 0x0.
+ */
+ if (cmd->opcode == 12)
+ cmdtype = 0x3;
+
+ cmdreg = (cmd->opcode << 24) | (resptype << 16) | (cmdtype << 22);
+
+ if (data) {
+ cmdreg |= DP_SELECT | MSBS | BCE;
+ if (data->flags & MMC_DATA_READ)
+ cmdreg |= DDIR;
+ else
+ cmdreg &= ~(DDIR);
+ }
+
+ if (host->use_dma)
+ cmdreg |= DMA_EN;
+
+ OMAP_HSMMC_WRITE(host->base, ARG, cmd->arg);
+ OMAP_HSMMC_WRITE(host->base, CMD, cmdreg);
+}
+
+/*
+ * Notify the transfer complete to MMC core
+ */
+static void
+mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data)
+{
+ host->data = NULL;
+
+ if (host->use_dma && host->dma_ch != -1)
+ dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len,
+ host->dma_dir);
+
+ host->datadir = OMAP_MMC_DATADIR_NONE;
+
+ if (!data->error)
+ data->bytes_xfered += data->blocks * (data->blksz);
+ else
+ data->bytes_xfered = 0;
+
+ if (!data->stop) {
+ host->mrq = NULL;
+ mmc_request_done(host->mmc, data->mrq);
+ return;
+ }
+ mmc_omap_start_command(host, data->stop, NULL);
+}
+
+/*
+ * Notify the core about command completion
+ */
+static void
+mmc_omap_cmd_done(struct mmc_omap_host *host, struct mmc_command *cmd)
+{
+ host->cmd = NULL;
+
+ if (cmd->flags & MMC_RSP_PRESENT) {
+ if (cmd->flags & MMC_RSP_136) {
+ /* response type 2 */
+ cmd->resp[3] = OMAP_HSMMC_READ(host->base, RSP10);
+ cmd->resp[2] = OMAP_HSMMC_READ(host->base, RSP32);
+ cmd->resp[1] = OMAP_HSMMC_READ(host->base, RSP54);
+ cmd->resp[0] = OMAP_HSMMC_READ(host->base, RSP76);
+ } else {
+ /* response types 1, 1b, 3, 4, 5, 6 */
+ cmd->resp[0] = OMAP_HSMMC_READ(host->base, RSP10);
+ }
+ }
+ if (host->data == NULL || cmd->error) {
+ host->mrq = NULL;
+ mmc_request_done(host->mmc, cmd->mrq);
+ }
+}
+
+/*
+ * DMA clean up for command errors
+ */
+static void mmc_dma_cleanup(struct mmc_omap_host *host)
+{
+ host->data->error = -ETIMEDOUT;
+
+ if (host->use_dma && host->dma_ch != -1) {
+ dma_unmap_sg(mmc_dev(host->mmc), host->data->sg, host->dma_len,
+ host->dma_dir);
+ omap_free_dma(host->dma_ch);
+ host->dma_ch = -1;
+ up(&host->sem);
+ }
+ host->data = NULL;
+ host->datadir = OMAP_MMC_DATADIR_NONE;
+}
+
+/*
+ * MMC controller IRQ handler
+ */
+static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
+{
+ struct mmc_omap_host *host = dev_id;
+ int end_cmd = 0, end_trans = 0, status;
+
+ if (host->cmd == NULL && host->data == NULL) {
+ OMAP_HSMMC_WRITE(host->base, STAT,
+ OMAP_HSMMC_READ(host->base, STAT));
+ return IRQ_HANDLED;
+ }
+
+ status = OMAP_HSMMC_READ(host->base, STAT);
+ dev_dbg(mmc_dev(host->mmc), "IRQ Status is %x\n", status);
+
+ if (status & ERR) {
+ if ((status & CMD_TIMEOUT) ||
+ (status & CMD_CRC)) {
+ if (host->cmd) {
+ if (status & CMD_TIMEOUT)
+ host->cmd->error = -ETIMEDOUT;
+ else
+ host->cmd->error = -EILSEQ;
+ end_cmd = 1;
+ }
+ if (host->data)
+ mmc_dma_cleanup(host);
+ }
+ if ((status & DATA_TIMEOUT) ||
+ (status & DATA_CRC)) {
+ if (host->data) {
+ if (status & DATA_TIMEOUT)
+ mmc_dma_cleanup(host);
+ else
+ host->data->error = -EILSEQ;
+ end_trans = 1;
+ }
+ }
+ if (status & CARD_ERR) {
+ dev_dbg(mmc_dev(host->mmc),
+ "Ignoring card err CMD%d\n", host->cmd->opcode);
+ if (host->cmd)
+ end_cmd = 1;
+ if (host->data)
+ end_trans = 1;
+ }
+ }
+
+ OMAP_HSMMC_WRITE(host->base, STAT, status);
+
+ if (end_cmd || (status & CC))
+ mmc_omap_cmd_done(host, host->cmd);
+ if (end_trans || (status & TC))
+ mmc_omap_xfer_done(host, host->data);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * Switch MMC operating voltage
+ */
+static int omap_mmc_switch_opcond(struct mmc_omap_host *host, int vdd)
+{
+ u32 reg_val = 0;
+ int ret;
+
+ /* Disable the clocks */
+ clk_disable(host->fclk);
+ clk_disable(host->iclk);
+ clk_disable(host->dbclk);
+
+ /* Turn the power off */
+ ret = mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0);
+ if (ret != 0)
+ goto err;
+
+ /* Turn the power ON with given VDD 1.8 or 3.0v */
+ ret = mmc_slot(host).set_power(host->dev, host->slot_id, 1, vdd);
+ if (ret != 0)
+ goto err;
+
+ clk_enable(host->fclk);
+ clk_enable(host->iclk);
+ clk_enable(host->dbclk);
+
+ OMAP_HSMMC_WRITE(host->base, HCTL,
+ OMAP_HSMMC_READ(host->base, HCTL) & SDVSCLR);
+ reg_val = OMAP_HSMMC_READ(host->base, HCTL);
+ /*
+ * If a MMC dual voltage card is detected, the set_ios fn calls
+ * this fn with VDD bit set for 1.8V. Upon card removal from the
+ * slot, mmc_omap_detect fn sets the VDD back to 3V.
+ *
+ * Only MMC1 supports 3.0V. MMC2 will not function if SDVS30 is
+ * set in HCTL.
+ */
+ if (host->id == OMAP_MMC1_DEVID && (((1 << vdd) == MMC_VDD_32_33) ||
+ ((1 << vdd) == MMC_VDD_33_34)))
+ reg_val |= SDVS30;
+ if ((1 << vdd) == MMC_VDD_165_195)
+ reg_val |= SDVS18;
+
+ OMAP_HSMMC_WRITE(host->base, HCTL, reg_val);
+
+ OMAP_HSMMC_WRITE(host->base, HCTL,
+ OMAP_HSMMC_READ(host->base, HCTL) | SDBP);
+
+ return 0;
+err:
+ dev_dbg(mmc_dev(host->mmc), "Unable to switch operating voltage\n");
+ return ret;
+}
+
+/*
+ * Work Item to notify the core about card insertion/removal
+ */
+static void mmc_omap_detect(struct work_struct *work)
+{
+ u16 vdd = 0;
+ struct mmc_omap_host *host = container_of(work, struct mmc_omap_host,
+ mmc_carddetect_work);
+
+ if (host->carddetect) {
+ if (!(OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET)) {
+ /*
+ * Set the VDD back to 3V when the card is removed
+ * before the set_ios fn turns off the power.
+ */
+ vdd = fls(host->mmc->ocr_avail) - 1;
+ if (omap_mmc_switch_opcond(host, vdd) != 0)
+ host->mmc->ios.vdd = vdd;
+ }
+ mmc_detect_change(host->mmc, (HZ * 200) / 1000);
+ } else
+ mmc_detect_change(host->mmc, (HZ * 50) / 1000);
+}
+
+/*
+ * ISR for handling card insertion and removal
+ */
+static irqreturn_t omap_mmc_cd_handler(int irq, void *dev_id)
+{
+ struct mmc_omap_host *host = (struct mmc_omap_host *)dev_id;
+
+ host->carddetect = mmc_slot(host).card_detect(irq);
+ schedule_work(&host->mmc_carddetect_work);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * DMA call back function
+ */
+static void mmc_omap_dma_cb(int lch, u16 ch_status, void *data)
+{
+ struct mmc_omap_host *host = data;
+
+ if (ch_status & OMAP2_DMA_MISALIGNED_ERR_IRQ)
+ dev_dbg(mmc_dev(host->mmc), "MISALIGNED_ADRS_ERR\n");
+
+ if (host->dma_ch < 0)
+ return;
+
+ omap_free_dma(host->dma_ch);
+ host->dma_ch = -1;
+ /*
+ * DMA Callback: run in interrupt context.
+ * mutex_unlock will through a kernel warning if used.
+ */
+ up(&host->sem);
+}
+
+/*
+ * Configure dma src and destination parameters
+ */
+static int mmc_omap_config_dma_param(int sync_dir, struct mmc_omap_host *host,
+ struct mmc_data *data)
+{
+ if (sync_dir == 0) {
+ omap_set_dma_dest_params(host->dma_ch, 0,
+ OMAP_DMA_AMODE_CONSTANT,
+ (host->mapbase + OMAP_HSMMC_DATA), 0, 0);
+ omap_set_dma_src_params(host->dma_ch, 0,
+ OMAP_DMA_AMODE_POST_INC,
+ sg_dma_address(&data->sg[0]), 0, 0);
+ } else {
+ omap_set_dma_src_params(host->dma_ch, 0,
+ OMAP_DMA_AMODE_CONSTANT,
+ (host->mapbase + OMAP_HSMMC_DATA), 0, 0);
+ omap_set_dma_dest_params(host->dma_ch, 0,
+ OMAP_DMA_AMODE_POST_INC,
+ sg_dma_address(&data->sg[0]), 0, 0);
+ }
+ return 0;
+}
+/*
+ * Routine to configure and start DMA for the MMC card
+ */
+static int
+mmc_omap_start_dma_transfer(struct mmc_omap_host *host, struct mmc_request *req)
+{
+ int sync_dev, sync_dir = 0;
+ int dma_ch = 0, ret = 0, err = 1;
+ struct mmc_data *data = req->data;
+
+ /*
+ * If for some reason the DMA transfer is still active,
+ * we wait for timeout period and free the dma
+ */
+ if (host->dma_ch != -1) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(100);
+ if (down_trylock(&host->sem)) {
+ omap_free_dma(host->dma_ch);
+ host->dma_ch = -1;
+ up(&host->sem);
+ return err;
+ }
+ } else {
+ if (down_trylock(&host->sem))
+ return err;
+ }
+
+ if (!(data->flags & MMC_DATA_WRITE)) {
+ host->dma_dir = DMA_FROM_DEVICE;
+ if (host->id == OMAP_MMC1_DEVID)
+ sync_dev = OMAP24XX_DMA_MMC1_RX;
+ else
+ sync_dev = OMAP24XX_DMA_MMC2_RX;
+ } else {
+ host->dma_dir = DMA_TO_DEVICE;
+ if (host->id == OMAP_MMC1_DEVID)
+ sync_dev = OMAP24XX_DMA_MMC1_TX;
+ else
+ sync_dev = OMAP24XX_DMA_MMC2_TX;
+ }
+
+ ret = omap_request_dma(sync_dev, "MMC/SD", mmc_omap_dma_cb,
+ host, &dma_ch);
+ if (ret != 0) {
+ dev_dbg(mmc_dev(host->mmc),
+ "%s: omap_request_dma() failed with %d\n",
+ mmc_hostname(host->mmc), ret);
+ return ret;
+ }
+
+ host->dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg,
+ data->sg_len, host->dma_dir);
+ host->dma_ch = dma_ch;
+
+ if (!(data->flags & MMC_DATA_WRITE))
+ mmc_omap_config_dma_param(1, host, data);
+ else
+ mmc_omap_config_dma_param(0, host, data);
+
+ if ((data->blksz % 4) == 0)
+ omap_set_dma_transfer_params(dma_ch, OMAP_DMA_DATA_TYPE_S32,
+ (data->blksz / 4), data->blocks, OMAP_DMA_SYNC_FRAME,
+ sync_dev, sync_dir);
+ else
+ /* REVISIT: The MMC buffer increments only when MSB is written.
+ * Return error for blksz which is non multiple of four.
+ */
+ return -EINVAL;
+
+ omap_start_dma(dma_ch);
+ return 0;
+}
+
+/*
+ * Configure block length for MMC/SD cards and initiate the transfer.
+ */
+static int
+mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req)
+{
+ int ret;
+ host->data = req->data;
+
+ if (req->data == NULL) {
+ host->datadir = OMAP_MMC_DATADIR_NONE;
+ OMAP_HSMMC_WRITE(host->base, BLK, 0);
+ return 0;
+ }
+
+ OMAP_HSMMC_WRITE(host->base, BLK, (req->data->blksz)
+ | (req->data->blocks << 16));
+
+ host->datadir = (req->data->flags & MMC_DATA_WRITE) ?
+ OMAP_MMC_DATADIR_WRITE : OMAP_MMC_DATADIR_READ;
+
+ if (host->use_dma) {
+ ret = mmc_omap_start_dma_transfer(host, req);
+ if (ret != 0) {
+ dev_dbg(mmc_dev(host->mmc), "MMC start dma failure\n");
+ return ret;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Request function. for read/write operation
+ */
+static void omap_mmc_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;
+ mmc_omap_prepare_data(host, req);
+ mmc_omap_start_command(host, req->cmd, req->data);
+}
+
+
+/* Routine to configure clock values. Exposed API to core */
+static void omap_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ struct mmc_omap_host *host = mmc_priv(mmc);
+ u16 dsor = 0;
+ unsigned long regval;
+ unsigned long timeout;
+
+ switch (ios->power_mode) {
+ case MMC_POWER_OFF:
+ mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0);
+ break;
+ case MMC_POWER_UP:
+ mmc_slot(host).set_power(host->dev, host->slot_id, 1, ios->vdd);
+ break;
+ }
+
+ switch (mmc->ios.bus_width) {
+ case MMC_BUS_WIDTH_4:
+ OMAP_HSMMC_WRITE(host->base, HCTL,
+ OMAP_HSMMC_READ(host->base, HCTL) | FOUR_BIT);
+ break;
+ case MMC_BUS_WIDTH_1:
+ OMAP_HSMMC_WRITE(host->base, HCTL,
+ OMAP_HSMMC_READ(host->base, HCTL) & ~FOUR_BIT);
+ break;
+ }
+
+ if (host->id == OMAP_MMC1_DEVID) {
+ /* Only MMC1 can operate at 3V/1.8V */
+ if ((OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET) &&
+ (ios->vdd == DUAL_VOLT_OCR_BIT)) {
+ /*
+ * The mmc_select_voltage fn of the core does
+ * not seem to set the power_mode to
+ * MMC_POWER_UP upon recalculating the voltage.
+ * vdd 1.8v.
+ */
+ if (omap_mmc_switch_opcond(host, ios->vdd) != 0)
+ dev_dbg(mmc_dev(host->mmc),
+ "Switch operation failed\n");
+ }
+ }
+
+ if (ios->clock) {
+ dsor = OMAP_MMC_MASTER_CLOCK / ios->clock;
+ if (dsor < 1)
+ dsor = 1;
+
+ if (OMAP_MMC_MASTER_CLOCK / dsor > ios->clock)
+ dsor++;
+
+ if (dsor > 250)
+ dsor = 250;
+ }
+ omap_mmc_stop_clock(host);
+ regval = OMAP_HSMMC_READ(host->base, SYSCTL);
+ regval = regval & ~(CLKD_MASK);
+ regval = regval | (dsor << 6) | (DTO << 16);
+ OMAP_HSMMC_WRITE(host->base, SYSCTL, regval);
+ OMAP_HSMMC_WRITE(host->base, SYSCTL,
+ OMAP_HSMMC_READ(host->base, SYSCTL) | ICE);
+
+ /* Wait till the ICS bit is set */
+ timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
+ while ((OMAP_HSMMC_READ(host->base, SYSCTL) & ICS) != 0x2
+ && time_before(jiffies, timeout))
+ msleep(1);
+
+ OMAP_HSMMC_WRITE(host->base, SYSCTL,
+ OMAP_HSMMC_READ(host->base, SYSCTL) | CEN);
+
+ if (ios->power_mode == MMC_POWER_ON)
+ send_init_stream(host);
+
+ if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
+ OMAP_HSMMC_WRITE(host->base, CON,
+ OMAP_HSMMC_READ(host->base, CON) | OD);
+}
+/* NOTE: Read only switch not supported yet */
+static struct mmc_host_ops mmc_omap_ops = {
+ .request = omap_mmc_request,
+ .set_ios = omap_mmc_set_ios,
+};
+
+static int __init omap_mmc_probe(struct platform_device *pdev)
+{
+ struct omap_mmc_platform_data *pdata = pdev->dev.platform_data;
+ struct mmc_host *mmc;
+ struct mmc_omap_host *host = NULL;
+ struct resource *res;
+ int ret = 0, irq;
+ u32 hctl, capa;
+
+ if (pdata == NULL) {
+ dev_err(&pdev->dev, "Platform Data is missing\n");
+ return -ENXIO;
+ }
+
+ if (pdata->nr_slots == 0) {
+ dev_err(&pdev->dev, "No Slots\n");
+ return -ENXIO;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ irq = platform_get_irq(pdev, 0);
+ if (res == NULL || irq < 0)
+ return -ENXIO;
+
+ res = request_mem_region(res->start, res->end - res->start + 1,
+ pdev->name);
+ if (res == NULL)
+ return -EBUSY;
+
+ mmc = mmc_alloc_host(sizeof(struct mmc_omap_host), &pdev->dev);
+ if (!mmc) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ host = mmc_priv(mmc);
+ host->mmc = mmc;
+ host->pdata = pdata;
+ host->use_dma = 1;
+ host->dma_ch = -1;
+ host->irq = irq;
+ host->id = pdev->id;
+ host->slot_id = 0;
+ host->mapbase = res->start;
+ host->base = ioremap(host->mapbase, SZ_4K);
+ mmc->ops = &mmc_omap_ops;
+ mmc->f_min = 400000;
+ mmc->f_max = 52000000;
+
+ sema_init(&host->sem, 1);
+
+ host->iclk = clk_get(&pdev->dev, "mmchs_ick");
+ if (IS_ERR(host->iclk)) {
+ ret = PTR_ERR(host->iclk);
+ host->iclk = NULL;
+ goto err;
+ }
+ host->fclk = clk_get(&pdev->dev, "mmchs_fck");
+ if (IS_ERR(host->fclk)) {
+ ret = PTR_ERR(host->fclk);
+ host->fclk = NULL;
+ clk_put(host->iclk);
+ goto err;
+ }
+
+ if (clk_enable(host->fclk) != 0)
+ goto err;
+
+ if (clk_enable(host->iclk) != 0) {
+ clk_disable(host->fclk);
+ clk_put(host->fclk);
+ goto err;
+ }
+
+ host->dbclk = clk_get(&pdev->dev, "mmchsdb_fck");
+ /*
+ * MMC can still work without debounce clock.
+ */
+ if (IS_ERR(host->dbclk))
+ dev_dbg(mmc_dev(host->mmc), "Failed to get debounce clock\n");
+ else
+ if (clk_enable(host->dbclk) != 0)
+ dev_dbg(mmc_dev(host->mmc), "Enabling debounce"
+ " clk failed\n");
+ else
+ host->dbclk_enabled = 1;
+
+ mmc->ocr_avail = mmc_slot(host).ocr_mask;
+ mmc->caps |= MMC_CAP_MULTIWRITE | MMC_CAP_MMC_HIGHSPEED |
+ MMC_CAP_SD_HIGHSPEED;
+
+ if (pdata->conf.wire4)
+ mmc->caps |= MMC_CAP_4_BIT_DATA;
+
+ /* Only MMC1 supports 3.0V */
+ if (host->id == OMAP_MMC1_DEVID) {
+ hctl = SDVS30;
+ capa = VS30 | VS18;
+ } else {
+ hctl = SDVS18;
+ capa = VS18;
+ }
+
+ OMAP_HSMMC_WRITE(host->base, HCTL,
+ OMAP_HSMMC_READ(host->base, HCTL) | hctl);
+
+ OMAP_HSMMC_WRITE(host->base, CAPA,
+ OMAP_HSMMC_READ(host->base, CAPA) | capa);
+
+ /* Set the controller to AUTO IDLE mode */
+ OMAP_HSMMC_WRITE(host->base, SYSCONFIG,
+ OMAP_HSMMC_READ(host->base, SYSCONFIG) | AUTOIDLE);
+
+ /* Set SD bus power bit */
+ OMAP_HSMMC_WRITE(host->base, HCTL,
+ OMAP_HSMMC_READ(host->base, HCTL) | SDBP);
+
+ /* Request IRQ for MMC operations */
+ ret = request_irq(host->irq, mmc_omap_irq, IRQF_DISABLED, pdev->name,
+ host);
+ if (ret) {
+ dev_dbg(mmc_dev(host->mmc), "Unable to grab HSMMC IRQ\n");
+ goto irq_err;
+ }
+
+ /* Request IRQ for card detect */
+ if ((mmc_slot(host).card_detect_irq) && (mmc_slot(host).card_detect)) {
+ ret = request_irq(mmc_slot(host).card_detect_irq,
+ omap_mmc_cd_handler, IRQF_DISABLED, "MMC CD",
+ host);
+ if (ret) {
+ dev_dbg(mmc_dev(host->mmc),
+ "Unable to grab MMC CD IRQ");
+ free_irq(host->irq, host);
+ goto irq_err;
+ }
+ }
+
+ INIT_WORK(&host->mmc_carddetect_work, mmc_omap_detect);
+ if (pdata->init != NULL) {
+ if (pdata->init(&pdev->dev) != 0) {
+ free_irq(mmc_slot(host).card_detect_irq, host);
+ free_irq(host->irq, host);
+ goto irq_err;
+ }
+ }
+
+ OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
+ OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
+
+ platform_set_drvdata(pdev, host);
+ mmc_add_host(mmc);
+
+ return 0;
+
+err:
+ dev_dbg(mmc_dev(host->mmc), "Probe Failed\n");
+ if (host)
+ mmc_free_host(mmc);
+ return ret;
+
+irq_err:
+ dev_dbg(mmc_dev(host->mmc), "Unable to configure MMC IRQs\n");
+ clk_disable(host->fclk);
+ clk_disable(host->iclk);
+ clk_put(host->fclk);
+ clk_put(host->iclk);
+ if (host->dbclk_enabled) {
+ clk_disable(host->dbclk);
+ clk_put(host->dbclk);
+ }
+
+ if (host)
+ mmc_free_host(mmc);
+ return ret;
+}
+
+static int omap_mmc_remove(struct platform_device *pdev)
+{
+ struct mmc_omap_host *host = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+ if (host) {
+ host->pdata->cleanup(&pdev->dev);
+ free_irq(host->irq, host);
+ if (mmc_slot(host).card_detect_irq)
+ free_irq(mmc_slot(host).card_detect_irq, host);
+ flush_scheduled_work();
+
+ clk_disable(host->fclk);
+ clk_disable(host->iclk);
+ clk_put(host->fclk);
+ clk_put(host->iclk);
+ if (host->dbclk_enabled) {
+ clk_disable(host->dbclk);
+ clk_put(host->dbclk);
+ }
+
+ mmc_free_host(host->mmc);
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int omap_mmc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ int ret = 0;
+ struct mmc_omap_host *host = platform_get_drvdata(pdev);
+
+ if (host && host->suspended)
+ return 0;
+
+ if (host) {
+ ret = mmc_suspend_host(host->mmc, state);
+ if (ret == 0) {
+ host->suspended = 1;
+
+ OMAP_HSMMC_WRITE(host->base, ISE, 0);
+ OMAP_HSMMC_WRITE(host->base, IE, 0);
+
+ ret = host->pdata->suspend(&pdev->dev, host->slot_id);
+ if (ret)
+ dev_dbg(mmc_dev(host->mmc),
+ "Unable to handle MMC board"
+ " level suspend\n");
+
+ if (!(OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET)) {
+ OMAP_HSMMC_WRITE(host->base, HCTL,
+ OMAP_HSMMC_READ(host->base, HCTL)
+ & SDVSCLR);
+ OMAP_HSMMC_WRITE(host->base, HCTL,
+ OMAP_HSMMC_READ(host->base, HCTL)
+ | SDVS30);
+ OMAP_HSMMC_WRITE(host->base, HCTL,
+ OMAP_HSMMC_READ(host->base, HCTL)
+ | SDBP);
+ }
+
+ clk_disable(host->fclk);
+ clk_disable(host->iclk);
+ clk_disable(host->dbclk);
+ }
+
+ }
+ return ret;
+}
+
+/* Routine to resume the MMC device */
+static int omap_mmc_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 = clk_enable(host->fclk);
+ if (ret)
+ goto clk_en_err;
+
+ ret = clk_enable(host->iclk);
+ if (ret) {
+ clk_disable(host->fclk);
+ clk_put(host->fclk);
+ goto clk_en_err;
+ }
+
+ if (clk_enable(host->dbclk) != 0)
+ dev_dbg(mmc_dev(host->mmc),
+ "Enabling debounce clk failed\n");
+
+ ret = host->pdata->resume(&pdev->dev, host->slot_id);
+ if (ret)
+ dev_dbg(mmc_dev(host->mmc),
+ "Unmask interrupt failed\n");
+
+ /* Notify the core to resume the host */
+ ret = mmc_resume_host(host->mmc);
+ if (ret == 0)
+ host->suspended = 0;
+ }
+
+ return ret;
+
+clk_en_err:
+ dev_dbg(mmc_dev(host->mmc),
+ "Failed to enable MMC clocks during resume\n");
+ return ret;
+}
+
+#else
+#define omap_mmc_suspend NULL
+#define omap_mmc_resume NULL
+#endif
+
+static struct platform_driver omap_mmc_driver = {
+ .probe = omap_mmc_probe,
+ .remove = omap_mmc_remove,
+ .suspend = omap_mmc_suspend,
+ .resume = omap_mmc_resume,
+ .driver = {
+ .name = DRIVER_NAME,
+ },
+};
+
+static int __init omap_mmc_init(void)
+{
+ /* Register the MMC driver */
+ return platform_driver_register(&omap_mmc_driver);
+}
+
+static void __exit omap_mmc_cleanup(void)
+{
+ /* Unregister MMC driver */
+ platform_driver_unregister(&omap_mmc_driver);
+}
+
+module_init(omap_mmc_init);
+module_exit(omap_mmc_cleanup);
+
+MODULE_DESCRIPTION("OMAP High Speed Multimedia Card driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS(DRIVER_NAME);
+MODULE_AUTHOR("Texas Instruments Inc");
*
* This function needs to be visible for bootloaders.
*/
-static int mtdpart_setup(char *s)
+int mtdpart_setup(char *s)
{
cmdline = s;
return 1;
{
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_class_is_omap1()) {
+ 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 __exit 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
Support for NAND flash on Amstrad E3 (Delta).
+config MTD_NAND_OMAP2
+ tristate "NAND Flash device on OMAP 2420H4/2430SDP boards"
+ depends on (ARM && ARCH_OMAP2 && MTD_NAND)
+ help
+ Support for NAND flash on Texas Instruments 2430SDP/2420H4 platforms.
+
+config MTD_NAND_OMAP
+ tristate "NAND Flash device on OMAP H3/H2/P2 boards"
+ depends on ARM && ARCH_OMAP1 && MTD_NAND && (MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_PERSEUS2)
+ help
+ Support for NAND flash on Texas Instruments H3/H2/P2 platforms.
+
+config MTD_NAND_OMAP_HW
+ bool "OMAP HW NAND Flash controller support"
+ depends on ARM && ARCH_OMAP16XX && MTD_NAND
+
+ help
+ Driver for TI OMAP16xx hardware NAND flash controller.
+
config MTD_NAND_TOTO
tristate "NAND Flash device on TOTO board"
depends on ARCH_OMAP && BROKEN
obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o
obj-$(CONFIG_MTD_NAND_CS553X) += cs553x_nand.o
obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o
+obj-$(CONFIG_MTD_NAND_OMAP) += omap-nand-flash.o
+obj-$(CONFIG_MTD_NAND_OMAP2) += omap2.o
+obj-$(CONFIG_MTD_NAND_OMAP_HW) += omap-hw.o
obj-$(CONFIG_MTD_NAND_AT91) += at91_nand.o
obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o
obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o
--- /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;
+ dma_cache_maint(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)
+ dma_cache_maint(addr, len, DMA_FROM_DEVICE);
+
+ nand_write_reg(NND_CTRL, nand_read_reg(NND_CTRL) & ~((1 << 16) | (1 << 17)));
+}
+
+static void fifo_read(u32 *out, unsigned int len)
+{
+ const int block_size = 16;
+ unsigned long status_reg, fifo_reg;
+ int c;
+
+ status_reg = omap_nand_base + NND_STATUS;
+ fifo_reg = omap_nand_base + NND_FIFO;
+ len = len * 4 / block_size;
+ nand_write_reg(NND_FIFOCTRL, (block_size << 24) | len);
+ nand_write_reg(NND_STATUS, 0x0f);
+ nand_write_reg(NND_CTRL, nand_read_reg(NND_CTRL) | (1 << 17));
+ c = block_size / 4;
+ while (len--) {
+ int i;
+
+ while ((__raw_readl(status_reg) & (1 << 2)) == 0);
+ __raw_writel(0x0f, status_reg);
+ for (i = 0; i < c; i++) {
+ u32 l = __raw_readl(fifo_reg);
+ *out++ = l;
+ }
+ }
+ nand_write_reg(NND_CTRL, nand_read_reg(NND_CTRL) & ~(1 << 17));
+ nand_write_reg(NND_STATUS, 0x0f);
+}
+
+static void omap_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+ unsigned long access_reg;
+
+ if (likely(((unsigned long) buf & 3) == 0 && (len & 3) == 0)) {
+ int u32_count = len >> 2;
+ u32 *dest = (u32 *) buf;
+ /* If the transfer is big enough and the length divisible by
+ * 16, we try to use DMA transfer, or FIFO copy in case of
+ * DMA failure (e.g. all channels busy) */
+ if (u32_count > 64 && (u32_count & 3) == 0) {
+ if (omap_nand_dma_ch >= 0) {
+ omap_nand_dma_transfer(mtd, buf, u32_count, 0);
+ return;
+ }
+ /* In case of an error, fallback to FIFO copy */
+ fifo_read((u32 *) buf, u32_count);
+ return;
+ }
+ access_reg = omap_nand_base + NND_ACCESS;
+ /* Small buffers we just read directly */
+ while (u32_count--)
+ *dest++ = __raw_readl(access_reg);
+ } else {
+ /* If we're not word-aligned, we use byte copy */
+ access_reg = omap_nand_base + NND_ACCESS;
+ while (len--)
+ *buf++ = __raw_readb(access_reg);
+ }
+}
+
+static void omap_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+{
+ if (likely(((unsigned long) buf & 3) == 0 && (len & 3) == 0)) {
+ const u32 *src = (const u32 *) buf;
+
+ len >>= 2;
+#if 0
+ /* If the transfer is big enough and length divisible by 16,
+ * we try to use DMA transfer. */
+ if (len > 256 / 4 && (len & 3) == 0) {
+ if (omap_nand_dma_transfer(mtd, (void *) buf, len, 1) == 0)
+ return;
+ /* In case of an error, fallback to CPU copy */
+ }
+#endif
+ while (len--)
+ nand_write_reg(NND_ACCESS, *src++);
+ } else {
+ while (len--)
+ nand_write_reg8(NND_ACCESS, *buf++);
+ }
+}
+
+static int omap_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
+{
+ if (likely(((unsigned long) buf & 3) == 0 && (len & 3) == 0)) {
+ const u32 *dest = (const u32 *) buf;
+ len >>= 2;
+ while (len--)
+ if (*dest++ != nand_read_reg(NND_ACCESS))
+ return -EFAULT;
+ } else {
+ while (len--)
+ if (*buf++ != nand_read_reg8(NND_ACCESS))
+ return -EFAULT;
+ }
+ return 0;
+}
+
+static u_char omap_nand_read_byte(struct mtd_info *mtd)
+{
+ return nand_read_reg8(NND_ACCESS);
+}
+
+static int omap_nand_dev_ready(struct mtd_info *mtd)
+{
+ u32 l;
+
+ l = nand_read_reg(NND_READY);
+ return l & 0x01;
+}
+
+static int nand_write_command(u8 cmd, u32 addr, int addr_valid)
+{
+ if (addr_valid) {
+ nand_write_reg(NND_ADDR_SRC, addr);
+ nand_write_reg8(NND_COMMAND, cmd);
+ } else {
+ nand_write_reg(NND_ADDR_SRC, 0);
+ nand_write_reg8(NND_COMMAND_SEC, cmd);
+ }
+ while (!omap_nand_dev_ready(NULL));
+ return 0;
+}
+
+/*
+ * Send command to NAND device
+ */
+static void omap_nand_command(struct mtd_info *mtd, unsigned command, int column, int page_addr)
+{
+ struct nand_chip *this = mtd->priv;
+
+ /*
+ * Write out the command to the device.
+ */
+ if (command == NAND_CMD_SEQIN) {
+ int readcmd;
+
+ if (column >= mtd->writesize) {
+ /* OOB area */
+ column -= mtd->writesize;
+ readcmd = NAND_CMD_READOOB;
+ } else if (column < 256) {
+ /* First 256 bytes --> READ0 */
+ readcmd = NAND_CMD_READ0;
+ } else {
+ column -= 256;
+ readcmd = NAND_CMD_READ1;
+ }
+ nand_write_command(readcmd, 0, 0);
+ }
+ switch (command) {
+ case NAND_CMD_RESET:
+ case NAND_CMD_PAGEPROG:
+ case NAND_CMD_STATUS:
+ case NAND_CMD_ERASE2:
+ nand_write_command(command, 0, 0);
+ break;
+ case NAND_CMD_ERASE1:
+ nand_write_command(command, ((page_addr & 0xFFFFFF00) << 1) | (page_addr & 0XFF), 1);
+ break;
+ default:
+ nand_write_command(command, (page_addr << this->page_shift) | column, 1);
+ }
+}
+
+static void omap_nand_command_lp(struct mtd_info *mtd, unsigned command, int column, int page_addr)
+{
+ struct nand_chip *this = mtd->priv;
+
+ if (command == NAND_CMD_READOOB) {
+ column += mtd->writesize;
+ command = NAND_CMD_READ0;
+ }
+ switch (command) {
+ case NAND_CMD_RESET:
+ case NAND_CMD_PAGEPROG:
+ case NAND_CMD_STATUS:
+ case NAND_CMD_ERASE2:
+ nand_write_command(command, 0, 0);
+ break;
+ case NAND_CMD_ERASE1:
+ nand_write_command(command, page_addr << this->page_shift >> 11, 1);
+ break;
+ default:
+ nand_write_command(command, (page_addr << 16) | column, 1);
+ }
+ if (command == NAND_CMD_READ0)
+ nand_write_command(NAND_CMD_READSTART, 0, 0);
+}
+
+/*
+ * Generate non-inverted ECC bytes.
+ *
+ * Using noninverted ECC can be considered ugly since writing a blank
+ * page ie. padding will clear the ECC bytes. This is no problem as long
+ * nobody is trying to write data on the seemingly unused page.
+ *
+ * Reading an erased page will produce an ECC mismatch between
+ * generated and read ECC bytes that has to be dealt with separately.
+ */
+static int omap_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
+{
+ u32 l;
+ int reg;
+ int n;
+ struct nand_chip *this = mtd->priv;
+
+ /* Ex NAND_ECC_HW12_2048 */
+ if ((this->ecc.mode == NAND_ECC_HW) && (this->ecc.size == 2048))
+ n = 4;
+ else
+ n = 1;
+ reg = NND_ECC_START;
+ while (n--) {
+ l = nand_read_reg(reg);
+ *ecc_code++ = l; // P128e, ..., P1e
+ *ecc_code++ = l >> 16; // P128o, ..., P1o
+ // P2048o, P1024o, P512o, P256o, P2048e, P1024e, P512e, P256e
+ *ecc_code++ = ((l >> 8) & 0x0f) | ((l >> 20) & 0xf0);
+ reg += 4;
+ }
+ return 0;
+}
+
+/*
+ * This function will generate true ECC value, which can be used
+ * when correcting data read from NAND flash memory core
+ */
+static void gen_true_ecc(u8 *ecc_buf)
+{
+ u32 tmp = ecc_buf[0] | (ecc_buf[1] << 16) | ((ecc_buf[2] & 0xF0) << 20) | ((ecc_buf[2] & 0x0F) << 8);
+
+ ecc_buf[0] = ~(P64o(tmp) | P64e(tmp) | P32o(tmp) | P32e(tmp) | P16o(tmp) | P16e(tmp) | P8o(tmp) | P8e(tmp) );
+ ecc_buf[1] = ~(P1024o(tmp) | P1024e(tmp) | P512o(tmp) | P512e(tmp) | P256o(tmp) | P256e(tmp) | P128o(tmp) | P128e(tmp));
+ ecc_buf[2] = ~( P4o(tmp) | P4e(tmp) | P2o(tmp) | P2e(tmp) | P1o(tmp) | P1e(tmp) | P2048o(tmp) | P2048e(tmp));
+}
+
+/*
+ * This function compares two ECC's and indicates if there is an error.
+ * If the error can be corrected it will be corrected to the buffer
+ */
+static int omap_nand_compare_ecc(u8 *ecc_data1, /* read from NAND memory */
+ u8 *ecc_data2, /* read from register */
+ u8 *page_data)
+{
+ uint i;
+ u8 tmp0_bit[8], tmp1_bit[8], tmp2_bit[8];
+ u8 comp0_bit[8], comp1_bit[8], comp2_bit[8];
+ u8 ecc_bit[24];
+ u8 ecc_sum = 0;
+ u8 find_bit = 0;
+ uint find_byte = 0;
+ int isEccFF;
+
+ isEccFF = ((*(u32 *)ecc_data1 & 0xFFFFFF) == 0xFFFFFF);
+
+ gen_true_ecc(ecc_data1);
+ gen_true_ecc(ecc_data2);
+
+ for (i = 0; i <= 2; i++) {
+ *(ecc_data1 + i) = ~(*(ecc_data1 + i));
+ *(ecc_data2 + i) = ~(*(ecc_data2 + i));
+ }
+
+ for (i = 0; i < 8; i++) {
+ tmp0_bit[i] = *ecc_data1 % 2;
+ *ecc_data1 = *ecc_data1 / 2;
+ }
+
+ for (i = 0; i < 8; i++) {
+ tmp1_bit[i] = *(ecc_data1 + 1) % 2;
+ *(ecc_data1 + 1) = *(ecc_data1 + 1) / 2;
+ }
+
+ for (i = 0; i < 8; i++) {
+ tmp2_bit[i] = *(ecc_data1 + 2) % 2;
+ *(ecc_data1 + 2) = *(ecc_data1 + 2) / 2;
+ }
+
+ for (i = 0; i < 8; i++) {
+ comp0_bit[i] = *ecc_data2 % 2;
+ *ecc_data2 = *ecc_data2 / 2;
+ }
+
+ for (i = 0; i < 8; i++) {
+ comp1_bit[i] = *(ecc_data2 + 1) % 2;
+ *(ecc_data2 + 1) = *(ecc_data2 + 1) / 2;
+ }
+
+ for (i = 0; i < 8; i++) {
+ comp2_bit[i] = *(ecc_data2 + 2) % 2;
+ *(ecc_data2 + 2) = *(ecc_data2 + 2) / 2;
+ }
+
+ for (i = 0; i< 6; i++ )
+ ecc_bit[i] = tmp2_bit[i + 2] ^ comp2_bit[i + 2];
+
+ for (i = 0; i < 8; i++)
+ ecc_bit[i + 6] = tmp0_bit[i] ^ comp0_bit[i];
+
+ for (i = 0; i < 8; i++)
+ ecc_bit[i + 14] = tmp1_bit[i] ^ comp1_bit[i];
+
+ ecc_bit[22] = tmp2_bit[0] ^ comp2_bit[0];
+ ecc_bit[23] = tmp2_bit[1] ^ comp2_bit[1];
+
+ for (i = 0; i < 24; i++)
+ ecc_sum += ecc_bit[i];
+
+ switch (ecc_sum) {
+ case 0:
+ /* Not reached because this function is not called if
+ ECC values are equal */
+ return 0;
+
+ case 1:
+ /* Uncorrectable error */
+ DEBUG (MTD_DEBUG_LEVEL0, "ECC UNCORRECTED_ERROR 1\n");
+ return -1;
+
+ case 12:
+ /* Correctable error */
+ find_byte = (ecc_bit[23] << 8) +
+ (ecc_bit[21] << 7) +
+ (ecc_bit[19] << 6) +
+ (ecc_bit[17] << 5) +
+ (ecc_bit[15] << 4) +
+ (ecc_bit[13] << 3) +
+ (ecc_bit[11] << 2) +
+ (ecc_bit[9] << 1) +
+ ecc_bit[7];
+
+ find_bit = (ecc_bit[5] << 2) + (ecc_bit[3] << 1) + ecc_bit[1];
+
+ DEBUG (MTD_DEBUG_LEVEL0, "Correcting single bit ECC error at offset: %d, bit: %d\n", find_byte, find_bit);
+
+ page_data[find_byte] ^= (1 << find_bit);
+
+ return 0;
+ default:
+ if (isEccFF) {
+ if (ecc_data2[0] == 0 && ecc_data2[1] == 0 && ecc_data2[2] == 0)
+ return 0;
+ }
+ DEBUG (MTD_DEBUG_LEVEL0, "UNCORRECTED_ERROR default\n");
+ return -1;
+ }
+}
+
+static int omap_nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc)
+{
+ struct nand_chip *this;
+ int block_count = 0, i, r;
+
+ this = mtd->priv;
+ /* Ex NAND_ECC_HW12_2048 */
+ if ((this->ecc.mode == NAND_ECC_HW) && (this->ecc.size == 2048))
+ block_count = 4;
+ else
+ block_count = 1;
+ for (i = 0; i < block_count; i++) {
+ if (memcmp(read_ecc, calc_ecc, 3) != 0) {
+ r = omap_nand_compare_ecc(read_ecc, calc_ecc, dat);
+ if (r < 0)
+ return r;
+ }
+ read_ecc += 3;
+ calc_ecc += 3;
+ dat += 512;
+ }
+ return 0;
+}
+
+static void omap_nand_enable_hwecc(struct mtd_info *mtd, int mode)
+{
+ nand_write_reg(NND_RESET, 0x01);
+}
+
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+
+extern int mtdpart_setup(char *);
+
+static int __init add_dynamic_parts(struct mtd_info *mtd)
+{
+ static const char *part_parsers[] = { "cmdlinepart", NULL };
+ struct mtd_partition *parts;
+ const struct omap_flash_part_str_config *cfg;
+ char *part_str = NULL;
+ size_t part_str_len;
+ int c;
+
+ cfg = omap_get_var_config(OMAP_TAG_FLASH_PART_STR, &part_str_len);
+ if (cfg != NULL) {
+ part_str = kmalloc(part_str_len + 1, GFP_KERNEL);
+ if (part_str == NULL)
+ return -ENOMEM;
+ memcpy(part_str, cfg->part_table, part_str_len);
+ part_str[part_str_len] = '\0';
+ mtdpart_setup(part_str);
+ }
+ c = parse_mtd_partitions(omap_mtd, part_parsers, &parts, 0);
+ if (part_str != NULL) {
+ mtdpart_setup(NULL);
+ kfree(part_str);
+ }
+ if (c <= 0)
+ return -1;
+
+ add_mtd_partitions(mtd, parts, c);
+
+ return 0;
+}
+
+#else
+
+static inline int add_dynamic_parts(struct mtd_info *mtd)
+{
+ return -1;
+}
+
+#endif
+
+static inline int calc_psc(int ns, int cycle_ps)
+{
+ return (ns * 1000 + (cycle_ps - 1)) / cycle_ps;
+}
+
+static void set_psc_regs(int psc_ns, int psc1_ns, int psc2_ns)
+{
+ int psc[3], i;
+ unsigned long rate, ps;
+
+ rate = clk_get_rate(omap_nand_clk);
+ ps = 1000000000 / (rate / 1000);
+ psc[0] = calc_psc(psc_ns, ps);
+ psc[1] = calc_psc(psc1_ns, ps);
+ psc[2] = calc_psc(psc2_ns, ps);
+ for (i = 0; i < 3; i++) {
+ if (psc[i] < 2)
+ psc[i] = 2;
+ else if (psc[i] > 256)
+ psc[i] = 256;
+ }
+ nand_write_reg(NND_PSC_CLK, psc[0] - 1);
+ nand_write_reg(NND_PSC1_CLK, psc[1] - 1);
+ nand_write_reg(NND_PSC2_CLK, psc[2] - 1);
+ printk(KERN_INFO "omap-hw-nand: using PSC values %d, %d, %d\n", psc[0], psc[1], psc[2]);
+}
+
+/*
+ * Main initialization routine
+ */
+static int __init omap_nand_init(void)
+{
+ struct nand_chip *this;
+ int err = 0;
+ u32 l;
+
+ omap_nand_clk = clk_get(NULL, "armper_ck");
+ BUG_ON(omap_nand_clk == NULL);
+ clk_enable(omap_nand_clk);
+
+ l = nand_read_reg(NND_REVISION);
+ printk(KERN_INFO "omap-hw-nand: OMAP NAND Controller rev. %d.%d\n", l>>4, l & 0xf);
+
+ /* Reset the NAND Controller */
+ nand_write_reg(NND_SYSCFG, 0x02);
+ while ((nand_read_reg(NND_SYSSTATUS) & 0x01) == 0);
+
+ /* No Prefetch, no postwrite, write prot & enable pairs disabled,
+ addres counter set to send 4 byte addresses to flash,
+ A8 is set not to be sent to flash (erase addre needs formatting),
+ choose little endian, enable 512 byte ECC logic,
+ */
+ nand_write_reg(NND_CTRL, 0xFF01);
+
+ /* Allocate memory for MTD device structure and private data */
+ omap_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
+ if (!omap_mtd) {
+ printk(KERN_WARNING "omap-hw-nand: Unable to allocate OMAP NAND MTD device structure.\n");
+ err = -ENOMEM;
+ goto free_clock;
+ }
+#if 1
+ err = omap_request_dma(OMAP_DMA_NAND, "NAND", nand_dma_cb,
+ &omap_nand_dma_comp, &omap_nand_dma_ch);
+ if (err < 0) {
+ printk(KERN_WARNING "omap-hw-nand: Unable to reserve DMA channel\n");
+ omap_nand_dma_ch = -1;
+ }
+#else
+ omap_nand_dma_ch = -1;
+#endif
+ /* Get pointer to private data */
+ this = (struct nand_chip *) (&omap_mtd[1]);
+
+ /* Initialize structures */
+ memset((char *) omap_mtd, 0, sizeof(struct mtd_info));
+ memset((char *) this, 0, sizeof(struct nand_chip));
+
+ /* Link the private data with the MTD structure */
+ omap_mtd->priv = this;
+ omap_mtd->name = "omap-nand";
+
+ this->options = NAND_SKIP_BBTSCAN;
+
+ /* Used from chip select and nand_command() */
+ this->read_byte = omap_nand_read_byte;
+
+ this->select_chip = omap_nand_select_chip;
+ this->dev_ready = omap_nand_dev_ready;
+ this->chip_delay = 0;
+ this->ecc.mode = NAND_ECC_HW;
+ this->ecc.bytes = 3;
+ this->ecc.size = 512;
+ this->cmdfunc = omap_nand_command;
+ this->write_buf = omap_nand_write_buf;
+ this->read_buf = omap_nand_read_buf;
+ this->verify_buf = omap_nand_verify_buf;
+ this->ecc.calculate = omap_nand_calculate_ecc;
+ this->ecc.correct = omap_nand_correct_data;
+ this->ecc.hwctl = omap_nand_enable_hwecc;
+
+ nand_write_reg(NND_SYSCFG, 0x1); /* Enable auto idle */
+ nand_write_reg(NND_PSC_CLK, 10);
+ /* Scan to find existance of the device */
+ if (nand_scan(omap_mtd, 1)) {
+ err = -ENXIO;
+ goto out_mtd;
+ }
+
+ set_psc_regs(25, 15, 35);
+ if (this->page_shift == 11) {
+ this->cmdfunc = omap_nand_command_lp;
+ l = nand_read_reg(NND_CTRL);
+ l |= 1 << 4; /* Set the A8 bit in CTRL reg */
+ nand_write_reg(NND_CTRL, l);
+ this->ecc.mode = NAND_ECC_HW;
+ this->ecc.steps = 1;
+ this->ecc.size = 2048;
+ this->ecc.bytes = 12;
+ nand_write_reg(NND_ECC_SELECT, 6);
+ }
+
+ /* We have to do bbt scanning ourselves */
+ if (this->scan_bbt (omap_mtd)) {
+ err = -ENXIO;
+ goto out_mtd;
+ }
+
+ err = add_dynamic_parts(omap_mtd);
+ if (err < 0) {
+ printk(KERN_ERR "omap-hw-nand: no partitions defined\n");
+ err = -ENODEV;
+ nand_release(omap_mtd);
+ goto out_mtd;
+ }
+ /* init completed */
+ return 0;
+out_mtd:
+ if (omap_nand_dma_ch >= 0)
+ omap_free_dma(omap_nand_dma_ch);
+ kfree(omap_mtd);
+free_clock:
+ clk_put(omap_nand_clk);
+ return err;
+}
+
+module_init(omap_nand_init);
+
+/*
+ * Clean up routine
+ */
+static void __exit omap_nand_cleanup (void)
+{
+ clk_disable(omap_nand_clk);
+ clk_put(omap_nand_clk);
+ nand_release(omap_mtd);
+ kfree(omap_mtd);
+}
+
+module_exit(omap_nand_cleanup);
+
--- /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/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/flash.h>
+#include <asm/arch/tc.h>
+
+#include <asm/io.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/nand.h>
+
+#define DRIVER_NAME "omapnand"
+
+#ifdef CONFIG_MTD_PARTITIONS
+static const char *part_probes[] = { "cmdlinepart", NULL };
+#endif
+
+struct omap_nand_info {
+ struct omap_nand_platform_data *pdata;
+ struct mtd_partition *parts;
+ struct mtd_info mtd;
+ struct nand_chip nand;
+};
+
+/*
+ * hardware specific access to control-lines
+ * NOTE: boards may use different bits for these!!
+ *
+ * ctrl:
+ * NAND_NCE: bit 0 - don't care
+ * NAND_CLE: bit 1 -> bit 1 (0x0002)
+ * NAND_ALE: bit 2 -> bit 2 (0x0004)
+ */
+
+static void omap_nand_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+{
+ struct nand_chip *chip = mtd->priv;
+ unsigned long mask;
+
+ if (cmd == NAND_CMD_NONE)
+ return;
+
+ mask = (ctrl & NAND_CLE) ? 0x02 : 0;
+ if (ctrl & NAND_ALE)
+ mask |= 0x04;
+ writeb(cmd, (unsigned long)chip->IO_ADDR_W | mask);
+}
+
+static int omap_nand_dev_ready(struct mtd_info *mtd)
+{
+ struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, mtd);
+
+ return info->pdata->dev_ready(info->pdata);
+}
+
+static int __devinit omap_nand_probe(struct platform_device *pdev)
+{
+ struct omap_nand_info *info;
+ struct omap_nand_platform_data *pdata = pdev->dev.platform_data;
+ struct resource *res = pdev->resource;
+ unsigned long size = res->end - res->start + 1;
+ int err;
+
+ info = kzalloc(sizeof(struct omap_nand_info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ if (!request_mem_region(res->start, size, pdev->dev.driver->name)) {
+ err = -EBUSY;
+ goto out_free_info;
+ }
+
+ info->nand.IO_ADDR_R = ioremap(res->start, size);
+ if (!info->nand.IO_ADDR_R) {
+ err = -ENOMEM;
+ goto out_release_mem_region;
+ }
+ info->nand.IO_ADDR_W = info->nand.IO_ADDR_R;
+ info->nand.cmd_ctrl = omap_nand_hwcontrol;
+ info->nand.ecc.mode = NAND_ECC_SOFT;
+ info->nand.options = pdata->options;
+ if (pdata->dev_ready)
+ info->nand.dev_ready = omap_nand_dev_ready;
+ else
+ info->nand.chip_delay = 20;
+
+ info->mtd.name = pdev->dev.bus_id;
+ info->mtd.priv = &info->nand;
+
+ info->pdata = pdata;
+
+ /* DIP switches on H2 and some other boards change between 8 and 16 bit
+ * bus widths for flash. Try the other width if the first try fails.
+ */
+ if (nand_scan(&info->mtd, 1)) {
+ info->nand.options ^= NAND_BUSWIDTH_16;
+ if (nand_scan(&info->mtd, 1)) {
+ err = -ENXIO;
+ goto out_iounmap;
+ }
+ }
+ info->mtd.owner = THIS_MODULE;
+
+#ifdef CONFIG_MTD_PARTITIONS
+ err = parse_mtd_partitions(&info->mtd, part_probes, &info->parts, 0);
+ if (err > 0)
+ add_mtd_partitions(&info->mtd, info->parts, err);
+ else if (err < 0 && pdata->parts)
+ add_mtd_partitions(&info->mtd, pdata->parts, pdata->nr_parts);
+ else
+#endif
+ add_mtd_device(&info->mtd);
+
+ platform_set_drvdata(pdev, info);
+
+ return 0;
+
+out_iounmap:
+ iounmap(info->nand.IO_ADDR_R);
+out_release_mem_region:
+ release_mem_region(res->start, size);
+out_free_info:
+ kfree(info);
+
+ return err;
+}
+
+static int omap_nand_remove(struct platform_device *pdev)
+{
+ struct omap_nand_info *info = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+ /* Release NAND device, its internal structures and partitions */
+ nand_release(&info->mtd);
+ iounmap(info->nand.IO_ADDR_R);
+ kfree(info);
+ return 0;
+}
+
+static struct platform_driver omap_nand_driver = {
+ .probe = omap_nand_probe,
+ .remove = omap_nand_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ },
+};
+MODULE_ALIAS(DRIVER_NAME);
+
+static int __init omap_nand_init(void)
+{
+ return platform_driver_register(&omap_nand_driver);
+}
+
+static void __exit omap_nand_exit(void)
+{
+ platform_driver_unregister(&omap_nand_driver);
+}
+
+module_init(omap_nand_init);
+module_exit(omap_nand_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jian Zhang <jzhang@ti.com> (and others)");
+MODULE_DESCRIPTION("Glue layer for NAND flash on TI OMAP boards");
+
--- /dev/null
+/*
+ * drivers/mtd/nand/omap2.c
+ *
+ * Copyright (c) 2004 Texas Instruments, Jian Zhang <jzhang@ti.com>
+ * Copyright (c) 2004 Micron Technology Inc.
+ * 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/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/io.h>
+
+#include <asm/dma.h>
+
+#include <asm/arch/gpmc.h>
+#include <asm/arch/nand.h>
+
+#define GPMC_IRQ_STATUS 0x18
+#define GPMC_ECC_CONFIG 0x1F4
+#define GPMC_ECC_CONTROL 0x1F8
+#define GPMC_ECC_SIZE_CONFIG 0x1FC
+#define GPMC_ECC1_RESULT 0x200
+
+#define DRIVER_NAME "omap2-nand"
+#define NAND_IO_SIZE SZ_4K
+
+#define NAND_WP_ON 1
+#define NAND_WP_OFF 0
+#define NAND_WP_BIT 0x00000010
+#define WR_RD_PIN_MONITORING 0x00600000
+
+#define GPMC_BUF_FULL 0x00000001
+#define GPMC_BUF_EMPTY 0x00000000
+
+#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)
+
+#ifdef CONFIG_MTD_PARTITIONS
+static const char *part_probes[] = { "cmdlinepart", NULL };
+#endif
+
+static int hw_ecc = 1;
+
+/* new oob placement block for use with hardware ecc generation */
+static struct nand_ecclayout omap_hw_eccoob = {
+ .eccbytes = 12,
+ .eccpos = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13},
+ .oobfree = {{16, 32}, {33, 63} },
+};
+
+struct omap_nand_info {
+ struct nand_hw_control controller;
+ struct omap_nand_platform_data *pdata;
+ struct mtd_info mtd;
+ struct mtd_partition *parts;
+ struct nand_chip nand;
+ struct platform_device *pdev;
+
+ int gpmc_cs;
+ unsigned long phys_base;
+ void __iomem *gpmc_cs_baseaddr;
+ void __iomem *gpmc_baseaddr;
+};
+static void omap_nand_wp(struct mtd_info *mtd, int mode)
+{
+ struct omap_nand_info *info = container_of(mtd,
+ struct omap_nand_info, mtd);
+
+ unsigned long config = __raw_readl(info->gpmc_baseaddr + GPMC_CONFIG);
+
+ if (mode)
+ config &= ~(NAND_WP_BIT); /* WP is ON */
+ else
+ config |= (NAND_WP_BIT); /* WP is OFF */
+
+ __raw_writel(config, (info->gpmc_baseaddr + GPMC_CONFIG));
+}
+
+/*
+ * hardware specific access to control-lines
+ * NOTE: boards may use different bits for these!!
+ *
+ * ctrl:
+ * NAND_NCE: bit 0 - don't care
+ * NAND_CLE: bit 1 -> Command Latch
+ * NAND_ALE: bit 2 -> Address Latch
+ */
+static void omap_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+{
+ struct omap_nand_info *info = container_of(mtd,
+ struct omap_nand_info, mtd);
+ switch (ctrl) {
+ case NAND_CTRL_CHANGE | NAND_CTRL_CLE:
+ info->nand.IO_ADDR_W = info->gpmc_cs_baseaddr +
+ GPMC_CS_NAND_COMMAND;
+ info->nand.IO_ADDR_R = info->gpmc_cs_baseaddr +
+ GPMC_CS_NAND_DATA;
+ break;
+
+ case NAND_CTRL_CHANGE | NAND_CTRL_ALE:
+ info->nand.IO_ADDR_W = info->gpmc_cs_baseaddr +
+ GPMC_CS_NAND_ADDRESS;
+ info->nand.IO_ADDR_R = info->gpmc_cs_baseaddr +
+ GPMC_CS_NAND_DATA;
+ break;
+
+ case NAND_CTRL_CHANGE | NAND_NCE:
+ info->nand.IO_ADDR_W = info->gpmc_cs_baseaddr +
+ GPMC_CS_NAND_DATA;
+ info->nand.IO_ADDR_R = info->gpmc_cs_baseaddr +
+ GPMC_CS_NAND_DATA;
+ break;
+ }
+
+ if (cmd != NAND_CMD_NONE)
+ __raw_writeb(cmd, info->nand.IO_ADDR_W);
+}
+
+/*
+* omap_read_buf - read data from NAND controller into buffer
+* @mtd: MTD device structure
+* @buf: buffer to store date
+* @len: number of bytes to read
+*/
+static void omap_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+ struct omap_nand_info *info = container_of(mtd,
+ struct omap_nand_info, mtd);
+ u16 *p = (u16 *) buf;
+
+ len >>= 1;
+
+ while (len--)
+ *p++ = cpu_to_le16(readw(info->nand.IO_ADDR_R));
+}
+
+/*
+* omap_write_buf - write buffer to NAND controller
+* @mtd: MTD device structure
+* @buf: data buffer
+* @len: number of bytes to write
+*/
+static void omap_write_buf(struct mtd_info *mtd, const u_char * buf, int len)
+{
+ struct omap_nand_info *info = container_of(mtd,
+ struct omap_nand_info, mtd);
+ u16 *p = (u16 *) buf;
+
+ len >>= 1;
+
+ while (len--) {
+ writew(cpu_to_le16(*p++), info->nand.IO_ADDR_W);
+
+ while (GPMC_BUF_EMPTY == (readl(info->gpmc_baseaddr +
+ GPMC_STATUS) & GPMC_BUF_FULL));
+ }
+}
+/*
+ * omap_verify_buf - Verify chip data against buffer
+ * @mtd: MTD device structure
+ * @buf: buffer containing the data to compare
+ * @len: number of bytes to compare
+ */
+static int omap_verify_buf(struct mtd_info *mtd, const u_char * buf, int len)
+{
+ struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
+ mtd);
+ u16 *p = (u16 *) buf;
+
+ len >>= 1;
+
+ while (len--) {
+
+ if (*p++ != cpu_to_le16(readw(info->nand.IO_ADDR_R)))
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static void omap_hwecc_init(struct mtd_info *mtd)
+{
+ struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
+ mtd);
+ unsigned long val = 0x0;
+
+ /* Read from ECC Control Register */
+ val = __raw_readl(info->gpmc_baseaddr + GPMC_ECC_CONTROL);
+ /* Clear all ECC | Enable Reg1 */
+ val = ((0x00000001<<8) | 0x00000001);
+ __raw_writel(val, info->gpmc_baseaddr + GPMC_ECC_CONTROL);
+
+ /* Read from ECC Size Config Register */
+ val = __raw_readl(info->gpmc_baseaddr + GPMC_ECC_SIZE_CONFIG);
+ /* ECCSIZE1=512 | ECCSIZE0=8bytes | Select eccResultsize[0123] */
+ val = ((0x000000FF<<22) | (0x00000003<<12) | (0x0000000F));
+ __raw_writel(val, info->gpmc_baseaddr + GPMC_ECC_SIZE_CONFIG);
+
+
+}
+
+/*
+ * 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_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 11:
+ /* UN-Correctable error */
+ DEBUG(MTD_DEBUG_LEVEL0, "ECC UNCORRECTED_ERROR B\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_correct_data(struct mtd_info *mtd, u_char * dat,
+ u_char * read_ecc, u_char * calc_ecc)
+{
+ struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
+ mtd);
+ int blockCnt = 0, i = 0, ret = 0;
+
+ /* Ex NAND_ECC_HW12_2048 */
+ if ((info->nand.ecc.mode == NAND_ECC_HW) &&
+ (info->nand.ecc.size == 2048))
+ blockCnt = 4;
+ else
+ blockCnt = 1;
+
+ for (i = 0; i < blockCnt; i++) {
+ if (memcmp(read_ecc, calc_ecc, 3) != 0) {
+ ret = omap_compare_ecc(read_ecc, calc_ecc, dat);
+ if (ret < 0) return ret;
+ }
+ read_ecc += 3;
+ calc_ecc += 3;
+ dat += 512;
+ }
+ return 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_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
+ u_char *ecc_code)
+{
+ struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
+ mtd);
+ unsigned long val = 0x0;
+ unsigned long reg, n;
+
+ /* Ex NAND_ECC_HW12_2048 */
+ if ((info->nand.ecc.mode == NAND_ECC_HW) &&
+ (info->nand.ecc.size == 2048))
+ n = 4;
+ else
+ n = 1;
+
+ /* Start Reading from HW ECC1_Result = 0x200 */
+ reg = (unsigned long)(info->gpmc_baseaddr + GPMC_ECC1_RESULT);
+ while (n--) {
+ val = __raw_readl(reg);
+ *ecc_code++ = val; /* P128e, ..., P1e */
+ *ecc_code++ = val >> 16; /* P128o, ..., P1o */
+ /* P2048o, P1024o, P512o, P256o, P2048e, P1024e, P512e, P256e */
+ *ecc_code++ = ((val >> 8) & 0x0f) | ((val >> 20) & 0xf0);
+ reg += 4;
+ }
+
+ return 0;
+} /* omap_calculate_ecc */
+
+static void omap_enable_hwecc(struct mtd_info *mtd, int mode)
+{
+ struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
+ mtd);
+ unsigned long val = __raw_readl(info->gpmc_baseaddr + GPMC_ECC_CONFIG);
+
+ switch (mode) {
+ case NAND_ECC_READ :
+ __raw_writel(0x101, info->gpmc_baseaddr + GPMC_ECC_CONTROL);
+ /* ECC 16 bit col) | ( CS 0 ) | ECC Enable */
+ val = (1 << 7) | (0x0) | (0x1) ;
+ break;
+ case NAND_ECC_READSYN :
+ __raw_writel(0x100, info->gpmc_baseaddr + GPMC_ECC_CONTROL);
+ /* ECC 16 bit col) | ( CS 0 ) | ECC Enable */
+ val = (1 << 7) | (0x0) | (0x1) ;
+ break;
+ case NAND_ECC_WRITE :
+ __raw_writel(0x101, info->gpmc_baseaddr + GPMC_ECC_CONTROL);
+ /* ECC 16 bit col) | ( CS 0 ) | ECC Enable */
+ val = (1 << 7) | (0x0) | (0x1) ;
+ break;
+ default:
+ DEBUG(MTD_DEBUG_LEVEL0, "Error: Unrecognized Mode[%d]!\n",
+ mode);
+ break;
+ }
+
+ __raw_writel(val, info->gpmc_baseaddr + GPMC_ECC_CONFIG);
+}
+
+static int omap_dev_ready(struct mtd_info *mtd)
+{
+ struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
+ mtd);
+ unsigned int val = __raw_readl(info->gpmc_baseaddr + GPMC_IRQ_STATUS);
+
+ if ((val & 0x100) == 0x100) {
+ /* Clear IRQ Interrupt */
+ val |= 0x100;
+ val &= ~(0x0);
+ __raw_writel(val, info->gpmc_baseaddr + GPMC_IRQ_STATUS);
+ } else {
+ unsigned int cnt = 0;
+ while (cnt++ < 0x1FF) {
+ if ((val & 0x100) == 0x100)
+ return 0;
+ val = __raw_readl(info->gpmc_baseaddr +
+ GPMC_IRQ_STATUS);
+ }
+ }
+
+ return 1;
+}
+
+static int __devinit omap_nand_probe(struct platform_device *pdev)
+{
+ struct omap_nand_info *info;
+ struct omap_nand_platform_data *pdata;
+ int err;
+ unsigned long val;
+
+
+ pdata = pdev->dev.platform_data;
+ if (pdata == NULL) {
+ dev_err(&pdev->dev, "platform data missing\n");
+ return -ENODEV;
+ }
+
+ info = kzalloc(sizeof(struct omap_nand_info), GFP_KERNEL);
+ if (!info) return -ENOMEM;
+
+ platform_set_drvdata(pdev, info);
+
+ spin_lock_init(&info->controller.lock);
+ init_waitqueue_head(&info->controller.wq);
+
+ info->pdev = pdev;
+
+ info->gpmc_cs = pdata->cs;
+ info->gpmc_baseaddr = pdata->gpmc_baseaddr;
+ info->gpmc_cs_baseaddr = pdata->gpmc_cs_baseaddr;
+
+ info->mtd.priv = &info->nand;
+ info->mtd.name = pdev->dev.bus_id;
+ info->mtd.owner = THIS_MODULE;
+
+ err = gpmc_cs_request(info->gpmc_cs, NAND_IO_SIZE, &info->phys_base);
+ if (err < 0) {
+ dev_err(&pdev->dev, "Cannot request GPMC CS\n");
+ goto out_free_info;
+ }
+
+ /* Enable RD PIN Monitoring Reg */
+ val = gpmc_cs_read_reg(info->gpmc_cs, GPMC_CS_CONFIG1);
+ val |= WR_RD_PIN_MONITORING;
+ gpmc_cs_write_reg(info->gpmc_cs, GPMC_CS_CONFIG1, val);
+
+ val = gpmc_cs_read_reg(info->gpmc_cs, GPMC_CS_CONFIG7);
+ val &= ~(0xf << 8);
+ val |= (0xc & 0xf) << 8;
+ gpmc_cs_write_reg(info->gpmc_cs, GPMC_CS_CONFIG7, val);
+
+ if (!request_mem_region(info->phys_base, NAND_IO_SIZE,
+ pdev->dev.driver->name)) {
+ err = -EBUSY;
+ goto out_free_cs;
+ }
+
+ info->nand.IO_ADDR_R = ioremap(info->phys_base, NAND_IO_SIZE);
+ if (!info->nand.IO_ADDR_R) {
+ err = -ENOMEM;
+ goto out_release_mem_region;
+ }
+ info->nand.controller = &info->controller;
+
+ info->nand.IO_ADDR_W = info->nand.IO_ADDR_R;
+ info->nand.cmd_ctrl = omap_hwcontrol;
+
+ info->nand.read_buf = omap_read_buf;
+ info->nand.write_buf = omap_write_buf;
+ info->nand.verify_buf = omap_verify_buf;
+
+ info->nand.dev_ready = omap_dev_ready;
+ info->nand.chip_delay = 0;
+
+ /* Options */
+ info->nand.options = NAND_BUSWIDTH_16;
+ info->nand.options |= NAND_SKIP_BBTSCAN;
+
+ if (hw_ecc) {
+ /* init HW ECC */
+ omap_hwecc_init(&info->mtd);
+
+ info->nand.ecc.calculate = omap_calculate_ecc;
+ info->nand.ecc.hwctl = omap_enable_hwecc;
+ info->nand.ecc.correct = omap_correct_data;
+ info->nand.ecc.mode = NAND_ECC_HW;
+ info->nand.ecc.bytes = 12;
+ info->nand.ecc.size = 2048;
+ info->nand.ecc.layout = &omap_hw_eccoob;
+
+ } else {
+ info->nand.ecc.mode = NAND_ECC_SOFT;
+ }
+
+
+ /* DIP switches on some 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_release_mem_region;
+ }
+ }
+
+#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);
+
+ omap_nand_wp(&info->mtd, NAND_WP_OFF);
+
+ platform_set_drvdata(pdev, &info->mtd);
+
+ return 0;
+
+out_release_mem_region:
+ release_mem_region(info->phys_base, NAND_IO_SIZE);
+out_free_cs:
+ gpmc_cs_free(info->gpmc_cs);
+out_free_info:
+ kfree(info);
+
+ return err;
+}
+
+static int omap_nand_remove(struct platform_device *pdev)
+{
+ struct mtd_info *mtd = platform_get_drvdata(pdev);
+ struct omap_nand_info *info = mtd->priv;
+
+ 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->mtd);
+ return 0;
+}
+
+static struct platform_driver omap_nand_driver = {
+ .probe = omap_nand_probe,
+ .remove = omap_nand_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+MODULE_ALIAS(DRIVER_NAME);
+
+static int __init omap_nand_init(void)
+{
+ printk(KERN_INFO "%s driver initializing\n", DRIVER_NAME);
+ 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_DESCRIPTION("Glue layer for NAND flash on TI OMAP boards");
help
Support for OneNAND flash via platform device driver.
+config MTD_ONENAND_OMAP2
+ tristate "OneNAND on OMAP2/OMAP3 support"
+ depends on MTD_ONENAND && (ARCH_OMAP2 || ARCH_OMAP3)
+ help
+ Support for a OneNAND flash device connected to an OMAP2/OMAP3 CPU
+ via the GPMC memory controller.
+
config MTD_ONENAND_OTP
bool "OneNAND OTP Support"
help
# Board specific.
obj-$(CONFIG_MTD_ONENAND_GENERIC) += generic.o
+obj-$(CONFIG_MTD_ONENAND_OMAP2) += omap2.o
# Simulator
obj-$(CONFIG_MTD_ONENAND_SIM) += onenand_sim.o
--- /dev/null
+/*
+ * linux/drivers/mtd/onenand/omap2.c
+ *
+ * OneNAND driver for OMAP2
+ *
+ * Copyright (C) 2005-2006 Nokia Corporation
+ *
+ * Author: Jarkko Lavinen <jarkko.lavinen@nokia.com> and Juha Yrjola
+ * IRQ and DMA support written by Timo Teras
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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/device.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/onenand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+
+#include <asm/io.h>
+#include <asm/mach/flash.h>
+#include <asm/arch/gpmc.h>
+#include <asm/arch/onenand.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/gpmc.h>
+#include <asm/arch/pm.h>
+
+#include <linux/dma-mapping.h>
+#include <asm/dma-mapping.h>
+#include <asm/arch/dma.h>
+
+#include <asm/arch/board.h>
+
+#define DRIVER_NAME "omap2-onenand"
+
+#define ONENAND_IO_SIZE SZ_128K
+#define ONENAND_BUFRAM_SIZE (1024 * 5)
+
+struct omap2_onenand {
+ struct platform_device *pdev;
+ int gpmc_cs;
+ unsigned long phys_base;
+ int gpio_irq;
+ struct mtd_info mtd;
+ struct mtd_partition *parts;
+ struct onenand_chip onenand;
+ struct completion irq_done;
+ struct completion dma_done;
+ int dma_channel;
+ int freq;
+ int (*setup)(void __iomem *base, int freq);
+};
+
+static unsigned short omap2_onenand_readw(void __iomem *addr)
+{
+ return readw(addr);
+}
+
+static void omap2_onenand_writew(unsigned short value, void __iomem *addr)
+{
+ writew(value, addr);
+}
+
+static void omap2_onenand_dma_cb(int lch, u16 ch_status, void *data)
+{
+ struct omap2_onenand *info = data;
+
+ complete(&info->dma_done);
+}
+
+static irqreturn_t omap2_onenand_interrupt(int irq, void *dev_id)
+{
+ struct omap2_onenand *info = dev_id;
+
+ complete(&info->irq_done);
+
+ return IRQ_HANDLED;
+}
+
+static int omap2_onenand_wait(struct mtd_info *mtd, int state)
+{
+ struct omap2_onenand *info = container_of(mtd, struct omap2_onenand, mtd);
+ unsigned int interrupt = 0;
+ unsigned int ctrl;
+ unsigned long timeout;
+ u32 syscfg;
+
+ if (state == FL_RESETING) {
+ int i;
+
+ for (i = 0; i < 20; i++) {
+ udelay(1);
+ interrupt = omap2_onenand_readw(info->onenand.base + ONENAND_REG_INTERRUPT);
+ if (interrupt & ONENAND_INT_MASTER)
+ break;
+ }
+ ctrl = omap2_onenand_readw(info->onenand.base + ONENAND_REG_CTRL_STATUS);
+ if (ctrl & ONENAND_CTRL_ERROR) {
+ printk(KERN_ERR "onenand_wait: reset error! ctrl 0x%04x intr 0x%04x\n", ctrl, interrupt);
+ return -EIO;
+ }
+ if (!(interrupt & ONENAND_INT_RESET)) {
+ printk(KERN_ERR "onenand_wait: reset timeout! ctrl 0x%04x intr 0x%04x\n", ctrl, interrupt);
+ return -EIO;
+ }
+ return 0;
+ }
+
+ if (state != FL_READING) {
+ int result;
+ /* Turn interrupts on */
+ syscfg = omap2_onenand_readw(info->onenand.base + ONENAND_REG_SYS_CFG1);
+ syscfg |= ONENAND_SYS_CFG1_IOBE;
+ omap2_onenand_writew(syscfg, info->onenand.base + ONENAND_REG_SYS_CFG1);
+
+ INIT_COMPLETION(info->irq_done);
+ if (info->gpio_irq) {
+ result = omap_get_gpio_datain(info->gpio_irq);
+ if (result == -1) {
+ ctrl = omap2_onenand_readw(info->onenand.base + ONENAND_REG_CTRL_STATUS);
+ printk(KERN_ERR "onenand_wait: gpio error, state = %d, ctrl = 0x%04x\n", state, ctrl);
+ return -EIO;
+ }
+ } else {
+ result = 0;
+ }
+ if (result == 0) {
+ int retry_cnt = 0;
+retry:
+ result = wait_for_completion_timeout(&info->irq_done,
+ msecs_to_jiffies(20));
+ if (result == 0) {
+ /* Timeout after 20ms */
+ ctrl = omap2_onenand_readw(info->onenand.base + ONENAND_REG_CTRL_STATUS);
+ if (ctrl & ONENAND_CTRL_ONGO) {
+ /* The operation seems to be still going - so give it some more time */
+ retry_cnt += 1;
+ if (retry_cnt < 3)
+ goto retry;
+ interrupt = omap2_onenand_readw(info->onenand.base + ONENAND_REG_INTERRUPT);
+ printk(KERN_ERR "onenand_wait: timeout state=%d ctrl=0x%04x intr=0x%04x\n", state, ctrl, interrupt);
+ return -EIO;
+ }
+ interrupt = omap2_onenand_readw(info->onenand.base + ONENAND_REG_INTERRUPT);
+ if ((interrupt & ONENAND_INT_MASTER) == 0)
+ printk(KERN_WARNING "onenand_wait: timeout state=%d ctrl=0x%04x intr=0x%04x\n", state, ctrl, interrupt);
+ }
+ }
+ } else {
+ /* Turn interrupts off */
+ syscfg = omap2_onenand_readw(info->onenand.base + ONENAND_REG_SYS_CFG1);
+ syscfg &= ~ONENAND_SYS_CFG1_IOBE;
+ omap2_onenand_writew(syscfg, info->onenand.base + ONENAND_REG_SYS_CFG1);
+
+ timeout = jiffies + msecs_to_jiffies(20);
+ while (time_before(jiffies, timeout)) {
+ if (omap2_onenand_readw(info->onenand.base + ONENAND_REG_INTERRUPT) &
+ ONENAND_INT_MASTER)
+ break;
+ }
+ }
+
+ /* To get correct interrupt status in timeout case */
+ interrupt = omap2_onenand_readw(info->onenand.base + ONENAND_REG_INTERRUPT);
+ ctrl = omap2_onenand_readw(info->onenand.base + ONENAND_REG_CTRL_STATUS);
+
+ if (ctrl & ONENAND_CTRL_ERROR) {
+ printk(KERN_ERR "onenand_wait: controller error = 0x%04x\n", ctrl);
+ if (ctrl & ONENAND_CTRL_LOCK)
+ printk(KERN_ERR "onenand_erase: Device is write protected!!!\n");
+ return -EIO;
+ }
+
+ if (ctrl & 0xFE9F)
+ printk(KERN_WARNING "onenand_wait: unexpected controller status = 0x%04x state = %d interrupt = 0x%04x\n", ctrl, state, interrupt);
+
+ if (interrupt & ONENAND_INT_READ) {
+ int ecc = omap2_onenand_readw(info->onenand.base + ONENAND_REG_ECC_STATUS);
+ if (ecc) {
+ if (ecc & ONENAND_ECC_2BIT_ALL) {
+ printk(KERN_ERR "onenand_wait: ECC error = 0x%04x\n", ecc);
+ mtd->ecc_stats.failed++;
+ return -EBADMSG;
+ } else if (ecc & ONENAND_ECC_1BIT_ALL)
+ printk(KERN_NOTICE "onenand_wait: correctable ECC error = 0x%04x\n", ecc);
+ mtd->ecc_stats.corrected++;
+ }
+ } else if (state == FL_READING) {
+ printk(KERN_ERR "onenand_wait: read timeout! ctrl=0x%04x intr=0x%04x\n", ctrl, interrupt);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static inline int omap2_onenand_bufferram_offset(struct mtd_info *mtd, int area)
+{
+ struct onenand_chip *this = mtd->priv;
+
+ if (ONENAND_CURRENT_BUFFERRAM(this)) {
+ if (area == ONENAND_DATARAM)
+ return mtd->writesize;
+ if (area == ONENAND_SPARERAM)
+ return mtd->oobsize;
+ }
+
+ return 0;
+}
+
+static int omap2_onenand_read_bufferram(struct mtd_info *mtd, int area,
+ unsigned char *buffer, int offset,
+ size_t count)
+{
+ struct omap2_onenand *info = container_of(mtd, struct omap2_onenand, mtd);
+ struct onenand_chip *this = mtd->priv;
+ dma_addr_t dma_src, dma_dst;
+ int bram_offset;
+
+ bram_offset = omap2_onenand_bufferram_offset(mtd, area) + area + offset;
+ if (1 || (info->dma_channel < 0) || ((void *) buffer >= (void *) high_memory) ||
+ (bram_offset & 3) || (((unsigned int) buffer) & 3) ||
+ (count < 1024) || (count & 3)) {
+ memcpy(buffer, (void *)(this->base + bram_offset), count);
+ return 0;
+ }
+
+ dma_src = info->phys_base + bram_offset;
+ dma_dst = dma_map_single(&info->pdev->dev, buffer, count, DMA_FROM_DEVICE);
+ if (dma_mapping_error(dma_dst)) {
+ dev_err(&info->pdev->dev,
+ "Couldn't DMA map a %d byte buffer\n",
+ count);
+ return -1;
+ }
+
+ omap_set_dma_transfer_params(info->dma_channel, OMAP_DMA_DATA_TYPE_S32,
+ count / 4, 1, 0, 0, 0);
+ omap_set_dma_src_params(info->dma_channel, 0, OMAP_DMA_AMODE_POST_INC,
+ dma_src, 0, 0);
+ omap_set_dma_dest_params(info->dma_channel, 0, OMAP_DMA_AMODE_POST_INC,
+ dma_dst, 0, 0);
+
+ INIT_COMPLETION(info->dma_done);
+ omap2_block_sleep();
+ omap_start_dma(info->dma_channel);
+ wait_for_completion(&info->dma_done);
+ omap2_allow_sleep();
+
+ dma_unmap_single(&info->pdev->dev, dma_dst, count, DMA_FROM_DEVICE);
+
+ return 0;
+}
+
+static int omap2_onenand_write_bufferram(struct mtd_info *mtd, int area,
+ const unsigned char *buffer, int offset,
+ size_t count)
+{
+ struct omap2_onenand *info = container_of(mtd, struct omap2_onenand, mtd);
+ struct onenand_chip *this = mtd->priv;
+ dma_addr_t dma_src, dma_dst;
+ int bram_offset;
+
+ bram_offset = omap2_onenand_bufferram_offset(mtd, area) + area + offset;
+ if (1 || (info->dma_channel < 0) || ((void *) buffer >= (void *) high_memory) ||
+ (bram_offset & 3) || (((unsigned int) buffer) & 3) ||
+ (count < 1024) || (count & 3)) {
+ memcpy((void *)(this->base + bram_offset), buffer, count);
+ return 0;
+ }
+
+ dma_src = dma_map_single(&info->pdev->dev, (void *) buffer, count,
+ DMA_TO_DEVICE);
+ dma_dst = info->phys_base + bram_offset;
+ if (dma_mapping_error(dma_dst)) {
+ dev_err(&info->pdev->dev,
+ "Couldn't DMA map a %d byte buffer\n",
+ count);
+ return -1;
+ }
+
+ omap_set_dma_transfer_params(info->dma_channel, OMAP_DMA_DATA_TYPE_S16,
+ count / 2, 1, 0, 0, 0);
+ omap_set_dma_src_params(info->dma_channel, 0, OMAP_DMA_AMODE_POST_INC,
+ dma_src, 0, 0);
+ omap_set_dma_dest_params(info->dma_channel, 0, OMAP_DMA_AMODE_POST_INC,
+ dma_dst, 0, 0);
+
+ INIT_COMPLETION(info->dma_done);
+ omap_start_dma(info->dma_channel);
+ wait_for_completion(&info->dma_done);
+
+ dma_unmap_single(&info->pdev->dev, dma_dst, count, DMA_TO_DEVICE);
+
+ return 0;
+}
+
+static struct platform_driver omap2_onenand_driver;
+
+static int __adjust_timing(struct device *dev, void *data)
+{
+ int ret = 0;
+ struct omap2_onenand *info;
+
+ info = dev_get_drvdata(dev);
+
+ BUG_ON(info->setup == NULL);
+
+ /* DMA is not in use so this is all that is needed */
+ ret = info->setup(info->onenand.base, info->freq);
+
+ return ret;
+}
+
+int omap2_onenand_rephase(void)
+{
+ return driver_for_each_device(&omap2_onenand_driver.driver, NULL,
+ NULL, __adjust_timing);
+}
+
+static void __devexit omap2_onenand_shutdown(struct platform_device *pdev)
+{
+ struct omap2_onenand *info = dev_get_drvdata(&pdev->dev);
+
+ /* With certain content in the buffer RAM, the OMAP boot ROM code
+ * can recognize the flash chip incorrectly. Zero it out before
+ * soft reset.
+ */
+ memset(info->onenand.base, 0, ONENAND_BUFRAM_SIZE);
+}
+
+static int __devinit omap2_onenand_probe(struct platform_device *pdev)
+{
+ struct omap_onenand_platform_data *pdata;
+ struct omap2_onenand *info;
+ int r;
+
+ pdata = pdev->dev.platform_data;
+ if (pdata == NULL) {
+ dev_err(&pdev->dev, "platform data missing\n");
+ return -ENODEV;
+ }
+
+ info = kzalloc(sizeof(struct omap2_onenand), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ init_completion(&info->irq_done);
+ init_completion(&info->dma_done);
+ info->gpmc_cs = pdata->cs;
+ info->gpio_irq = pdata->gpio_irq;
+ info->dma_channel = pdata->dma_channel;
+ if (info->dma_channel < 0) {
+ /* if -1, don't use DMA */
+ info->gpio_irq = 0;
+ }
+
+ r = gpmc_cs_request(info->gpmc_cs, ONENAND_IO_SIZE, &info->phys_base);
+ if (r < 0) {
+ dev_err(&pdev->dev, "Cannot request GPMC CS\n");
+ goto err_kfree;
+ }
+
+ if (request_mem_region(info->phys_base, ONENAND_IO_SIZE,
+ pdev->dev.driver->name) == NULL) {
+ dev_err(&pdev->dev, "Cannot reserve memory region at 0x%08lx, size: 0x%x\n",
+ info->phys_base, ONENAND_IO_SIZE);
+ r = -EBUSY;
+ goto err_free_cs;
+ }
+ info->onenand.base = ioremap(info->phys_base, ONENAND_IO_SIZE);
+ if (info->onenand.base == NULL) {
+ r = -ENOMEM;
+ goto err_release_mem_region;
+ }
+
+ if (pdata->onenand_setup != NULL) {
+ r = pdata->onenand_setup(info->onenand.base, info->freq);
+ if (r < 0) {
+ dev_err(&pdev->dev, "Onenand platform setup failed: %d\n", r);
+ goto err_iounmap;
+ }
+ info->setup = pdata->onenand_setup;
+ }
+
+ if (info->gpio_irq) {
+ if ((r = omap_request_gpio(info->gpio_irq)) < 0) {
+ dev_err(&pdev->dev, "Failed to request GPIO%d for OneNAND\n",
+ info->gpio_irq);
+ goto err_iounmap;
+ }
+ omap_set_gpio_direction(info->gpio_irq, 1);
+
+ if ((r = request_irq(OMAP_GPIO_IRQ(info->gpio_irq),
+ omap2_onenand_interrupt, IRQF_TRIGGER_RISING,
+ pdev->dev.driver->name, info)) < 0)
+ goto err_release_gpio;
+ }
+
+ if (info->dma_channel >= 0) {
+ r = omap_request_dma(0, pdev->dev.driver->name,
+ omap2_onenand_dma_cb, (void *) info,
+ &info->dma_channel);
+ if (r == 0) {
+ omap_set_dma_write_mode(info->dma_channel, OMAP_DMA_WRITE_NON_POSTED);
+ omap_set_dma_src_data_pack(info->dma_channel, 1);
+ omap_set_dma_src_burst_mode(info->dma_channel, OMAP_DMA_DATA_BURST_8);
+ omap_set_dma_dest_data_pack(info->dma_channel, 1);
+ omap_set_dma_dest_burst_mode(info->dma_channel, OMAP_DMA_DATA_BURST_8);
+ } else {
+ dev_info(&pdev->dev,
+ "failed to allocate DMA for OneNAND, using PIO instead\n");
+ info->dma_channel = -1;
+ }
+ }
+
+ dev_info(&pdev->dev, "initializing on CS%d, phys base 0x%08lx, virtual base %p\n",
+ info->gpmc_cs, info->phys_base, info->onenand.base);
+
+ info->pdev = pdev;
+ info->mtd.name = pdev->dev.bus_id;
+ info->mtd.priv = &info->onenand;
+ info->mtd.owner = THIS_MODULE;
+
+ if (info->dma_channel >= 0) {
+ info->onenand.wait = omap2_onenand_wait;
+ info->onenand.read_bufferram = omap2_onenand_read_bufferram;
+ info->onenand.write_bufferram = omap2_onenand_write_bufferram;
+ }
+
+ if ((r = onenand_scan(&info->mtd, 1)) < 0)
+ goto err_release_dma;
+
+ switch ((info->onenand.version_id >> 4) & 0xf) {
+ case 0:
+ info->freq = 40;
+ break;
+ case 1:
+ info->freq = 54;
+ break;
+ case 2:
+ info->freq = 66;
+ break;
+ case 3:
+ info->freq = 83;
+ break;
+ }
+
+#ifdef CONFIG_MTD_PARTITIONS
+ if (pdata->parts != NULL)
+ r = add_mtd_partitions(&info->mtd, pdata->parts, pdata->nr_parts);
+ else
+#endif
+ r = add_mtd_device(&info->mtd);
+ if (r < 0)
+ goto err_release_onenand;
+
+ platform_set_drvdata(pdev, info);
+
+ return 0;
+
+err_release_onenand:
+ onenand_release(&info->mtd);
+err_release_dma:
+ if (info->dma_channel != -1)
+ omap_free_dma(info->dma_channel);
+ if (info->gpio_irq)
+ free_irq(OMAP_GPIO_IRQ(info->gpio_irq), info);
+err_release_gpio:
+ if (info->gpio_irq)
+ omap_free_gpio(info->gpio_irq);
+err_iounmap:
+ iounmap(info->onenand.base);
+err_release_mem_region:
+ release_mem_region(info->phys_base, ONENAND_IO_SIZE);
+err_free_cs:
+ gpmc_cs_free(info->gpmc_cs);
+err_kfree:
+ kfree(info);
+
+ return r;
+}
+
+static int __devexit omap2_onenand_remove(struct platform_device *pdev)
+{
+ struct omap2_onenand *info = dev_get_drvdata(&pdev->dev);
+
+ BUG_ON(info == NULL);
+
+#ifdef CONFIG_MTD_PARTITIONS
+ if (info->parts)
+ del_mtd_partitions(&info->mtd);
+ else
+ del_mtd_device(&info->mtd);
+#else
+ del_mtd_device(&info->mtd);
+#endif
+
+ onenand_release(&info->mtd);
+ if (info->dma_channel != -1)
+ omap_free_dma(info->dma_channel);
+ omap2_onenand_shutdown(pdev);
+ platform_set_drvdata(pdev, NULL);
+ if (info->gpio_irq) {
+ free_irq(OMAP_GPIO_IRQ(info->gpio_irq), info);
+ omap_free_gpio(info->gpio_irq);
+ }
+ iounmap(info->onenand.base);
+ release_mem_region(info->phys_base, ONENAND_IO_SIZE);
+ kfree(info);
+
+ return 0;
+}
+
+static struct platform_driver omap2_onenand_driver = {
+ .probe = omap2_onenand_probe,
+ .remove = omap2_onenand_remove,
+ .shutdown = omap2_onenand_shutdown,
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init omap2_onenand_init(void)
+{
+ printk(KERN_INFO "OMAP2 OneNAND driver initializing\n");
+ return platform_driver_register(&omap2_onenand_driver);
+}
+
+static void __exit omap2_onenand_exit(void)
+{
+ platform_driver_unregister(&omap2_onenand_driver);
+}
+
+module_init(omap2_onenand_init);
+module_exit(omap2_onenand_exit);
+
+MODULE_ALIAS(DRIVER_NAME);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jarkko Lavinen <jarkko.lavinen@nokia.com>");
+MODULE_DESCRIPTION("Glue layer for OneNAND flash on OMAP2");
To compile it as a module, choose M here: the module will be called
mcs7780.
+config OMAP_IR
+ tristate "OMAP IrDA(SIR/MIR/FIR)"
+ depends on IRDA && ARCH_OMAP
+ select GPIOEXPANDER_OMAP if (MACH_OMAP_H3 || MACH_OMAP_H4)
+ help
+ Say Y here if you want to build support for the Texas Instruments
+ OMAP IrDA device driver, which supports SIR/MIR/FIR. This driver
+ relies on platform specific helper routines so available capabilities
+ may vary from one OMAP target to another.
+
endmenu
obj-$(CONFIG_VIA_FIR) += via-ircc.o
obj-$(CONFIG_PXA_FICP) += pxaficp_ir.o
obj-$(CONFIG_MCS_FIR) += mcs7780.o
+obj-$(CONFIG_OMAP_IR) += omap-ir.o
obj-$(CONFIG_AU1000_FIR) += au1k_ir.o
# SIR drivers
obj-$(CONFIG_IRTTY_SIR) += irtty-sir.o sir-dev.o
--- /dev/null
+/*
+ * BRIEF MODULE DESCRIPTION
+ *
+ * Infra-red driver for the OMAP1610-H2 and OMAP1710-H3 and H4 Platforms
+ * (SIR/MIR/FIR modes)
+ * (based on omap-sir.c)
+ *
+ * Copyright 2003 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * source@mvista.com
+ *
+ * Copyright 2004 Texas Instruments.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ Modifications:
+ Feb 2004, Texas Instruments
+ - Ported to 2.6 kernel (Feb 2004).
+ *
+ Apr 2004, Texas Instruments
+ - Added support for H3 (Apr 2004).
+ Nov 2004, Texas Instruments
+ - Added support for Power Management.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/slab.h>
+#include <linux/rtnetlink.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/workqueue.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/irmod.h>
+#include <net/irda/wrapper.h>
+#include <net/irda/irda_device.h>
+
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/serial.h>
+#include <asm/mach-types.h>
+#include <asm/dma.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/irda.h>
+
+#define UART3_EFR_EN (1 << 4)
+#define UART3_MCR_EN_TCR_TLR (1 << 6)
+
+#define UART3_LCR_WL_8 (3 << 0)
+#define UART3_LCR_SP2 (1 << 2)
+#define UART3_LCR_DIVEN (1 << 7)
+
+#define UART3_FCR_FIFO_EN (1 << 0)
+#define UART3_FCR_FIFO_RX (1 << 1)
+#define UART3_FCR_FIFO_TX (1 << 2)
+#define UART3_FCR_FIFO_DMA1 (1 << 3)
+#define UART3_FCR_FIFO_TX_TRIG16 (1 << 4)
+#define UART3_FCR_FIFO_RX_TRIG16 (1 << 6)
+#define UART3_FCR_CONFIG (\
+ UART3_FCR_FIFO_EN | UART3_FCR_FIFO_RX |\
+ UART3_FCR_FIFO_TX | UART3_FCR_FIFO_DMA1 |\
+ UART3_FCR_FIFO_TX_TRIG16 |\
+ UART3_FCR_FIFO_RX_TRIG16)
+
+#define UART3_SCR_TX_TRIG1 (1 << 6)
+#define UART3_SCR_RX_TRIG1 (1 << 7)
+
+#define UART3_MDR1_RESET (0x07)
+#define UART3_MDR1_SIR (1 << 0)
+#define UART3_MDR1_MIR (4 << 0)
+#define UART3_MDR1_FIR (5 << 0)
+#define UART3_MDR1_SIP_AUTO (1 << 6)
+
+#define UART3_MDR2_TRIG1 (0 << 1)
+#define UART3_MDR2_IRTX_UNDERRUN (1 << 0)
+
+#define UART3_ACERG_TX_UNDERRUN_DIS (1 << 4)
+#define UART3_ACERG_SD_MODE_LOW (1 << 6)
+#define UART3_ACERG_DIS_IR_RX (1 << 5)
+
+#define UART3_IER_EOF (1 << 5)
+#define UART3_IER_CTS (1 << 7)
+
+#define UART3_IIR_TX_STATUS (1 << 5)
+#define UART3_IIR_EOF (0x80)
+
+#define IS_FIR(omap_ir) ((omap_ir)->speed >= 4000000)
+
+struct omap_irda {
+ unsigned char open;
+ int speed; /* Current IrDA speed */
+ int newspeed;
+
+ struct net_device_stats stats;
+ struct irlap_cb *irlap;
+ struct qos_info qos;
+
+ int rx_dma_channel;
+ int tx_dma_channel;
+
+ dma_addr_t rx_buf_dma_phys; /* Physical address of RX DMA buffer */
+ dma_addr_t tx_buf_dma_phys; /* Physical address of TX DMA buffer */
+
+ void *rx_buf_dma_virt; /* Virtual address of RX DMA buffer */
+ void *tx_buf_dma_virt; /* Virtual address of TX DMA buffer */
+
+ struct device *dev;
+ struct omap_irda_config *pdata;
+};
+
+static void inline uart_reg_out(int idx, u8 val)
+{
+ omap_writeb(val, idx);
+}
+
+static u8 inline uart_reg_in(int idx)
+{
+ u8 b = omap_readb(idx);
+ return b;
+}
+
+/* forward declarations */
+extern void omap_stop_dma(int lch);
+static int omap_irda_set_speed(struct net_device *dev, int speed);
+
+static void omap_irda_start_rx_dma(struct omap_irda *omap_ir)
+{
+ /* Configure DMA */
+ omap_set_dma_src_params(omap_ir->rx_dma_channel, 0x3, 0x0,
+ omap_ir->pdata->src_start,
+ 0, 0);
+
+ omap_enable_dma_irq(omap_ir->rx_dma_channel, 0x01);
+
+ omap_set_dma_dest_params(omap_ir->rx_dma_channel, 0x0, 0x1,
+ omap_ir->rx_buf_dma_phys,
+ 0, 0);
+
+ omap_set_dma_transfer_params(omap_ir->rx_dma_channel, 0x0,
+ IRDA_SKB_MAX_MTU, 0x1,
+ 0x0, omap_ir->pdata->rx_trigger, 0);
+
+ omap_start_dma(omap_ir->rx_dma_channel);
+}
+
+static void omap_start_tx_dma(struct omap_irda *omap_ir, int size)
+{
+ /* Configure DMA */
+ omap_set_dma_dest_params(omap_ir->tx_dma_channel, 0x03, 0x0,
+ omap_ir->pdata->dest_start, 0, 0);
+
+ omap_enable_dma_irq(omap_ir->tx_dma_channel, 0x01);
+
+ omap_set_dma_src_params(omap_ir->tx_dma_channel, 0x0, 0x1,
+ omap_ir->tx_buf_dma_phys,
+ 0, 0);
+
+ omap_set_dma_transfer_params(omap_ir->tx_dma_channel, 0x0, size, 0x1,
+ 0x0, omap_ir->pdata->tx_trigger, 0);
+
+ /* Start DMA */
+ omap_start_dma(omap_ir->tx_dma_channel);
+}
+
+/* DMA RX callback - normally, we should not go here,
+ * it calls only if something is going wrong
+ */
+static void omap_irda_rx_dma_callback(int lch, u16 ch_status, void *data)
+{
+ struct net_device *dev = data;
+ struct omap_irda *omap_ir = netdev_priv(dev);
+
+ printk(KERN_ERR "RX Transfer error or very big frame\n");
+
+ /* Clear interrupts */
+ uart_reg_in(UART3_IIR);
+
+ omap_ir->stats.rx_frame_errors++;
+
+ uart_reg_in(UART3_RESUME);
+
+ /* Re-init RX DMA */
+ omap_irda_start_rx_dma(omap_ir);
+}
+
+/* DMA TX callback - calling when frame transfer has been finished */
+static void omap_irda_tx_dma_callback(int lch, u16 ch_status, void *data)
+{
+ struct net_device *dev = data;
+ struct omap_irda *omap_ir = netdev_priv(dev);
+
+ /*Stop DMA controller */
+ omap_stop_dma(omap_ir->tx_dma_channel);
+}
+
+/*
+ * Set the IrDA communications speed.
+ * Interrupt have to be disabled here.
+ */
+static int omap_irda_startup(struct net_device *dev)
+{
+ struct omap_irda *omap_ir = netdev_priv(dev);
+
+ /* FIXME: use clk_* apis for UART3 clock*/
+ /* Enable UART3 clock and set UART3 to IrDA mode */
+ if (machine_is_omap_h2() || machine_is_omap_h3())
+ omap_writel(omap_readl(MOD_CONF_CTRL_0) | (1 << 31) | (1 << 15),
+ MOD_CONF_CTRL_0);
+
+ /* Only for H2?
+ */
+ if (omap_ir->pdata->transceiver_mode && machine_is_omap_h2()) {
+ /* Is it select_irda on H2 ? */
+ omap_writel(omap_readl(FUNC_MUX_CTRL_A) | 7,
+ FUNC_MUX_CTRL_A);
+ omap_ir->pdata->transceiver_mode(omap_ir->dev, IR_SIRMODE);
+ }
+
+ uart_reg_out(UART3_MDR1, UART3_MDR1_RESET); /* Reset mode */
+
+ /* Clear DLH and DLL */
+ uart_reg_out(UART3_LCR, UART3_LCR_DIVEN);
+
+ uart_reg_out(UART3_DLL, 0);
+ uart_reg_out(UART3_DLH, 0);
+ uart_reg_out(UART3_LCR, 0xbf); /* FIXME: Add #define */
+
+ uart_reg_out(UART3_EFR, UART3_EFR_EN);
+ uart_reg_out(UART3_LCR, UART3_LCR_DIVEN);
+
+ /* Enable access to UART3_TLR and UART3_TCR registers */
+ uart_reg_out(UART3_MCR, UART3_MCR_EN_TCR_TLR);
+
+ uart_reg_out(UART3_SCR, 0);
+ /* Set Rx trigger to 1 and Tx trigger to 1 */
+ uart_reg_out(UART3_TLR, 0);
+
+ /* Set LCR to 8 bits and 1 stop bit */
+ uart_reg_out(UART3_LCR, 0x03);
+
+ /* Clear RX and TX FIFO and enable FIFO */
+ /* Use DMA Req for transfers */
+ uart_reg_out(UART3_FCR, UART3_FCR_CONFIG);
+
+ uart_reg_out(UART3_MCR, 0);
+
+ uart_reg_out(UART3_SCR, UART3_SCR_TX_TRIG1 |
+ UART3_SCR_RX_TRIG1);
+
+ /* Enable UART3 SIR Mode,(Frame-length method to end frames) */
+ uart_reg_out(UART3_MDR1, UART3_MDR1_SIR);
+
+ /* Set Status FIFO trig to 1 */
+ uart_reg_out(UART3_MDR2, 0);
+
+ /* Enables RXIR input */
+ /* and disable TX underrun */
+ /* SEND_SIP pulse */
+ uart_reg_out(UART3_ACREG, UART3_ACERG_SD_MODE_LOW |
+ UART3_ACERG_TX_UNDERRUN_DIS);
+
+ /* Enable EOF Interrupt only */
+ uart_reg_out(UART3_IER, UART3_IER_CTS | UART3_IER_EOF);
+
+ /* Set Maximum Received Frame size to 2048 bytes */
+ uart_reg_out(UART3_RXFLL, 0x00);
+ uart_reg_out(UART3_RXFLH, 0x08);
+
+ uart_reg_in(UART3_RESUME);
+
+ return 0;
+}
+
+static int omap_irda_shutdown(struct omap_irda *omap_ir)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ /* Disable all UART3 Interrupts */
+ uart_reg_out(UART3_IER, 0);
+
+ /* Disable UART3 and disable baud rate generator */
+ uart_reg_out(UART3_MDR1, UART3_MDR1_RESET);
+
+ /* set SD_MODE pin to high and Disable RX IR */
+ uart_reg_out(UART3_ACREG, (UART3_ACERG_DIS_IR_RX |
+ ~(UART3_ACERG_SD_MODE_LOW)));
+
+ /* Clear DLH and DLL */
+ uart_reg_out(UART3_LCR, UART3_LCR_DIVEN);
+ uart_reg_out(UART3_DLL, 0);
+ uart_reg_out(UART3_DLH, 0);
+
+ local_irq_restore(flags);
+
+ return 0;
+}
+
+static irqreturn_t
+omap_irda_irq(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct omap_irda *omap_ir = netdev_priv(dev);
+ struct sk_buff *skb;
+
+ u8 status;
+ int w = 0;
+
+ /* Clear EOF interrupt */
+ status = uart_reg_in(UART3_IIR);
+
+ if (status & UART3_IIR_TX_STATUS) {
+ u8 mdr2 = uart_reg_in(UART3_MDR2);
+ if (mdr2 & UART3_MDR2_IRTX_UNDERRUN)
+ printk(KERN_ERR "IrDA Buffer underrun error\n");
+
+ omap_ir->stats.tx_packets++;
+
+ if (omap_ir->newspeed) {
+ omap_irda_set_speed(dev, omap_ir->newspeed);
+ omap_ir->newspeed = 0;
+ }
+
+ netif_wake_queue(dev);
+ if (!(status & UART3_IIR_EOF))
+ return IRQ_HANDLED;
+ }
+
+ /* Stop DMA and if there are no errors, send frame to upper layer */
+ omap_stop_dma(omap_ir->rx_dma_channel);
+
+ status = uart_reg_in(UART3_SFLSR); /* Take a frame status */
+
+ if (status != 0) { /* Bad frame? */
+ omap_ir->stats.rx_frame_errors++;
+ uart_reg_in(UART3_RESUME);
+ } else {
+ /* We got a frame! */
+ skb = dev_alloc_skb(IRDA_SKB_MAX_MTU);
+
+ if (!skb) {
+ printk(KERN_ERR "omap_sir: out of memory for RX SKB\n");
+ return IRQ_HANDLED;
+ }
+ /*
+ * Align any IP headers that may be contained
+ * within the frame.
+ */
+
+ skb_reserve(skb, 1);
+
+ w = OMAP_DMA_CDAC_REG(omap_ir->rx_dma_channel);
+
+ if (cpu_is_omap16xx())
+ w -= OMAP1_DMA_CDSA_L_REG(omap_ir->rx_dma_channel);
+ if (cpu_is_omap24xx())
+ w -= OMAP2_DMA_CDSA_REG(omap_ir->rx_dma_channel);
+
+ if (!IS_FIR(omap_ir))
+ /* Copy DMA buffer to skb */
+ memcpy(skb_put(skb, w - 2), omap_ir->rx_buf_dma_virt,
+ w - 2);
+ else
+ /* Copy DMA buffer to skb */
+ memcpy(skb_put(skb, w - 4), omap_ir->rx_buf_dma_virt,
+ w - 4);
+
+ skb->dev = dev;
+ skb_reset_mac_header(skb);
+ skb->protocol = htons(ETH_P_IRDA);
+ omap_ir->stats.rx_packets++;
+ omap_ir->stats.rx_bytes += skb->len;
+ netif_receive_skb(skb); /* Send data to upper level */
+ }
+
+ /* Re-init RX DMA */
+ omap_irda_start_rx_dma(omap_ir);
+
+ dev->last_rx = jiffies;
+
+ return IRQ_HANDLED;
+}
+
+static int omap_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct omap_irda *omap_ir = netdev_priv(dev);
+ int speed = irda_get_next_speed(skb);
+ int mtt = irda_get_mtt(skb);
+ int xbofs = irda_get_next_xbofs(skb);
+
+
+ /*
+ * Does this packet contain a request to change the interface
+ * speed? If so, remember it until we complete the transmission
+ * of this frame.
+ */
+ if (speed != omap_ir->speed && speed != -1)
+ omap_ir->newspeed = speed;
+
+ if (xbofs) /* Set number of addtional BOFS */
+ uart_reg_out(UART3_EBLR, xbofs + 1);
+
+ /*
+ * If this is an empty frame, we can bypass a lot.
+ */
+ if (skb->len == 0) {
+ if (omap_ir->newspeed) {
+ omap_ir->newspeed = 0;
+ omap_irda_set_speed(dev, speed);
+ }
+ dev_kfree_skb(skb);
+ return 0;
+ }
+
+ netif_stop_queue(dev);
+
+ /* Copy skb data to DMA buffer */
+ skb_copy_from_linear_data(skb, omap_ir->tx_buf_dma_virt, skb->len);
+
+ /* Copy skb data to DMA buffer */
+ omap_ir->stats.tx_bytes += skb->len;
+
+ /* Set frame length */
+ uart_reg_out(UART3_TXFLL, (skb->len & 0xff));
+ uart_reg_out(UART3_TXFLH, (skb->len >> 8));
+
+ if (mtt > 1000)
+ mdelay(mtt / 1000);
+ else
+ udelay(mtt);
+
+ /* Start TX DMA transfer */
+ omap_start_tx_dma(omap_ir, skb->len);
+
+ /* We can free skb now because it's already in DMA buffer */
+ dev_kfree_skb(skb);
+
+ dev->trans_start = jiffies;
+
+ return 0;
+}
+
+static int
+omap_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd)
+{
+ struct if_irda_req *rq = (struct if_irda_req *)ifreq;
+ struct omap_irda *omap_ir = netdev_priv(dev);
+ int ret = -EOPNOTSUPP;
+
+
+ switch (cmd) {
+ case SIOCSBANDWIDTH:
+ if (capable(CAP_NET_ADMIN)) {
+ /*
+ * We are unable to set the speed if the
+ * device is not running.
+ */
+ if (omap_ir->open)
+ ret = omap_irda_set_speed(dev,
+ rq->ifr_baudrate);
+ else {
+ printk(KERN_ERR "omap_ir: SIOCSBANDWIDTH:"
+ " !netif_running\n");
+ ret = 0;
+ }
+ }
+ break;
+
+ case SIOCSMEDIABUSY:
+ ret = -EPERM;
+ if (capable(CAP_NET_ADMIN)) {
+ irda_device_set_media_busy(dev, TRUE);
+ ret = 0;
+ }
+ break;
+
+ case SIOCGRECEIVING:
+ rq->ifr_receiving = 0;
+ break;
+
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+static struct net_device_stats *omap_irda_stats(struct net_device *dev)
+{
+ struct omap_irda *omap_ir = netdev_priv(dev);
+ return &omap_ir->stats;
+}
+
+static int omap_irda_start(struct net_device *dev)
+{
+ struct omap_irda *omap_ir = netdev_priv(dev);
+ int err;
+
+ omap_ir->speed = 9600;
+
+ err = request_irq(dev->irq, omap_irda_irq, 0, dev->name, dev);
+ if (err)
+ goto err_irq;
+
+ /*
+ * The interrupt must remain disabled for now.
+ */
+ disable_irq(dev->irq);
+
+ /* Request DMA channels for IrDA hardware */
+ if (omap_request_dma(omap_ir->pdata->rx_channel, "IrDA Rx DMA",
+ (void *)omap_irda_rx_dma_callback,
+ dev, &(omap_ir->rx_dma_channel))) {
+ printk(KERN_ERR "Failed to request IrDA Rx DMA\n");
+ goto err_irq;
+ }
+
+ if (omap_request_dma(omap_ir->pdata->tx_channel, "IrDA Tx DMA",
+ (void *)omap_irda_tx_dma_callback,
+ dev, &(omap_ir->tx_dma_channel))) {
+ printk(KERN_ERR "Failed to request IrDA Tx DMA\n");
+ goto err_irq;
+ }
+
+ /* Allocate TX and RX buffers for DMA channels */
+ omap_ir->rx_buf_dma_virt =
+ dma_alloc_coherent(NULL, IRDA_SKB_MAX_MTU,
+ &(omap_ir->rx_buf_dma_phys),
+ GFP_KERNEL);
+
+ if (!omap_ir->rx_buf_dma_virt) {
+ printk(KERN_ERR "Unable to allocate memory for rx_buf_dma\n");
+ goto err_irq;
+ }
+
+ omap_ir->tx_buf_dma_virt =
+ dma_alloc_coherent(NULL, IRDA_SIR_MAX_FRAME,
+ &(omap_ir->tx_buf_dma_phys),
+ GFP_KERNEL);
+
+ if (!omap_ir->tx_buf_dma_virt) {
+ printk(KERN_ERR "Unable to allocate memory for tx_buf_dma\n");
+ goto err_mem1;
+ }
+
+ /*
+ * Setup the serial port for the specified config.
+ */
+ if (omap_ir->pdata->select_irda)
+ omap_ir->pdata->select_irda(omap_ir->dev, IR_SEL);
+
+ err = omap_irda_startup(dev);
+
+ if (err)
+ goto err_startup;
+
+ omap_irda_set_speed(dev, omap_ir->speed = 9600);
+
+ /*
+ * Open a new IrLAP layer instance.
+ */
+ omap_ir->irlap = irlap_open(dev, &omap_ir->qos, "omap_sir");
+
+ err = -ENOMEM;
+ if (!omap_ir->irlap)
+ goto err_irlap;
+
+ /* Now enable the interrupt and start the queue */
+ omap_ir->open = 1;
+
+ /* Start RX DMA */
+ omap_irda_start_rx_dma(omap_ir);
+
+ enable_irq(dev->irq);
+ netif_start_queue(dev);
+
+ return 0;
+
+err_irlap:
+ omap_ir->open = 0;
+ omap_irda_shutdown(omap_ir);
+err_startup:
+ dma_free_coherent(NULL, IRDA_SIR_MAX_FRAME,
+ omap_ir->tx_buf_dma_virt, omap_ir->tx_buf_dma_phys);
+err_mem1:
+ dma_free_coherent(NULL, IRDA_SKB_MAX_MTU,
+ omap_ir->rx_buf_dma_virt, omap_ir->rx_buf_dma_phys);
+err_irq:
+ free_irq(dev->irq, dev);
+ return err;
+}
+
+static int omap_irda_stop(struct net_device *dev)
+{
+ struct omap_irda *omap_ir = netdev_priv(dev);
+
+ disable_irq(dev->irq);
+
+ netif_stop_queue(dev);
+
+ omap_free_dma(omap_ir->rx_dma_channel);
+ omap_free_dma(omap_ir->tx_dma_channel);
+
+ if (omap_ir->rx_buf_dma_virt)
+ dma_free_coherent(NULL, IRDA_SKB_MAX_MTU,
+ omap_ir->rx_buf_dma_virt,
+ omap_ir->rx_buf_dma_phys);
+ if (omap_ir->tx_buf_dma_virt)
+ dma_free_coherent(NULL, IRDA_SIR_MAX_FRAME,
+ omap_ir->tx_buf_dma_virt,
+ omap_ir->tx_buf_dma_phys);
+
+ omap_irda_shutdown(omap_ir);
+
+ /* Stop IrLAP */
+ if (omap_ir->irlap) {
+ irlap_close(omap_ir->irlap);
+ omap_ir->irlap = NULL;
+ }
+
+ omap_ir->open = 0;
+
+ /*
+ * Free resources
+ */
+ free_irq(dev->irq, dev);
+
+ return 0;
+}
+
+static int omap_irda_set_speed(struct net_device *dev, int speed)
+{
+ struct omap_irda *omap_ir = netdev_priv(dev);
+ int divisor;
+ unsigned long flags;
+
+ /* Set IrDA speed */
+ if (speed <= 115200) {
+
+ local_irq_save(flags);
+
+ /* SIR mode */
+ if (omap_ir->pdata->transceiver_mode)
+ omap_ir->pdata->transceiver_mode(omap_ir->dev,
+ IR_SIRMODE);
+
+ /* Set SIR mode */
+ uart_reg_out(UART3_MDR1, 1);
+ uart_reg_out(UART3_EBLR, 1);
+
+ divisor = 48000000 / (16 * speed); /* Base clock 48 MHz */
+
+ uart_reg_out(UART3_LCR, UART3_LCR_DIVEN);
+ uart_reg_out(UART3_DLL, (divisor & 0xff));
+ uart_reg_out(UART3_DLH, (divisor >> 8));
+ uart_reg_out(UART3_LCR, 0x03);
+
+ uart_reg_out(UART3_MCR, 0);
+
+ local_irq_restore(flags);
+ } else if (speed <= 1152000) {
+
+ local_irq_save(flags);
+
+ /* Set MIR mode, auto SIP */
+ uart_reg_out(UART3_MDR1, UART3_MDR1_MIR |
+ UART3_MDR1_SIP_AUTO);
+
+ uart_reg_out(UART3_EBLR, 2);
+
+ divisor = 48000000 / (41 * speed); /* Base clock 48 MHz */
+
+ uart_reg_out(UART3_LCR, UART3_LCR_DIVEN);
+ uart_reg_out(UART3_DLL, (divisor & 0xff));
+ uart_reg_out(UART3_DLH, (divisor >> 8));
+ uart_reg_out(UART3_LCR, 0x03);
+
+ if (omap_ir->pdata->transceiver_mode)
+ omap_ir->pdata->transceiver_mode(omap_ir->dev,
+ IR_MIRMODE);
+
+ local_irq_restore(flags);
+ } else {
+ local_irq_save(flags);
+
+ /* FIR mode */
+ uart_reg_out(UART3_MDR1, UART3_MDR1_FIR |
+ UART3_MDR1_SIP_AUTO);
+
+ if (omap_ir->pdata->transceiver_mode)
+ omap_ir->pdata->transceiver_mode(omap_ir->dev,
+ IR_FIRMODE);
+
+ local_irq_restore(flags);
+ }
+
+ omap_ir->speed = speed;
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+/*
+ * Suspend the IrDA interface.
+ */
+static int omap_irda_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct net_device *dev = platform_get_drvdata(pdev);
+ struct omap_irda *omap_ir = netdev_priv(dev);
+
+ if (!dev)
+ return 0;
+
+ if (omap_ir->open) {
+ /*
+ * Stop the transmit queue
+ */
+ netif_device_detach(dev);
+ disable_irq(dev->irq);
+ omap_irda_shutdown(omap_ir);
+ }
+ return 0;
+}
+
+/*
+ * Resume the IrDA interface.
+ */
+static int omap_irda_resume(struct platform_device *pdev)
+{
+ struct net_device *dev = platform_get_drvdata(pdev);
+ struct omap_irda *omap_ir= netdev_priv(dev);
+
+ if (!dev)
+ return 0;
+
+ if (omap_ir->open) {
+ /*
+ * If we missed a speed change, initialise at the new speed
+ * directly. It is debatable whether this is actually
+ * required, but in the interests of continuing from where
+ * we left off it is desireable. The converse argument is
+ * that we should re-negotiate at 9600 baud again.
+ */
+ if (omap_ir->newspeed) {
+ omap_ir->speed = omap_ir->newspeed;
+ omap_ir->newspeed = 0;
+ }
+
+ omap_irda_startup(dev);
+ omap_irda_set_speed(dev, omap_ir->speed);
+ enable_irq(dev->irq);
+
+ /*
+ * This automatically wakes up the queue
+ */
+ netif_device_attach(dev);
+ }
+
+ return 0;
+}
+#else
+#define omap_irda_suspend NULL
+#define omap_irda_resume NULL
+#endif
+
+static int omap_irda_probe(struct platform_device *pdev)
+{
+ struct net_device *dev;
+ struct omap_irda *omap_ir;
+ struct omap_irda_config *pdata = pdev->dev.platform_data;
+ unsigned int baudrate_mask;
+ int err = 0;
+ int irq = NO_IRQ;
+
+ if (!pdata) {
+ printk(KERN_ERR "IrDA Platform data not supplied\n");
+ return -ENOENT;
+ }
+
+ if (!pdata->rx_channel || !pdata->tx_channel) {
+ printk(KERN_ERR "IrDA invalid rx/tx channel value\n");
+ return -ENOENT;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq <= 0) {
+ printk(KERN_WARNING "no irq for IrDA\n");
+ return -ENOENT;
+ }
+
+ dev = alloc_irdadev(sizeof(struct omap_irda));
+ if (!dev)
+ goto err_mem_1;
+
+
+ omap_ir = netdev_priv(dev);
+ omap_ir->dev = &pdev->dev;
+ omap_ir->pdata = pdata;
+
+ dev->hard_start_xmit = omap_irda_hard_xmit;
+ dev->open = omap_irda_start;
+ dev->stop = omap_irda_stop;
+ dev->do_ioctl = omap_irda_ioctl;
+ dev->get_stats = omap_irda_stats;
+ dev->irq = irq;
+
+ irda_init_max_qos_capabilies(&omap_ir->qos);
+
+ baudrate_mask = 0;
+ if (omap_ir->pdata->transceiver_cap & IR_SIRMODE)
+ baudrate_mask |= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
+ if (omap_ir->pdata->transceiver_cap & IR_MIRMODE)
+ baudrate_mask |= IR_57600 | IR_1152000;
+ if (omap_ir->pdata->transceiver_cap & IR_FIRMODE)
+ baudrate_mask |= IR_4000000 << 8;
+
+ omap_ir->qos.baud_rate.bits &= baudrate_mask;
+ omap_ir->qos.min_turn_time.bits = 7;
+
+ irda_qos_bits_to_value(&omap_ir->qos);
+
+ /* Any better way to avoid this? No. */
+ if (machine_is_omap_h3() || machine_is_omap_h4())
+ INIT_DELAYED_WORK(&omap_ir->pdata->gpio_expa, NULL);
+
+ err = register_netdev(dev);
+ if (!err)
+ platform_set_drvdata(pdev, dev);
+ else
+ free_netdev(dev);
+
+err_mem_1:
+ return err;
+}
+
+static int omap_irda_remove(struct platform_device *pdev)
+{
+ struct net_device *dev = platform_get_drvdata(pdev);
+
+ if (pdev) {
+ unregister_netdev(dev);
+ free_netdev(dev);
+ }
+ return 0;
+}
+
+static struct platform_driver omapir_driver = {
+ .probe = omap_irda_probe,
+ .remove = omap_irda_remove,
+ .suspend = omap_irda_suspend,
+ .resume = omap_irda_resume,
+ .driver = {
+ .name = "omapirda",
+ },
+};
+
+static char __initdata banner[] = KERN_INFO "OMAP IrDA driver initializing\n";
+
+static int __init omap_irda_init(void)
+{
+ printk(banner);
+ return platform_driver_register(&omapir_driver);
+}
+
+static void __exit omap_irda_exit(void)
+{
+ platform_driver_unregister(&omapir_driver);
+}
+
+module_init(omap_irda_init);
+module_exit(omap_irda_exit);
+
+MODULE_AUTHOR("MontaVista");
+MODULE_DESCRIPTION("OMAP IrDA Driver");
+MODULE_LICENSE("GPL");
+
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)) {
help
Say Y to enable support for the battery on the OLPC laptop.
+config BATTERY_BQ27x00
+ tristate "BQ27x00 battery driver"
+ help
+ Say Y here to enable support for batteries with BQ27000 or BQ27200 chip.
+
+config BATTERY_BQ27000
+ bool "BQ27000 battery driver"
+ depends on BATTERY_BQ27x00
+ select W1
+ select W1_SLAVE_BQ27000
+ help
+ Say Y here to enable support for batteries with BQ27000(HDQ) chip.
+
+config BATTERY_BQ27200
+ bool "BQ27200 battery driver"
+ depends on BATTERY_BQ27x00
+ select I2C
+ select I2C_OMAP
+ help
+ Say Y here to enable support for batteries with BQ27200(I2C) chip.
+
endif # POWER_SUPPLY
obj-$(CONFIG_BATTERY_DS2760) += ds2760_battery.o
obj-$(CONFIG_BATTERY_PMU) += pmu_battery.o
obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o
+obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o
--- /dev/null
+/*
+ * linux/drivers/power/bq27x00_battery.c
+ *
+ * BQ27000/BQ27200 battery driver
+ *
+ * Copyright (C) 2008 Texas Instruments, Inc.
+ *
+ * Author: Texas Instruments
+ *
+ * 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/module.h>
+#include <linux/param.h>
+#include <linux/jiffies.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+
+#ifdef CONFIG_BATTERY_BQ27000
+#include "../w1/w1.h"
+#endif
+#ifdef CONFIG_BATTERY_BQ27200
+#include <linux/i2c.h>
+#endif
+
+#define BQ27x00_REG_TEMP 0x06
+#define BQ27x00_REG_VOLT 0x08
+#define BQ27x00_REG_RSOC 0x0B /* Relative State-of-Charge */
+#define BQ27x00_REG_AI 0x14
+#define BQ27x00_REG_FLAGS 0x0A
+#define HIGH_BYTE(A) ((A) << 8)
+
+#ifdef CONFIG_BATTERY_BQ27000
+extern int w1_bq27000_read(struct device *dev, u8 reg);
+#endif
+
+struct bq27x00_device_info;
+struct bq27x00_access_methods {
+ int (*read)(u8 reg, int *rt_value, int b_single,
+ struct bq27x00_device_info *di);
+};
+
+struct bq27x00_device_info {
+ struct device *dev;
+#ifdef CONFIG_BATTERY_BQ27000
+ struct device *w1_dev;
+#endif
+#ifdef CONFIG_BATTERY_BQ27200
+ struct i2c_client *client;
+#endif
+ unsigned long update_time;
+ int voltage_uV;
+ int current_uA;
+ int temp_C;
+ int charge_rsoc;
+ struct bq27x00_access_methods *bus;
+ struct power_supply bat;
+ struct delayed_work monitor_work;
+};
+
+static unsigned int cache_time = 60000;
+module_param(cache_time, uint, 0644);
+MODULE_PARM_DESC(cache_time, "cache time in milliseconds");
+
+static enum power_supply_property bq27x00_battery_props[] = {
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_CHARGE_NOW,
+ POWER_SUPPLY_PROP_CAPACITY,
+ POWER_SUPPLY_PROP_TEMP,
+};
+
+static int bq27x00_read(u8 reg, int *rt_value, int b_single,
+ struct bq27x00_device_info *di);
+
+#ifdef CONFIG_BATTERY_BQ27000
+static int bq27000_battery_probe(struct platform_device *dev);
+static int bq27000_battery_remove(struct platform_device *dev);
+#ifdef CONFIG_PM
+static int bq27000_battery_suspend(struct platform_device *dev,
+ pm_message_t state);
+static int bq27000_battery_resume(struct platform_device *dev);
+#endif /* CONFIG_PM */
+
+static struct platform_driver bq27000_battery_driver = {
+ .probe = bq27000_battery_probe,
+ .remove = bq27000_battery_remove,
+#ifdef CONFIG_PM
+ .suspend = bq27000_battery_suspend,
+ .resume = bq27000_battery_resume,
+#endif /* CONFIG_PM */
+ .driver = {
+ .name = "bq27000-battery",
+ },
+};
+#endif /* CONFIG_BATTERY_BQ27000 */
+
+#ifdef CONFIG_BATTERY_BQ27200
+static int bq27200_battery_probe(struct i2c_client *client);
+static int bq27200_battery_remove(struct i2c_client *client);
+#ifdef CONFIG_PM
+static int bq27200_battery_suspend(struct i2c_client *client,
+ pm_message_t mesg);
+static int bq27200_battery_resume(struct i2c_client *client);
+#endif /* CONFIG_PM */
+static struct i2c_driver bq27200_battery_driver = {
+ .driver = {
+ .name = "bq27200-bat",
+ },
+ .probe = bq27200_battery_probe,
+ .remove = bq27200_battery_remove,
+#ifdef CONFIG_PM
+ .suspend = bq27200_battery_suspend,
+ .resume = bq27200_battery_resume,
+#endif /* CONFIG_PM */
+};
+#endif /* CONFIG_BATTERY_BQ27200 */
+
+/*
+ * Return the battery temperature in Celcius degrees
+ * Or < 0 if something fails.
+ */
+static int bq27x00_battery_temperature(struct bq27x00_device_info *di)
+{
+ int ret, temp = 0;
+
+ ret = bq27x00_read(BQ27x00_REG_TEMP, &temp, 0, di);
+ if (ret) {
+ pr_err("BQ27x00 battery driver:"
+ "Error reading temperature from the battery\n");
+ return ret;
+ }
+
+ return (temp >> 2) - 273;
+}
+
+/*
+ * Return the battery Voltage in milivolts
+ * Or < 0 if something fails.
+ */
+static int bq27x00_battery_voltage(struct bq27x00_device_info *di)
+{
+ int ret, volt = 0;
+
+ ret = bq27x00_read(BQ27x00_REG_VOLT, &volt, 0, di);
+ if (ret) {
+ pr_err("BQ27x00 battery driver:"
+ "Error reading battery voltage from the battery\n");
+ return ret;
+ }
+
+ return volt;
+}
+
+/*
+ * Return the battery average current
+ * Note that current can be negative signed as well
+ * Or 0 if something fails.
+ */
+static int bq27x00_battery_current(struct bq27x00_device_info *di)
+{
+ int ret, curr = 0, flags = 0;
+
+ ret = bq27x00_read(BQ27x00_REG_AI, &curr, 0, di);
+ if (ret) {
+ pr_err("BQ27x00 battery driver:"
+ "Error reading current from the battery\n");
+ return 0;
+ }
+ ret = bq27x00_read(BQ27x00_REG_FLAGS, &flags, 0, di);
+ if (ret < 0) {
+ pr_err("BQ27x00 battery driver:"
+ "Error reading battery flags\n");
+ return 0;
+ }
+ if ((flags & (1 << 7)) != 0) {
+ pr_debug("Negative current\n");
+ return -curr;
+ } else {
+ return curr;
+ }
+}
+
+/*
+ * Return the battery Relative State-of-Charge
+ * Or < 0 if something fails.
+ */
+static int bq27x00_battery_rsoc(struct bq27x00_device_info *di)
+{
+ int ret, rsoc = 0;
+
+ ret = bq27x00_read(BQ27x00_REG_RSOC, &rsoc, 1, di);
+ if (ret) {
+ pr_err("BQ27x00 battery driver:"
+ "Error reading battery Relative"
+ "State-of-Charge\n");
+ return ret;
+ }
+ return rsoc;
+}
+
+#ifdef CONFIG_BATTERY_BQ27000
+static inline int bq27000_read(u8 reg, int *rt_value, int b_single,
+ struct bq27x00_device_info *di)
+{
+ u8 val;
+
+ val = w1_bq27000_read(di->w1_dev, reg);
+ *rt_value = val;
+
+ if (!b_single) {
+ val = 0;
+ val = w1_bq27000_read(di->w1_dev, reg + 1);
+ *rt_value += HIGH_BYTE((int) val);
+ }
+
+ return 0;
+}
+#else
+static inline int bq27000_read(u8 reg, int *rt_value, int b_single,
+ struct bq27x00_device_info *di)
+{
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_BATTERY_BQ27200
+static inline int bq27200_read(u8 reg, int *rt_value, int b_single,
+ struct bq27x00_device_info *di)
+{
+ struct i2c_client *client = di->client;
+ struct i2c_msg msg[1];
+ unsigned char data[2];
+ int err;
+
+ if (!client->adapter)
+ return -ENODEV;
+
+ msg->addr = client->addr;
+ msg->flags = 0;
+ msg->len = 1;
+ msg->buf = data;
+
+ data[0] = reg;
+ err = i2c_transfer(client->adapter, msg, 1);
+
+ if (err >= 0) {
+ if (!b_single)
+ msg->len = 2;
+ else
+ msg->len = 1;
+
+ msg->flags = I2C_M_RD;
+ err = i2c_transfer(client->adapter, msg, 1);
+ if (err >= 0) {
+ if (!b_single)
+ *rt_value = data[1] | HIGH_BYTE(data[0]);
+ else
+ *rt_value = data[0];
+
+ return 0;
+ } else {
+ pr_err("BQ27200 I2C read failed\n");
+ return err;
+ }
+ } else {
+ pr_err("BQ27200 I2C write failed\n");
+ return err;
+ }
+}
+#else
+static inline int bq27200_read(u8 reg, int *rt_value, int b_single,
+ struct bq27x00_device_info *di)
+{
+ return 0;
+}
+#endif
+
+static int bq27x00_read(u8 reg, int *rt_value, int b_single,
+ struct bq27x00_device_info *di)
+{
+ int ret;
+
+ ret = di->bus->read(reg, rt_value, b_single, di);
+ return ret;
+}
+
+/*
+ * Read the battery temp, voltage, current and relative state of charge.
+ */
+static void bq27x00_battery_read_status(struct bq27x00_device_info *di)
+{
+ if (di->update_time && time_before(jiffies, di->update_time +
+ msecs_to_jiffies(cache_time)))
+ return;
+
+ di->temp_C = bq27x00_battery_temperature(di);
+ di->voltage_uV = bq27x00_battery_voltage(di);
+ di->current_uA = bq27x00_battery_current(di);
+ di->charge_rsoc = bq27x00_battery_rsoc(di);
+
+ di->update_time = jiffies;
+
+ return;
+}
+
+static void bq27x00_battery_work(struct delayed_work *work)
+{
+ struct bq27x00_device_info *di = container_of(work,
+ struct bq27x00_device_info, monitor_work);
+
+ bq27x00_battery_read_status(di);
+ schedule_delayed_work(&di->monitor_work, 100);
+ return;
+}
+
+#define to_bq27x00_device_info(x) container_of((x), \
+ struct bq27x00_device_info, bat);
+
+static int bq27x00_battery_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct bq27x00_device_info *di = to_bq27x00_device_info(psy);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ val->intval = di->voltage_uV;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ val->intval = di->current_uA;
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_NOW:
+ val->intval = di->charge_rsoc;
+ break;
+ case POWER_SUPPLY_PROP_TEMP:
+ val->intval = di->temp_C;
+ break;
+ case POWER_SUPPLY_PROP_CAPACITY:
+ val->intval = di->charge_rsoc;
+ break;
+ case POWER_SUPPLY_PROP_PRESENT:
+ if (di->voltage_uV == 0)
+ val->intval = 0;
+ else
+ val->intval = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void bq27x00_powersupply_init(struct bq27x00_device_info *di)
+{
+ di->bat.type = POWER_SUPPLY_TYPE_BATTERY;
+ di->bat.properties = bq27x00_battery_props;
+ di->bat.num_properties = ARRAY_SIZE(bq27x00_battery_props);
+ di->bat.get_property = bq27x00_battery_get_property;
+ di->bat.external_power_changed = NULL;
+ return;
+}
+
+#ifdef CONFIG_BATTERY_BQ27200
+static int bq27200_battery_probe(struct i2c_client *client)
+{
+ struct bq27x00_device_info *di;
+ struct bq27x00_access_methods *bus;
+ int retval = 0;
+
+ di = kzalloc(sizeof(*di), GFP_KERNEL);
+ if (!di) {
+ pr_err("BQ27000 battery driver:"
+ "Failed to allocate device info structure\n");
+ return -ENOMEM;
+ }
+
+ bus = kzalloc(sizeof(*bus), GFP_KERNEL);
+ if (!bus) {
+ pr_err("BQ27000 battery driver:"
+ "Failed to allocate access method structure\n");
+ kfree(di);
+ return -ENOMEM;
+ }
+
+ i2c_set_clientdata(client, di);
+ di->dev = &client->dev;
+ di->bat.name = "bq27200";
+ bus->read = &bq27200_read;
+ di->bus = bus;
+ di->client = client;
+
+ bq27x00_powersupply_init(di);
+
+ retval = power_supply_register(&client->dev, &di->bat);
+ if (retval) {
+ pr_err("BQ27200 battery driver: Failed to register battery\n");
+ goto batt_failed;
+ }
+
+ INIT_DELAYED_WORK(&di->monitor_work, bq27x00_battery_work);
+ schedule_delayed_work(&di->monitor_work, 100);
+
+ return 0;
+
+batt_failed:
+ kfree(bus);
+ kfree(di);
+ return retval;
+}
+
+static int bq27200_battery_remove(struct i2c_client *client)
+{
+ struct bq27x00_device_info *di = i2c_get_clientdata(client);
+
+ flush_scheduled_work();
+ power_supply_unregister(&di->bat);
+ kfree(di);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int bq27200_battery_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+ struct bq27x00_device_info *di = i2c_get_clientdata(client);
+
+ cancel_delayed_work(&di->monitor_work);
+ return 0;
+}
+
+static int bq27200_battery_resume(struct i2c_client *client)
+{
+ struct bq27x00_device_info *di = i2c_get_clientdata(client);
+
+ schedule_delayed_work(&di->monitor_work, 0);
+ return 0;
+}
+#endif /* CONFIG_PM */
+#endif /* CONFIG_BATTERY_BQ27200 */
+
+#ifdef CONFIG_BATTERY_BQ27000
+static int bq27000_battery_probe(struct platform_device *pdev)
+{
+ struct bq27x00_device_info *di;
+ struct bq27x00_access_methods *bus;
+ int retval = 0;
+
+ di = kzalloc(sizeof(*di), GFP_KERNEL);
+ if (!di) {
+ pr_err("BQ27000 battery driver:"
+ "Failed to allocate device info structure\n");
+ return -ENOMEM;
+ }
+
+ bus = kzalloc(sizeof(*bus), GFP_KERNEL);
+ if (!bus) {
+ pr_err("BQ27000 battery driver:"
+ "Failed to allocate access method structure\n");
+ kfree(di);
+ return -ENOMEM;
+ }
+
+ platform_set_drvdata(pdev, di);
+
+ di->dev = &pdev->dev;
+ di->w1_dev = pdev->dev.parent;
+ di->bat.name = "bq27000";
+ bus->read = &bq27000_read;
+ di->bus = bus;
+
+ bq27x00_powersupply_init(di);
+
+ retval = power_supply_register(&pdev->dev, &di->bat);
+ if (retval) {
+ pr_err("BQ27000 battery driver: Failed to register battery\n");
+ goto batt_failed;
+ }
+
+ INIT_DELAYED_WORK(&di->monitor_work, bq27x00_battery_work);
+ schedule_delayed_work(&di->monitor_work, 50);
+
+ return 0;
+
+batt_failed:
+ kfree(bus);
+ kfree(di);
+ return retval;
+}
+
+static int bq27000_battery_remove(struct platform_device *pdev)
+{
+ struct bq27x00_device_info *di = platform_get_drvdata(pdev);
+
+ flush_scheduled_work();
+ power_supply_unregister(&di->bat);
+ platform_set_drvdata(pdev, NULL);
+ kfree(di);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int bq27000_battery_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ struct bq27x00_device_info *di = platform_get_drvdata(pdev);
+
+ cancel_delayed_work(&di->monitor_work);
+ return 0;
+}
+
+static int bq27000_battery_resume(struct platform_device *pdev)
+{
+ struct bq27x00_device_info *di = platform_get_drvdata(pdev);
+
+ schedule_delayed_work(&di->monitor_work, 0);
+ return 0;
+}
+#endif /* CONFIG_PM */
+#endif /* CONFIG_BATTERY_BQ27000 */
+
+static int __init bq27x00_battery_init(void)
+{
+ int status = 0;
+
+#ifdef CONFIG_BATTERY_BQ27000
+ status = platform_driver_register(&bq27000_battery_driver);
+ if (status)
+ printk(KERN_ERR "Unable to register BQ27000 driver\n");
+#endif
+#ifdef CONFIG_BATTERY_BQ27200
+ status = i2c_add_driver(&bq27200_battery_driver);
+ printk(KERN_ERR "Unable to register BQ27200 driver\n");
+#endif
+ return status;
+}
+
+static void __exit bq27x00_battery_exit(void)
+{
+#ifdef CONFIG_BATTERY_BQ27000
+ platform_driver_unregister(&bq27000_battery_driver);
+#endif
+#ifdef CONFIG_BATTERY_BQ27200
+ i2c_del_driver(&bq27200_battery_driver);
+#endif
+}
+
+module_init(bq27x00_battery_init);
+module_exit(bq27x00_battery_exit);
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("BQ27x00 battery moniter driver");
+MODULE_LICENSE("GPL");
platforms. The support is integrated with the rest of
the Menelaus driver; it's not separate module.
+config RTC_DRV_TWL4030
+ tristate "OMAP TWL4030 Real Time Clock"
+ depends on RTC_CLASS && TWL4030_CORE
+ help
+ If you say yes here you get support for internal Real-Time
+ Clock of TWL4030 chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-twl4030.
+
config RTC_DRV_S35390A
tristate "Seiko Instruments S-35390A"
select BITREVERSE
obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o
obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o
obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o
+obj-$(CONFIG_RTC_DRV_TWL4030) += rtc-twl4030.o
obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o
obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o
obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o
--- /dev/null
+/*
+ * drivers/rtc/rtc-twl4030.c
+ *
+ * TWL4030 Real Time Clock interface
+ *
+ * Copyright (C) 2007 MontaVista Software, Inc
+ * Author: Alexandre Rusev <source@mvista.com>
+ *
+ * Based on original TI driver twl4030-rtc.c
+ * Copyright (C) 2006 Texas Instruments, Inc.
+ *
+ * Based on rtc-omap.c
+ * Copyright (C) 2003 MontaVista Software, Inc.
+ * Author: George G. Davis <gdavis@mvista.com> or <source@mvista.com>
+ *
+ * Copyright (C) 2006 David Brownell
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/i2c/twl4030.h>
+#include <linux/i2c/twl4030-rtc.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+
+#include <asm/mach/time.h>
+#include <asm/system.h>
+#include <asm/hardware.h>
+
+#define ALL_TIME_REGS 6
+
+/*
+ * If this driver ever becomes modularised, it will be really nice
+ * to make the epoch retain its value across module reload...
+ */
+static int epoch = 1900; /* year corresponding to 0x00 */
+
+/*
+ * Supports 1 byte read from TWL4030 RTC register.
+ */
+static int twl4030_rtc_read_u8(u8 *data, u8 reg)
+{
+ int ret;
+
+ ret = twl4030_i2c_read_u8(TWL4030_MODULE_RTC, data, reg);
+ if (ret < 0) {
+ printk(KERN_WARNING "twl4030_rtc: Could not read TWL4030"
+ "register %X - returned %d[%x]\n", reg, ret, ret);
+ }
+ return ret;
+}
+
+/*
+ * Supports 1 byte write to TWL4030 RTC registers.
+ */
+static int twl4030_rtc_write_u8(u8 data, u8 reg)
+{
+ int ret;
+
+ ret = twl4030_i2c_write_u8(TWL4030_MODULE_RTC, data, reg);
+ if (ret < 0) {
+ printk(KERN_WARNING "twl4030_rtc: Could not write TWL4030"
+ "register %X - returned %d[%x]\n", reg, ret, ret);
+ }
+ return ret;
+}
+
+/*
+ * Enables timer or alarm interrupts.
+ */
+static int set_rtc_irq_bit(unsigned char bit)
+{
+ unsigned char val;
+ int ret;
+
+ ret = twl4030_rtc_read_u8(&val, REG_RTC_INTERRUPTS_REG);
+ if (ret < 0)
+ goto set_irq_out;
+
+ val |= bit;
+ ret = twl4030_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG);
+
+set_irq_out:
+ return ret;
+}
+
+#ifdef CONFIG_PM
+/*
+ * Read timer or alarm interrupts register.
+ */
+static int get_rtc_irq_bit(unsigned char *val)
+{
+ int ret;
+
+ ret = twl4030_rtc_read_u8(val, REG_RTC_INTERRUPTS_REG);
+ return ret;
+}
+#endif
+/*
+ * Disables timer or alarm interrupts.
+ */
+static int mask_rtc_irq_bit(unsigned char bit)
+{
+ unsigned char val;
+ int ret;
+
+ ret = twl4030_rtc_read_u8(&val, REG_RTC_INTERRUPTS_REG);
+ if (ret < 0)
+ goto mask_irq_out;
+
+ val &= ~bit;
+ ret = twl4030_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG);
+
+mask_irq_out:
+ return ret;
+}
+
+static int twl4030_rtc_alarm_irq_set_state(struct device *dev, int enabled)
+{
+ int ret;
+
+ /* Allow ints for RTC ALARM updates. */
+ if (enabled)
+ ret = set_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
+ else
+ ret = mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
+
+ return ret;
+}
+
+/*
+ * Gets current TWL4030 RTC time and date parameters.
+ */
+static int get_rtc_time(struct rtc_time *rtc_tm)
+{
+ unsigned char rtc_data[ALL_TIME_REGS + 1];
+ int ret;
+ u8 save_control;
+
+ ret = twl4030_rtc_read_u8(&save_control, REG_RTC_CTRL_REG);
+ if (ret < 0)
+ return ret;
+
+ save_control |= BIT_RTC_CTRL_REG_GET_TIME_M;
+
+ ret = twl4030_rtc_write_u8(save_control, REG_RTC_CTRL_REG);
+ if (ret < 0)
+ return ret;
+
+ ret = twl4030_i2c_read(TWL4030_MODULE_RTC, rtc_data,
+ REG_SECONDS_REG, ALL_TIME_REGS);
+
+ if (ret < 0) {
+ printk(KERN_ERR "twl4030_rtc: twl4030_i2c_read error.\n");
+ return ret;
+ }
+
+ rtc_tm->tm_sec = BCD2BIN(rtc_data[0]);
+ rtc_tm->tm_min = BCD2BIN(rtc_data[1]);
+ rtc_tm->tm_hour = BCD2BIN(rtc_data[2]);
+ rtc_tm->tm_mday = BCD2BIN(rtc_data[3]);
+ rtc_tm->tm_mon = BCD2BIN(rtc_data[4]);
+ rtc_tm->tm_year = BCD2BIN(rtc_data[5]);
+
+ /*
+ * Account for differences between how the RTC uses the values
+ * and how they are defined in a struct rtc_time;
+ */
+ rtc_tm->tm_year += (epoch - 1900);
+ if (rtc_tm->tm_year <= 69)
+ rtc_tm->tm_year += 100;
+
+ rtc_tm->tm_mon--;
+
+ return ret;
+}
+
+static int twl4030_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ unsigned char save_control;
+ unsigned char rtc_data[ALL_TIME_REGS + 1];
+ int ret;
+
+ /* Month range is 01..12 */
+ tm->tm_mon++;
+
+ rtc_data[1] = BIN2BCD(tm->tm_sec);
+ rtc_data[2] = BIN2BCD(tm->tm_min);
+ rtc_data[3] = BIN2BCD(tm->tm_hour);
+ rtc_data[4] = BIN2BCD(tm->tm_mday);
+ rtc_data[5] = BIN2BCD(tm->tm_mon);
+ rtc_data[6] = BIN2BCD(tm->tm_year);
+
+ /* Stop RTC while updating the TC registers */
+ ret = twl4030_rtc_read_u8(&save_control, REG_RTC_CTRL_REG);
+ if (ret < 0)
+ goto out;
+
+ save_control &= ~BIT_RTC_CTRL_REG_STOP_RTC_M;
+ twl4030_rtc_write_u8(save_control, REG_RTC_CTRL_REG);
+ if (ret < 0)
+ goto out;
+
+ /* update all the alarm registers in one shot */
+ ret = twl4030_i2c_write(TWL4030_MODULE_RTC, rtc_data,
+ REG_SECONDS_REG, ALL_TIME_REGS);
+ if (ret < 0) {
+ printk(KERN_ERR "twl4030: twl4030_i2c_write error.\n");
+ goto out;
+ }
+
+ /* Start back RTC */
+ save_control |= BIT_RTC_CTRL_REG_STOP_RTC_M;
+ ret = twl4030_rtc_write_u8(save_control, REG_RTC_CTRL_REG);
+
+out:
+ return ret;
+}
+
+/*
+ * Gets current TWL4030 RTC alarm time.
+ */
+static int get_rtc_alm_time(struct rtc_time *alm_tm)
+{
+ unsigned char rtc_data[ALL_TIME_REGS + 1];
+ int ret;
+
+ ret = twl4030_i2c_read(TWL4030_MODULE_RTC, rtc_data,
+ REG_ALARM_SECONDS_REG, ALL_TIME_REGS);
+ if (ret < 0) {
+ printk(KERN_ERR "twl4030_rtc: twl4030_i2c_read error.\n");
+ return ret;
+ }
+
+ alm_tm->tm_sec = BCD2BIN(rtc_data[0]);
+ alm_tm->tm_min = BCD2BIN(rtc_data[1]);
+ alm_tm->tm_hour = BCD2BIN(rtc_data[2]);
+ alm_tm->tm_mday = BCD2BIN(rtc_data[3]);
+ alm_tm->tm_mon = BCD2BIN(rtc_data[4]);
+ alm_tm->tm_year = BCD2BIN(rtc_data[5]);
+
+ /*
+ * Account for differences between how the RTC uses the values
+ * and how they are defined in a struct rtc_time;
+ */
+ alm_tm->tm_year += (epoch - 1900);
+ if (alm_tm->tm_year <= 69)
+ alm_tm->tm_year += 100;
+
+ alm_tm->tm_mon--;
+
+ return ret;
+}
+
+static int twl4030_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ int ret;
+
+ memset(tm, 0, sizeof(struct rtc_time));
+ ret = get_rtc_time(tm);
+
+ return ret;
+}
+
+/*
+ * Gets current TWL4030 RTC alarm time.
+ */
+static int twl4030_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
+{
+ int ret;
+ u8 rtc_interrupts_reg = 0;
+
+ /*
+ * 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(&alm->time, 0, sizeof(struct rtc_time));
+ ret = get_rtc_alm_time(&alm->time);
+
+ if (ret)
+ goto out;
+
+ /* Check alarm enabled flag state */
+ ret =
+ ret | twl4030_i2c_read_u8(TWL4030_MODULE_RTC, &rtc_interrupts_reg,
+ REG_RTC_INTERRUPTS_REG);
+
+ if (ret)
+ goto out;
+
+ if ((rtc_interrupts_reg & BIT_RTC_INTERRUPTS_REG_IT_ALARM_M) != 0)
+ alm->enabled = 1;
+ else
+ alm->enabled = 0;
+
+out:
+ return ret;
+}
+
+static int twl4030_rtc_irq_set_state(struct device *dev, int enabled)
+{
+ int ret;
+
+ /* Allow ints for RTC updates. */
+ if (enabled)
+ ret = set_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
+ else
+ ret = mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
+
+ return ret;
+}
+
+static int twl4030_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
+{
+ unsigned char alarm_data[ALL_TIME_REGS + 1];
+ int ret;
+
+ /* Month range is 01..12 */
+ alm->time.tm_mon++;
+
+ alarm_data[1] = BIN2BCD(alm->time.tm_sec);
+ alarm_data[2] = BIN2BCD(alm->time.tm_min);
+ alarm_data[3] = BIN2BCD(alm->time.tm_hour);
+ alarm_data[4] = BIN2BCD(alm->time.tm_mday);
+ alarm_data[5] = BIN2BCD(alm->time.tm_mon);
+ alarm_data[6] = BIN2BCD(alm->time.tm_year);
+
+ /* update all the alarm registers in one shot */
+ ret = twl4030_i2c_write(TWL4030_MODULE_RTC, alarm_data,
+ REG_ALARM_SECONDS_REG, ALL_TIME_REGS);
+ if (ret) {
+ printk(KERN_ERR "twl4030: twl4030_i2c_write error.\n");
+ goto out;
+ }
+
+ ret = twl4030_rtc_alarm_irq_set_state(dev, alm->enabled);
+out:
+ return ret;
+}
+
+/*
+ * We will just handle setting the frequency and make use the framework for
+ * reading the periodic interupts.
+ * @freq: Current periodic IRQ freq
+ */
+static int twl4030_rtc_irq_set_freq(struct device *dev, int freq)
+{
+ struct rtc_device *rtc = dev_get_drvdata(dev);
+
+ if (freq < 0 || freq > 3)
+ return -EINVAL;
+
+ rtc->irq_freq = freq;
+
+ /* set rtc irq freq to user defined value */
+ set_rtc_irq_bit(freq);
+
+ return 0;
+}
+
+#ifdef CONFIG_RTC_INTF_DEV
+
+static int twl4030_rtc_ioctl(struct device *dev, unsigned int cmd,
+ unsigned long arg)
+{
+
+ switch (cmd) {
+ case RTC_AIE_OFF:
+ return twl4030_rtc_alarm_irq_set_state(dev, 0);
+ case RTC_AIE_ON:
+ return twl4030_rtc_alarm_irq_set_state(dev, 1);
+
+ case RTC_UIE_OFF:
+ /* Fall Through */
+ case RTC_PIE_OFF:
+ /* Mask ints from RTC updates. */
+ return twl4030_rtc_irq_set_state(dev, 0);
+ case RTC_UIE_ON:
+ /* Fall Through */
+ case RTC_PIE_ON:
+ /* Allow ints for RTC updates. */
+ return twl4030_rtc_irq_set_state(dev, 1);
+
+ case RTC_EPOCH_READ:
+ return put_user(epoch, (unsigned long *)arg);
+ case RTC_EPOCH_SET:
+ /*
+ * There were no RTC clocks before 1900.
+ */
+ if (arg < 1900)
+ return -EINVAL;
+
+ if (!capable(CAP_SYS_TIME))
+ return -EACCES;
+
+ epoch = arg;
+ return 0;
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
+#else
+#define omap_rtc_ioctl NULL
+#endif
+
+static irqreturn_t twl4030_rtc_interrupt(int irq, void *rtc)
+{
+ unsigned long events = 0;
+ int ret = IRQ_NONE;
+ int res;
+ u8 rd_reg;
+
+ res = twl4030_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG);
+ if (res)
+ goto out;
+ /*
+ * Figure out source of interrupt: ALARM or TIMER in RTC_STATUS_REG.
+ * only one (ALARM or RTC) interrupt source may be enabled
+ * at time, we also could check our results
+ * by reading RTS_INTERRUPTS_REGISTER[IT_TIMER,IT_ALARM]
+ */
+ if (rd_reg & BIT_RTC_STATUS_REG_ALARM_M)
+ events |= RTC_IRQF | RTC_AF;
+ else
+ events |= RTC_IRQF | RTC_UF;
+
+ res = twl4030_rtc_write_u8(rd_reg | BIT_RTC_STATUS_REG_ALARM_M,
+ REG_RTC_STATUS_REG);
+ if (res)
+ goto out;
+ /*
+ * Workaround for strange behaviour with T2. Need to write into ISR
+ * register one more time to clear the interrupt. Otherwise, the same
+ * RTC event generates 2 interrupts in a row.
+ * (no errata document available)
+ */
+ res = twl4030_i2c_write_u8(TWL4030_MODULE_INT,
+ PWR_RTC_INT_CLR, REG_PWR_ISR1);
+ if (res)
+ goto out;
+
+ /* Notify RTC core on event */
+ rtc_update_irq(rtc, 1, events);
+
+ ret = IRQ_HANDLED;
+out:
+ return ret;
+}
+
+static struct rtc_class_ops twl4030_rtc_ops = {
+ .ioctl = twl4030_rtc_ioctl,
+ .read_time = twl4030_rtc_read_time,
+ .set_time = twl4030_rtc_set_time,
+ .read_alarm = twl4030_rtc_read_alarm,
+ .set_alarm = twl4030_rtc_set_alarm,
+ .irq_set_freq = twl4030_rtc_irq_set_freq,
+};
+
+static int __devinit twl4030_rtc_probe(struct platform_device *pdev)
+{
+ struct twl4030rtc_platform_data *pdata = pdev->dev.platform_data;
+ struct rtc_device *rtc;
+ int ret = 0;
+ u8 rd_reg;
+
+ if (pdata != NULL && pdata->init != NULL) {
+ ret = pdata->init();
+ if (ret < 0)
+ goto out;
+ }
+
+ rtc = rtc_device_register(pdev->name,
+ &pdev->dev, &twl4030_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc)) {
+ ret = -EINVAL;
+ dev_err(&pdev->dev, "can't register RTC device, err %ld\n",
+ PTR_ERR(rtc));
+ goto out0;
+
+ }
+
+ /* Set the irq freq to every second */
+ rtc->irq_freq = 0;
+
+ platform_set_drvdata(pdev, rtc);
+
+ ret = twl4030_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG);
+
+ if (ret < 0)
+ goto out1;
+
+ if (rd_reg & BIT_RTC_STATUS_REG_POWER_UP_M)
+ dev_warn(&pdev->dev, "Power up reset detected.\n");
+
+ if (rd_reg & BIT_RTC_STATUS_REG_ALARM_M)
+ dev_warn(&pdev->dev, "Pending Alarm interrupt detected.\n");
+
+ /* Clear RTC Power up reset and pending alarm interrupts */
+ ret = twl4030_rtc_write_u8(rd_reg, REG_RTC_STATUS_REG);
+ if (ret < 0)
+ goto out1;
+
+ ret = request_irq(TWL4030_PWRIRQ_RTC, twl4030_rtc_interrupt,
+ 0, rtc->dev.bus_id, rtc);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "IRQ is not free.\n");
+ goto out1;
+ }
+
+ /* Check RTC module status, Enable if it is off */
+ ret = twl4030_rtc_read_u8(&rd_reg, REG_RTC_CTRL_REG);
+ if (ret < 0)
+ goto out2;
+
+ if (!(rd_reg & BIT_RTC_CTRL_REG_STOP_RTC_M)) {
+ dev_info(&pdev->dev, "Enabling TWL4030-RTC.\n");
+ rd_reg = BIT_RTC_CTRL_REG_STOP_RTC_M;
+ ret = twl4030_rtc_write_u8(rd_reg, REG_RTC_CTRL_REG);
+ if (ret < 0)
+ goto out2;
+ }
+
+ ret = twl4030_i2c_read_u8(TWL4030_MODULE_INT, &rd_reg, REG_PWR_IMR1);
+ if (ret < 0)
+ goto out2;
+
+ rd_reg &= PWR_RTC_IT_UNMASK;
+ /* MASK PWR - we will need this */
+ ret = twl4030_i2c_write_u8(TWL4030_MODULE_INT, rd_reg, REG_PWR_IMR1);
+ if (ret < 0)
+ goto out2;
+
+ ret = twl4030_i2c_read_u8(TWL4030_MODULE_INT, &rd_reg, REG_PWR_EDR1);
+ if (ret < 0)
+ goto out2;
+
+ /* Rising edge detection enabled, needed for RTC alarm */
+ rd_reg |= 0x80;
+ ret = twl4030_i2c_write_u8(TWL4030_MODULE_INT, rd_reg, REG_PWR_EDR1);
+ if (ret < 0)
+ goto out2;
+
+ return ret;
+
+
+out2:
+ free_irq(TWL4030_MODIRQ_PWR, rtc);
+out1:
+ rtc_device_unregister(rtc);
+out0:
+ if (pdata != NULL && pdata->exit != NULL)
+ pdata->exit();
+out:
+ return ret;
+}
+
+/*
+ * Disable all TWL4030 RTC module interrupts.
+ * Sets status flag to free.
+ */
+static int __devexit twl4030_rtc_remove(struct platform_device *pdev)
+{
+ /* leave rtc running, but disable irqs */
+ struct twl4030rtc_platform_data *pdata = pdev->dev.platform_data;
+ struct rtc_device *rtc = platform_get_drvdata(pdev);
+
+ mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
+ mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
+
+ free_irq(TWL4030_MODIRQ_PWR, rtc);
+
+ if (pdata != NULL && pdata->exit != NULL)
+ pdata->exit();
+
+ rtc_device_unregister(rtc);
+ platform_set_drvdata(pdev, NULL);
+ return 0;
+}
+
+static void twl4030_rtc_shutdown(struct platform_device *pdev)
+{
+ twl4030_rtc_alarm_irq_set_state(&pdev->dev, 0);
+ twl4030_rtc_irq_set_state(&pdev->dev, 0);
+}
+
+#ifdef CONFIG_PM
+
+static unsigned char irqstat;
+
+static int twl4030_rtc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ get_rtc_irq_bit(&irqstat);
+
+ mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M |
+ BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
+ return 0;
+}
+
+static int twl4030_rtc_resume(struct platform_device *pdev)
+{
+ set_rtc_irq_bit(irqstat);
+ return 0;
+}
+#else
+#define twl4030_rtc_suspend NULL
+#define twl4030_rtc_resume NULL
+#endif
+
+MODULE_ALIAS("twl4030_rtc");
+static struct platform_driver twl4030rtc_driver = {
+ .probe = twl4030_rtc_probe,
+ .remove = __devexit_p(twl4030_rtc_remove),
+ .shutdown = twl4030_rtc_shutdown,
+ .suspend = twl4030_rtc_suspend,
+ .resume = twl4030_rtc_resume,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "twl4030_rtc",
+ },
+};
+
+static int __init twl4030_rtc_init(void)
+{
+ return platform_driver_register(&twl4030rtc_driver);
+}
+
+static void __exit twl4030_rtc_exit(void)
+{
+ platform_driver_unregister(&twl4030rtc_driver);
+}
+
+MODULE_AUTHOR("Texas Instruments, MontaVista Software");
+MODULE_LICENSE("GPL");;
+
+module_init(twl4030_rtc_init);
+module_exit(twl4030_rtc_exit);
DEBUG_INTR("end.\n");
+#ifdef CONFIG_ARCH_OMAP15XX
+ return IRQ_HANDLED; /* FIXME: iir status not ready on 1510 */
+#else
return IRQ_RETVAL(handled);
+#endif
}
/*
/* 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_AU:
size = 0x100000;
This driver can also be built as a module. If so, the module
will be called at25.
+config SPI_TSC2101
+ depends on SPI_MASTER
+ tristate "TSC2101 chip support"
+ ---help---
+ Say Y here if you want support for the TSC2101 chip.
+ At the moment it provides basic register read / write interface
+ as well as a way to enable the MCLK clock.
+
+config SPI_TSC2102
+ depends on SPI_MASTER
+ tristate "TSC2102 codec support"
+ ---help---
+ Say Y here if you want support for the TSC2102 chip. It
+ will be needed for the touchscreen driver on some boards.
+
+config SPI_TSC210X
+ depends on SPI_MASTER && EXPERIMENTAL
+ tristate "TI TSC210x (TSC2101/TSC2102) support"
+ help
+ Say Y here if you want support for the TSC210x chips. Some
+ boards use these for touchscreen and audio support.
+
+ These are members of a family of highly integrated PDA analog
+ interface circuit. They include a 12-bit ADC used for battery,
+ temperature, touchscreen, and other sensors. They also have
+ an audio DAC and amplifier, and in some models an audio ADC.
+ The audio support is highly chip-specific, but most of the
+ sensor support works the same.
+
+ Note that the device has to be present in the board's SPI
+ devices table for this driver to load. This driver doesn't
+ automatically enable touchscreen, sensors or audio
+ functionality - enable these in their respective menus.
+
+config SPI_TSC2301
+ tristate "TSC2301 driver"
+ depends on SPI_MASTER
+ help
+ Say Y here if you have a TSC2301 chip connected to an SPI
+ bus on your board.
+
+ The TSC2301 is a highly integrated PDA analog interface circuit.
+ It contains a complete 12-bit A/D resistive touch screen
+ converter (ADC) including drivers, touch pressure measurement
+ capability, keypad controller, and 8-bit D/A converter (DAC) output
+ for LCD contrast control.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tsc2301.
+
+config SPI_TSC2301_AUDIO
+ boolean "TSC2301 audio support"
+ depends on SPI_TSC2301 && SND
+ help
+ Say Y here for if you are using the audio features of TSC2301.
+
config SPI_SPIDEV
tristate "User mode SPI device driver support"
depends on SPI_MASTER && EXPERIMENTAL
obj-$(CONFIG_SPI_AT25) += at25.o
obj-$(CONFIG_SPI_SPIDEV) += spidev.o
obj-$(CONFIG_SPI_TLE62X0) += tle62x0.o
+obj-$(CONFIG_SPI_TSC2101) += tsc2101.o
+obj-$(CONFIG_SPI_TSC2102) += tsc2102.o
+obj-$(CONFIG_SPI_TSC210X) += tsc210x.o
+obj-$(CONFIG_SPI_TSC2301) += tsc2301.o
+tsc2301-objs := tsc2301-core.o
+tsc2301-$(CONFIG_SPI_TSC2301_AUDIO) += tsc2301-mixer.o
# ... add above this line ...
# SPI slave controller drivers (upstream link)
--- /dev/null
+/*
+ * linux/drivers/spi/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/kernel.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/tsc2101.h>
+
+struct tsc2101_device {
+ struct mutex mutex;
+ int mclk_enabled;
+ struct clock *mclk_ck;
+ struct spi_message message;
+ struct spi_transfer transfer[2];
+ u16 command;
+ void (*enable_mclk)(struct spi_device *spi);
+ void (*disable_mclk)(struct spi_device *spi);
+};
+
+int tsc2101_enable_mclk(struct spi_device *spi)
+{
+ struct tsc2101_device *tsc2101;
+
+ tsc2101 = spi_get_drvdata(spi);
+
+ mutex_lock(&tsc2101->mutex);
+
+ if (spi->dev.power.power_state.event != PM_EVENT_ON) {
+ mutex_unlock(&tsc2101->mutex);
+ return -ENODEV;
+ }
+
+ if (tsc2101->mclk_enabled++ == 0) {
+ if (tsc2101->enable_mclk != NULL)
+ tsc2101->enable_mclk(spi);
+ }
+
+ mutex_unlock(&tsc2101->mutex);
+ return 0;
+}
+EXPORT_SYMBOL(tsc2101_enable_mclk);
+
+void tsc2101_disable_mclk(struct spi_device *spi)
+{
+ struct tsc2101_device *tsc2101;
+
+ tsc2101 = spi_get_drvdata(spi);
+
+ mutex_lock(&tsc2101->mutex);
+
+ if (--tsc2101->mclk_enabled == 0) {
+ if (tsc2101->disable_mclk != NULL &&
+ spi->dev.power.power_state.event == PM_EVENT_ON)
+ tsc2101->disable_mclk(spi);
+ }
+
+ mutex_lock(&tsc2101->mutex);
+}
+EXPORT_SYMBOL(tsc2101_disable_mclk);
+
+int tsc2101_write_sync(struct spi_device *spi, int page, u8 address, u16 data)
+{
+ struct tsc2101_device *tsc2101;
+ struct spi_message *m;
+ struct spi_transfer *t;
+ int ret;
+
+ tsc2101 = spi_get_drvdata(spi);
+
+ mutex_lock(&tsc2101->mutex);
+ if (spi->dev.power.power_state.event != PM_EVENT_ON) {
+ mutex_unlock(&tsc2101->mutex);
+ return -ENODEV;
+ }
+
+ m = &tsc2101->message;
+ spi_message_init(m);
+ t = &tsc2101->transfer[0];
+ memset(t, 0, sizeof(tsc2101->transfer));
+
+ /* Address */
+ tsc2101->command = (page << 11) | (address << 5);
+ t->tx_buf = &tsc2101->command;
+ t->len = 2;
+ spi_message_add_tail(t, m);
+
+ /* Data */
+ t++;
+ t->tx_buf = &data;
+ t->len = 2;
+ spi_message_add_tail(t, m);
+
+ ret = spi_sync(spi, m);
+ if (!ret)
+ ret = tsc2101->message.status;
+ mutex_unlock(&tsc2101->mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL(tsc2101_write_sync);
+
+int tsc2101_reads_sync(struct spi_device *spi,
+ int page, u8 startaddress, u16 *data, int numregs)
+{
+ struct tsc2101_device *tsc2101;
+ struct spi_message *m;
+ struct spi_transfer *t;
+ int ret;
+
+ tsc2101 = spi_get_drvdata(spi);
+
+ mutex_lock(&tsc2101->mutex);
+ if (spi->dev.power.power_state.event != PM_EVENT_ON) {
+ mutex_unlock(&tsc2101->mutex);
+ return -ENODEV;
+ }
+
+ m = &tsc2101->message;
+ spi_message_init(m);
+ t = &tsc2101->transfer[0];
+ memset(t, 0, sizeof(tsc2101->transfer));
+
+ /* Address */
+ tsc2101->command = 0x8000 | (page << 11) | (startaddress << 5);
+ t->tx_buf = &tsc2101->command;
+ t->len = 2;
+ spi_message_add_tail(t, m);
+
+ /* Data */
+ t++;
+ t->rx_buf = data;
+ t->len = numregs << 1;
+ spi_message_add_tail(t, m);
+
+ ret = spi_sync(spi, m);
+ if (!ret)
+ ret = tsc2101->message.status;
+
+ mutex_unlock(&tsc2101->mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL(tsc2101_reads_sync);
+
+int tsc2101_read_sync(struct spi_device *spi, int page, u8 address)
+{
+ int err;
+ u16 val;
+
+ err = tsc2101_reads_sync(spi, page, address, &val, 1);
+ if (err)
+ return err;
+ return val;
+}
+EXPORT_SYMBOL(tsc2101_read_sync);
+
+static int tsc2101_suspend(struct spi_device *spi, pm_message_t state)
+{
+ struct tsc2101_device *tsc2101;
+
+ tsc2101 = spi_get_drvdata(spi);
+
+ if (tsc2101 == NULL)
+ return 0;
+
+ mutex_lock(&tsc2101->mutex);
+
+ spi->dev.power.power_state = state;
+ if (tsc2101->mclk_enabled && tsc2101->disable_mclk != NULL)
+ tsc2101->disable_mclk(spi);
+
+ mutex_unlock(&tsc2101->mutex);
+
+ return 0;
+}
+
+static int tsc2101_resume(struct spi_device *spi)
+{
+ struct tsc2101_device *tsc2101;
+
+ tsc2101 = spi_get_drvdata(spi);
+
+ if (tsc2101 == NULL)
+ return 0;
+
+ mutex_lock(&tsc2101->mutex);
+
+ spi->dev.power.power_state = PMSG_ON;
+ if (tsc2101->mclk_enabled && tsc2101->enable_mclk != NULL)
+ tsc2101->enable_mclk(spi);
+
+ mutex_unlock(&tsc2101->mutex);
+
+ return 0;
+}
+
+static int tsc2101_probe(struct spi_device *spi)
+{
+ struct tsc2101_platform_data *pdata;
+ struct tsc2101_device *tsc2101;
+ u16 w;
+ int r;
+
+ pdata = spi->dev.platform_data;
+ if (pdata == NULL) {
+ dev_err(&spi->dev, "no platform data\n");
+ return -ENODEV;
+ }
+
+ tsc2101 = kzalloc(sizeof(*tsc2101), GFP_KERNEL);
+ if (tsc2101 == NULL) {
+ dev_err(&spi->dev, "out of mem\n");
+ return -ENOMEM;
+ }
+
+ spi_set_drvdata(spi, tsc2101);
+ tsc2101->enable_mclk = pdata->enable_mclk;
+ tsc2101->disable_mclk = pdata->disable_mclk;
+
+ mutex_init(&tsc2101->mutex);
+
+ spi->mode = SPI_MODE_1;
+ spi->bits_per_word = 16;
+ if ((r = spi_setup(spi)) < 0) {
+ dev_err(&spi->dev, "SPI setup failed\n");
+ goto err;
+ }
+
+ w = tsc2101_read_sync(spi, 1, 0);
+ if (!(w & (1 << 14))) {
+ dev_err(&spi->dev, "invalid ADC register value %04x\n", w);
+ goto err;
+ }
+
+ if (pdata->init != NULL) {
+ if ((r = pdata->init(spi)) < 0) {
+ dev_err(&spi->dev, "platform init failed\n");
+ goto err;
+ }
+ }
+
+ dev_info(&spi->dev, "initialized\n");
+
+ return 0;
+err:
+ kfree(tsc2101);
+ return r;
+}
+
+static int tsc2101_remove(struct spi_device *spi)
+{
+ struct tsc2101_platform_data *pdata;
+ struct tsc2101_device *tsc2101;
+
+ pdata = spi->dev.platform_data;
+ tsc2101 = spi_get_drvdata(spi);
+
+ /* We assume that this can't race with the rest of the driver. */
+ if (tsc2101->mclk_enabled && tsc2101->disable_mclk != NULL)
+ tsc2101->disable_mclk(spi);
+
+ if (pdata->cleanup != NULL)
+ pdata->cleanup(spi);
+
+ spi_set_drvdata(spi, NULL);
+ kfree(tsc2101);
+
+ return 0;
+}
+
+static struct spi_driver tsc2101_driver = {
+ .probe = tsc2101_probe,
+ .remove = tsc2101_remove,
+ .suspend = tsc2101_suspend,
+ .resume = tsc2101_resume,
+ .driver = {
+ .name = "tsc2101",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int tsc2101_init(void)
+{
+ return spi_register_driver(&tsc2101_driver);
+}
+
+static void tsc2101_exit(void)
+{
+ spi_unregister_driver(&tsc2101_driver);
+}
+
+module_init(tsc2101_init);
+module_exit(tsc2101_exit);
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION
+ ("Glue audio driver for the TI OMAP1610/OMAP1710 TSC2101 codec.");
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * drivers/spi/tsc2102.c
+ *
+ * TSC2102 interface driver.
+ *
+ * Copyright (c) 2005 Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this package; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/suspend.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/tsc2102.h>
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+#include <asm/hardware.h>
+
+#ifdef CONFIG_APM
+#include <asm/apm.h>
+#endif
+
+/* Bit field definitions for chip registers */
+#define TSC2102_ADC_TS_CONTROL 0x8bf4
+#define TSC2102_ADC_SCAN_CONTROL 0x2ff4
+#define TSC2102_ADC_T1_CONTROL 0x2bf4
+#define TSC2102_ADC_T2_CONTROL 0x33f4
+#define TSC2102_ADC_DAV 0x4000
+#define TSC2102_ADC_INT_REF 0x0016
+#define TSC2102_ADC_EXT_REF 0x0002
+#define TSC2102_CONFIG_TIMES 0x0008
+#define TSC2102_RESET 0xbb00
+#define TSC2102_ADC_PSTCM (1 << 15)
+#define TSC2102_ADC_ADST (1 << 14)
+#define TSC2102_TS_DAV 0x0780
+#define TSC2102_PS_DAV 0x0078
+#define TSC2102_T1_DAV 0x0004
+#define TSC2102_T2_DAV 0x0002
+#define TSC2102_DAC_ON 0x3ba0
+#define TSC2102_DAC_OFF 0xafa0
+#define TSC2102_FS44K (1 << 13)
+#define TSC2102_PLL1_OFF 0x0000
+#define TSC2102_PLL1_44K 0x811c
+#define TSC2102_PLL1_48K 0x8120
+#define TSC2102_PLL2_44K (5462 << 2)
+#define TSC2102_PLL2_48K (1920 << 2)
+#define TSC2102_SLVMS (1 << 11)
+#define TSC2102_DEEMPF (1 << 0)
+#define TSC2102_BASSBC (1 << 1)
+#define TSC2102_KEYCLICK_OFF 0x0000
+
+#define CS_CHANGE(val) 0
+
+struct tsc2102_spi_req {
+ struct spi_device *dev;
+ uint16_t command;
+ uint16_t data;
+ struct spi_transfer *transfer;
+ struct spi_message message;
+};
+
+struct tsc2102_dev {
+ struct tsc2102_config *pdata;
+ spinlock_t lock, lock_sync;
+ struct clk *bclk_ck;
+
+ int state; /* 0: TS, 1: Portscan, 2-3: Temps */
+ struct timer_list ts_timer; /* Busy-wait for PEN UP */
+ struct timer_list mode_timer; /* Change .state every some time */
+ int pendown;
+ int data_pending;
+ uint16_t status, adc_status, adc_data[4];
+ tsc2102_touch_t touch_cb;
+ tsc2102_coords_t coords_cb;
+ tsc2102_ports_t ports_cb;
+ tsc2102_temp_t temp1_cb;
+ tsc2102_temp_t temp2_cb;
+ unsigned int ts_msecs; /* Interval for .ts_timer */
+ unsigned int mode_msecs; /* Interval for .mode_timer */
+
+ struct spi_device *spi;
+ struct spi_transfer *transfers;
+ struct tsc2102_spi_req req_adc;
+ struct tsc2102_spi_req req_status;
+ struct tsc2102_spi_req req_pressure;
+ struct tsc2102_spi_req req_stopadc;
+ struct tsc2102_spi_req req_mode;
+
+ int bat[2], aux[1], temp[2];
+ struct class_device *hwmondev;
+};
+
+static struct tsc2102_dev tsc;
+
+module_param_named(touch_check_msecs, tsc.ts_msecs, uint, 0);
+MODULE_PARM_DESC(touch_check_msecs, "Pen-up polling interval in msecs");
+
+module_param_named(sensor_scan_msecs, tsc.mode_msecs, uint, 0);
+MODULE_PARM_DESC(sensor_scan_msecs, "Temperature & battery scan interval");
+
+void tsc2102_write_sync(int page, u8 address, u16 data)
+{
+ static struct tsc2102_spi_req req;
+ static struct spi_transfer transfer[2];
+ int ret;
+
+ spi_message_init(&req.message);
+ req.transfer = transfer;
+
+ /* Address */
+ req.command = (page << 11) | (address << 5);
+ req.transfer[0].tx_buf = &req.command;
+ req.transfer[0].rx_buf = 0;
+ req.transfer[0].len = 2;
+ spi_message_add_tail(&req.transfer[0], &req.message);
+
+ /* Data */
+ req.transfer[1].tx_buf = &data;
+ req.transfer[1].rx_buf = 0;
+ req.transfer[1].len = 2;
+ req.transfer[1].cs_change = CS_CHANGE(1);
+ spi_message_add_tail(&req.transfer[1], &req.message);
+
+ ret = spi_sync(tsc.spi, &req.message);
+ if (!ret && req.message.status)
+ ret = req.message.status;
+
+ if (ret)
+ printk(KERN_ERR "%s: error %i in SPI request\n",
+ __FUNCTION__, ret);
+}
+
+void tsc2102_reads_sync(int page, u8 startaddress, u16 *data, int numregs)
+{
+ static struct tsc2102_spi_req req;
+ static struct spi_transfer transfer[6];
+ int ret, i, j;
+
+ BUG_ON(numregs + 1 > ARRAY_SIZE(transfer));
+
+ spi_message_init(&req.message);
+ req.transfer = transfer;
+ i = 0;
+ j = 0;
+
+ /* Address */
+ req.command = 0x8000 | (page << 11) | (startaddress << 5);
+ req.transfer[i].tx_buf = &req.command;
+ req.transfer[i].rx_buf = 0;
+ req.transfer[i].len = 2;
+ spi_message_add_tail(&req.transfer[i ++], &req.message);
+
+ /* Data */
+ while (j < numregs) {
+ req.transfer[i].tx_buf = 0;
+ req.transfer[i].rx_buf = &data[j ++];
+ req.transfer[i].len = 2;
+ req.transfer[i].cs_change = CS_CHANGE(j == numregs);
+ spi_message_add_tail(&req.transfer[i ++], &req.message);
+ }
+
+ ret = spi_sync(tsc.spi, &req.message);
+ if (!ret && req.message.status)
+ ret = req.message.status;
+
+ if (ret)
+ printk(KERN_ERR "%s: error %i in SPI request\n",
+ __FUNCTION__, ret);
+}
+
+u16 tsc2102_read_sync(int page, u8 address)
+{
+ u16 ret;
+ tsc2102_reads_sync(page, address, &ret, 1);
+ return ret;
+}
+
+static void tsc2102_write_async(
+ struct tsc2102_spi_req *spi, int page, u8 address, u16 data,
+ void (*complete)(struct tsc2102_dev *context))
+{
+ int ret;
+
+ spi_message_init(&spi->message);
+ spi->message.complete = (void (*)(void *)) complete;
+ spi->message.context = &tsc;
+
+ /* Address */
+ spi->command = (page << 11) | (address << 5);
+ spi->transfer[0].tx_buf = &spi->command;
+ spi->transfer[0].rx_buf = 0;
+ spi->transfer[0].len = 2;
+ spi_message_add_tail(&spi->transfer[0], &spi->message);
+
+ /* Data */
+ spi->data = data;
+ spi->transfer[1].tx_buf = &spi->data;
+ spi->transfer[1].rx_buf = 0;
+ spi->transfer[1].len = 2;
+ spi->transfer[1].cs_change = CS_CHANGE(1);
+ spi_message_add_tail(&spi->transfer[1], &spi->message);
+
+ ret = spi_async(spi->dev, &spi->message);
+ if (ret)
+ printk(KERN_ERR "%s: error %i in SPI request\n",
+ __FUNCTION__, ret);
+}
+
+static void tsc2102_reads_async(struct tsc2102_spi_req *spi,
+ int page, u8 startaddress, u16 *data, int numregs,
+ void (*complete)(struct tsc2102_dev *context))
+{
+ int ret, i, j;
+
+ spi_message_init(&spi->message);
+ spi->message.complete = (void (*)(void *)) complete;
+ spi->message.context = &tsc;
+ i = 0;
+ j = 0;
+
+ /* Address */
+ spi->command = 0x8000 | (page << 11) | (startaddress << 5);
+ spi->transfer[i].tx_buf = &spi->command;
+ spi->transfer[i].rx_buf = 0;
+ spi->transfer[i].len = 2;
+ spi_message_add_tail(&spi->transfer[i ++], &spi->message);
+
+ /* Data */
+ while (j < numregs) {
+ spi->transfer[i].tx_buf = 0;
+ spi->transfer[i].rx_buf = &data[j ++];
+ spi->transfer[i].len = 2;
+ spi->transfer[i].cs_change = CS_CHANGE(j == numregs);
+ spi_message_add_tail(&spi->transfer[i ++], &spi->message);
+ }
+
+ ret = spi_async(spi->dev, &spi->message);
+ if (ret)
+ printk(KERN_ERR "%s: error %i in SPI request\n",
+ __FUNCTION__, ret);
+}
+
+static void tsc2102_read_async(struct tsc2102_spi_req *spi,
+ int page, u8 address, u16 *ret,
+ void (*complete)(struct tsc2102_dev *context))
+{
+ tsc2102_reads_async(spi, page, address, ret, 1, complete);
+}
+
+static void tsc2102_request_alloc(struct tsc2102_dev *dev,
+ struct tsc2102_spi_req *spi, int direction, int numregs,
+ struct spi_transfer **buffer)
+{
+ spi->dev = dev->spi;
+
+ if (direction == 1) /* Write */
+ numregs = 2;
+ else /* Read */
+ numregs += 1;
+
+ spi->transfer = *buffer;
+ *buffer += numregs;
+}
+
+#define tsc2102_cb_register_func(cb, cb_t) \
+int tsc2102_ ## cb(cb_t handler) \
+{ \
+ spin_lock(&tsc.lock); \
+ \
+ /* Lock the module */ \
+ if (handler && !tsc.cb) \
+ if (!try_module_get(THIS_MODULE)) { \
+ printk(KERN_INFO "Failed to get TSC module\n"); \
+ } \
+ if (!handler && tsc.cb) \
+ module_put(THIS_MODULE); \
+ \
+ tsc.cb = handler; \
+ \
+ spin_unlock(&tsc.lock); \
+ return 0; \
+}
+
+tsc2102_cb_register_func(touch_cb, tsc2102_touch_t)
+tsc2102_cb_register_func(coords_cb, tsc2102_coords_t)
+tsc2102_cb_register_func(ports_cb, tsc2102_ports_t)
+tsc2102_cb_register_func(temp1_cb, tsc2102_temp_t)
+tsc2102_cb_register_func(temp2_cb, tsc2102_temp_t)
+
+#ifdef DEBUG
+static void tsc2102_print_dav(void)
+{
+ u16 status = tsc2102_read_sync(TSC2102_TS_STATUS_CTRL);
+ if (status & 0x0fff)
+ printk("TSC2102: data in");
+ if (status & 0x0400)
+ printk(" X");
+ if (status & 0x0200)
+ printk(" Y");
+ if (status & 0x0100)
+ printk(" Z1");
+ if (status & 0x0080)
+ printk(" Z2");
+ if (status & 0x0040)
+ printk(" BAT1");
+ if (status & 0x0020)
+ printk(" BAT2");
+ if (status & 0x0010)
+ printk(" AUX1");
+ if (status & 0x0008)
+ printk(" AUX2");
+ if (status & 0x0004)
+ printk(" TEMP1");
+ if (status & 0x0002)
+ printk(" TEMP2");
+ if (status & 0x0001)
+ printk(" KP");
+ if (status & 0x0fff)
+ printk(".\n");
+}
+#endif
+
+static void tsc2102_complete_dummy(struct tsc2102_dev *dev)
+{
+}
+
+static inline void tsc2102_touchscreen_mode(struct tsc2102_dev *dev)
+{
+ /* Scan X, Y, Z1, Z2, chip controlled, 12-bit, 16 samples, 500 usec */
+ tsc2102_write_async(&dev->req_mode,
+ TSC2102_TS_ADC_CTRL, TSC2102_ADC_TS_CONTROL,
+ tsc2102_complete_dummy);
+}
+
+static inline void tsc2102_portscan_mode(struct tsc2102_dev *dev)
+{
+ /* Scan BAT1, BAT2, AUX, 12-bit, 16 samples, 500 usec */
+ tsc2102_write_async(&dev->req_mode,
+ TSC2102_TS_ADC_CTRL, TSC2102_ADC_SCAN_CONTROL,
+ tsc2102_complete_dummy);
+}
+
+static inline void tsc2102_temp1_mode(struct tsc2102_dev *dev)
+{
+ /* Scan TEMP1, 12-bit, 16 samples, 500 usec */
+ tsc2102_write_async(&dev->req_mode,
+ TSC2102_TS_ADC_CTRL, TSC2102_ADC_T1_CONTROL,
+ tsc2102_complete_dummy);
+}
+
+static inline void tsc2102_temp2_mode(struct tsc2102_dev *dev)
+{
+ /* Scan TEMP2, 12-bit, 16 samples, 500 usec */
+ tsc2102_write_async(&dev->req_mode,
+ TSC2102_TS_ADC_CTRL, TSC2102_ADC_T2_CONTROL,
+ tsc2102_complete_dummy);
+}
+
+static void tsc2102_mode(struct tsc2102_dev *dev)
+{
+ switch (dev->state) {
+ case 0:
+ tsc2102_touchscreen_mode(dev);
+ break;
+ case 1:
+ tsc2102_portscan_mode(dev);
+ break;
+ case 2:
+ tsc2102_temp1_mode(dev);
+ break;
+ case 3:
+ tsc2102_temp2_mode(dev);
+ break;
+ default:
+ dev->state = 0;
+ tsc2102_touchscreen_mode(dev);
+ break;
+ }
+}
+
+/* Lock is held when this is called. */
+static void tsc2102_new_mode(struct tsc2102_dev *dev)
+{
+ /* Abort current conversion if any */
+ tsc2102_write_async(&dev->req_stopadc,
+ TSC2102_TS_ADC_CTRL, TSC2102_ADC_ADST,
+ tsc2102_complete_dummy);
+
+ dev->state ++;
+ tsc2102_mode(dev);
+}
+
+static void tsc2102_check_status(struct tsc2102_dev *dev);
+
+/* TSC has new data for us availiable. */
+static irqreturn_t tsc2102_handler(int irq, void *dev_id)
+{
+ struct tsc2102_dev *dev = (struct tsc2102_dev *) dev_id;
+ spin_lock_irq(&dev->lock);
+
+ if (!dev->data_pending)
+ tsc2102_check_status(dev);
+
+ dev->data_pending ++;
+
+ spin_unlock_irq(&dev->lock);
+ return IRQ_HANDLED;
+}
+
+static void tsc2102_data_report(struct tsc2102_dev *dev)
+{
+ if (dev->status & TSC2102_TS_DAV) {
+ if (dev->coords_cb)
+ dev->coords_cb(
+ dev->adc_data[0], dev->adc_data[1],
+ dev->adc_data[2], dev->adc_data[3]);
+ }
+
+ if (dev->status & TSC2102_PS_DAV) {
+ if (dev->ports_cb)
+ dev->ports_cb(dev->adc_data[0],
+ dev->adc_data[1], dev->adc_data[2]);
+ dev->bat[0] = dev->adc_data[0];
+ dev->bat[1] = dev->adc_data[1];
+ dev->aux[0] = dev->adc_data[2];
+ }
+
+ if (dev->status & TSC2102_T1_DAV) {
+ if (dev->temp1_cb)
+ dev->temp1_cb(*dev->adc_data);
+ dev->temp[0] = *dev->adc_data;
+ }
+
+ if (dev->status & TSC2102_T2_DAV) {
+ if (dev->temp2_cb)
+ dev->temp2_cb(*dev->adc_data);
+ dev->temp[1] = *dev->adc_data;
+ }
+
+ spin_lock_irq(&dev->lock);
+
+ dev->data_pending --;
+
+ /*
+ * This may happen if the registers were successfully read and a
+ * new conversion was started and completed by the TSC before the
+ * completion for SPI read was called.
+ */
+ if (dev->data_pending)
+ tsc2102_check_status(dev);
+
+ if (dev->status & (TSC2102_PS_DAV | TSC2102_T1_DAV | TSC2102_T2_DAV))
+ tsc2102_new_mode(dev);
+
+ spin_unlock_irq(&dev->lock);
+}
+
+static void tsc2102_status_report(struct tsc2102_dev *dev)
+{
+ /*
+ * Read all converted data from corresponding registers
+ * so that the ADC can move on to a new conversion.
+ */
+ if (dev->status & TSC2102_TS_DAV) {
+ tsc2102_reads_async(&dev->req_adc, TSC2102_TS_X,
+ dev->adc_data, 4, tsc2102_data_report);
+ if (!dev->pendown) {
+ dev->pendown = 1;
+ if (dev->touch_cb)
+ dev->touch_cb(1);
+
+ mod_timer(&dev->ts_timer, jiffies +
+ msecs_to_jiffies(dev->ts_msecs));
+ }
+ }
+
+ if (dev->status & TSC2102_PS_DAV) {
+ tsc2102_reads_async(&dev->req_adc, TSC2102_TS_BAT1,
+ dev->adc_data, 3, tsc2102_data_report);
+ }
+
+ if (dev->status & TSC2102_T1_DAV) {
+ tsc2102_read_async(&dev->req_adc, TSC2102_TS_TEMP1,
+ dev->adc_data, tsc2102_data_report);
+ }
+
+ if (dev->status & TSC2102_T2_DAV) {
+ tsc2102_read_async(&dev->req_adc, TSC2102_TS_TEMP2,
+ dev->adc_data, tsc2102_data_report);
+ }
+
+ if (!(dev->status & (TSC2102_TS_DAV | TSC2102_PS_DAV |
+ TSC2102_T1_DAV | TSC2102_T2_DAV))) {
+ spin_lock_irq(&dev->lock);
+ dev->data_pending --;
+ spin_unlock_irq(&dev->lock);
+
+ WARN_ON(!dev->state);
+ }
+}
+
+static void tsc2102_check_status(struct tsc2102_dev *dev)
+{
+ tsc2102_read_async(&dev->req_status, TSC2102_TS_STATUS_CTRL,
+ &dev->status, tsc2102_status_report);
+}
+
+static void tsc2102_mode_timer(unsigned long data)
+{
+ struct tsc2102_dev *dev = (struct tsc2102_dev *) data;
+ spin_lock_irq(&dev->lock);
+
+ BUG_ON(dev->state);
+
+ tsc2102_new_mode(dev);
+
+ mod_timer(&dev->mode_timer, jiffies +
+ msecs_to_jiffies(dev->mode_msecs));
+ spin_unlock_irq(&dev->lock);
+}
+
+/*
+ * There are at least three ways to check for pen-up:
+ * - the PINT/DAV pin state,
+ * - reading PSTCM bit in ADC Control register (D15, offset 0x00),
+ * - reading ADST bit in ADC Control register (D14, offset 0x00),
+ * ADC idle would indicate no screen touch.
+ * Unfortunately none of them seems to be 100% accurate and you will
+ * find they are totally inconsistent, i.e. you get to see any arbitrary
+ * combination of values in these three bits. So we will busy-wait
+ * for a moment when all three indicate a pen-up, using a timer, before
+ * we report a pen-up.
+ */
+static void tsc2102_pressure_report(struct tsc2102_dev *dev)
+{
+ if (!dev->pendown)
+ return;
+
+ if (dev->state ||
+ (dev->adc_status & TSC2102_ADC_PSTCM) ||
+ !(dev->adc_status & TSC2102_ADC_ADST)) {
+ mod_timer(&dev->ts_timer, jiffies +
+ msecs_to_jiffies(dev->ts_msecs));
+ } else {
+ dev->pendown = 0;
+ if (dev->touch_cb)
+ dev->touch_cb(0);
+ }
+}
+
+static void tsc2102_pressure(unsigned long data)
+{
+ struct tsc2102_dev *dev = (struct tsc2102_dev *) data;
+
+ BUG_ON(!dev->pendown);
+
+ tsc2102_read_async(&dev->req_pressure, TSC2102_TS_ADC_CTRL,
+ &dev->adc_status, tsc2102_pressure_report);
+}
+
+#if defined(CONFIG_SND_OMAP_TSC2102) || defined(CONFIG_SND_OMAP_TSC2102_MODULE)
+
+/*
+ * Volume level values should be in the range [0, 127].
+ * Higher values mean lower volume.
+ */
+void tsc2102_set_volume(uint8_t left_ch, uint8_t right_ch)
+{
+ u16 val;
+ if (left_ch == 0x00 || left_ch == 0x7f) /* All 0's or all 1's */
+ left_ch ^= 0x7f;
+ if (right_ch == 0x00 || right_ch == 0x7f)
+ right_ch ^= 0x7f;
+
+ spin_lock(&tsc.lock_sync);
+
+ val = tsc2102_read_sync(TSC2102_DAC_GAIN_CTRL);
+
+ val &= 0x8080; /* Preserve mute-bits */
+ val |= (left_ch << 8) | right_ch;
+
+ tsc2102_write_sync(TSC2102_DAC_GAIN_CTRL, val);
+
+ spin_unlock(&tsc.lock_sync);
+}
+EXPORT_SYMBOL_GPL(tsc2102_set_volume);
+
+void tsc2102_set_mute(int left_ch, int right_ch)
+{
+ u16 val;
+ spin_lock(&tsc.lock_sync);
+
+ val = tsc2102_read_sync(TSC2102_DAC_GAIN_CTRL);
+
+ val &= 0x7f7f; /* Preserve volume settings */
+ val |= (left_ch << 15) | (right_ch << 7);
+
+ tsc2102_write_sync(TSC2102_DAC_GAIN_CTRL, val);
+
+ spin_unlock(&tsc.lock_sync);
+}
+EXPORT_SYMBOL_GPL(tsc2102_set_mute);
+
+void tsc2102_get_mute(int *left_ch, int *right_ch)
+{
+ u16 val;
+ spin_lock(&tsc.lock_sync);
+
+ val = tsc2102_read_sync(TSC2102_DAC_GAIN_CTRL);
+
+ spin_unlock(&tsc.lock_sync);
+
+ *left_ch = !!(val & (1 << 15));
+ *right_ch = !!(val & (1 << 7));
+}
+
+void tsc2102_set_deemphasis(int enable)
+{
+ u16 val;
+ spin_lock(&tsc.lock_sync);
+ val = tsc2102_read_sync(TSC2102_DAC_POWER_CTRL);
+
+ if (enable)
+ val &= ~TSC2102_DEEMPF;
+ else
+ val |= TSC2102_DEEMPF;
+
+ tsc2102_write_sync(TSC2102_DAC_POWER_CTRL, val);
+ spin_unlock(&tsc.lock_sync);
+}
+EXPORT_SYMBOL_GPL(tsc2102_set_deemphasis);
+
+void tsc2102_set_bassboost(int enable)
+{
+ u16 val;
+ spin_lock(&tsc.lock_sync);
+ val = tsc2102_read_sync(TSC2102_DAC_POWER_CTRL);
+
+ if (enable)
+ val &= ~TSC2102_BASSBC;
+ else
+ val |= TSC2102_BASSBC;
+
+ tsc2102_write_sync(TSC2102_DAC_POWER_CTRL, val);
+ spin_unlock(&tsc.lock_sync);
+}
+EXPORT_SYMBOL_GPL(tsc2102_set_bassboost);
+
+/* {rate, dsor, fsref} */
+static const struct tsc2102_rate_info_s tsc2102_rates[] = {
+ /* Fsref / 6.0 */
+ {7350, 63, 1},
+ {8000, 63, 0},
+ /* Fsref / 6.0 */
+ {7350, 54, 1},
+ {8000, 54, 0},
+ /* Fsref / 5.0 */
+ {8820, 45, 1},
+ {9600, 45, 0},
+ /* Fsref / 4.0 */
+ {11025, 36, 1},
+ {12000, 36, 0},
+ /* Fsref / 3.0 */
+ {14700, 27, 1},
+ {16000, 27, 0},
+ /* Fsref / 2.0 */
+ {22050, 18, 1},
+ {24000, 18, 0},
+ /* Fsref / 1.5 */
+ {29400, 9, 1},
+ {32000, 9, 0},
+ /* Fsref */
+ {44100, 0, 1},
+ {48000, 0, 0},
+
+ {0, 0, 0},
+};
+
+int tsc2102_set_rate(int rate)
+{
+ int i;
+ uint16_t val;
+
+ for (i = 0; tsc2102_rates[i].sample_rate; i ++)
+ if (tsc2102_rates[i].sample_rate == rate)
+ break;
+ if (tsc2102_rates[i].sample_rate == 0) {
+ printk(KERN_ERR "Unknown sampling rate %i.0 Hz\n", rate);
+ return -EINVAL;
+ }
+
+ spin_lock(&tsc.lock_sync);
+
+ tsc2102_write_sync(TSC2102_AUDIO1_CTRL, tsc2102_rates[i].divisor);
+
+ val = tsc2102_read_sync(TSC2102_AUDIO3_CTRL);
+
+ if (tsc2102_rates[i].fs_44k) {
+ tsc2102_write_sync(TSC2102_AUDIO3_CTRL, val | TSC2102_FS44K);
+ /* Enable Phase-locked-loop, set up clock dividers */
+ tsc2102_write_sync(TSC2102_PLL1_CTRL, TSC2102_PLL1_44K);
+ tsc2102_write_sync(TSC2102_PLL2_CTRL, TSC2102_PLL2_44K);
+ } else {
+ tsc2102_write_sync(TSC2102_AUDIO3_CTRL, val & ~TSC2102_FS44K);
+ /* Enable Phase-locked-loop, set up clock dividers */
+ tsc2102_write_sync(TSC2102_PLL1_CTRL, TSC2102_PLL1_48K);
+ tsc2102_write_sync(TSC2102_PLL2_CTRL, TSC2102_PLL2_48K);
+ }
+
+ spin_unlock(&tsc.lock_sync);
+ return 0;
+}
+EXPORT_SYMBOL(tsc2102_set_rate);
+
+/*
+ * Perform basic set-up with default values and power the DAC on.
+ */
+void tsc2102_dac_power(int state)
+{
+ spin_lock(&tsc.lock_sync);
+
+ if (state) {
+ /* 16-bit words, DSP mode, sample at Fsref */
+ tsc2102_write_sync(TSC2102_AUDIO1_CTRL, 0x0100);
+ /* Keyclicks off, soft-stepping at normal rate */
+ tsc2102_write_sync(TSC2102_AUDIO2_CTRL, TSC2102_KEYCLICK_OFF);
+ /* 44.1 kHz Fsref, continuous transfer mode, master DAC */
+ tsc2102_write_sync(TSC2102_AUDIO3_CTRL, 0x2800);
+ /* Soft-stepping enabled */
+ tsc2102_write_sync(TSC2102_AUDIO4_CTRL, 0x0000);
+
+ /* PLL generates 44.1 kHz */
+ tsc2102_write_sync(TSC2102_PLL1_CTRL, TSC2102_PLL1_44K);
+ tsc2102_write_sync(TSC2102_PLL2_CTRL, TSC2102_PLL2_44K);
+
+ /* Codec & DAC power up, virtual ground disabled */
+ tsc2102_write_sync(TSC2102_DAC_POWER_CTRL, TSC2102_DAC_ON);
+ } else {
+ /* All off */
+ tsc2102_write_sync(TSC2102_AUDIO4_CTRL, TSC2102_KEYCLICK_OFF);
+ tsc2102_write_sync(TSC2102_PLL1_CTRL, TSC2102_PLL1_OFF);
+ }
+
+ spin_unlock(&tsc.lock_sync);
+}
+EXPORT_SYMBOL_GPL(tsc2102_dac_power);
+
+void tsc2102_set_i2s_master(int state)
+{
+ uint16_t val;
+ spin_lock(&tsc.lock_sync);
+
+ val = tsc2102_read_sync(TSC2102_AUDIO3_CTRL);
+
+ if (state)
+ tsc2102_write_sync(TSC2102_AUDIO3_CTRL, val | TSC2102_SLVMS);
+ else
+ tsc2102_write_sync(TSC2102_AUDIO3_CTRL, val & ~TSC2102_SLVMS);
+
+ spin_unlock(&tsc.lock_sync);
+}
+EXPORT_SYMBOL_GPL(tsc2102_set_i2s_master);
+
+#endif /* CONFIG_SND_OMAP_TSC2101 */
+
+static int tsc2102_configure(struct tsc2102_dev *dev)
+{
+ /* Reset the chip */
+ tsc2102_write_sync(TSC2102_TS_RESET_CTRL, TSC2102_RESET);
+
+ /* Reference mode, 100 usec delay, 1.25 V reference */
+ if (dev->pdata->use_internal)
+ tsc2102_write_sync(TSC2102_TS_REF_CTRL, TSC2102_ADC_INT_REF);
+ else
+ tsc2102_write_sync(TSC2102_TS_REF_CTRL, TSC2102_ADC_EXT_REF);
+
+ /* 84 usec precharge time, 32 usec sense time */
+ tsc2102_write_sync(TSC2102_TS_CONFIG_CTRL, TSC2102_CONFIG_TIMES);
+
+ /* PINT/DAV acts as DAV */
+ tsc2102_write_sync(TSC2102_TS_STATUS_CTRL, TSC2102_ADC_DAV);
+
+ tsc2102_mode(dev);
+ mod_timer(&dev->mode_timer, jiffies +
+ msecs_to_jiffies(dev->mode_msecs));
+ return 0;
+}
+
+/*
+ * Retrieves chip revision. Should be always 1.
+ */
+int tsc2102_get_revision(void)
+{
+ return tsc2102_read_sync(TSC2102_AUDIO3_CTRL) & 7;
+}
+
+/*
+ * Emit a short keyclick typically in order to give feedback to
+ * user on specific events.
+ *
+ * amplitude must be between 0 (lowest) and 2 (highest).
+ * freq must be between 0 (corresponds to 62.5 Hz) and 7 (8 kHz).
+ * length should be between 2 and 32 periods.
+ *
+ * This function sleeps but doesn't sleep until the sound has
+ * finished.
+ */
+void tsc2102_keyclick(int amplitude, int freq, int length)
+{
+ u16 val;
+ spin_lock(&tsc.lock_sync);
+ val = tsc2102_read_sync(TSC2102_AUDIO2_CTRL);
+ val &= 0x800f;
+
+ /* Set amplitude */
+ switch (amplitude) {
+ case 1:
+ val |= 4 << 12;
+ break;
+ case 2:
+ val |= 7 << 12;
+ break;
+ default:
+ break;
+ }
+
+ /* Frequency */
+ val |= (freq & 0x7) << 8;
+
+ /* Round to nearest supported length */
+ if (length > 20)
+ val |= 4 << 4;
+ else if (length > 6)
+ val |= 3 << 4;
+ else if (length > 4)
+ val |= 2 << 4;
+ else if (length > 2)
+ val |= 1 << 4;
+
+ /* Enable keyclick */
+ val |= 0x8000;
+
+ tsc2102_write_sync(TSC2102_AUDIO2_CTRL, val);
+ spin_unlock(&tsc.lock_sync);
+}
+
+#ifdef CONFIG_HWMON
+#define TSC2102_INPUT(devname, field) \
+static ssize_t show_ ## devname(struct device *dev, \
+ struct device_attribute *devattr, char *buf) \
+{ \
+ struct tsc2102_dev *devhwmon = dev_get_drvdata(dev); \
+ int value = devhwmon->field; \
+ return sprintf(buf, "%i\n", value); \
+} \
+static DEVICE_ATTR(devname ## _input, S_IRUGO, show_ ## devname, NULL);
+
+TSC2102_INPUT(in0, bat[0])
+TSC2102_INPUT(in1, bat[1])
+TSC2102_INPUT(in2, aux[0])
+TSC2102_INPUT(in3, temp[0])
+TSC2102_INPUT(in4, temp[1])
+
+static ssize_t show_temp1(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct tsc2102_dev *devhwmon = dev_get_drvdata(dev);
+ int t1, t2;
+ int value, diff;
+
+ t1 = devhwmon->temp[0];
+ t2 = devhwmon->temp[1];
+
+ /*
+ * Use method #2 (differential) to calculate current temperature.
+ * The difference between TEMP2 and TEMP1 input values is
+ * multiplied by a constant to obtain current temperature.
+ * To find this constant we use the values measured at 25 C as
+ * thermometer calibration data.
+ *
+ * 298150 is 25 degrees Celcius represented in Kelvins and
+ * multiplied by 1000 for fixed point precision (273.15 + 25).
+ * 273150 is zero degrees Celcius.
+ */
+ diff = devhwmon->pdata->temp_at25c[1] - devhwmon->pdata->temp_at25c[0];
+ BUG_ON(diff == 0);
+ value = (t2 - t1) * 298150 / diff; /* This is in Kelvins now */
+
+ t1 = value - 273150; /* Celcius millidegree */
+ return sprintf(buf, "%i\n", t1);
+}
+static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp1, NULL);
+#endif /* CONFIG_HWMON */
+
+#ifdef CONFIG_APM
+static void tsc2102_get_power_status(struct apm_power_info *info)
+{
+ tsc.pdata->apm_report(info, tsc.bat);
+}
+#endif
+
+#ifdef CONFIG_PM
+/*
+ * Suspend the chip.
+ */
+static int
+tsc2102_suspend(struct spi_device *spi, pm_message_t state)
+{
+ struct tsc2102_dev *dev = dev_get_drvdata(&spi->dev);
+
+ if (!dev)
+ return 0;
+
+ spin_lock(&dev->lock_sync);
+
+ del_timer(&dev->mode_timer);
+ del_timer(&dev->ts_timer);
+
+ if (dev->pendown && dev->touch_cb)
+ dev->touch_cb(0);
+
+ /* Abort current conversion and power down the ADC */
+ tsc2102_write_sync(TSC2102_TS_ADC_CTRL, TSC2102_ADC_ADST);
+
+ dev->spi->dev.power.power_state = state;
+
+ spin_unlock(&dev->lock_sync);
+ return 0;
+}
+
+/*
+ * Resume chip operation.
+ */
+static int tsc2102_resume(struct spi_device *spi)
+{
+ struct tsc2102_dev *dev = dev_get_drvdata(&spi->dev);
+ int err;
+
+ if (!dev)
+ return 0;
+
+ spin_lock(&dev->lock_sync);
+
+ dev->spi->dev.power.power_state = PMSG_ON;
+
+ dev->state = 0;
+ dev->pendown = 0;
+
+ err = tsc2102_configure(dev);
+
+ spin_unlock(&dev->lock_sync);
+ return err;
+}
+#else
+#define tsc2102_suspend NULL
+#define tsc2102_resume NULL
+#endif
+
+static struct platform_device tsc2102_ts_device = {
+ .name = "tsc2102-ts",
+ .id = -1,
+};
+
+static struct platform_device tsc2102_alsa_device = {
+ .name = "tsc2102-alsa",
+ .id = -1,
+};
+
+static int tsc2102_probe(struct spi_device *spi)
+{
+ struct tsc2102_config *pdata = spi->dev.platform_data;
+ struct spi_transfer *spi_buffer;
+ int err = 0;
+
+ if (!pdata) {
+ printk(KERN_ERR "TSC2102: Platform data not supplied\n");
+ return -ENOENT;
+ }
+
+ if (!spi->irq) {
+ printk(KERN_ERR "TSC2102: Invalid irq value\n");
+ return -ENOENT;
+ }
+
+ tsc.pdata = pdata;
+ tsc.state = 0;
+ tsc.pendown = 0;
+ tsc.data_pending = 0;
+ tsc.ts_msecs = 20;
+ tsc.mode_msecs = 1000;
+ tsc.spi = spi;
+
+ /* Allocate enough struct spi_transfer's for all requests */
+ spi_buffer = kzalloc(sizeof(struct spi_transfer) * 16, GFP_KERNEL);
+ if (!spi_buffer) {
+ printk(KERN_ERR "TSC2102: No memory for SPI buffers\n");
+ return -ENOMEM;
+ }
+
+ tsc.transfers = spi_buffer;
+ tsc2102_request_alloc(&tsc, &tsc.req_adc, 0, 4, &spi_buffer);
+ tsc2102_request_alloc(&tsc, &tsc.req_status, 0, 1, &spi_buffer);
+ tsc2102_request_alloc(&tsc, &tsc.req_pressure, 0, 1, &spi_buffer);
+ tsc2102_request_alloc(&tsc, &tsc.req_stopadc, 1, 1, &spi_buffer);
+ tsc2102_request_alloc(&tsc, &tsc.req_mode, 1, 1, &spi_buffer);
+
+ spin_lock_init(&tsc.lock);
+ spin_lock(&tsc.lock_sync);
+
+ /* Get the BCLK - assuming the rate is at 12000000 */
+ tsc.bclk_ck = clk_get(0, "bclk");
+ if (!tsc.bclk_ck) {
+ printk(KERN_ERR "Unable to get the clock BCLK\n");
+ err = -EPERM;
+ goto done;
+ }
+
+ clk_enable(tsc.bclk_ck);
+
+ if (request_irq(spi->irq, tsc2102_handler, IRQF_SAMPLE_RANDOM |
+ IRQF_TRIGGER_FALLING, "tsc2102", &tsc)) {
+ printk(KERN_ERR "Could not allocate touchscreen IRQ!\n");
+ err = -EINVAL;
+ goto err_clk;
+ }
+
+ setup_timer(&tsc.ts_timer,
+ tsc2102_pressure, (unsigned long) &tsc);
+ setup_timer(&tsc.mode_timer,
+ tsc2102_mode_timer, (unsigned long) &tsc);
+
+ /* Set up the communication bus */
+ dev_set_drvdata(&spi->dev, &tsc);
+ spi->dev.power.power_state = PMSG_ON;
+ spi->mode = SPI_MODE_1;
+ spi->bits_per_word = 16;
+ err = spi_setup(spi);
+ if (err)
+ goto err_timer;
+
+ /* Now try to detect the chip, make first contact */
+ if (tsc2102_get_revision() != 0x1) {
+ printk(KERN_ERR "No TI TSC2102 chip found!\n");
+ goto err_timer;
+ }
+
+ err = tsc2102_configure(&tsc);
+ if (err)
+ goto err_timer;
+
+ /* Register devices controlled by TSC 2102 */
+ tsc2102_ts_device.dev.platform_data = pdata;
+ tsc2102_ts_device.dev.parent = &spi->dev;
+ err = platform_device_register(&tsc2102_ts_device);
+ if (err)
+ goto err_timer;
+
+ tsc2102_alsa_device.dev.platform_data = pdata->alsa_config;
+ tsc2102_alsa_device.dev.parent = &spi->dev;
+ err = platform_device_register(&tsc2102_alsa_device);
+ if (err)
+ goto err_ts;
+
+#ifdef CONFIG_HWMON
+ tsc.hwmondev = hwmon_device_register(&spi->dev);
+ if (IS_ERR(tsc.hwmondev)) {
+ printk(KERN_ERR "tsc2102_hwmon: Device registration failed\n");
+ err = PTR_ERR(tsc.hwmondev);
+ goto err_alsa;
+ }
+
+ if (pdata->monitor & TSC_BAT1)
+ err |= device_create_file(&spi->dev, &dev_attr_in0_input);
+ if (pdata->monitor & TSC_BAT2)
+ err |= device_create_file(&spi->dev, &dev_attr_in1_input);
+ if (pdata->monitor & TSC_AUX)
+ err |= device_create_file(&spi->dev, &dev_attr_in2_input);
+ if (pdata->monitor & TSC_TEMP) {
+ err |= device_create_file(&spi->dev, &dev_attr_temp1_input);
+ err |= device_create_file(&spi->dev, &dev_attr_in3_input);
+ err |= device_create_file(&spi->dev, &dev_attr_in4_input);
+ }
+
+ if (err)
+ printk(KERN_ERR "tsc2102_hwmon: Creating one or more "
+ "attribute files failed\n");
+ err = 0; /* Not fatal */
+#endif
+
+#ifdef CONFIG_APM
+ if (pdata->apm_report)
+ apm_get_power_status = tsc2102_get_power_status;
+#endif
+
+ if (!err)
+ goto done;
+
+err_alsa:
+ platform_device_unregister(&tsc2102_alsa_device);
+err_ts:
+ platform_device_unregister(&tsc2102_ts_device);
+err_timer:
+ del_timer(&tsc.ts_timer);
+ del_timer(&tsc.mode_timer);
+ dev_set_drvdata(&spi->dev, NULL);
+err_clk:
+ clk_disable(tsc.bclk_ck);
+ clk_put(tsc.bclk_ck);
+done:
+ spin_unlock(&tsc.lock_sync);
+ return err;
+}
+
+static int tsc2102_remove(struct spi_device *spi)
+{
+ struct tsc2102_dev *dev = dev_get_drvdata(&spi->dev);
+
+ spin_lock(&dev->lock_sync);
+
+ platform_device_unregister(&tsc2102_ts_device);
+ platform_device_unregister(&tsc2102_alsa_device);
+
+ dev_set_drvdata(&spi->dev, NULL);
+
+ /* Release the BCLK */
+ clk_disable(dev->bclk_ck);
+ clk_put(dev->bclk_ck);
+
+ del_timer(&tsc.mode_timer);
+ del_timer(&tsc.ts_timer);
+
+ kfree(tsc.transfers);
+
+#ifdef CONFIG_HWMON
+ hwmon_device_unregister(dev->hwmondev);
+#endif
+
+#ifdef CONFIG_APM
+ apm_get_power_status = 0;
+#endif
+
+ spin_unlock(&dev->lock_sync);
+
+ return 0;
+}
+
+static struct spi_driver tsc2102_driver = {
+ .probe = tsc2102_probe,
+ .remove = tsc2102_remove,
+ .suspend = tsc2102_suspend,
+ .resume = tsc2102_resume,
+ .driver = {
+ .name = "tsc2102",
+ .owner = THIS_MODULE,
+ .bus = &spi_bus_type,
+ },
+};
+
+static char __initdata banner[] = KERN_INFO "TI TSC2102 driver initializing\n";
+
+static int __init tsc2102_init(void)
+{
+ printk(banner);
+ return spi_register_driver(&tsc2102_driver);
+}
+
+static void __exit tsc2102_exit(void)
+{
+ spi_unregister_driver(&tsc2102_driver);
+}
+
+module_init(tsc2102_init);
+module_exit(tsc2102_exit);
+
+EXPORT_SYMBOL(tsc2102_read_sync);
+EXPORT_SYMBOL(tsc2102_reads_sync);
+EXPORT_SYMBOL(tsc2102_write_sync);
+EXPORT_SYMBOL(tsc2102_keyclick);
+
+MODULE_AUTHOR("Andrzej Zaborowski");
+MODULE_DESCRIPTION("Interface driver for TI TSC2102 chips.");
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * tsc210x.c - TSC2101/2102/... driver core
+ *
+ * Copyright (c) 2005-2007 Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this package; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/suspend.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/completion.h>
+#include <linux/autoconf.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/tsc210x.h>
+
+
+/* NOTE: It should be straightforward to make this driver framework handle
+ * tsc2100 and tsc2111 chips, and maybe others too. The main differences
+ * are in the audio codec capabilities, but there are also some differences
+ * in how the various sensors (including touchscreen) are handled.
+ */
+
+/* Bit field definitions for chip registers */
+
+/* Scan X, Y, Z1, Z2, chip controlled, 12-bit, 16 samples, 500 usec */
+#define TSC210X_ADC_TS_CONTROL 0x8bf4
+/* Scan BAT1, BAT2, AUX1, AUX2, 12-bit, 16 samples, 500 usec */
+#define TSC210X_ADC_SCAN_CONTROL 0x2ff4
+/* Scan TEMP1, 12-bit, 16 samples, 500 usec */
+#define TSC210X_ADC_T1_CONTROL 0x2bf4
+/* Scan TEMP2, 12-bit, 16 samples, 500 usec */
+#define TSC210X_ADC_T2_CONTROL 0x33f4
+/* PINT/DAV acts as DAV */
+#define TSC210X_ADC_DAV 0x4000
+/* Internal reference, 100 usec delay, 1.25 V reference */
+#define TSC210X_ADC_INT_REF 0x0016
+/* External reference, 100 usec delay, 1.25 V reference */
+#define TSC210X_ADC_EXT_REF 0x0002
+/* 84 usec precharge time, 32 usec sense time */
+#define TSC210X_CONFIG_TIMES 0x0008
+/* The reset sequence */
+#define TSC210X_RESET 0xbb00
+/* Pen Status bit */
+#define TSC210X_ADC_PSTCM (1 << 15)
+/* A/D Status bit */
+#define TSC210X_ADC_ADST (1 << 14)
+/* (At least) One of X, Y, Z1, Z2 contains data */
+#define TSC210X_TS_DAV 0x0780
+/* (At least) One of BAT1, BAT2, AUX1, AUX2 contains data */
+#define TSC210X_PS_DAV 0x0078
+/* TEMP1 contains data */
+#define TSC210X_T1_DAV 0x0004
+/* TEMP2 contains data */
+#define TSC210X_T2_DAV 0x0002
+#define TSC2101_DAC_ON 0x0000
+#define TSC2101_DAC_OFF 0xe7fc
+#define TSC2102_DAC_ON 0x3ba0
+#define TSC2102_DAC_OFF 0xafa0
+#define TSC210X_FS44K (1 << 13)
+#define TSC210X_PLL1_OFF 0x0000
+#define TSC210X_PLL1_44K 0x811c
+#define TSC210X_PLL1_48K 0x8120
+#define TSC210X_PLL2_44K (5462 << 2)
+#define TSC210X_PLL2_48K (1920 << 2)
+#define TSC210X_SLVMS (1 << 11)
+#define TSC210X_DEEMPF (1 << 0)
+#define TSC2102_BASSBC (1 << 1)
+#define TSC210X_KEYCLICK_OFF 0x0000
+
+#define CS_CHANGE(val) 0
+
+struct tsc210x_spi_req {
+ struct spi_device *dev;
+ u16 command;
+ u16 data;
+ struct spi_message message;
+};
+
+struct tsc210x_dev {
+ enum tsc_type {
+ tsc2101,
+ tsc2102,
+ } kind;
+ struct tsc210x_config *pdata;
+ struct clk *bclk_ck;
+
+ struct workqueue_struct *queue;
+ struct delayed_work ts_worker; /* Poll-wait for PEN UP */
+ struct delayed_work sensor_worker; /* Scan the ADC inputs */
+ struct mutex queue_lock;
+ struct completion data_avail;
+
+ tsc210x_touch_t touch_cb;
+ void *touch_cb_ctx;
+
+ tsc210x_coords_t coords_cb;
+ void *coords_cb_ctx;
+
+ tsc210x_ports_t ports_cb;
+ void *ports_cb_ctx;
+
+ tsc210x_temp_t temp1_cb;
+ void *temp2_cb_ctx;
+
+ tsc210x_temp_t temp2_cb;
+ void *temp1_cb_ctx;
+
+ struct spi_device *spi;
+ struct spi_transfer *transfers;
+ struct tsc210x_spi_req req_adc;
+ struct tsc210x_spi_req req_status;
+ struct tsc210x_spi_req req_mode;
+ struct tsc210x_spi_req req_stop;
+
+ int pendown;
+ int flushing; /* Queue flush in progress */
+ u16 status;
+ u16 adc_data[4];
+ int bat[2], aux[2], temp[2];
+};
+
+static struct {
+ unsigned int ts_msecs; /* Interval for .ts_timer */
+ unsigned int mode_msecs; /* Interval for .mode_timer */
+} settings;
+
+module_param_named(touch_check_msecs, settings.ts_msecs, uint, 0);
+MODULE_PARM_DESC(touch_check_msecs, "Pen-up polling interval in msecs");
+
+module_param_named(sensor_scan_msecs, settings.mode_msecs, uint, 0);
+MODULE_PARM_DESC(sensor_scan_msecs, "Temperature & battery scan interval");
+
+int tsc210x_write_sync(struct tsc210x_dev *dev,
+ int page, u8 address, u16 data)
+{
+ static struct tsc210x_spi_req req;
+ static struct spi_transfer transfer[2];
+ int ret;
+
+ spi_message_init(&req.message);
+
+ /* Address */
+ req.command = (page << 11) | (address << 5);
+ transfer[0].tx_buf = &req.command;
+ transfer[0].rx_buf = NULL;
+ transfer[0].len = 2;
+ spi_message_add_tail(&transfer[0], &req.message);
+
+ /* Data */
+ transfer[1].tx_buf = &data;
+ transfer[1].rx_buf = NULL;
+ transfer[1].len = 2;
+ transfer[1].cs_change = CS_CHANGE(1);
+ spi_message_add_tail(&transfer[1], &req.message);
+
+ ret = spi_sync(dev->spi, &req.message);
+ if (!ret && req.message.status)
+ ret = req.message.status;
+ if (ret)
+ dev_dbg(&dev->spi->dev, "write_sync --> %d\n", ret);
+
+ return ret;
+}
+EXPORT_SYMBOL(tsc210x_write_sync);
+
+int tsc210x_reads_sync(struct tsc210x_dev *dev,
+ int page, u8 startaddress, u16 *data, int numregs)
+{
+ static struct tsc210x_spi_req req;
+ static struct spi_transfer transfer[6];
+ int ret, i, j;
+
+ if (numregs + 1 > ARRAY_SIZE(transfer))
+ return -EINVAL;
+
+ spi_message_init(&req.message);
+ i = 0;
+ j = 0;
+
+ /* Address */
+ req.command = 0x8000 | (page << 11) | (startaddress << 5);
+ transfer[i].tx_buf = &req.command;
+ transfer[i].rx_buf = NULL;
+ transfer[i].len = 2;
+ spi_message_add_tail(&transfer[i ++], &req.message);
+
+ /* Data */
+ while (j < numregs) {
+ transfer[i].tx_buf = NULL;
+ transfer[i].rx_buf = &data[j ++];
+ transfer[i].len = 2;
+ transfer[i].cs_change = CS_CHANGE(j == numregs);
+ spi_message_add_tail(&transfer[i ++], &req.message);
+ }
+
+ ret = spi_sync(dev->spi, &req.message);
+ if (!ret && req.message.status)
+ ret = req.message.status;
+ if (ret)
+ dev_dbg(&dev->spi->dev, "reads_sync --> %d\n", ret);
+
+ return ret;
+}
+EXPORT_SYMBOL(tsc210x_reads_sync);
+
+int tsc210x_read_sync(struct tsc210x_dev *dev, int page, u8 address)
+{
+ u16 ret;
+ int status;
+
+ status = tsc210x_reads_sync(dev, page, address, &ret, 1);
+ return status ? : ret;
+}
+EXPORT_SYMBOL(tsc210x_read_sync);
+
+
+static void tsc210x_submit_async(struct tsc210x_spi_req *spi)
+{
+ int ret;
+
+ ret = spi_async(spi->dev, &spi->message);
+ if (ret)
+ dev_dbg(&spi->dev->dev, "%s: error %i in SPI request\n",
+ __FUNCTION__, ret);
+}
+
+static void tsc210x_request_alloc(struct tsc210x_dev *dev,
+ struct tsc210x_spi_req *spi, int direction,
+ int page, u8 startaddress, int numregs, u16 *data,
+ void (*complete)(struct tsc210x_dev *context),
+ struct spi_transfer **transfer)
+{
+ spi->dev = dev->spi;
+
+ if (direction == 1) /* Write */
+ numregs = 2;
+ else /* Read */
+ numregs += 1;
+
+ spi_message_init(&spi->message);
+ spi->message.complete = (void (*)(void *)) complete;
+ spi->message.context = dev;
+
+ /* Address */
+ spi->command = (page << 11) | (startaddress << 5);
+ if (direction != 1)
+ spi->command |= 1 << 15;
+
+ (*transfer)->tx_buf = &spi->command;
+ (*transfer)->rx_buf = NULL;
+ (*transfer)->len = 2;
+ spi_message_add_tail((*transfer) ++, &spi->message);
+
+ /* Data */
+ while (-- numregs) {
+ if (direction == 1)
+ (*transfer)->tx_buf = &spi->data;
+ else
+ (*transfer)->rx_buf = data++;
+ (*transfer)->len = 2;
+ (*transfer)->cs_change = CS_CHANGE(numregs != 1);
+ spi_message_add_tail((*transfer) ++, &spi->message);
+ }
+}
+
+#define tsc210x_cb_register_func(cb, cb_t) \
+int tsc210x_ ## cb(struct device *dev, cb_t handler, void *context) \
+{ \
+ struct tsc210x_dev *tsc = dev_get_drvdata(dev); \
+ \
+ /* Lock the module */ \
+ if (handler && !tsc->cb) \
+ if (!try_module_get(THIS_MODULE)) { \
+ dev_err(dev, "Failed to get TSC module\n"); \
+ } \
+ if (!handler && tsc->cb) \
+ module_put(THIS_MODULE); \
+ \
+ tsc->cb = handler; \
+ tsc->cb ## _ctx = context; \
+ return 0; \
+} \
+EXPORT_SYMBOL(tsc210x_ ## cb);
+
+tsc210x_cb_register_func(touch_cb, tsc210x_touch_t)
+tsc210x_cb_register_func(coords_cb, tsc210x_coords_t)
+tsc210x_cb_register_func(ports_cb, tsc210x_ports_t)
+tsc210x_cb_register_func(temp1_cb, tsc210x_temp_t)
+tsc210x_cb_register_func(temp2_cb, tsc210x_temp_t)
+
+#ifdef DEBUG
+static void tsc210x_print_dav(struct tsc210x_dev *dev)
+{
+ int status = tsc210x_read_sync(dev, TSC210X_TS_STATUS_CTRL);
+
+ if (status < 0) {
+ dev_dbg(&dev->spi->dev, "status %d\n", status);
+ return;
+ }
+
+ if (!(status & 0x0fff))
+ return;
+
+ dev_dbg(&dev->spi->dev, "data in %s%s%s%s%s%s%s%s%s%s%s\n",
+ (status & 0x0400) ? " X" : "",
+ (status & 0x0200) ? " Y" : "",
+ (status & 0x0100) ? " Z1" : "",
+ (status & 0x0080) ? " Z2" : "",
+ (status & 0x0040) ? " BAT1" : "",
+ (status & 0x0020) ? " BAT2" : "",
+ (status & 0x0010) ? " AUX1" : "",
+ (status & 0x0008) ? " AUX2" : "",
+ (status & 0x0004) ? " TEMP1" : "",
+ (status & 0x0002) ? " TEMP2" : "",
+ (status & 0x0001) ? " KP" : "");
+}
+#endif
+
+static void tsc210x_complete_dummy(struct tsc210x_dev *dev)
+{
+}
+
+static inline void tsc210x_touchscreen_mode(struct tsc210x_dev *dev)
+{
+ /* Scan X, Y, Z1, Z2, chip controlled, 12-bit, 16 samples, 500 usec */
+ dev->req_mode.data = TSC210X_ADC_TS_CONTROL;
+ tsc210x_submit_async(&dev->req_mode);
+}
+
+static inline void tsc210x_portscan_mode(struct tsc210x_dev *dev)
+{
+ /* Scan BAT1, BAT2, AUX1, AUX2, 12-bit, 16 samples, 500 usec */
+ dev->req_mode.data = TSC210X_ADC_SCAN_CONTROL;
+ tsc210x_submit_async(&dev->req_mode);
+}
+
+static inline void tsc210x_temp1_mode(struct tsc210x_dev *dev)
+{
+ /* Scan TEMP1, 12-bit, 16 samples, 500 usec */
+ dev->req_mode.data = TSC210X_ADC_T1_CONTROL;
+ tsc210x_submit_async(&dev->req_mode);
+}
+
+static inline void tsc210x_temp2_mode(struct tsc210x_dev *dev)
+{
+ /* Scan TEMP2, 12-bit, 16 samples, 500 usec */
+ dev->req_mode.data = TSC210X_ADC_T2_CONTROL;
+ tsc210x_submit_async(&dev->req_mode);
+}
+
+/* Abort current conversion if any */
+static void tsc210x_new_mode(struct tsc210x_dev *dev)
+{
+ dev->req_stop.data = TSC210X_ADC_ADST;
+ tsc210x_submit_async(&dev->req_stop);
+}
+
+static void tsc210x_queue_scan(struct tsc210x_dev *dev)
+{
+ if (dev->pdata->monitor)
+ if (!queue_delayed_work(dev->queue,
+ &dev->sensor_worker,
+ msecs_to_jiffies(settings.mode_msecs)))
+ dev_err(&dev->spi->dev,
+ "%s: can't queue measurements\n",
+ __FUNCTION__);
+}
+
+static void tsc210x_queue_penup(struct tsc210x_dev *dev)
+{
+ if (!queue_delayed_work(dev->queue,
+ &dev->ts_worker,
+ msecs_to_jiffies(settings.ts_msecs)))
+ dev_err(&dev->spi->dev,
+ "%s: can't queue pen-up poll\n",
+ __FUNCTION__);
+}
+
+static void tsc210x_status_report(struct tsc210x_dev *dev)
+{
+ /*
+ * Read all converted data from corresponding registers
+ * so that the ADC can move on to a new conversion.
+ */
+ if (dev->status & TSC210X_TS_DAV) {
+ if (!dev->pendown && !dev->flushing) {
+ dev->pendown = 1;
+ if (dev->touch_cb)
+ dev->touch_cb(dev->touch_cb_ctx, 1);
+
+ tsc210x_queue_penup(dev);
+ }
+
+ tsc210x_submit_async(&dev->req_adc);
+ }
+
+ if (dev->status & (TSC210X_PS_DAV | TSC210X_T1_DAV | TSC210X_T2_DAV))
+ complete(&dev->data_avail);
+}
+
+static void tsc210x_data_report(struct tsc210x_dev *dev)
+{
+ u16 adc_data[4];
+
+ if (dev->status & TSC210X_PS_DAV) {
+ tsc210x_reads_sync(dev, TSC210X_TS_BAT1, adc_data, 4);
+ /* NOTE: reads_sync() could fail */
+
+ dev->bat[0] = adc_data[0];
+ dev->bat[1] = adc_data[1];
+ dev->aux[0] = adc_data[2];
+ dev->aux[1] = adc_data[3];
+ if (dev->ports_cb)
+ dev->ports_cb(dev->ports_cb_ctx, dev->bat, dev->aux);
+ }
+
+ if (dev->status & TSC210X_T1_DAV) {
+ dev->temp[0] = tsc210x_read_sync(dev, TSC210X_TS_TEMP1);
+
+ if (dev->temp[0] >= 0 && dev->temp1_cb)
+ dev->temp1_cb(dev->temp1_cb_ctx, dev->temp[0]);
+ }
+
+ if (dev->status & TSC210X_T2_DAV) {
+ dev->temp[1] = tsc210x_read_sync(dev, TSC210X_TS_TEMP2);
+
+ if (dev->temp[1] >= 0 && dev->temp2_cb)
+ dev->temp2_cb(dev->temp2_cb_ctx, dev->temp[1]);
+ }
+}
+
+static void tsc210x_coords_report(struct tsc210x_dev *dev)
+{
+ if (dev->coords_cb)
+ dev->coords_cb(dev->coords_cb_ctx,
+ dev->adc_data[0], dev->adc_data[1],
+ dev->adc_data[2], dev->adc_data[3]);
+}
+
+/*
+ * There are at least three ways to check for pen-up:
+ * - the PINT/DAV pin state,
+ * - reading PSTCM bit in ADC Control register (D15, offset 0x00),
+ * - reading ADST bit in ADC Control register (D14, offset 0x00),
+ * ADC idle would indicate no screen touch.
+ * Unfortunately none of them seems to be 100% accurate and you will
+ * find they are totally inconsistent, i.e. you get to see any arbitrary
+ * combination of values in these three bits. So we will busy-wait
+ * for a moment when the latter two indicate a pen-up, using a queue,
+ * before we report a pen-up.
+ */
+static void tsc210x_pressure(struct work_struct *work)
+{
+ struct tsc210x_dev *dev =
+ container_of(work, struct tsc210x_dev, ts_worker.work);
+ int adc_status;
+
+ WARN_ON(!dev->pendown);
+
+ adc_status = tsc210x_read_sync(dev, TSC210X_TS_ADC_CTRL);
+ if (adc_status < 0) {
+ dev_dbg(&dev->spi->dev, "pressure, err %d\n", adc_status);
+ return;
+ }
+
+ if ((adc_status & TSC210X_ADC_PSTCM) != 0
+ || !(adc_status & TSC210X_ADC_ADST))
+ tsc210x_queue_penup(dev);
+ else {
+ dev->pendown = 0;
+ if (dev->touch_cb)
+ dev->touch_cb(dev->touch_cb_ctx, 0);
+ }
+}
+
+static void tsc210x_wait_data(struct tsc210x_dev *dev)
+{
+ wait_for_completion(&dev->data_avail);
+
+ tsc210x_data_report(dev);
+}
+
+static void tsc210x_input_scan(struct work_struct *work)
+{
+ struct tsc210x_dev *dev = (struct tsc210x_dev *)
+ container_of(work, struct tsc210x_dev, sensor_worker.work);
+
+ tsc210x_new_mode(dev);
+
+ if (dev->pdata->monitor &
+ (TSC_BAT1 | TSC_BAT2 | TSC_AUX1 | TSC_AUX2)) {
+ tsc210x_portscan_mode(dev);
+ tsc210x_wait_data(dev);
+ }
+
+ if (dev->pdata->monitor & TSC_TEMP) {
+ tsc210x_temp1_mode(dev);
+ tsc210x_wait_data(dev);
+
+ tsc210x_temp2_mode(dev);
+ tsc210x_wait_data(dev);
+ }
+
+ tsc210x_touchscreen_mode(dev);
+
+ mutex_lock(&dev->queue_lock);
+ if (!dev->flushing)
+ tsc210x_queue_scan(dev);
+ mutex_unlock(&dev->queue_lock);
+}
+
+/* ADC has finished a new conversion for us. */
+static irqreturn_t tsc210x_handler(int irq, void *dev_id)
+{
+ struct tsc210x_dev *dev = (struct tsc210x_dev *) dev_id;
+
+ /* See what data became available. */
+ tsc210x_submit_async(&dev->req_status);
+
+ return IRQ_HANDLED;
+}
+
+#if defined(CONFIG_SOUND) || defined(CONFIG_SOUND_MODULE)
+
+/*
+ * FIXME the audio support shouldn't be included in upstream patches
+ * until it's ready. They might be better as utility functions linked
+ * with a chip-specific tsc21xx audio module ... e.g. chips with input
+ * channels need more, as will ones with multiple output channels and
+ * so on. Each of these functions should probably return a fault code,
+ * and will need to be exported so the sound drier can be modular.
+ */
+
+/*
+ * Volume level values should be in the range [0, 127].
+ * Higher values mean lower volume.
+ */
+void tsc210x_set_dac_volume(struct device *dev, u8 left_ch, u8 right_ch)
+{
+ struct tsc210x_dev *tsc = dev_get_drvdata(dev);
+ int val;
+
+ if (tsc->kind == tsc2102) {
+ /* All 0's or all 1's */
+ if (left_ch == 0x00 || left_ch == 0x7f)
+ left_ch ^= 0x7f;
+ if (right_ch == 0x00 || right_ch == 0x7f)
+ right_ch ^= 0x7f;
+ }
+
+ val = tsc210x_read_sync(tsc, TSC210X_DAC_GAIN_CTRL);
+ if (val < 0) {
+ dev_dbg(dev, "%s, err %d\n", __FUNCTION__, val);
+ return;
+ }
+
+ val &= 0x8080; /* Preserve mute-bits */
+ val |= (left_ch << 8) | right_ch;
+
+ tsc210x_write_sync(tsc, TSC210X_DAC_GAIN_CTRL, val);
+ /* NOTE: write_sync() could fail */
+}
+
+void tsc210x_set_dac_mute(struct device *dev, int left_ch, int right_ch)
+{
+ struct tsc210x_dev *tsc = dev_get_drvdata(dev);
+ int val;
+
+ val = tsc210x_read_sync(tsc, TSC210X_DAC_GAIN_CTRL);
+ if (val < 0) {
+ dev_dbg(dev, "%s, err %d\n", __FUNCTION__, val);
+ return;
+ }
+
+ val &= 0x7f7f; /* Preserve volume settings */
+ val |= (left_ch << 15) | (right_ch << 7);
+
+ tsc210x_write_sync(tsc, TSC210X_DAC_GAIN_CTRL, val);
+ /* NOTE: write_sync() could fail */
+}
+
+void tsc210x_get_dac_mute(struct device *dev, int *left_ch, int *right_ch)
+{
+ struct tsc210x_dev *tsc = dev_get_drvdata(dev);
+ int val;
+
+ val = tsc210x_read_sync(tsc, TSC210X_DAC_GAIN_CTRL);
+ if (val < 0) {
+ dev_dbg(dev, "%s, err %d\n", __FUNCTION__, val);
+ return;
+ }
+
+ *left_ch = !!(val & (1 << 15));
+ *right_ch = !!(val & (1 << 7));
+}
+
+void tsc210x_set_deemphasis(struct device *dev, int enable)
+{
+ struct tsc210x_dev *tsc = dev_get_drvdata(dev);
+ int val;
+
+ val = tsc210x_read_sync(tsc, TSC210X_POWER_CTRL);
+ if (val < 0) {
+ dev_dbg(dev, "%s, err %d\n", __FUNCTION__, val);
+ return;
+ }
+
+ if (enable)
+ val &= ~TSC210X_DEEMPF;
+ else
+ val |= TSC210X_DEEMPF;
+
+ tsc210x_write_sync(tsc, TSC210X_POWER_CTRL, val);
+ /* NOTE: write_sync() could fail */
+}
+
+void tsc2102_set_bassboost(struct device *dev, int enable)
+{
+ struct tsc210x_dev *tsc = dev_get_drvdata(dev);
+ int val;
+
+ val = tsc210x_read_sync(tsc, TSC210X_POWER_CTRL);
+ if (val < 0) {
+ dev_dbg(dev, "%s, err %d\n", __FUNCTION__, val);
+ return;
+ }
+
+ if (enable)
+ val &= ~TSC2102_BASSBC;
+ else
+ val |= TSC2102_BASSBC;
+
+ tsc210x_write_sync(tsc, TSC210X_POWER_CTRL, val);
+ /* NOTE: write_sync() could fail */
+}
+
+/* {rate, dsor, fsref} */
+static const struct tsc210x_rate_info_s tsc2101_rates[] = {
+ /* Fsref / 6.0 */
+ {7350, 7, 1},
+ {8000, 7, 0},
+ /* Fsref / 5.5 */
+ {8018, 6, 1},
+ {8727, 6, 0},
+ /* Fsref / 5.0 */
+ {8820, 5, 1},
+ {9600, 5, 0},
+ /* Fsref / 4.0 */
+ {11025, 4, 1},
+ {12000, 4, 0},
+ /* Fsref / 3.0 */
+ {14700, 3, 1},
+ {16000, 3, 0},
+ /* Fsref / 2.0 */
+ {22050, 2, 1},
+ {24000, 2, 0},
+ /* Fsref / 1.5 */
+ {29400, 1, 1},
+ {32000, 1, 0},
+ /* Fsref */
+ {44100, 0, 1},
+ {48000, 0, 0},
+
+ {0, 0, 0},
+};
+
+/* {rate, dsor, fsref} */
+static const struct tsc210x_rate_info_s tsc2102_rates[] = {
+ /* Fsref / 6.0 */
+ {7350, 63, 1},
+ {8000, 63, 0},
+ /* Fsref / 6.0 */
+ {7350, 54, 1},
+ {8000, 54, 0},
+ /* Fsref / 5.0 */
+ {8820, 45, 1},
+ {9600, 45, 0},
+ /* Fsref / 4.0 */
+ {11025, 36, 1},
+ {12000, 36, 0},
+ /* Fsref / 3.0 */
+ {14700, 27, 1},
+ {16000, 27, 0},
+ /* Fsref / 2.0 */
+ {22050, 18, 1},
+ {24000, 18, 0},
+ /* Fsref / 1.5 */
+ {29400, 9, 1},
+ {32000, 9, 0},
+ /* Fsref */
+ {44100, 0, 1},
+ {48000, 0, 0},
+
+ {0, 0, 0},
+};
+
+int tsc210x_set_rate(struct device *dev, int rate)
+{
+ struct tsc210x_dev *tsc = dev_get_drvdata(dev);
+ int i;
+ int val;
+ const struct tsc210x_rate_info_s *rates;
+
+ if (tsc->kind == tsc2101)
+ rates = tsc2101_rates;
+ else
+ rates = tsc2102_rates;
+
+ for (i = 0; rates[i].sample_rate; i ++)
+ if (rates[i].sample_rate == rate)
+ break;
+ if (rates[i].sample_rate == 0) {
+ dev_err(dev, "Unknown sampling rate %i.0 Hz\n", rate);
+ return -EINVAL;
+ }
+
+ if (tsc->kind == tsc2101) {
+ val = tsc210x_read_sync(tsc, TSC210X_AUDIO1_CTRL);
+ if (val < 0) {
+ dev_dbg(dev, "%s, err %d\n", __FUNCTION__, val);
+ return val;
+ }
+ val &= ~((7 << 3) | (7 << 0));
+ val |= rates[i].divisor << 3;
+ val |= rates[i].divisor << 0;
+ } else
+ val = rates[i].divisor;
+
+ tsc210x_write_sync(tsc, TSC210X_AUDIO1_CTRL, val);
+ /* NOTE: write_sync() could fail */
+
+ val = tsc210x_read_sync(tsc, TSC210X_AUDIO3_CTRL);
+ if (val < 0) {
+ dev_dbg(dev, "%s, err %d\n", __FUNCTION__, val);
+ return val;
+ }
+
+ if (tsc2102_rates[i].fs_44k) {
+ tsc210x_write_sync(tsc,
+ TSC210X_AUDIO3_CTRL, val | TSC210X_FS44K);
+ /* Enable Phase-locked-loop, set up clock dividers */
+ tsc210x_write_sync(tsc, TSC210X_PLL1_CTRL, TSC210X_PLL1_44K);
+ tsc210x_write_sync(tsc, TSC210X_PLL2_CTRL, TSC210X_PLL2_44K);
+ } else {
+ tsc210x_write_sync(tsc,
+ TSC210X_AUDIO3_CTRL, val & ~TSC210X_FS44K);
+ /* Enable Phase-locked-loop, set up clock dividers */
+ tsc210x_write_sync(tsc, TSC210X_PLL1_CTRL, TSC210X_PLL1_48K);
+ tsc210x_write_sync(tsc, TSC210X_PLL2_CTRL, TSC210X_PLL2_48K);
+ }
+
+ return 0;
+}
+
+/*
+ * Perform basic set-up with default values and power the DAC/ADC on.
+ */
+void tsc210x_dac_power(struct device *dev, int on)
+{
+ struct tsc210x_dev *tsc = dev_get_drvdata(dev);
+
+ /* NOTE: write_sync() could fail */
+ if (on) {
+ /* 16-bit words, DSP mode, sample at Fsref */
+ tsc210x_write_sync(tsc,
+ TSC210X_AUDIO1_CTRL, 0x0100);
+ /* Keyclicks off, soft-stepping at normal rate */
+ tsc210x_write_sync(tsc,
+ TSC210X_AUDIO2_CTRL, TSC210X_KEYCLICK_OFF);
+ /* 44.1 kHz Fsref, continuous transfer mode, master DAC */
+ tsc210x_write_sync(tsc,
+ TSC210X_AUDIO3_CTRL, 0x2000);
+ /* Soft-stepping enabled, 1 dB MIX AGC hysteresis */
+ tsc210x_write_sync(tsc,
+ TSC210X_AUDIO4_CTRL, 0x0000);
+
+ /* PLL generates 44.1 kHz */
+ tsc210x_write_sync(tsc,
+ TSC210X_PLL1_CTRL, TSC210X_PLL1_44K);
+ tsc210x_write_sync(tsc,
+ TSC210X_PLL2_CTRL, TSC210X_PLL2_44K);
+
+ /* Codec & DAC power up, virtual ground disabled */
+ tsc210x_write_sync(tsc,
+ TSC210X_POWER_CTRL, (tsc->kind == tsc2101) ?
+ TSC2101_DAC_ON : TSC2102_DAC_ON);
+ } else {
+ /* All off */
+ tsc210x_write_sync(tsc,
+ TSC210X_AUDIO2_CTRL, TSC210X_KEYCLICK_OFF);
+ tsc210x_write_sync(tsc,
+ TSC210X_PLL1_CTRL, TSC210X_PLL1_OFF);
+#if 0
+ tsc210x_write_sync(tsc,
+ TSC210X_POWER_CTRL, (tsc->kind == tsc2101) ?
+ TSC2102_DAC_OFF : TSC2102_DAC_OFF);
+#endif
+ }
+}
+
+void tsc210x_set_i2s_master(struct device *dev, int state)
+{
+ struct tsc210x_dev *tsc = dev_get_drvdata(dev);
+ int val;
+
+ val = tsc210x_read_sync(tsc, TSC210X_AUDIO3_CTRL);
+ if (val < 0) {
+ dev_dbg(dev, "%s, err %d\n", __FUNCTION__, val);
+ return;
+ }
+
+ /* NOTE: write_sync() could fail */
+ if (state)
+ tsc210x_write_sync(tsc, TSC210X_AUDIO3_CTRL,
+ val | TSC210X_SLVMS);
+ else
+ tsc210x_write_sync(tsc, TSC210X_AUDIO3_CTRL,
+ val & ~TSC210X_SLVMS);
+}
+#endif /* CONFIG_SOUND */
+
+static int tsc210x_configure(struct tsc210x_dev *dev)
+{
+ /* NOTE: write_sync() could fail */
+
+ /* Reset the chip */
+ tsc210x_write_sync(dev, TSC210X_TS_RESET_CTRL, TSC210X_RESET);
+
+ /* Reference mode */
+ if (dev->pdata->use_internal)
+ tsc210x_write_sync(dev,
+ TSC210X_TS_REF_CTRL, TSC210X_ADC_INT_REF);
+ else
+ tsc210x_write_sync(dev,
+ TSC210X_TS_REF_CTRL, TSC210X_ADC_EXT_REF);
+
+ /* Precharge and sense delays, pen touch detection on */
+ tsc210x_write_sync(dev, TSC210X_TS_CONFIG_CTRL, TSC210X_CONFIG_TIMES);
+
+ /* PINT/DAV acts as DAV */
+ tsc210x_write_sync(dev, TSC210X_TS_STATUS_CTRL, TSC210X_ADC_DAV);
+
+ tsc210x_queue_scan(dev);
+ return 0;
+}
+
+void tsc210x_keyclick(struct tsc210x_dev *dev,
+ int amplitude, int freq, int length)
+{
+ int val;
+
+ val = tsc210x_read_sync(dev, TSC210X_AUDIO2_CTRL);
+ if (val < 0) {
+ dev_dbg(&dev->spi->dev, "%s, err %d\n",
+ __FUNCTION__, val);
+ return;
+ }
+ val &= 0x800f;
+
+ /* Set amplitude */
+ switch (amplitude) {
+ case 1:
+ val |= 4 << 12;
+ break;
+ case 2:
+ val |= 7 << 12;
+ break;
+ default:
+ break;
+ }
+
+ /* Frequency */
+ val |= (freq & 0x7) << 8;
+
+ /* Round to nearest supported length */
+ if (dev->kind == tsc2101)
+ val = (min(length - 1, 31) >> 1) << 4;
+ else {
+ if (length > 20)
+ val |= 4 << 4;
+ else if (length > 6)
+ val |= 3 << 4;
+ else if (length > 4)
+ val |= 2 << 4;
+ else if (length > 2)
+ val |= 1 << 4;
+ }
+
+ /* Enable keyclick */
+ val |= 0x8000;
+
+ /* NOTE: write_sync() could fail */
+ tsc210x_write_sync(dev, TSC210X_AUDIO2_CTRL, val);
+}
+EXPORT_SYMBOL(tsc210x_keyclick);
+
+#ifdef CONFIG_PM
+/*
+ * Suspend the chip.
+ */
+static int
+tsc210x_suspend(struct spi_device *spi, pm_message_t state)
+{
+ struct tsc210x_dev *dev = dev_get_drvdata(&spi->dev);
+
+ if (!dev)
+ return -ENODEV;
+
+ /* Stop the inputs scan loop */
+ mutex_lock(&dev->queue_lock);
+ dev->flushing = 1;
+ cancel_delayed_work(&dev->sensor_worker);
+ mutex_unlock(&dev->queue_lock);
+ flush_workqueue(dev->queue);
+
+ /* Wait until pen-up happens */
+ while (dev->pendown)
+ flush_workqueue(dev->queue);
+
+ /* Abort current conversion and power down the ADC */
+ tsc210x_write_sync(dev, TSC210X_TS_ADC_CTRL, TSC210X_ADC_ADST);
+ /* NOTE: write_sync() could fail */
+
+ return 0;
+}
+
+/*
+ * Resume chip operation.
+ */
+static int tsc210x_resume(struct spi_device *spi)
+{
+ struct tsc210x_dev *dev = dev_get_drvdata(&spi->dev);
+ int err;
+
+ if (!dev)
+ return 0;
+
+ mutex_lock(&dev->queue_lock);
+ err = tsc210x_configure(dev);
+
+ dev->flushing = 0;
+ mutex_unlock(&dev->queue_lock);
+
+ return err;
+}
+#else
+#define tsc210x_suspend NULL
+#define tsc210x_resume NULL
+#endif
+
+/* REVISIT don't make these static */
+static struct platform_device tsc210x_ts_device = {
+ .name = "tsc210x-ts",
+ .id = -1,
+};
+
+static struct platform_device tsc210x_hwmon_device = {
+ .name = "tsc210x-hwmon",
+ .id = -1,
+};
+
+static struct platform_device tsc210x_alsa_device = {
+ .name = "tsc210x-alsa",
+ .id = -1,
+};
+
+static int tsc210x_probe(struct spi_device *spi, enum tsc_type type)
+{
+ struct tsc210x_config *pdata = spi->dev.platform_data;
+ struct spi_transfer *spi_buffer;
+ struct tsc210x_dev *dev;
+ int reg;
+ int err = 0;
+
+ if (!pdata) {
+ dev_dbg(&spi->dev, "Platform data not supplied\n");
+ return -ENOENT;
+ }
+
+ if (!spi->irq) {
+ dev_dbg(&spi->dev, "Invalid irq value\n");
+ return -EINVAL;
+ }
+
+ dev = (struct tsc210x_dev *)
+ kzalloc(sizeof(struct tsc210x_dev), GFP_KERNEL);
+ if (!dev) {
+ dev_dbg(&spi->dev, "No memory\n");
+ return -ENOMEM;
+ }
+
+ dev->pdata = pdata;
+ dev->pendown = 0;
+ dev->spi = spi;
+ dev->kind = type;
+ dev->queue = create_singlethread_workqueue(spi->dev.driver->name);
+ if (!dev->queue) {
+ dev_dbg(&spi->dev, "Can't make a workqueue\n");
+ err = -ENOMEM;
+ goto err_queue;
+ }
+
+ mutex_init(&dev->queue_lock);
+ init_completion(&dev->data_avail);
+
+ /* Allocate enough struct spi_transfer's for all requests */
+ spi_buffer = kzalloc(sizeof(struct spi_transfer) * 16, GFP_KERNEL);
+ if (!spi_buffer) {
+ dev_dbg(&spi->dev, "No memory for SPI buffers\n");
+ err = -ENOMEM;
+ goto err_buffers;
+ }
+
+ dev->transfers = spi_buffer;
+ tsc210x_request_alloc(dev, &dev->req_adc, 0,
+ TSC210X_TS_X, 4, dev->adc_data,
+ tsc210x_coords_report, &spi_buffer);
+ tsc210x_request_alloc(dev, &dev->req_status, 0,
+ TSC210X_TS_STATUS_CTRL, 1, &dev->status,
+ tsc210x_status_report, &spi_buffer);
+ tsc210x_request_alloc(dev, &dev->req_mode, 1,
+ TSC210X_TS_ADC_CTRL, 1, NULL,
+ tsc210x_complete_dummy, &spi_buffer);
+ tsc210x_request_alloc(dev, &dev->req_stop, 1,
+ TSC210X_TS_ADC_CTRL, 1, NULL,
+ tsc210x_complete_dummy, &spi_buffer);
+
+ if (pdata->bclk) {
+ /* Get the BCLK */
+ dev->bclk_ck = clk_get(&spi->dev, pdata->bclk);
+ if (IS_ERR(dev->bclk_ck)) {
+ err = PTR_ERR(dev->bclk_ck);
+ dev_dbg(&spi->dev, "Unable to get '%s': %i\n",
+ pdata->bclk, err);
+ goto err_clk;
+ }
+
+ clk_enable(dev->bclk_ck);
+ }
+
+ INIT_DELAYED_WORK(&dev->ts_worker, tsc210x_pressure);
+ INIT_DELAYED_WORK(&dev->sensor_worker, tsc210x_input_scan);
+
+ /* Setup the communication bus */
+ dev_set_drvdata(&spi->dev, dev);
+ spi->mode = SPI_MODE_1;
+ spi->bits_per_word = 16;
+ err = spi_setup(spi);
+ if (err)
+ goto err_spi;
+
+ /* Now try to detect the chip, make first contact. These chips
+ * don't self-identify, but we can expect that the status register
+ * reports the ADC is idle and use that as a sanity check. (It'd
+ * be even better if we did a soft reset first...)
+ */
+ reg = tsc210x_read_sync(dev, TSC210X_TS_ADC_CTRL);
+ if (reg < 0) {
+ err = reg;
+ dev_dbg(&dev->spi->dev, "adc_ctrl, err %d\n", err);
+ goto err_spi;
+ }
+ if (!(reg & (1 << 14))) {
+ err = -EIO;
+ dev_dbg(&dev->spi->dev, "adc_ctrl, busy? - %04x\n", reg);
+ goto err_spi;
+ }
+
+ reg = tsc210x_read_sync(dev, TSC210X_AUDIO3_CTRL);
+ if (reg < 0) {
+ err = reg;
+ dev_dbg(&dev->spi->dev, "revision, err %d\n", err);
+ goto err_spi;
+ }
+ if (reg == 0xffff) {
+ err = -ENODEV;
+ dev_dbg(&dev->spi->dev, "no device, err %d\n", err);
+ goto err_spi;
+ }
+ dev_info(&spi->dev, "rev %d, irq %d\n", reg & 0x0007, spi->irq);
+
+ err = tsc210x_configure(dev);
+ if (err)
+ goto err_spi;
+
+ /* We want no interrupts before configuration succeeds. */
+ mutex_lock(&dev->queue_lock);
+ dev->flushing = 1;
+
+ if (request_irq(spi->irq, tsc210x_handler, IRQF_SAMPLE_RANDOM |
+ IRQF_TRIGGER_FALLING, spi->dev.driver->name,
+ dev)) {
+ dev_dbg(&spi->dev, "Could not allocate touchscreen IRQ!\n");
+ err = -EINVAL;
+ goto err_irq;
+ }
+
+ /* Register subdevices controlled by the TSC 2101/2102 */
+ tsc210x_ts_device.dev.platform_data = dev;
+ tsc210x_ts_device.dev.parent = &spi->dev;
+ err = platform_device_register(&tsc210x_ts_device);
+ if (err)
+ goto err_irq;
+
+ tsc210x_hwmon_device.dev.platform_data = pdata;
+ tsc210x_hwmon_device.dev.parent = &spi->dev;
+ err = platform_device_register(&tsc210x_hwmon_device);
+ if (err)
+ goto err_hwmon;
+
+ tsc210x_alsa_device.dev.platform_data = pdata->alsa_config;
+ tsc210x_alsa_device.dev.parent = &spi->dev;
+ err = platform_device_register(&tsc210x_alsa_device);
+ if (err)
+ goto err_alsa;
+
+ dev->flushing = 0;
+ mutex_unlock(&dev->queue_lock);
+ return 0;
+
+err_alsa:
+ platform_device_unregister(&tsc210x_hwmon_device);
+err_hwmon:
+ platform_device_unregister(&tsc210x_ts_device);
+err_irq:
+ mutex_unlock(&dev->queue_lock);
+err_spi:
+ dev_set_drvdata(&spi->dev, NULL);
+ clk_disable(dev->bclk_ck);
+ clk_put(dev->bclk_ck);
+err_clk:
+ kfree(dev->transfers);
+err_buffers:
+ destroy_workqueue(dev->queue);
+err_queue:
+ kfree(dev);
+ return err;
+}
+
+static int tsc2101_probe(struct spi_device *spi)
+{
+ return tsc210x_probe(spi, tsc2101);
+}
+
+static int tsc2102_probe(struct spi_device *spi)
+{
+ return tsc210x_probe(spi, tsc2102);
+}
+
+static int tsc210x_remove(struct spi_device *spi)
+{
+ struct tsc210x_dev *dev = dev_get_drvdata(&spi->dev);
+
+ /* Stop the inputs scan loop */
+ mutex_lock(&dev->queue_lock);
+ dev->flushing = 1;
+ cancel_delayed_work(&dev->sensor_worker);
+ mutex_unlock(&dev->queue_lock);
+ flush_workqueue(dev->queue);
+
+ /* Wait for pen-up */
+ while (dev->pendown)
+ flush_workqueue(dev->queue);
+
+ /* Abort current conversion and power down the ADC */
+ tsc210x_write_sync(dev, TSC210X_TS_ADC_CTRL, TSC210X_ADC_ADST);
+ /* NOTE: write_sync() could fail */
+
+ destroy_workqueue(dev->queue);
+
+ platform_device_unregister(&tsc210x_ts_device);
+ platform_device_unregister(&tsc210x_hwmon_device);
+ platform_device_unregister(&tsc210x_alsa_device);
+
+ dev_set_drvdata(&spi->dev, NULL);
+
+ /* Release the BCLK */
+ clk_disable(dev->bclk_ck);
+ clk_put(dev->bclk_ck);
+
+ kfree(dev->transfers);
+ kfree(dev);
+
+ return 0;
+}
+
+static struct spi_driver tsc2101_driver = {
+ .probe = tsc2101_probe,
+ .remove = tsc210x_remove,
+ .suspend = tsc210x_suspend,
+ .resume = tsc210x_resume,
+ .driver = {
+ .name = "tsc2101",
+ .owner = THIS_MODULE,
+ .bus = &spi_bus_type,
+ },
+};
+
+static struct spi_driver tsc2102_driver = {
+ .probe = tsc2102_probe,
+ .remove = tsc210x_remove,
+ .suspend = tsc210x_suspend,
+ .resume = tsc210x_resume,
+ .driver = {
+ .name = "tsc2102",
+ .owner = THIS_MODULE,
+ .bus = &spi_bus_type,
+ },
+};
+
+static char __initdata banner[] = KERN_INFO "TI TSC210x driver initializing\n";
+
+static int __init tsc210x_init(void)
+{
+ int err;
+ printk(banner);
+
+ settings.ts_msecs = 20;
+ settings.mode_msecs = 1000;
+
+ err = spi_register_driver(&tsc2101_driver);
+ if (err != 0)
+ return err;
+
+ err = spi_register_driver(&tsc2102_driver);
+ if (err != 0)
+ spi_unregister_driver(&tsc2101_driver);
+
+ return err;
+}
+module_init(tsc210x_init);
+
+static void __exit tsc210x_exit(void)
+{
+ spi_unregister_driver(&tsc2101_driver);
+ spi_unregister_driver(&tsc2102_driver);
+}
+module_exit(tsc210x_exit);
+
+MODULE_AUTHOR("Andrzej Zaborowski");
+MODULE_DESCRIPTION("Interface driver for TI TSC210x chips.");
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * TSC2301 driver
+ *
+ * Copyright (C) 2005, 2006 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/device.h>
+#include <linux/delay.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/tsc2301.h>
+
+#ifdef CONFIG_ARCH_OMAP
+#include <asm/arch/gpio.h>
+#endif
+
+u16 tsc2301_read_reg(struct tsc2301 *tsc, int reg)
+{
+ struct spi_transfer t[2];
+ struct spi_message m;
+ u16 data = 0, cmd;
+
+ cmd = reg;
+ cmd |= 0x8000;
+
+ memset(t, 0, sizeof(t));
+ spi_message_init(&m);
+ m.spi = tsc->spi;
+
+ t[0].tx_buf = &cmd;
+ t[0].rx_buf = NULL;
+ t[0].len = 2;
+ spi_message_add_tail(&t[0], &m);
+
+ t[1].tx_buf = NULL;
+ t[1].rx_buf = &data;
+ t[1].len = 2;
+ spi_message_add_tail(&t[1], &m);
+
+ spi_sync(m.spi, &m);
+
+ return data;
+}
+
+void tsc2301_write_reg(struct tsc2301 *tsc, int reg, u16 val)
+{
+ struct spi_transfer t;
+ struct spi_message m;
+ u16 data[2];
+
+ /* Now we prepare the command for transferring */
+ data[0] = reg;
+ data[1] = val;
+
+ spi_message_init(&m);
+ m.spi = tsc->spi;
+
+ memset(&t, 0, sizeof(t));
+ t.tx_buf = data;
+ t.rx_buf = NULL;
+ t.len = 4;
+ spi_message_add_tail(&t, &m);
+
+ spi_sync(m.spi, &m);
+}
+
+void tsc2301_write_kbc(struct tsc2301 *tsc, int val)
+{
+ u16 w;
+
+ w = tsc->config2_shadow;
+ w &= ~(0x03 << 14);
+ w |= (val & 0x03) << 14;
+ tsc2301_write_reg(tsc, TSC2301_REG_CONFIG2, w);
+ tsc->config2_shadow = w;
+}
+
+void tsc2301_write_pll(struct tsc2301 *tsc,
+ int pll_n, int pll_a, int pll_pdc, int pct_e, int pll_o)
+{
+ u16 w;
+
+ w = tsc->config2_shadow;
+ w &= ~0x3fff;
+ w |= (pll_n & 0x0f) | ((pll_a & 0x0f) << 4) | ((pll_pdc & 0x0f) << 8);
+ w |= pct_e ? (1 << 12) : 0;
+ w |= pll_o ? (1 << 13) : 0;
+ tsc2301_write_reg(tsc, TSC2301_REG_CONFIG2, w);
+ tsc->config2_shadow = w;
+}
+
+void tsc2301_read_buf(struct tsc2301 *tsc, int reg, u16 *rx_buf, int len)
+{
+ struct spi_transfer t[2];
+ struct spi_message m;
+ u16 cmd, i;
+
+ cmd = reg;
+ cmd |= 0x8000;
+
+ spi_message_init(&m);
+ m.spi = tsc->spi;
+
+ memset(t, 0, sizeof(t));
+ t[0].tx_buf = &cmd;
+ t[0].rx_buf = NULL;
+ t[0].len = 2;
+ spi_message_add_tail(&t[0], &m);
+
+ t[1].tx_buf = NULL;
+ t[1].rx_buf = rx_buf;
+ t[1].len = 2 * len;
+ spi_message_add_tail(&t[1], &m);
+
+ spi_sync(m.spi, &m);
+
+ for (i = 0; i < len; i++)
+ printk(KERN_DEBUG "rx_buf[%d]: %04x\n", i, rx_buf[i]);
+}
+
+static int __devinit tsc2301_probe(struct spi_device *spi)
+{
+ struct tsc2301 *tsc;
+ struct tsc2301_platform_data *pdata = spi->dev.platform_data;
+ int r;
+ u16 w;
+
+ if (!pdata) {
+ dev_dbg(&spi->dev, "no platform data?\n");
+ return -ENODEV;
+ }
+
+ tsc = kzalloc(sizeof(*tsc), GFP_KERNEL);
+ if (tsc == NULL)
+ return -ENOMEM;
+
+ dev_set_drvdata(&spi->dev, tsc);
+ tsc->spi = spi;
+
+ tsc->enable_clock = pdata->enable_clock;
+ tsc->disable_clock = pdata->disable_clock;
+
+ if (pdata->reset_gpio >= 0) {
+ tsc->reset_gpio = pdata->reset_gpio;
+#ifdef CONFIG_ARCH_OMAP
+ r = omap_request_gpio(tsc->reset_gpio);
+ if (r < 0)
+ goto err1;
+ omap_set_gpio_dataout(tsc->reset_gpio, 1);
+ omap_set_gpio_direction(tsc->reset_gpio, 0);
+ mdelay(1);
+ omap_set_gpio_dataout(tsc->reset_gpio, 0);
+#endif
+ } else
+ tsc->reset_gpio = -1;
+
+ spi->mode = SPI_MODE_1;
+ spi->bits_per_word = 16;
+ /* The max speed might've been defined by the board-specific
+ * struct */
+ if (!spi->max_speed_hz)
+ spi->max_speed_hz = TSC2301_HZ;
+ spi_setup(spi);
+
+ /* Soft reset */
+ tsc2301_write_reg(tsc, TSC2301_REG_RESET, 0xbb00);
+ msleep(1);
+
+ w = tsc2301_read_reg(tsc, TSC2301_REG_ADC);
+ if (!(w & (1 << 14))) {
+ dev_err(&spi->dev, "invalid ADC reg value: %04x\n", w);
+ r = -ENODEV;
+ goto err1;
+ }
+
+ w = tsc2301_read_reg(tsc, TSC2301_REG_DAC);
+ if (!(w & (1 << 15))) {
+ dev_err(&spi->dev, "invalid DAC reg value: %04x\n", w);
+ r = -ENODEV;
+ goto err1;
+ }
+
+ /* Stop keypad scanning */
+ tsc2301_write_reg(tsc, TSC2301_REG_KEY, 0x4000);
+
+ /* We have to cache this for read-modify-write, since we can't
+ * read back BIT15 */
+ w = tsc2301_read_reg(tsc, TSC2301_REG_CONFIG2);
+ /* By default BIT15 is set */
+ w |= 1 << 15;
+ tsc->config2_shadow = w;
+
+ r = tsc2301_kp_init(tsc, pdata);
+ if (r)
+ goto err1;
+ r = tsc2301_ts_init(tsc, pdata);
+ if (r)
+ goto err2;
+ r = tsc2301_mixer_init(tsc, pdata);
+ if (r)
+ goto err3;
+ return 0;
+
+err3:
+ tsc2301_ts_exit(tsc);
+err2:
+ tsc2301_kp_exit(tsc);
+err1:
+ kfree(tsc);
+ return r;
+}
+
+static int __devexit tsc2301_remove(struct spi_device *spi)
+{
+ struct tsc2301 *tsc = dev_get_drvdata(&spi->dev);
+
+ tsc2301_mixer_exit(tsc);
+ tsc2301_ts_exit(tsc);
+ tsc2301_kp_exit(tsc);
+ kfree(tsc);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int tsc2301_suspend(struct spi_device *spi, pm_message_t mesg)
+{
+ struct tsc2301 *tsc = dev_get_drvdata(&spi->dev);
+ int r;
+
+ if ((r = tsc2301_mixer_suspend(tsc)) < 0)
+ return r;
+ if ((r = tsc2301_kp_suspend(tsc)) < 0)
+ goto err1;
+ if ((r = tsc2301_ts_suspend(tsc)) < 0)
+ goto err2;
+
+ return 0;
+err2:
+ tsc2301_kp_resume(tsc);
+err1:
+ tsc2301_mixer_resume(tsc);
+ return r;
+}
+
+static int tsc2301_resume(struct spi_device *spi)
+{
+ struct tsc2301 *tsc = dev_get_drvdata(&spi->dev);
+
+ tsc2301_ts_resume(tsc);
+ tsc2301_kp_resume(tsc);
+ tsc2301_mixer_resume(tsc);
+ return 0;
+}
+#endif
+
+static struct spi_driver tsc2301_driver = {
+ .driver = {
+ .name = "tsc2301",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+#ifdef CONFIG_PM
+ .suspend = tsc2301_suspend,
+ .resume = tsc2301_resume,
+#endif
+ .probe = tsc2301_probe,
+ .remove = __devexit_p(tsc2301_remove),
+};
+
+static int __init tsc2301_init(void)
+{
+ printk("TSC2301 driver initializing\n");
+
+ return spi_register_driver(&tsc2301_driver);
+}
+module_init(tsc2301_init);
+
+static void __exit tsc2301_exit(void)
+{
+ spi_unregister_driver(&tsc2301_driver);
+}
+module_exit(tsc2301_exit);
+
+MODULE_AUTHOR("Juha Yrjölä <juha.yrjola@nokia.com>");
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * ALSA Mixer implementation for TSC2301
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Jarkko Nikula <jarkko.nikula@nokia.com>
+ * Juha Yrjola
+ *
+ * Some notes about TSC2301:
+ * - PLL will stop when DAC and ADC's are powered down.
+ * - Touchscreen will stop working when audio part is powered up and if audio
+ * MCLK is stopped. Problem is avoided if audio is powered down before
+ * stopping MCLK.
+ * - Audio DAC or audio outputs will activate only after 100 msec from the
+ * chip power-up. Reason seems to be VCM since there is no this delay if the
+ * chip and VCM (bit AVPD on PD/MISC) were not powered down. The chip will
+ * consume about 1 mA if all other audio blocks are powered down except the
+ * chip itself and VCM. Full power down consumes only about few uA.
+ * - Power-down transition could happen earliest about 100 msec after the chip
+ * power-up. Otherwise power-down will fail if there is no that 100 msec
+ * on time before it. It's not obvious why is that since chip reports
+ * power-up to be completed and also PLL output on GPIO_0 is active in few
+ * milliseconds.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/tsc2301.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/control.h>
+
+/* shadow register indexes */
+enum {
+ /* audio control and volume registers */
+ AUDCNTL_INDEX,
+ ADCVOL_INDEX,
+ DACVOL_INDEX,
+ BPVOL_INDEX,
+ /* keyclick control register (not needed here) */
+ /* audio power control register */
+ PD_MISC_INDEX,
+ /* TSC2301 GPIO control register */
+ GPIO_INDEX,
+
+ SHADOW_REG_COUNT,
+};
+
+/* structure for driver private data */
+struct tsc2301_mixer {
+ struct tsc2301 *tsc;
+ struct mutex mutex;
+
+ /* shadow registers holding TSC2301 audio registers. Used to hold
+ * their states during the sleep and also to reduce communication with
+ * the chip since get callback functions could get register values
+ * directly from these shadow registers without needing to read them
+ * from the chip */
+ u16 shadow_regs[SHADOW_REG_COUNT];
+
+ /* audio controller driver usage of the ADC and DAC */
+ unsigned adc_enabled:1, dac_enabled:1;
+ unsigned pll_output:1;
+ unsigned mclk_enabled;
+
+ /* latest audio power-up timestamp */
+ unsigned long pu_jiffies;
+
+ /* these are used when upper layer(s) are going to power-down TSC2301
+ * before 100 msec is passed from power-up */
+ struct delayed_work delayed_power_down;
+ unsigned delayed_pd_active:1;
+
+ int (* platform_init)(struct device *);
+ void (* platform_cleanup)(struct device *);
+
+ struct tsc2301_mixer_gpio *mixer_gpios;
+ int n_mixer_gpios;
+};
+
+#define TSC2301_DAC_DELAY msecs_to_jiffies(100)
+#define TSC2301_MIN_PU_PERIOD msecs_to_jiffies(100)
+
+#define TSC2301_REG_TO_PVAL(reg) \
+ (TSC2301_REG_TO_PAGE(reg) << 6 | TSC2301_REG_TO_ADDR(reg))
+#define TSC2301_PVAL_TO_REG(v) \
+ (TSC2301_REG((((v) >> 6) & 3),((v) & 0x1f)))
+
+#define TSC2301_VOLUME_MASK 0x7f
+#define TSC2301_MIN_ADCVOL 6
+#define TSC2301_MIN_DACVOL 0
+#define TSC2301_MIN_BPVOL 31
+#define TSC2301_MUTE_LEFT_SHIFT 15
+#define TSC2301_VOL_LEFT_SHIFT 8
+#define TSC2301_MUTE_RIGHT_SHIFT 7
+#define TSC2301_VOL_RIGHT_SHIFT 0
+
+#define TSC2301_INM_MASK 3
+#define TSC2301_INML_SHIFT 12
+#define TSC2301_INMR_SHIFT 10
+
+#define TSC2301_MICG_MASK 3
+#define TSC2301_MICG_MIN 1 /* values 0 & 1 both mean 0 dB */
+#define TSC2301_MICG_SHIFT 8
+
+#define TSC2301_REG_AUDCNTL_MCLK(v) (((v) & 3) << 6)
+#define TSC2301_REG_AUDCNTL_I2SFS(v) (((v) & 0xf) << 2)
+#define TSC2301_REG_AUDCNTL_I2SFM(v) (((v) & 3) << 0)
+
+#define TSC2301_SINGLE(xname, xindex, reg, shadow_index, shift, mask, min) \
+{\
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .index = xindex, \
+ .info = snd_tsc2301_info_single, \
+ .get = snd_tsc2301_get_single, \
+ .put = snd_tsc2301_put_single, \
+ .private_value = TSC2301_REG_TO_PVAL(reg) | \
+ (shadow_index << 8) | (shift << 16) | (mask << 24) | \
+ (min << 28) \
+}
+#define TSC2301_SINGLE_MINVAL(v) (((v) >> 28) & 15)
+#define TSC2301_SINGLE_SHIFT(v) (((v) >> 16) & 15)
+#define TSC2301_SINGLE_MASK(v) (((v) >> 24) & 15)
+
+#define TSC2301_DOUBLE(xname, xindex, reg, shadow_index, ls, rs, mask, min) \
+{\
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .index = xindex, \
+ .info = snd_tsc2301_info_double, \
+ .get = snd_tsc2301_get_double, \
+ .put = snd_tsc2301_put_double, \
+ .private_value = TSC2301_REG_TO_PVAL(reg) | \
+ (shadow_index << 8) | (min << 11) | \
+ (ls << 16) | (rs << 20) | (mask << 24) \
+}
+#define TSC2301_DOUBLE_MINVAL(v) (((v) >> 11) & 0x1f)
+#define TSC2301_DOUBLE_LEFT_SHIFT(v) (((v) >> 16) & 15)
+#define TSC2301_DOUBLE_RIGHT_SHIFT(v) (((v) >> 20) & 15)
+#define TSC2301_DOUBLE_MASK(v) (((v) >> 24) & TSC2301_VOLUME_MASK)
+
+#define TSC2301_MUX(xname, xindex, reg, shadow_index, ls, rs, mask) \
+{\
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .index = xindex, \
+ .info = snd_tsc2301_info_mux, \
+ .get = snd_tsc2301_get_mux, \
+ .put = snd_tsc2301_put_mux, \
+ .private_value = TSC2301_REG_TO_PVAL(reg) | \
+ (shadow_index << 8) | (ls << 16) | (rs << 20) | (mask << 24) \
+}
+#define TSC2301_MUX_LEFT_SHIFT(v) (((v) >> 16) & 15)
+#define TSC2301_MUX_RIGHT_SHIFT(v) (((v) >> 20) & 15)
+#define TSC2301_MUX_MASK(v) (((v) >> 24) & TSC2301_VOLUME_MASK)
+
+#define TSC2301_BOOL(xname, xindex, reg, shadow_index, shift, invert, state) \
+{ \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .index = xindex, \
+ .info = snd_tsc2301_info_bool, \
+ .get = snd_tsc2301_get_bool, \
+ .put = snd_tsc2301_put_bool, \
+ .private_value = TSC2301_REG_TO_PVAL(reg) | \
+ (shadow_index << 8) | (shift << 16) | \
+ (invert << 24) | (state << 25) \
+}
+#define TSC2301_BOOL_SHIFT(v) (((v) >> 16) & 7)
+#define TSC2301_BOOL_INVERT(v) (((v) >> 24) & 1)
+#define TSC2301_BOOL_STATE(v) (((v) >> 25) & 1)
+
+#define TSC2301_SHADOW_INDEX(v) (((v) >> 8) & 7)
+
+/*
+ * Power-down handler for additional GPIO mixer controls. GPIO state of GPIO
+ * controls whose power-down flag is enabled are set to their false/deactivate
+ * state
+ *
+ * Must be called tsc->mixer->mutex locked
+ */
+static void tsc2301_gpio_power_down(struct tsc2301 *tsc)
+{
+ struct tsc2301_mixer *mix = tsc->mixer;
+ u16 temp;
+ int i;
+
+ temp = mix->shadow_regs[GPIO_INDEX];
+ for (i = 0; i < mix->n_mixer_gpios; i++) {
+ const struct tsc2301_mixer_gpio *mg;
+
+ mg = mix->mixer_gpios + i;
+ if (mg->deactivate_on_pd) {
+ int gpio = mg->gpio;
+
+ temp &= ~(1 << gpio);
+ temp |= mg->inverted << gpio;
+ }
+ }
+ tsc2301_write_reg(tsc, TSC2301_REG_GPIO, temp);
+}
+
+/*
+ * Powers down/up audio blocks which are muted or become unused.
+ * shadow_index >= 0, changes power state of single audio block
+ * shadow_index < 0, changes power state of all blocks
+ *
+ * Must be called tsc->mixer->mutex locked
+ */
+#define TSC2301_MUTE_MASK \
+ ((1 << TSC2301_MUTE_LEFT_SHIFT) | (1 << TSC2301_MUTE_RIGHT_SHIFT))
+static void tsc2301_power_ctrl(struct tsc2301 *tsc, int shadow_index,
+ int poll_pdsts)
+{
+ struct tsc2301_mixer *mix = tsc->mixer;
+ u16 pd_ctrl, pd_ctrl_old, w;
+ unsigned long timeout;
+ int power_up = 0;
+
+ if (mix->delayed_pd_active) {
+ mix->delayed_pd_active = 0;
+ mix->mclk_enabled--;
+ cancel_delayed_work(&mix->delayed_power_down);
+ }
+
+ pd_ctrl = pd_ctrl_old = mix->shadow_regs[PD_MISC_INDEX];
+ /* power control helper based on used space mixer selections. See
+ * actual power control decisions below */
+ if (shadow_index < 0 || shadow_index == ADCVOL_INDEX) {
+ /* ADC left and right power down control */
+ if (mix->shadow_regs[ADCVOL_INDEX] &
+ (1 << TSC2301_MUTE_LEFT_SHIFT))
+ /* left ADC muted. Power down the left ADC */
+ pd_ctrl |= TSC2301_REG_PD_MISC_ADPDL;
+ else
+ pd_ctrl &= ~TSC2301_REG_PD_MISC_ADPDL;
+ if (mix->shadow_regs[ADCVOL_INDEX] &
+ (1 << TSC2301_MUTE_LEFT_SHIFT))
+ /* right ADC muted. Power down the right ADC */
+ pd_ctrl |= TSC2301_REG_PD_MISC_ADPDR;
+ else
+ pd_ctrl &= ~TSC2301_REG_PD_MISC_ADPDR;
+ }
+ if (shadow_index < 0 || shadow_index == DACVOL_INDEX) {
+ /* DAC power down control */
+ if ((mix->shadow_regs[DACVOL_INDEX] &
+ TSC2301_MUTE_MASK) == TSC2301_MUTE_MASK)
+ /* both DACs muted. Power down the DAC */
+ pd_ctrl |= TSC2301_REG_PD_MISC_DAPD;
+ else
+ pd_ctrl &= ~TSC2301_REG_PD_MISC_DAPD;
+ }
+ if (shadow_index < 0 || shadow_index == BPVOL_INDEX) {
+ /* line bypass power down control */
+ if ((mix->shadow_regs[BPVOL_INDEX] &
+ TSC2301_MUTE_MASK) == TSC2301_MUTE_MASK)
+ /* both line bypasses muted. Power down the bypass
+ * path */
+ pd_ctrl |= TSC2301_REG_PD_MISC_ABPD;
+ else
+ pd_ctrl &= ~TSC2301_REG_PD_MISC_ABPD;
+ }
+ if (shadow_index < 0 || shadow_index == AUDCNTL_INDEX) {
+ /* mic bias power down control */
+ if ((mix->shadow_regs[AUDCNTL_INDEX] &
+ (3 << TSC2301_INML_SHIFT)) &&
+ (mix->shadow_regs[AUDCNTL_INDEX] &
+ (3 << TSC2301_INMR_SHIFT)))
+ /* both ADC channels use other than mic input. Power
+ * down the mic bias output */
+ pd_ctrl |= TSC2301_REG_PD_MISC_MIBPD;
+ else
+ pd_ctrl &= ~TSC2301_REG_PD_MISC_MIBPD;
+ }
+
+ /* power control decisions based on codec usage and user space mixer
+ * selections detected above */
+ pd_ctrl &= ~TSC2301_REG_PD_MISC_APD; /* audio not powered down */
+ if (mix->mclk_enabled) {
+ if (!mix->adc_enabled) {
+ /* ADC not used, power down both ADC's and mic bias
+ * output independently of user space mixer
+ * selections */
+ pd_ctrl |= TSC2301_REG_PD_MISC_ADPDL;
+ pd_ctrl |= TSC2301_REG_PD_MISC_ADPDR;
+ pd_ctrl |= TSC2301_REG_PD_MISC_MIBPD;
+ }
+ if (!mix->dac_enabled) {
+ /* DAC not used, power down DAC independently of user
+ * space mixer selections */
+ pd_ctrl |= TSC2301_REG_PD_MISC_DAPD;
+ }
+
+ if (mix->pll_output) {
+ /* GPIO_0 is configured as PLL output so audio
+ * controller is expecting clock from TSC2301. Either
+ * ADC or DAC must be active in order to keep PLL on */
+ if ((pd_ctrl & TSC2301_REG_PD_MISC_ADPDL) &&
+ (pd_ctrl & TSC2301_REG_PD_MISC_ADPDR) &&
+ (pd_ctrl & TSC2301_REG_PD_MISC_DAPD)) {
+ /* neither ADC or DAC used. Force ADC on in
+ * order to keep PLL active */
+ pd_ctrl &= ~(TSC2301_REG_PD_MISC_ADPDL |
+ TSC2301_REG_PD_MISC_ADPDR);
+ }
+ }
+ } else {
+ /* audio input clock is not enabled so power down DAC and ADC
+ * in order to shutdown PLL and to keep touchscreen and keypad
+ * parts working. Touchscreen and keypad use audio clock when
+ * PLL is on and internal clock otherwise */
+ pd_ctrl |= TSC2301_REG_PD_MISC_DAPD |
+ TSC2301_REG_PD_MISC_ADPDL |
+ TSC2301_REG_PD_MISC_ADPDR;
+ }
+
+ if ((pd_ctrl & TSC2301_REG_PD_MISC_ADPDL) &&
+ (pd_ctrl & TSC2301_REG_PD_MISC_ADPDR) &&
+ (pd_ctrl & TSC2301_REG_PD_MISC_DAPD) &&
+ (pd_ctrl & TSC2301_REG_PD_MISC_ABPD)) {
+ /* all ADC, DAC and line bypass path unused. Power down the
+ * whole audio part of the TSC2301 */
+ pd_ctrl |= TSC2301_REG_PD_MISC_APD;
+ }
+
+ if (pd_ctrl == pd_ctrl_old)
+ return;
+
+ /* power down control changed. Update into TSC2301 */
+ if ((pd_ctrl ^ pd_ctrl_old) & TSC2301_REG_PD_MISC_APD) {
+ /* whole audio power state changed. Update GPIO states */
+ if (pd_ctrl & TSC2301_REG_PD_MISC_APD) {
+ /* power down GPIO controls before powering down
+ * the codec */
+ tsc2301_gpio_power_down(tsc);
+ /* we must really ensure that codec has been on no less
+ * than 100 msec before doing power-down */
+ timeout = mix->pu_jiffies + TSC2301_MIN_PU_PERIOD -
+ jiffies;
+ if (timeout <= TSC2301_MIN_PU_PERIOD) {
+ mix->delayed_pd_active = 1;
+ mix->mclk_enabled++;
+ schedule_delayed_work(&mix->delayed_power_down,
+ timeout + 1);
+ return;
+ }
+ } else
+ /* restore GPIOs after codec is powered up */
+ power_up = 1;
+ }
+ mix->shadow_regs[PD_MISC_INDEX] = pd_ctrl;
+ tsc2301_write_reg(tsc, TSC2301_REG_PD_MISC, pd_ctrl);
+ if (power_up)
+ mix->pu_jiffies = jiffies;
+ if (!poll_pdsts) {
+ if (power_up)
+ tsc2301_write_reg(tsc, TSC2301_REG_GPIO,
+ mix->shadow_regs[GPIO_INDEX]);
+ return;
+ }
+
+ /* wait until power-up/-down is completed */
+ timeout = jiffies + msecs_to_jiffies(100);
+ w = 0;
+ do {
+ if (time_after(jiffies, timeout)) {
+ /* Print a warning only if the I2S clock is not
+ * present / out of sync. This can happen during
+ * init time, when that clock will be turned on
+ * by another driver like in the OMAP EAC with
+ * external clock case.
+ */
+ if (w & TSC2301_REG_PD_MISC_OTSYN) {
+ dev_warn(&tsc->spi->dev,
+ "I2S clock not in sync or off.\n");
+ } else {
+ dev_err(&tsc->spi->dev,
+ "power-up/-down timed out "
+ "(0x%04x, 0x%04x -> 0x%04x)\n",
+ w, pd_ctrl_old, pd_ctrl);
+ }
+ goto out;
+ }
+ w = tsc2301_read_reg(tsc, TSC2301_REG_PD_MISC);
+ } while (!(w & TSC2301_REG_PD_MISC_PDSTS));
+
+out:
+ if (((pd_ctrl ^ pd_ctrl_old) & TSC2301_REG_PD_MISC_DAPD) &&
+ !(pd_ctrl & TSC2301_REG_PD_MISC_DAPD)) {
+ /* DAC powered up now. Ensure that DAC and audio outputs are
+ * activated. They are up 100 msec after the chip power-up
+ * command */
+ timeout = mix->pu_jiffies + TSC2301_DAC_DELAY - jiffies;
+ if (timeout <= TSC2301_DAC_DELAY)
+ schedule_timeout_interruptible(timeout);
+ /* FIXME: This is lazy. We restore GPIOs only after activating
+ * the DAC. It would be better to do some kind of delayed GPIO
+ * restore. That ensures that we restore them also if only ADC
+ * path is activated. But this is required only if there is
+ * some input amplifier, bias control, etc. and their power
+ * state is under TSC GPIO control */
+ tsc2301_write_reg(tsc, TSC2301_REG_GPIO,
+ mix->shadow_regs[GPIO_INDEX]);
+ }
+}
+
+static int snd_tsc2301_info_single(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ int mask = TSC2301_SINGLE_MASK(kcontrol->private_value);
+ int minval = TSC2301_SINGLE_MINVAL(kcontrol->private_value);
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = minval;
+ uinfo->value.integer.max = mask;
+
+ return 0;
+}
+
+static int snd_tsc2301_get_single(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tsc2301 *tsc = kcontrol->private_data;
+ unsigned long priv = kcontrol->private_value;
+ int mask = TSC2301_SINGLE_MASK(priv);
+ int shift = TSC2301_SINGLE_SHIFT(priv);
+ int shadow_index = TSC2301_SHADOW_INDEX(priv);
+ u16 shadow_reg;
+
+ shadow_reg = tsc->mixer->shadow_regs[shadow_index];
+
+ ucontrol->value.integer.value[0] = (shadow_reg >> shift) & mask;
+
+ return 0;
+}
+
+static int snd_tsc2301_put_single(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tsc2301 *tsc = kcontrol->private_data;
+ unsigned long priv = kcontrol->private_value;
+ int mask = TSC2301_SINGLE_MASK(priv);
+ int shadow_index = TSC2301_SHADOW_INDEX(priv);
+ u16 shadow_reg, shadow_reg_old;
+ int shift = TSC2301_SINGLE_SHIFT(priv);
+ int reg = TSC2301_PVAL_TO_REG(priv);
+ int changed;
+
+ mutex_lock(&tsc->mixer->mutex);
+ shadow_reg = shadow_reg_old = tsc->mixer->shadow_regs[shadow_index];
+
+ /* zero bits to be modified */
+ shadow_reg &= ~(mask << shift);
+ /* modify with new value */
+ shadow_reg |= ((ucontrol->value.integer.value[0] & mask) << shift);
+
+ changed = (shadow_reg != shadow_reg_old);
+ tsc->mixer->shadow_regs[shadow_index] = shadow_reg;
+
+ /* update into TSC2301 if necessary */
+ if (changed)
+ tsc2301_write_reg(tsc, reg, shadow_reg);
+ mutex_unlock(&tsc->mixer->mutex);
+
+ return changed;
+}
+
+static int snd_tsc2301_info_double(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ /* mask == 1 : Switch
+ * mask > 1 : Max volume */
+ int mask = TSC2301_DOUBLE_MASK(kcontrol->private_value);
+ int minval = TSC2301_DOUBLE_MINVAL(kcontrol->private_value);
+
+ uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN :
+ SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 2;
+ uinfo->value.integer.min = minval;
+ uinfo->value.integer.max = mask;
+
+ return 0;
+}
+
+static int snd_tsc2301_get_double(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tsc2301 *tsc = kcontrol->private_data;
+ unsigned long priv = kcontrol->private_value;
+ /* mask == 1 : Switch
+ * mask > 1 : Volume */
+ int mask = TSC2301_DOUBLE_MASK(priv);
+ int ls = TSC2301_DOUBLE_LEFT_SHIFT(priv);
+ int rs = TSC2301_DOUBLE_RIGHT_SHIFT(priv);
+ int shadow_index = TSC2301_SHADOW_INDEX(priv);
+ u16 shadow_reg;
+
+ shadow_reg = tsc->mixer->shadow_regs[shadow_index];
+
+ /* invert mute bits for the switches */
+ if (mask == 1)
+ shadow_reg = ~shadow_reg;
+
+ ucontrol->value.integer.value[0] = (shadow_reg >> ls) & mask;
+ ucontrol->value.integer.value[1] = (shadow_reg >> rs) & mask;
+
+ return 0;
+}
+
+static int snd_tsc2301_put_double(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tsc2301 *tsc = kcontrol->private_data;
+ unsigned long priv = kcontrol->private_value;
+ /* mask == 1 : Switch
+ * mask > 1 : Volume */
+ int mask = TSC2301_DOUBLE_MASK(priv);
+ int shadow_index = TSC2301_SHADOW_INDEX(priv);
+ u16 shadow_reg, shadow_reg_old;
+ int ls = TSC2301_DOUBLE_LEFT_SHIFT(priv);
+ int rs = TSC2301_DOUBLE_RIGHT_SHIFT(priv);
+ int reg = TSC2301_PVAL_TO_REG(priv);
+ int changed;
+
+ mutex_lock(&tsc->mixer->mutex);
+ shadow_reg = shadow_reg_old = tsc->mixer->shadow_regs[shadow_index];
+
+ /* zero bits to be modified */
+ shadow_reg &= ~((mask << ls) | (mask << rs));
+ /* modify with new value */
+ if (mask == 1) {
+ /* switch. Invert switch values for the mute bits */
+ shadow_reg |=
+ ((~ucontrol->value.integer.value[0] & mask) << ls) |
+ ((~ucontrol->value.integer.value[1] & mask) << rs);
+ } else {
+ /* volume */
+ shadow_reg |=
+ (ucontrol->value.integer.value[0] << ls) |
+ (ucontrol->value.integer.value[1] << rs);
+ }
+
+ changed = (shadow_reg != shadow_reg_old);
+ tsc->mixer->shadow_regs[shadow_index] = shadow_reg;
+
+ /* update into TSC2301 if necessary */
+ if (changed)
+ tsc2301_write_reg(tsc, reg, shadow_reg);
+
+ if (mask == 1)
+ /* check is need to power down/up audio blocks in case of
+ * muted state change */
+ tsc2301_power_ctrl(tsc, shadow_index, 0);
+ mutex_unlock(&tsc->mixer->mutex);
+
+ return changed;
+}
+
+static int snd_tsc2301_info_mux(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ static char *texts[4] = {"Mic", "Line", "Line swapped", "Line mono"};
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 2;
+ uinfo->value.enumerated.items = 4;
+ if (uinfo->value.enumerated.item > 3)
+ uinfo->value.enumerated.item = 3;
+ strcpy(uinfo->value.enumerated.name,
+ texts[uinfo->value.enumerated.item]);
+
+ return 0;
+}
+
+static int snd_tsc2301_get_mux(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tsc2301 *tsc = kcontrol->private_data;
+ unsigned long priv = kcontrol->private_value;
+ int mask = TSC2301_MUX_MASK(priv);
+ int ls = TSC2301_MUX_LEFT_SHIFT(priv);
+ int rs = TSC2301_MUX_RIGHT_SHIFT(priv);
+ int shadow_index = TSC2301_SHADOW_INDEX(priv);
+ u16 shadow_reg;
+
+ shadow_reg = tsc->mixer->shadow_regs[shadow_index];
+ ucontrol->value.enumerated.item[0] = (shadow_reg >> ls) & mask;
+ ucontrol->value.enumerated.item[1] = (shadow_reg >> rs) & mask;
+
+ return 0;
+}
+
+static int snd_tsc2301_put_mux(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tsc2301 *tsc = kcontrol->private_data;
+ unsigned long priv = kcontrol->private_value;
+ int mask = TSC2301_MUX_MASK(priv);
+ int shadow_index = TSC2301_SHADOW_INDEX(priv);
+ u16 shadow_reg, shadow_reg_old;
+ int ls = TSC2301_MUX_LEFT_SHIFT(priv);
+ int rs = TSC2301_MUX_RIGHT_SHIFT(priv);
+ int reg = TSC2301_PVAL_TO_REG(priv);
+ int changed;
+
+ mutex_lock(&tsc->mixer->mutex);
+ shadow_reg = shadow_reg_old = tsc->mixer->shadow_regs[shadow_index];
+
+ /* zero bits to be modified */
+ shadow_reg &= ~((mask << ls) | (mask << rs));
+ /* modify with new value */
+ shadow_reg |= (ucontrol->value.enumerated.item[0] << ls);
+ shadow_reg |= (ucontrol->value.enumerated.item[1] << rs);
+
+ changed = (shadow_reg != shadow_reg_old);
+
+ /* update into TSC2301 if necessary */
+ if (changed) {
+ tsc->mixer->shadow_regs[shadow_index] = shadow_reg;
+ tsc2301_write_reg(tsc, reg, shadow_reg);
+ }
+
+ /* check is need to power up/down audio blocks in case of ADC input
+ * change */
+ tsc2301_power_ctrl(tsc, shadow_index, 0);
+ mutex_unlock(&tsc->mixer->mutex);
+
+ return changed;
+}
+
+static int snd_tsc2301_info_bool(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+
+ return 0;
+}
+
+static int snd_tsc2301_get_bool(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tsc2301 *tsc = kcontrol->private_data;
+ unsigned long priv = kcontrol->private_value;
+ int shadow_index = TSC2301_SHADOW_INDEX(priv);
+ int shift = TSC2301_BOOL_SHIFT(priv);
+ int invert = TSC2301_BOOL_INVERT(priv);
+ u16 shadow_reg;
+
+ shadow_reg = tsc->mixer->shadow_regs[shadow_index];
+ ucontrol->value.integer.value[0] =
+ invert ^ ((shadow_reg >> shift) & 1);
+
+ return 0;
+}
+
+static int snd_tsc2301_put_bool(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tsc2301 *tsc = kcontrol->private_data;
+ unsigned long priv = kcontrol->private_value;
+ int shadow_index = TSC2301_SHADOW_INDEX(priv);
+ int shift = TSC2301_BOOL_SHIFT(priv);
+ int invert = TSC2301_BOOL_INVERT(priv);
+ int reg = TSC2301_PVAL_TO_REG(priv);
+ u16 shadow_reg, shadow_reg_old;
+ int changed;
+
+ mutex_lock(&tsc->mixer->mutex);
+ shadow_reg = shadow_reg_old = tsc->mixer->shadow_regs[shadow_index];
+
+ /* zero bit to be modified */
+ shadow_reg &= ~(1 << shift);
+ /* modify with new value */
+ shadow_reg |=
+ (invert ^ (ucontrol->value.integer.value[0] & 1)) << shift;
+
+ changed = (shadow_reg != shadow_reg_old);
+
+ /* update into TSC2301 if necessary */
+ if (changed) {
+ tsc->mixer->shadow_regs[shadow_index] = shadow_reg;
+ if ((shadow_index == GPIO_INDEX) &&
+ (tsc->mixer->shadow_regs[PD_MISC_INDEX] &
+ TSC2301_REG_PD_MISC_APD)) {
+ /* changing GPIO control and audio is powered down.
+ * Update GPIO states according to their power-down
+ * flag */
+ tsc2301_gpio_power_down(tsc);
+ } else
+ tsc2301_write_reg(tsc, reg, shadow_reg);
+ }
+ mutex_unlock(&tsc->mixer->mutex);
+
+ return changed;
+}
+
+/* TSC2301 internal mixer controls */
+static struct snd_kcontrol_new snd_tsc2301_controls[] = {
+ /* stereo ADC input switches and volumes */
+ TSC2301_DOUBLE("Capture Switch", 0,
+ TSC2301_REG_ADCVOL, ADCVOL_INDEX,
+ TSC2301_MUTE_LEFT_SHIFT, TSC2301_MUTE_RIGHT_SHIFT,
+ 1, 0),
+ TSC2301_DOUBLE("Capture Volume", 0,
+ TSC2301_REG_ADCVOL, ADCVOL_INDEX,
+ TSC2301_VOL_LEFT_SHIFT, TSC2301_VOL_RIGHT_SHIFT,
+ TSC2301_VOLUME_MASK, TSC2301_MIN_ADCVOL),
+
+ /* stereo DAC output switches and volumes */
+ TSC2301_DOUBLE("PCM Playback Switch", 0,
+ TSC2301_REG_DACVOL, DACVOL_INDEX,
+ TSC2301_MUTE_LEFT_SHIFT, TSC2301_MUTE_RIGHT_SHIFT,
+ 1, 0),
+ TSC2301_DOUBLE("PCM Playback Volume", 0,
+ TSC2301_REG_DACVOL, DACVOL_INDEX,
+ TSC2301_VOL_LEFT_SHIFT, TSC2301_VOL_RIGHT_SHIFT,
+ TSC2301_VOLUME_MASK, TSC2301_MIN_DACVOL),
+
+ /* stereo line input bypass switches and volumes */
+ TSC2301_DOUBLE("Line Playback Switch", 0,
+ TSC2301_REG_BPVOL, BPVOL_INDEX,
+ TSC2301_MUTE_LEFT_SHIFT, TSC2301_MUTE_RIGHT_SHIFT,
+ 1, 0),
+ TSC2301_DOUBLE("Line Playback Volume", 0,
+ TSC2301_REG_BPVOL, BPVOL_INDEX,
+ TSC2301_VOL_LEFT_SHIFT, TSC2301_VOL_RIGHT_SHIFT,
+ TSC2301_VOLUME_MASK, TSC2301_MIN_BPVOL),
+
+ /* mono microphone input gain */
+ TSC2301_SINGLE("Mic Boost", 0,
+ TSC2301_REG_AUDCNTL, AUDCNTL_INDEX,
+ TSC2301_MICG_SHIFT,
+ TSC2301_MICG_MASK, TSC2301_MICG_MIN),
+
+ /* ADC input sources. Both channels could be selected separately */
+ TSC2301_MUX("Capture Source", 0,
+ TSC2301_REG_AUDCNTL, AUDCNTL_INDEX,
+ TSC2301_INML_SHIFT, TSC2301_INMR_SHIFT,
+ TSC2301_INM_MASK),
+};
+
+/* must be called tsc->mixer->mutex locked */
+static void tsc2301_flush_shadow_regs(struct tsc2301 *tsc)
+{
+ int i, page, addr;
+ u16 temp;
+
+ page = TSC2301_REG_TO_PAGE(TSC2301_REG_AUDCNTL);
+ addr = TSC2301_REG_TO_ADDR(TSC2301_REG_AUDCNTL);
+
+ for (i = 0; i < 4; i++) {
+ temp = tsc->mixer->shadow_regs[i];
+ tsc2301_write_reg(tsc, TSC2301_REG(page, addr + i), temp);
+ }
+ temp = tsc->mixer->shadow_regs[GPIO_INDEX];
+ tsc2301_write_reg(tsc, TSC2301_REG_GPIO, temp);
+
+ /* Update power state of all audio blocks depending are they
+ * muted or unused. */
+ tsc2301_power_ctrl(tsc, -1, 0);
+}
+
+#ifdef CONFIG_PM
+int tsc2301_mixer_suspend(struct tsc2301 *tsc)
+{
+ /* power down entire audio section inside TSC2301 in case the
+ * chip is still powered during the system sleep. However this driver
+ * doesn't require that chip is powered because registers are restored
+ * in function tsc2301_mixer_resume */
+ mutex_lock(&tsc->mixer->mutex);
+ tsc2301_gpio_power_down(tsc);
+ tsc->mixer->shadow_regs[PD_MISC_INDEX] |= TSC2301_REG_PD_MISC_APD;
+ tsc2301_write_reg(tsc, TSC2301_REG_PD_MISC,
+ tsc->mixer->shadow_regs[PD_MISC_INDEX]);
+ mutex_unlock(&tsc->mixer->mutex);
+ return 0;
+}
+
+void tsc2301_mixer_resume(struct tsc2301 *tsc)
+{
+ /* power up the TSC2301 audio section and restore registers */
+ mutex_lock(&tsc->mixer->mutex);
+ tsc->mixer->shadow_regs[PD_MISC_INDEX] &= ~TSC2301_REG_PD_MISC_APD;
+ tsc2301_flush_shadow_regs(tsc);
+ mutex_unlock(&tsc->mixer->mutex);
+}
+#endif
+
+void tsc2301_mixer_enable_mclk(struct device *dev)
+{
+ struct tsc2301 *tsc = dev_get_drvdata(dev);
+ struct tsc2301_mixer *mix = tsc->mixer;
+
+ mutex_lock(&mix->mutex);
+ if (!mix->mclk_enabled++ && tsc->enable_clock != NULL) {
+ tsc->enable_clock(dev);
+ }
+ tsc2301_power_ctrl(tsc, -1, 1);
+ mutex_unlock(&mix->mutex);
+}
+
+void tsc2301_mixer_disable_mclk(struct device *dev)
+{
+ struct tsc2301 *tsc = dev_get_drvdata(dev);
+ struct tsc2301_mixer *mix = tsc->mixer;
+
+ mutex_lock(&mix->mutex);
+ mix->mclk_enabled--;
+ tsc2301_power_ctrl(tsc, -1, 1);
+ if (!mix->mclk_enabled && tsc->disable_clock != NULL) {
+ tsc->disable_clock(dev);
+ }
+ mutex_unlock(&mix->mutex);
+}
+
+static void tsc2301_mixer_delayed_power_down(struct work_struct *work)
+{
+ struct tsc2301_mixer *mix = container_of(work, struct tsc2301_mixer,
+ delayed_power_down.work);
+ struct tsc2301 *tsc = mix->tsc;
+
+ mutex_lock(&mix->mutex);
+ if (!mix->delayed_pd_active) {
+ mutex_unlock(&mix->mutex);
+ return;
+ }
+ mix->delayed_pd_active = 0;
+ mutex_unlock(&mix->mutex);
+ tsc2301_mixer_disable_mclk(&tsc->spi->dev);
+}
+
+/*
+ * Allows audio controller driver to notify its usage of ADC and DAC
+ */
+void tsc2301_mixer_set_power(struct device *dev, int dac, int adc)
+{
+ struct tsc2301 *tsc = dev_get_drvdata(dev);
+
+ mutex_lock(&tsc->mixer->mutex);
+ tsc->mixer->adc_enabled = adc;
+ tsc->mixer->dac_enabled = dac;
+
+ /* update power state of all audio blocks */
+ tsc2301_power_ctrl(tsc, -1, 1);
+ mutex_unlock(&tsc->mixer->mutex);
+}
+
+/*
+ * Registers TSC2301 ALSA Mixer controls for the given sound card
+ */
+int tsc2301_mixer_register_controls(struct device *dev, struct snd_card *card)
+{
+ struct tsc2301 *tsc = dev_get_drvdata(dev);
+ struct tsc2301_mixer *mix = tsc->mixer;
+ int i, err;
+
+ /* Register ALSA mixer controls */
+ for (i = 0; i < ARRAY_SIZE(snd_tsc2301_controls); i++) {
+ err = snd_ctl_add(card,
+ snd_ctl_new1(&snd_tsc2301_controls[i], tsc));
+ if (err < 0)
+ return err;
+ }
+
+ if (!mix->n_mixer_gpios)
+ return 0;
+
+ /* Register additional GPIO controls if defined */
+ for (i = 0; i < mix->n_mixer_gpios; i++) {
+ const struct tsc2301_mixer_gpio *mg = mix->mixer_gpios + i;
+ struct snd_kcontrol *ctrlp;
+ struct snd_kcontrol_new ctrl =
+ TSC2301_BOOL((char *)mg->name, 0,
+ TSC2301_REG_GPIO, GPIO_INDEX,
+ mg->gpio, mg->inverted, mg->def_enable);
+
+ ctrlp = snd_ctl_new1(&ctrl, tsc);
+ err = snd_ctl_add(card, ctrlp);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+int tsc2301_mixer_init(struct tsc2301 *tsc,
+ struct tsc2301_platform_data *pdata)
+{
+ struct tsc2301_mixer *mix;
+ int err = 0;
+ u16 w;
+
+ mix = kzalloc(sizeof(*mix), GFP_KERNEL);
+ if (mix == NULL)
+ return -ENOMEM;
+ tsc->mixer = mix;
+
+ mix->tsc = tsc;
+ mutex_init(&mix->mutex);
+ mix->platform_init = pdata->codec_init;
+ mix->platform_cleanup = pdata->codec_cleanup;
+ mix->pll_output = pdata->pll_output;
+
+ INIT_DELAYED_WORK(&mix->delayed_power_down,
+ tsc2301_mixer_delayed_power_down);
+
+ /* initialize shadow register default values */
+ w = 0xc000;
+ w |= (pdata->mclk_ratio << 6) | (pdata->i2s_sample_rate << 2);
+ w |= pdata->i2s_format;
+ mix->shadow_regs[AUDCNTL_INDEX] = w;
+ mix->shadow_regs[ADCVOL_INDEX] = 0xd7d7;
+ mix->shadow_regs[DACVOL_INDEX] = 0xffff;
+ mix->shadow_regs[BPVOL_INDEX] = 0xe7e7;
+ mix->shadow_regs[PD_MISC_INDEX] = pdata->power_down_blocks;
+
+ /* if extra mixer controls configured, then configure associated
+ * GPIOs as output and drive their default state */
+ if (pdata->n_mixer_gpios) {
+ int i;
+
+ w = 0;
+ for (i = 0; i < pdata->n_mixer_gpios; i++) {
+ const struct tsc2301_mixer_gpio *mg;
+ int gpio;
+
+ mg = pdata->mixer_gpios + i;
+ gpio = mg->gpio;
+ w |= (1 << gpio) << 8;
+ w |= (mg->inverted ^ mg->def_enable) << gpio;
+ }
+ mix->shadow_regs[GPIO_INDEX] = w;
+
+ mix->mixer_gpios = kmalloc(sizeof(*pdata->mixer_gpios) *
+ pdata->n_mixer_gpios,
+ GFP_KERNEL);
+ if (mix->mixer_gpios == NULL) {
+ err = -ENOMEM;
+ goto err1;
+ }
+ memcpy(mix->mixer_gpios, pdata->mixer_gpios,
+ sizeof(*pdata->mixer_gpios) * pdata->n_mixer_gpios);
+ mix->n_mixer_gpios = pdata->n_mixer_gpios;
+ }
+
+ /* PLL control */
+ tsc2301_write_pll(tsc, pdata->pll_n, pdata->pll_a, pdata->pll_pdc,
+ 0, mix->pll_output ? 0 : 1);
+
+ tsc2301_flush_shadow_regs(tsc);
+
+ if (mix->platform_init != NULL) {
+ err = mix->platform_init(&tsc->spi->dev);
+ if (err < 0)
+ goto err2;
+ }
+
+ return 0;
+err2:
+ if (mix->mixer_gpios != NULL)
+ kfree(mix->mixer_gpios);
+err1:
+ kfree(mix);
+ return err;
+}
+
+void tsc2301_mixer_exit(struct tsc2301 *tsc)
+{
+ struct tsc2301_mixer *mixer = tsc->mixer;
+
+ if (mixer->platform_cleanup != NULL)
+ mixer->platform_cleanup(&tsc->spi->dev);
+
+ if (mixer->mixer_gpios != NULL)
+ kfree(mixer->mixer_gpios);
+}
+
+MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@nokia.com>");
+MODULE_LICENSE("GPL");
default y if PPC_83xx
default y if SOC_AU1200
default y if ARCH_IXP4XX
+ default y if ARCH_OMAP34XX
default PCI
# ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
source "drivers/usb/host/Kconfig"
+source "drivers/usb/musb/Kconfig"
+
source "drivers/usb/class/Kconfig"
source "drivers/usb/storage/Kconfig"
default USB_GADGET
select USB_GADGET_SELECTED
+# built in ../musb along with host support
+config USB_GADGET_MUSB_HDRC
+ boolean "Inventra HDRC USB Peripheral (TI, ...)"
+ depends on USB_MUSB_HDRC && (USB_MUSB_PERIPHERAL || USB_MUSB_OTG)
+ select USB_GADGET_DUALSPEED
+ select USB_GADGET_SELECTED
+ help
+ This OTG-capable silicon IP is used in dual designs including
+ the TI DaVinci, OMAP 243x, OMAP 343x, and TUSB 6010.
+
config USB_GADGET_OMAP
boolean "OMAP USB Device Controller"
depends on ARCH_OMAP
- select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3
+ select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_H4_OTG
help
Many Texas Instruments OMAP processors have flexible full
speed USB device controllers, with support for up to 30
#include <asm/arch/dma.h>
#include <asm/arch/usb.h>
+#include <asm/arch/control.h>
#include "omap_udc.h"
tmp = OTG_REV_REG;
if (cpu_is_omap24xx()) {
+ /*
+ * REVISIT: Not clear how this works on OMAP2. trans
+ * is ANDed to produce bits 7 and 8, which might make
+ * sense for USB_TRANSCEIVER_CTRL_REG on OMAP1,
+ * but with CONTROL_DEVCONF, these bits have something to
+ * do with the frame adjustment counter and McBSP2.
+ */
ctrl_name = "control_devconf";
- trans = CONTROL_DEVCONF_REG;
+ trans = omap_ctrl_readb(OMAP2_CONTROL_DEVCONF0);
} else {
ctrl_name = "tranceiver_ctrl";
trans = USB_TRANSCEIVER_CTRL_REG;
* and ignored for PIO-IN on newer chips
* (for more reliable behavior)
*/
- if (!use_dma || cpu_is_omap15xx() || cpu_is_omap24xx())
+ if ((!use_dma && (addr & USB_DIR_IN))
+ || machine_is_omap_apollon()
+ || cpu_is_omap15xx())
dbuf = 0;
switch (maxp) {
To compile this driver as a module, choose M here: the
module will be called ehci-hcd.
+choice
+ prompt "PHY/TLL mode"
+ depends on USB_EHCI_HCD && EXPERIMENTAL && ARCH_OMAP34XX
+ ---help---
+ Choose PHY or TLL mode of operation
+
+config OMAP_EHCI_PHY_MODE
+ bool "PHY mode: ISP1504 on Port1/2 (NEW 3430ES2.0)"
+ depends on USB_EHCI_HCD && EXPERIMENTAL && ARCH_OMAP34XX
+ ---help---
+ EHCI PHY mode. Port1 and Port2 are connected to ISP1504 transcievers
+
+config OMAP_EHCI_TLL_MODE
+ bool "TLL mode: (EXPERIMENTAL)"
+ depends on USB_EHCI_HCD && EXPERIMENTAL && ARCH_OMAP34XX
+ ---help---
+ OMAP EHCI controller has TLL mode of operation for all 3 ports.
+ Use this mode when no transciever is present
+endchoice
config USB_EHCI_ROOT_HUB_TT
bool "Root Hub Transaction Translators"
#define PLATFORM_DRIVER ehci_hcd_au1xxx_driver
#endif
+#ifdef CONFIG_ARCH_OMAP34XX
+#include "ehci-omap.c"
+#define PLATFORM_DRIVER ehci_hcd_omap_driver
+#endif
+
#ifdef CONFIG_PPC_PS3
#include "ehci-ps3.c"
#define PS3_SYSTEM_BUS_DRIVER ps3_ehci_driver
--- /dev/null
+/*
+ * ehci-omap.c - driver for USBHOST on OMAP 34xx processor
+ *
+ * Bus Glue for OMAP34xx USBHOST 3 port EHCI controller
+ * Tested on OMAP3430 ES2.0 SDP
+ *
+ * Copyright (C) 2007-2008 Texas Instruments, Inc.
+ * Author: Vikram Pandita <vikram.pandita@ti.com>
+ *
+ * Based on "ehci-fsl.c" and "ehci-au1xxx.c" ehci glue layers
+ *
+ * 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/platform_device.h>
+#include <linux/clk.h>
+#include <asm/arch/gpio.h>
+
+#include "ehci-omap.h"
+
+
+#ifdef CONFIG_OMAP_EHCI_PHY_MODE
+/* EHCI connected to External PHY */
+
+/* External USB connectivity board: 750-2083-001
+ * Connected to OMAP3430 SDP
+ * The board has Port1 and Port2 connected to ISP1504 in 12-pin ULPI mode
+ */
+
+/* ISSUE1:
+ * ISP1504 for input clocking mode needs special reset handling
+ * Hold the PHY in reset by asserting RESET_N signal
+ * Then start the 60Mhz clock input to PHY
+ * Release the reset after a delay -
+ * to get the PHY state machine in working state
+ */
+#define EXTERNAL_PHY_RESET
+#define EXT_PHY_RESET_GPIO_PORT1 (57)
+#define EXT_PHY_RESET_GPIO_PORT2 (61)
+#define EXT_PHY_RESET_DELAY (10)
+
+/* ISSUE2:
+ * USBHOST supports External charge pump PHYs only
+ * Use the VBUS from Port1 to power VBUS of Port2 externally
+ * So use Port2 as the working ULPI port
+ */
+#define VBUS_INTERNAL_CHARGEPUMP_HACK
+
+#endif /* CONFIG_OMAP_EHCI_PHY_MODE */
+
+/*-------------------------------------------------------------------------*/
+
+/* Define USBHOST clocks for clock management */
+struct ehci_omap_clock_defs {
+ struct clk *usbhost_ick_clk;
+ struct clk *usbhost2_120m_fck_clk;
+ struct clk *usbhost1_48m_fck_clk;
+ struct clk *usbtll_fck_clk;
+ struct clk *usbtll_ick_clk;
+};
+
+/* Clock names as per clock framework: May change so keep as #defs */
+#define USBHOST_ICKL "usbhost_ick"
+#define USBHOST_120M_FCLK "usbhost_120m_fck"
+#define USBHOST_48M_FCLK "usbhost_48m_fck"
+#define USBHOST_TLL_ICKL "usbtll_ick"
+#define USBHOST_TLL_FCLK "usbtll_fck"
+/*-------------------------------------------------------------------------*/
+
+
+#ifndef CONFIG_OMAP_EHCI_PHY_MODE
+
+static void omap_usb_utmi_init(struct usb_hcd *hcd, u8 tll_channel_mask)
+{
+ int i;
+
+ /* Use UTMI Ports of TLL */
+ omap_writel((1 << OMAP_UHH_HOSTCONFIG_ULPI_BYPASS_SHIFT)|
+ (1<<OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN_SHIFT)|
+ (1<<OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN_SHIFT)|
+ (1<<OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN_SHIFT)|
+ (0<<OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN_SHIFT),
+ OMAP_UHH_HOSTCONFIG);
+ /* Enusre bit is set */
+ while (!(omap_readl(OMAP_UHH_HOSTCONFIG) &
+ (1 << OMAP_UHH_HOSTCONFIG_ULPI_BYPASS_SHIFT)));
+
+ dev_dbg(hcd->self.controller, "\nEntered UTMI MODE: success\n");
+
+ /* Program the 3 TLL channels upfront */
+
+ for (i = 0; i < OMAP_TLL_CHANNEL_COUNT; i++) {
+
+ /* Disable AutoIdle */
+ omap_writel(omap_readl(OMAP_TLL_CHANNEL_CONF(i)) &
+ ~(1<<OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE_SHIFT),
+ OMAP_TLL_CHANNEL_CONF(i));
+ /* Disable BitStuffing */
+ omap_writel(omap_readl(OMAP_TLL_CHANNEL_CONF(i)) &
+ ~(1<<OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF_SHIFT),
+ OMAP_TLL_CHANNEL_CONF(i));
+ /* SDR Mode */
+ omap_writel(omap_readl(OMAP_TLL_CHANNEL_CONF(i)) &
+ ~(1<<OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE_SHIFT),
+ OMAP_TLL_CHANNEL_CONF(i));
+
+ }
+
+ /* Program Common TLL register */
+ omap_writel((1 << OMAP_TLL_SHARED_CONF_FCLK_IS_ON_SHIFT) |
+ (1 << OMAP_TLL_SHARED_CONF_USB_DIVRATION_SHIFT) |
+ (0 << OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN_SHIFT) |
+ (0 << OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN_SHFT),
+ OMAP_TLL_SHARED_CONF);
+
+ /* Enable channels now */
+ for (i = 0; i < OMAP_TLL_CHANNEL_COUNT; i++) {
+
+ /* Enable only the channel that is needed */
+ if (!(tll_channel_mask & 1<<i))
+ continue;
+
+ omap_writel(omap_readl(OMAP_TLL_CHANNEL_CONF(i)) |
+ (1<<OMAP_TLL_CHANNEL_CONF_CHANEN_SHIFT),
+ OMAP_TLL_CHANNEL_CONF(i));
+
+ omap_writeb(0xBE, OMAP_TLL_ULPI_SCRATCH_REGISTER(i));
+ dev_dbg(hcd->self.controller, "\nULPI_SCRATCH_REG[ch=%d]"
+ "= 0x%02x\n",
+ i+1, omap_readb(OMAP_TLL_ULPI_SCRATCH_REGISTER(i)));
+ }
+}
+
+#else
+# define omap_usb_utmi_init(x, y) 0
+#endif
+
+
+/* omap_start_ehc
+ * - Start the TI USBHOST controller
+ */
+static int omap_start_ehc(struct platform_device *dev, struct usb_hcd *hcd)
+{
+ struct ehci_omap_clock_defs *ehci_clocks;
+
+ dev_dbg(hcd->self.controller, ": starting TI EHCI USB Controller\n");
+
+ ehci_clocks = (struct ehci_omap_clock_defs *)(
+ ((char *)hcd_to_ehci(hcd)) +
+ sizeof(struct ehci_hcd));
+
+ /* Start DPLL5 Programming:
+ * Clock Framework is not doing this now:
+ * This will be done in clock framework later
+ */
+ /* Enable DPLL 5 : Based on Input of 13Mhz*/
+ cm_write_mod_reg((12 << OMAP3430ES2_PERIPH2_DPLL_DIV_SHIFT)|
+ (120 << OMAP3430ES2_PERIPH2_DPLL_MULT_SHIFT),
+ PLL_MOD, OMAP3430ES2_CM_CLKSEL4);
+
+ cm_write_mod_reg(1 << OMAP3430ES2_DIV_120M_SHIFT,
+ PLL_MOD, OMAP3430ES2_CM_CLKSEL5);
+
+ cm_write_mod_reg((7 << OMAP3430ES2_PERIPH2_DPLL_FREQSEL_SHIFT) |
+ (7 << OMAP3430ES2_EN_PERIPH2_DPLL_SHIFT),
+ PLL_MOD, OMAP3430ES2_CM_CLKEN2);
+
+ while (!(cm_read_mod_reg(PLL_MOD, CM_IDLEST2) &
+ OMAP3430ES2_ST_PERIPH2_CLK_MASK))
+ dev_dbg(hcd->self.controller,
+ "idlest2 = 0x%x\n",
+ cm_read_mod_reg(PLL_MOD, CM_IDLEST2));
+ /* End DPLL5 programming */
+
+
+ /* PRCM settings for USBHOST:
+ * Interface clk un-related to domain transition
+ */
+ cm_write_mod_reg(0 << OMAP3430ES2_AUTO_USBHOST_SHIFT,
+ OMAP3430ES2_USBHOST_MOD, CM_AUTOIDLE);
+
+ /* Disable sleep dependency with MPU and IVA */
+ cm_write_mod_reg((0 << OMAP3430ES2_EN_MPU_SHIFT) |
+ (0 << OMAP3430ES2_EN_IVA2_SHIFT),
+ OMAP3430ES2_USBHOST_MOD, OMAP3430_CM_SLEEPDEP);
+
+ /* Disable Automatic transition of clock */
+ cm_write_mod_reg(0 << OMAP3430ES2_CLKTRCTRL_USBHOST_SHIFT,
+ OMAP3430ES2_USBHOST_MOD, CM_CLKSTCTRL);
+
+ /* Enable Clocks for USBHOST */
+ ehci_clocks->usbhost_ick_clk = clk_get(&dev->dev,
+ USBHOST_ICKL);
+ if (IS_ERR(ehci_clocks->usbhost_ick_clk))
+ return PTR_ERR(ehci_clocks->usbhost_ick_clk);
+ clk_enable(ehci_clocks->usbhost_ick_clk);
+
+
+ ehci_clocks->usbhost2_120m_fck_clk = clk_get(&dev->dev,
+ USBHOST_120M_FCLK);
+ if (IS_ERR(ehci_clocks->usbhost2_120m_fck_clk))
+ return PTR_ERR(ehci_clocks->usbhost2_120m_fck_clk);
+ clk_enable(ehci_clocks->usbhost2_120m_fck_clk);
+
+ ehci_clocks->usbhost1_48m_fck_clk = clk_get(&dev->dev,
+ USBHOST_48M_FCLK);
+ if (IS_ERR(ehci_clocks->usbhost1_48m_fck_clk))
+ return PTR_ERR(ehci_clocks->usbhost1_48m_fck_clk);
+ clk_enable(ehci_clocks->usbhost1_48m_fck_clk);
+
+
+#ifdef EXTERNAL_PHY_RESET
+ /* Refer: ISSUE1 */
+ omap_request_gpio(EXT_PHY_RESET_GPIO_PORT1);
+ omap_set_gpio_direction(EXT_PHY_RESET_GPIO_PORT1, 0);
+ omap_request_gpio(EXT_PHY_RESET_GPIO_PORT2);
+ omap_set_gpio_direction(EXT_PHY_RESET_GPIO_PORT2, 0);
+ omap_set_gpio_dataout(EXT_PHY_RESET_GPIO_PORT1, 0);
+ omap_set_gpio_dataout(EXT_PHY_RESET_GPIO_PORT2, 0);
+ /* Hold the PHY in RESET for enough time till DIR is high */
+ udelay(EXT_PHY_RESET_DELAY);
+#endif
+
+ /* Configure TLL for 60Mhz clk for ULPI */
+ ehci_clocks->usbtll_fck_clk = clk_get(&dev->dev, USBHOST_TLL_FCLK);
+ if (IS_ERR(ehci_clocks->usbtll_fck_clk))
+ return PTR_ERR(ehci_clocks->usbtll_fck_clk);
+ clk_enable(ehci_clocks->usbtll_fck_clk);
+
+ ehci_clocks->usbtll_ick_clk = clk_get(&dev->dev, USBHOST_TLL_ICKL);
+ if (IS_ERR(ehci_clocks->usbtll_ick_clk))
+ return PTR_ERR(ehci_clocks->usbtll_ick_clk);
+ clk_enable(ehci_clocks->usbtll_ick_clk);
+
+ /* Disable Auto Idle of USBTLL */
+ cm_write_mod_reg((0 << OMAP3430ES2_AUTO_USBTLL_SHIFT),
+ CORE_MOD, CM_AUTOIDLE3);
+
+ /* Wait for TLL to be Active */
+ while ((cm_read_mod_reg(CORE_MOD, OMAP2430_CM_IDLEST3) &
+ (1 << OMAP3430ES2_ST_USBTLL_SHIFT)));
+
+ /* perform TLL soft reset, and wait until reset is complete */
+ omap_writel(1 << OMAP_USBTLL_SYSCONFIG_SOFTRESET_SHIFT,
+ OMAP_USBTLL_SYSCONFIG);
+ /* Wait for TLL reset to complete */
+ while (!(omap_readl(OMAP_USBTLL_SYSSTATUS) &
+ (1 << OMAP_USBTLL_SYSSTATUS_RESETDONE_SHIFT)));
+
+ dev_dbg(hcd->self.controller, "\n TLL RESET DONE\n");
+
+ /* (1<<3) = no idle mode only for initial debugging */
+ omap_writel((1 << OMAP_USBTLL_SYSCONFIG_ENAWAKEUP_SHIFT) |
+ (1 << OMAP_USBTLL_SYSCONFIG_SIDLEMODE_SHIFT) |
+ (1 << OMAP_USBTLL_SYSCONFIG_CACTIVITY_SHIFT),
+ OMAP_USBTLL_SYSCONFIG);
+
+
+ /* Put UHH in NoIdle/NoStandby mode */
+ omap_writel((0 << OMAP_UHH_SYSCONFIG_AUTOIDLE_SHIFT) |
+ (1 << OMAP_UHH_SYSCONFIG_ENAWAKEUP_SHIFT) |
+ (1 << OMAP_UHH_SYSCONFIG_SIDLEMODE_SHIFT) |
+ (1 << OMAP_UHH_SYSCONFIG_CACTIVITY_SHIFT) |
+ (1 << OMAP_UHH_SYSCONFIG_MIDLEMODE_SHIFT),
+ OMAP_UHH_SYSCONFIG);
+
+#ifdef CONFIG_OMAP_EHCI_PHY_MODE
+ /* Bypass the TLL module for PHY mode operation */
+ omap_writel((0 << OMAP_UHH_HOSTCONFIG_ULPI_BYPASS_SHIFT)|
+ (1<<OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN_SHIFT)|
+ (1<<OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN_SHIFT)|
+ (1<<OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN_SHIFT)|
+ (0<<OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN_SHIFT),
+ OMAP_UHH_HOSTCONFIG);
+ /* Ensure that BYPASS is set */
+ while (omap_readl(OMAP_UHH_HOSTCONFIG) &
+ (1 << OMAP_UHH_HOSTCONFIG_ULPI_BYPASS_SHIFT));
+
+ dev_dbg(hcd->self.controller, "Entered ULPI PHY MODE: success");
+
+#else
+ /* Enable UTMI mode for all 3 TLL channels */
+ omap_usb_utmi_init(hcd,
+ OMAP_TLL_CHANNEL_1_EN_MASK |
+ OMAP_TLL_CHANNEL_2_EN_MASK |
+ OMAP_TLL_CHANNEL_3_EN_MASK
+ );
+#endif
+
+#ifdef EXTERNAL_PHY_RESET
+ /* Refer ISSUE1:
+ * Hold the PHY in RESET for enough time till PHY is settled and ready
+ */
+ udelay(EXT_PHY_RESET_DELAY);
+ omap_set_gpio_dataout(EXT_PHY_RESET_GPIO_PORT1, 1);
+ omap_set_gpio_dataout(EXT_PHY_RESET_GPIO_PORT2, 1);
+#endif
+
+#ifdef VBUS_INTERNAL_CHARGEPUMP_HACK
+ /* Refer ISSUE2: LINK assumes external charge pump */
+
+ /* use Port1 VBUS to charge externally Port2:
+ * So for PHY mode operation use Port2 only
+ */
+ omap_writel((0xA << EHCI_INSNREG05_ULPI_REGADD_SHIFT) |/* OTG ctrl reg*/
+ (2 << EHCI_INSNREG05_ULPI_OPSEL_SHIFT) |/* Write */
+ (1 << EHCI_INSNREG05_ULPI_PORTSEL_SHIFT) |/* Port1 */
+ (1 << EHCI_INSNREG05_ULPI_CONTROL_SHIFT) |/* Start */
+ (0x26),
+ EHCI_INSNREG05_ULPI);
+
+ while (!(omap_readl(EHCI_INSNREG05_ULPI) &
+ (1<<EHCI_INSNREG05_ULPI_CONTROL_SHIFT)));
+
+#endif
+
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void omap_stop_ehc(struct platform_device *dev, struct usb_hcd *hcd)
+{
+ struct ehci_omap_clock_defs *ehci_clocks;
+
+ ehci_clocks = (struct ehci_omap_clock_defs *)
+ (((char *)hcd_to_ehci(hcd)) + sizeof(struct ehci_hcd));
+
+ dev_dbg(hcd->self.controller, ": stopping TI EHCI USB Controller\n");
+
+ /* Reset OMAP modules for insmod/rmmod to work */
+ omap_writel((1<<1), OMAP_UHH_SYSCONFIG);
+ while (!(omap_readl(OMAP_UHH_SYSSTATUS) & (1<<0)));
+ while (!(omap_readl(OMAP_UHH_SYSSTATUS) & (1<<1)));
+ while (!(omap_readl(OMAP_UHH_SYSSTATUS) & (1<<2)));
+ dev_dbg(hcd->self.controller,
+ "UHH RESET DONE OMAP_UHH_SYSSTATUS %x !!\n",
+ omap_readl(OMAP_UHH_SYSSTATUS));
+
+ omap_writel((1<<1), OMAP_USBTLL_SYSCONFIG);
+ while (!(omap_readl(OMAP_USBTLL_SYSSTATUS) & (1<<0)));
+ dev_dbg(hcd->self.controller, ":TLL RESEET DONE");
+
+ if (ehci_clocks->usbtll_fck_clk != NULL) {
+ clk_disable(ehci_clocks->usbtll_fck_clk);
+ clk_put(ehci_clocks->usbtll_fck_clk);
+ ehci_clocks->usbtll_fck_clk = NULL;
+ }
+
+ if (ehci_clocks->usbhost_ick_clk != NULL) {
+ clk_disable(ehci_clocks->usbhost_ick_clk);
+ clk_put(ehci_clocks->usbhost_ick_clk);
+ ehci_clocks->usbhost_ick_clk = NULL;
+ }
+
+ if (ehci_clocks->usbhost1_48m_fck_clk != NULL) {
+ clk_disable(ehci_clocks->usbhost1_48m_fck_clk);
+ clk_put(ehci_clocks->usbhost1_48m_fck_clk);
+ ehci_clocks->usbhost1_48m_fck_clk = NULL;
+ }
+
+ if (ehci_clocks->usbhost2_120m_fck_clk != NULL) {
+ clk_disable(ehci_clocks->usbhost2_120m_fck_clk);
+ clk_put(ehci_clocks->usbhost2_120m_fck_clk);
+ ehci_clocks->usbhost2_120m_fck_clk = NULL;
+ }
+
+ if (ehci_clocks->usbtll_ick_clk != NULL) {
+ clk_disable(ehci_clocks->usbtll_ick_clk);
+ clk_put(ehci_clocks->usbtll_ick_clk);
+ ehci_clocks->usbtll_ick_clk = NULL;
+ }
+
+
+#ifdef EXTERNAL_PHY_RESET
+ omap_free_gpio(EXT_PHY_RESET_GPIO_PORT1);
+ omap_free_gpio(EXT_PHY_RESET_GPIO_PORT2);
+#endif
+
+ dev_dbg(hcd->self.controller,
+ ": Clock to USB host has been disabled\n");
+}
+
+static const struct hc_driver ehci_omap_hc_driver;
+
+/*-------------------------------------------------------------------------*/
+/* configure so an HC device and id are always provided */
+/* always called with process context; sleeping is OK */
+
+/**
+ * ehci_hcd_omap_drv_probe - initialize TI-based HCDs
+ * Context: !in_interrupt()
+ *
+ * Allocates basic resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ *
+ */
+static int ehci_hcd_omap_drv_probe(struct platform_device *dev)
+{
+ int retval = 0;
+ struct usb_hcd *hcd;
+ struct ehci_hcd *ehci;
+
+ dev_dbg(&dev->dev, "ehci_hcd_omap_drv_probe()");
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ if (dev->resource[1].flags != IORESOURCE_IRQ) {
+ dev_dbg(&dev->dev, "resource[1] is not IORESOURCE_IRQ");
+ retval = -ENOMEM;
+ }
+
+ hcd = usb_create_hcd(&ehci_omap_hc_driver, &dev->dev, dev->dev.bus_id);
+ if (!hcd)
+ return -ENOMEM;
+
+ retval = omap_start_ehc(dev, hcd);
+ if (retval)
+ return retval;
+
+ hcd->rsrc_start = 0;
+ hcd->rsrc_len = 0;
+ hcd->rsrc_start = dev->resource[0].start;
+ hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1;
+
+ hcd->regs = (void __iomem *) (int) IO_ADDRESS(hcd->rsrc_start);
+
+ ehci = hcd_to_ehci(hcd);
+ ehci->caps = hcd->regs;
+
+ ehci->regs = hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase));
+ /* cache this readonly data; minimize chip reads */
+ ehci->hcs_params = readl(&ehci->caps->hcs_params);
+
+ /* SET 1 micro-frame Interrupt interval */
+ writel(readl(&ehci->regs->command) | (1<<16), &ehci->regs->command);
+
+ retval = usb_add_hcd(hcd, dev->resource[1].start,
+ IRQF_DISABLED | IRQF_SHARED);
+ if (retval == 0)
+ return retval;
+
+ dev_dbg(hcd->self.controller, "ERR: add_hcd");
+ omap_stop_ehc(dev, hcd);
+
+ usb_put_hcd(hcd);
+ return retval;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* may be called without controller electrically present */
+/* may be called with controller, bus, and devices active */
+
+/**
+ * ehci_hcd_omap_drv_remove - shutdown processing for EHCI HCDs
+ * @dev: USB Host Controller being removed
+ * Context: !in_interrupt()
+ *
+ * Reverses the effect of usb_ehci_hcd_omap_probe(), first invoking
+ * the HCD's stop() method. It is always called from a thread
+ * context, normally "rmmod", "apmd", or something similar.
+ *
+ */
+static int ehci_hcd_omap_drv_remove(struct platform_device *dev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(dev);
+
+ dev_dbg(&dev->dev, "ehci_hcd_omap_drv_remove()");
+
+ usb_remove_hcd(hcd);
+ usb_put_hcd(hcd);
+ omap_stop_ehc(dev, hcd);
+
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+#ifdef CONFIG_PM
+static int omap_ehci_bus_suspend(struct usb_hcd *hcd)
+{
+ return ehci_bus_suspend(hcd);
+}
+
+static int omap_ehci_bus_resume(struct usb_hcd *hcd)
+{
+ return ehci_bus_resume(hcd);
+}
+#endif
+/*-------------------------------------------------------------------------*/
+
+static const struct hc_driver ehci_omap_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "OMAP-EHCI Host Controller",
+ .hcd_priv_size = sizeof(struct ehci_hcd)
+ + sizeof(struct ehci_omap_clock_defs),
+
+ /*
+ * generic hardware linkage
+ */
+ .irq = ehci_irq,
+ .flags = HCD_MEMORY | HCD_USB2,
+
+ /*
+ * basic lifecycle operations
+ */
+ .reset = ehci_init,
+ .start = ehci_run,
+ .stop = ehci_stop,
+ .shutdown = ehci_shutdown,
+
+ /*
+ * managing i/o requests and associated device resources
+ */
+ .urb_enqueue = ehci_urb_enqueue,
+ .urb_dequeue = ehci_urb_dequeue,
+ .endpoint_disable = ehci_endpoint_disable,
+
+ /*
+ * scheduling support
+ */
+ .get_frame_number = ehci_get_frame,
+
+ /*
+ * root hub support
+ */
+ .hub_status_data = ehci_hub_status_data,
+ .hub_control = ehci_hub_control,
+#ifdef CONFIG_PM
+ .bus_suspend = omap_ehci_bus_suspend,
+ .bus_resume = omap_ehci_bus_resume,
+#endif
+};
+
+/*-------------------------------------------------------------------------*/
+MODULE_ALIAS("omap-ehci");
+static struct platform_driver ehci_hcd_omap_driver = {
+ .probe = ehci_hcd_omap_drv_probe,
+ .remove = ehci_hcd_omap_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
+ /*.suspend = ehci_hcd_omap_drv_suspend, */
+ /*.resume = ehci_hcd_omap_drv_resume, */
+ .driver = {
+ .name = "ehci-omap",
+ .bus = &platform_bus_type
+ }
+};
--- /dev/null
+/*
+ * ehci-omap.h - register definitions for USBHOST in OMAP 34xx
+ *
+ * Copyright (C) 2007-2008 Texas Instruments, Inc.
+ * Author: Vikram Pandita <vikram.pandita@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
+ *
+ */
+
+#ifndef __EHCI_OMAP_H
+#define __EHCI_OMAP_H
+
+#include <asm/hardware.h>
+#include "../../../arch/arm/mach-omap2/cm.h"
+#include "../../../arch/arm/mach-omap2/cm-regbits-34xx.h"
+
+/*
+ * OMAP USBHOST Register addresses: PHYSICAL ADDRESSES
+ * Use omap_readl()/omap_writel() functions
+ */
+
+/* USBHOST: TLL, UUH, OHCI, EHCI */
+#define OMAP_USBHOST_BASE (L4_34XX_BASE + 0x60000)
+
+/* TLL Register Set */
+#define OMAP_USBHOST_TLL_BASE (OMAP_USBHOST_BASE + 0x2000)
+#define OMAP_USBTLL_REVISION (OMAP_USBHOST_TLL_BASE + 0x00)
+#define OMAP_USBTLL_SYSCONFIG (OMAP_USBHOST_TLL_BASE + 0x10)
+ #define OMAP_USBTLL_SYSCONFIG_CACTIVITY_SHIFT 8
+ #define OMAP_USBTLL_SYSCONFIG_SIDLEMODE_SHIFT 3
+ #define OMAP_USBTLL_SYSCONFIG_ENAWAKEUP_SHIFT 2
+ #define OMAP_USBTLL_SYSCONFIG_SOFTRESET_SHIFT 1
+ #define OMAP_USBTLL_SYSCONFIG_AUTOIDLE_SHIFT 0
+#define OMAP_USBTLL_SYSSTATUS (OMAP_USBHOST_TLL_BASE + 0x14)
+ #define OMAP_USBTLL_SYSSTATUS_RESETDONE_SHIFT 0
+#define OMAP_USBTLL_IRQSTATUS (OMAP_USBHOST_TLL_BASE + 0x18)
+#define OMAP_USBTLL_IRQENABLE (OMAP_USBHOST_TLL_BASE + 0x1C)
+
+#define OMAP_TLL_SHARED_CONF (OMAP_USBHOST_TLL_BASE + 0x30)
+ #define OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN_SHFT 6
+ #define OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN_SHIFT 5
+ #define OMAP_TLL_SHARED_CONF_USB_DIVRATION_SHIFT 2
+ #define OMAP_TLL_SHARED_CONF_FCLK_REQ_SHIFT 1
+ #define OMAP_TLL_SHARED_CONF_FCLK_IS_ON_SHIFT 0
+
+#define OMAP_TLL_CHANNEL_CONF(num)\
+ (OMAP_USBHOST_TLL_BASE + (0x040 + 0x004 * num))
+ #define OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF_SHIFT 11
+ #define OMAP_TLL_CHANNEL_CONF_ULPI_ULPIAUTOIDLE_SHIFT 10
+ #define OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE_SHIFT 9
+ #define OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE_SHIFT 8
+ #define OMAP_TLL_CHANNEL_CONF_CHANEN_SHIFT 0
+
+#define OMAP_TLL_ULPI_FUNCTION_CTRL(num)\
+ (OMAP_USBHOST_TLL_BASE + (0x804 + 0x100 * num))
+#define OMAP_TLL_ULPI_INTERFACE_CTRL(num)\
+ (OMAP_USBHOST_TLL_BASE + (0x807 + 0x100 * num))
+#define OMAP_TLL_ULPI_OTG_CTRL(num)\
+ (OMAP_USBHOST_TLL_BASE + (0x80A + 0x100 * num))
+#define OMAP_TLL_ULPI_INT_EN_RISE(num)\
+ (OMAP_USBHOST_TLL_BASE + (0x80D + 0x100 * num))
+#define OMAP_TLL_ULPI_INT_EN_FALL(num)\
+ (OMAP_USBHOST_TLL_BASE + (0x810 + 0x100 * num))
+#define OMAP_TLL_ULPI_INT_STATUS(num)\
+ (OMAP_USBHOST_TLL_BASE + (0x813 + 0x100 * num))
+#define OMAP_TLL_ULPI_INT_LATCH(num)\
+ (OMAP_USBHOST_TLL_BASE + (0x814 + 0x100 * num))
+#define OMAP_TLL_ULPI_DEBUG(num)\
+ (OMAP_USBHOST_TLL_BASE + (0x815 + 0x100 * num))
+#define OMAP_TLL_ULPI_SCRATCH_REGISTER(num)\
+ (OMAP_USBHOST_TLL_BASE + (0x816 + 0x100 * num))
+
+#define OMAP_TLL_CHANNEL_COUNT 3
+ #define OMAP_TLL_CHANNEL_1_EN_MASK 1
+ #define OMAP_TLL_CHANNEL_2_EN_MASK 2
+ #define OMAP_TLL_CHANNEL_3_EN_MASK 4
+
+/* UHH Register Set */
+#define OMAP_USBHOST_UHH_BASE (OMAP_USBHOST_BASE + 0x4000)
+#define OMAP_UHH_REVISION (OMAP_USBHOST_UHH_BASE + 0x00)
+#define OMAP_UHH_SYSCONFIG (OMAP_USBHOST_UHH_BASE + 0x10)
+ #define OMAP_UHH_SYSCONFIG_MIDLEMODE_SHIFT 12
+ #define OMAP_UHH_SYSCONFIG_CACTIVITY_SHIFT 8
+ #define OMAP_UHH_SYSCONFIG_SIDLEMODE_SHIFT 3
+ #define OMAP_UHH_SYSCONFIG_ENAWAKEUP_SHIFT 2
+ #define OMAP_UHH_SYSCONFIG_SOFTRESET_SHIFT 1
+ #define OMAP_UHH_SYSCONFIG_AUTOIDLE_SHIFT 0
+
+#define OMAP_UHH_SYSSTATUS (OMAP_USBHOST_UHH_BASE + 0x14)
+#define OMAP_UHH_HOSTCONFIG (OMAP_USBHOST_UHH_BASE + 0x40)
+ #define OMAP_UHH_HOSTCONFIG_ULPI_BYPASS_SHIFT 0
+ #define OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN_SHIFT 2
+ #define OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN_SHIFT 3
+ #define OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN_SHIFT 4
+ #define OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN_SHIFT 5
+
+#define OMAP_UHH_DEBUG_CSR (OMAP_USBHOST_UHH_BASE + 0x44)
+
+/* EHCI Register Set */
+#define OMAP_USBHOST_EHCI_BASE (OMAP_USBHOST_BASE + 0x4800)
+#define EHCI_INSNREG05_ULPI (OMAP_USBHOST_EHCI_BASE + 0xA4)
+ #define EHCI_INSNREG05_ULPI_CONTROL_SHIFT 31
+ #define EHCI_INSNREG05_ULPI_PORTSEL_SHIFT 24
+ #define EHCI_INSNREG05_ULPI_OPSEL_SHIFT 22
+ #define EHCI_INSNREG05_ULPI_REGADD_SHIFT 16
+ #define EHCI_INSNREG05_ULPI_EXTREGADD_SHIFT 8
+ #define EHCI_INSNREG05_ULPI_WRDATA_SHIFT 0
+
+/* OHCI Register Set */
+#define OMAP_USBHOST_OHCI_BASE (OMAP_USBHOST_BASE + 0x4400)
+
+#endif/* __EHCI_OMAP_H*/
omap_ohci_clock_power(1);
- if (cpu_is_omap1510()) {
+ if (cpu_is_omap15xx()) {
omap_1510_local_bus_power(1);
omap_1510_local_bus_init();
}
if (IS_ERR(usb_host_ck))
return PTR_ERR(usb_host_ck);
- if (!cpu_is_omap1510())
+ if (!cpu_is_omap15xx())
usb_dc_ck = clk_get(0, "usb_dc_ck");
else
usb_dc_ck = clk_get(0, "lb_ck");
--- /dev/null
+#
+# USB Dual Role (OTG-ready) Controller Drivers
+# for silicon based on Mentor Graphics INVENTRA designs
+#
+
+comment "Enable Host or Gadget support to see Inventra options"
+ depends on !USB && USB_GADGET=n
+
+# (M)HDRC = (Multipoint) Highspeed Dual-Role Controller
+config USB_MUSB_HDRC
+ depends on USB || USB_GADGET
+ select TWL4030_USB if MACH_OMAP_3430SDP
+ tristate 'Inventra Highspeed Dual Role Controller (TI, ...)'
+ help
+ Say Y here if your system has a dual role high speed USB
+ controller based on the Mentor Graphics silicon IP. Then
+ configure options to match your silicon and the board
+ it's being used with, including the USB peripheral role,
+ or the USB host role, or both.
+
+ Texas Instruments parts using this IP include DaVinci 644x,
+ OMAP 243x, OMAP 343x, and TUSB 6010.
+
+ If you do not know what this is, please say N.
+
+ To compile this driver as a module, choose M here; the
+ module will be called "musb_hdrc".
+
+config USB_MUSB_SOC
+ boolean
+ depends on USB_MUSB_HDRC
+ default y if ARCH_DAVINCI
+ default y if ARCH_OMAP2430
+ default y if ARCH_OMAP34XX
+ help
+ Use a static <asm/arch/hdrc_cnf.h> file to describe how the
+ controller is configured (endpoints, mechanisms, etc) on the
+ current iteration of a given system-on-chip.
+
+comment "DaVinci 644x USB support"
+ depends on USB_MUSB_HDRC && ARCH_DAVINCI
+
+comment "OMAP 243x high speed USB support"
+ depends on USB_MUSB_HDRC && ARCH_OMAP2430
+
+comment "OMAP 343x high speed USB support"
+ depends on USB_MUSB_HDRC && ARCH_OMAP34XX
+
+config USB_TUSB6010
+ boolean "TUSB 6010 support"
+ depends on USB_MUSB_HDRC && !USB_MUSB_SOC
+ default y
+ help
+ The TUSB 6010 chip, from Texas Instruments, connects a discrete
+ HDRC core using a 16-bit parallel bus (NOR flash style) or VLYNQ
+ (a high speed serial link). It can use system-specific external
+ DMA controllers.
+
+choice
+ prompt "Driver Mode"
+ depends on USB_MUSB_HDRC
+ help
+ Dual-Role devices can support both host and peripheral roles,
+ as well as a the special "OTG Device" role which can switch
+ between both roles as needed.
+
+# use USB_MUSB_HDRC_HCD not USB_MUSB_HOST to #ifdef host side support;
+# OTG needs both roles, not just USB_MUSB_HOST.
+config USB_MUSB_HOST
+ depends on USB
+ bool "USB Host"
+ help
+ Say Y here if your system supports the USB host role.
+ If it has a USB "A" (rectangular), "Mini-A" (uncommon),
+ or "Mini-AB" connector, it supports the host role.
+ (With a "Mini-AB" connector, you should enable USB OTG.)
+
+# use USB_GADGET_MUSB_HDRC not USB_MUSB_PERIPHERAL to #ifdef peripheral
+# side support ... OTG needs both roles
+config USB_MUSB_PERIPHERAL
+ depends on USB_GADGET
+ bool "USB Peripheral (gadget stack)"
+ select USB_GADGET_MUSB_HDRC
+ help
+ Say Y here if your system supports the USB peripheral role.
+ If it has a USB "B" (squarish), "Mini-B", or "Mini-AB"
+ connector, it supports the peripheral role.
+ (With a "Mini-AB" connector, you should enable USB OTG.)
+
+config USB_MUSB_OTG
+ depends on USB && USB_GADGET && EXPERIMENTAL
+ bool "Both host and peripheral: USB OTG (On The Go) Device"
+ select USB_GADGET_MUSB_HDRC
+ select USB_OTG
+ select PM
+ help
+ The most notable feature of USB OTG is support for a
+ "Dual-Role" device, which can act as either a device
+ or a host. The initial role choice can be changed
+ later, when two dual-role devices talk to each other.
+
+ At this writing, the OTG support in this driver is incomplete,
+ omitting the mandatory HNP or SRP protocols. However, some
+ of the cable based role switching works. (That is, grounding
+ the ID pin switches the controller to host mode, while leaving
+ it floating leaves it in peripheral mode.)
+
+ Select this if your system has a Mini-AB connector, or
+ to simplify certain kinds of configuration.
+
+ To implement your OTG Targeted Peripherals List (TPL), enable
+ USB_OTG_WHITELIST and update "drivers/usb/core/otg_whitelist.h"
+ to match your requirements.
+
+endchoice
+
+# enable peripheral support (including with OTG)
+config USB_GADGET_MUSB_HDRC
+ bool
+ depends on USB_MUSB_HDRC && (USB_MUSB_PERIPHERAL || USB_MUSB_OTG)
+# default y
+# select USB_GADGET_DUALSPEED
+# select USB_GADGET_SELECTED
+
+# enables host support (including with OTG)
+config USB_MUSB_HDRC_HCD
+ bool
+ depends on USB_MUSB_HDRC && (USB_MUSB_HOST || USB_MUSB_OTG)
+ select USB_OTG if USB_GADGET_MUSB_HDRC
+ default y
+
+
+config MUSB_PIO_ONLY
+ bool 'Disable DMA (always use PIO)'
+ depends on USB_MUSB_HDRC
+ default y if USB_TUSB6010
+ help
+ All data is copied between memory and FIFO by the CPU.
+ DMA controllers are ignored.
+
+ Do not select 'n' here unless DMA support for your SOC or board
+ is unavailable (or unstable). When DMA is enabled at compile time,
+ you can still disable it at run time using the "use_dma=n" module
+ parameter.
+
+config USB_INVENTRA_DMA
+ bool
+ depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY
+ default ARCH_OMAP2430 || ARCH_OMAP34XX
+ help
+ Enable DMA transfers using Mentor's engine.
+
+config USB_TI_CPPI_DMA
+ bool
+ depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY
+ default ARCH_DAVINCI
+ help
+ Enable DMA transfers when TI CPPI DMA is available.
+
+config USB_TUSB_OMAP_DMA
+ bool
+ depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY
+ depends on USB_TUSB6010
+ depends on ARCH_OMAP
+ default y
+ help
+ Enable DMA transfers on TUSB 6010 when OMAP DMA is available.
+
+config USB_MUSB_LOGLEVEL
+ depends on USB_MUSB_HDRC
+ int 'Logging Level (0 - none / 3 - annoying / ... )'
+ default 0
+ help
+ Set the logging level. 0 disables the debugging altogether,
+ although when USB_DEBUG is set the value is at least 1.
+ Starting at level 3, per-transfer (urb, usb_request, packet,
+ or dma transfer) tracing may kick in.
--- /dev/null
+#
+# for USB OTG silicon based on Mentor Graphics INVENTRA designs
+#
+
+musb_hdrc-objs := musb_core.o
+
+obj-$(CONFIG_USB_MUSB_HDRC) += musb_hdrc.o
+
+ifeq ($(CONFIG_ARCH_DAVINCI),y)
+ musb_hdrc-objs += davinci.o
+endif
+
+ifeq ($(CONFIG_USB_TUSB6010),y)
+ musb_hdrc-objs += tusb6010.o
+endif
+
+ifeq ($(CONFIG_ARCH_OMAP2430),y)
+ musb_hdrc-objs += omap2430.o
+endif
+
+ifeq ($(CONFIG_ARCH_OMAP3430),y)
+ musb_hdrc-objs += omap2430.o
+endif
+
+ifeq ($(CONFIG_USB_GADGET_MUSB_HDRC),y)
+ musb_hdrc-objs += musb_gadget_ep0.o musb_gadget.o
+endif
+
+ifeq ($(CONFIG_USB_MUSB_HDRC_HCD),y)
+ musb_hdrc-objs += musb_virthub.o musb_host.o
+endif
+
+# the kconfig must guarantee that only one of the
+# possible I/O schemes will be enabled at a time ...
+# PIO only, or DMA (several potential schemes).
+# though PIO is always there to back up DMA, and for ep0
+
+ifneq ($(CONFIG_MUSB_PIO_ONLY),y)
+
+ ifeq ($(CONFIG_USB_INVENTRA_DMA),y)
+ musb_hdrc-objs += musbhsdma.o
+
+ else
+ ifeq ($(CONFIG_USB_TI_CPPI_DMA),y)
+ musb_hdrc-objs += cppi_dma.o
+
+ else
+ ifeq ($(CONFIG_USB_TUSB_OMAP_DMA),y)
+ musb_hdrc-objs += tusb6010_omap.o
+
+ endif
+ endif
+ endif
+endif
+
+
+################################################################################
+
+# FIXME remove all these extra "-DMUSB_* things, stick to CONFIG_*
+
+ifeq ($(CONFIG_USB_INVENTRA_MUSB_HAS_AHB_ID),y)
+ EXTRA_CFLAGS += -DMUSB_AHB_ID
+endif
+
+# Debugging
+
+MUSB_DEBUG:=$(CONFIG_USB_MUSB_LOGLEVEL)
+
+ifeq ("$(strip $(MUSB_DEBUG))","")
+ ifdef CONFIG_USB_DEBUG
+ MUSB_DEBUG:=1
+ else
+ MUSB_DEBUG:=0
+ endif
+endif
+
+ifneq ($(MUSB_DEBUG),0)
+ EXTRA_CFLAGS += -DDEBUG
+
+ ifeq ($(CONFIG_PROC_FS),y)
+ musb_hdrc-objs += musb_procfs.o
+ endif
+
+endif
+
+EXTRA_CFLAGS += -DMUSB_DEBUG=$(MUSB_DEBUG)
--- /dev/null
+/*
+ * Copyright (C) 2005-2006 by Texas Instruments
+ *
+ * This file implements a DMA interface using TI's CPPI DMA.
+ * For now it's DaVinci-only, but CPPI isn't specific to DaVinci or USB.
+ * The TUSB6020, using VLYNQ, has CPPI that looks much like DaVinci.
+ */
+
+#include <linux/usb.h>
+
+#include "musb_core.h"
+#include "cppi_dma.h"
+
+
+/* CPPI DMA status 7-mar-2006:
+ *
+ * - See musb_{host,gadget}.c for more info
+ *
+ * - Correct RX DMA generally forces the engine into irq-per-packet mode,
+ * which can easily saturate the CPU under non-mass-storage loads.
+ *
+ * NOTES 24-aug-2006 (2.6.18-rc4):
+ *
+ * - peripheral RXDMA wedged in a test with packets of length 512/512/1.
+ * evidently after the 1 byte packet was received and acked, the queue
+ * of BDs got garbaged so it wouldn't empty the fifo. (rxcsr 0x2003,
+ * and RX DMA0: 4 left, 80000000 8feff880, 8feff860 8feff860; 8f321401
+ * 004001ff 00000001 .. 8feff860) Host was just getting NAKed on tx
+ * of its next (512 byte) packet. IRQ issues?
+ *
+ * REVISIT: the "transfer DMA" glue between CPPI and USB fifos will
+ * evidently also directly update the RX and TX CSRs ... so audit all
+ * host and peripheral side DMA code to avoid CSR access after DMA has
+ * been started.
+ */
+
+/* REVISIT now we can avoid preallocating these descriptors; or
+ * more simply, switch to a global freelist not per-channel ones.
+ * Note: at full speed, 64 descriptors == 4K bulk data.
+ */
+#define NUM_TXCHAN_BD 64
+#define NUM_RXCHAN_BD 64
+
+static inline void cpu_drain_writebuffer(void)
+{
+ wmb();
+#ifdef CONFIG_CPU_ARM926T
+ /* REVISIT this "should not be needed",
+ * but lack of it sure seemed to hurt ...
+ */
+ asm("mcr p15, 0, r0, c7, c10, 4 @ drain write buffer\n");
+#endif
+}
+
+static inline struct cppi_descriptor *cppi_bd_alloc(struct cppi_channel *c)
+{
+ struct cppi_descriptor *bd = c->freelist;
+
+ if (bd)
+ c->freelist = bd->next;
+ return bd;
+}
+
+static inline void
+cppi_bd_free(struct cppi_channel *c, struct cppi_descriptor *bd)
+{
+ if (!bd)
+ return;
+ bd->next = c->freelist;
+ c->freelist = bd;
+}
+
+/*
+ * Start DMA controller
+ *
+ * Initialize the DMA controller as necessary.
+ */
+
+/* zero out entire rx state RAM entry for the channel */
+static void cppi_reset_rx(struct cppi_rx_stateram __iomem *rx)
+{
+ musb_writel(&rx->rx_skipbytes, 0, 0);
+ musb_writel(&rx->rx_head, 0, 0);
+ musb_writel(&rx->rx_sop, 0, 0);
+ musb_writel(&rx->rx_current, 0, 0);
+ musb_writel(&rx->rx_buf_current, 0, 0);
+ musb_writel(&rx->rx_len_len, 0, 0);
+ musb_writel(&rx->rx_cnt_cnt, 0, 0);
+}
+
+/* zero out entire tx state RAM entry for the channel */
+static void cppi_reset_tx(struct cppi_tx_stateram __iomem *tx, u32 ptr)
+{
+ musb_writel(&tx->tx_head, 0, 0);
+ musb_writel(&tx->tx_buf, 0, 0);
+ musb_writel(&tx->tx_current, 0, 0);
+ musb_writel(&tx->tx_buf_current, 0, 0);
+ musb_writel(&tx->tx_info, 0, 0);
+ musb_writel(&tx->tx_rem_len, 0, 0);
+ /* musb_writel(&tx->tx_dummy, 0, 0); */
+ musb_writel(&tx->tx_complete, 0, ptr);
+}
+
+static void __init cppi_pool_init(struct cppi *cppi, struct cppi_channel *c)
+{
+ int j;
+
+ /* initialize channel fields */
+ c->head = NULL;
+ c->tail = NULL;
+ c->last_processed = NULL;
+ c->channel.status = MUSB_DMA_STATUS_UNKNOWN;
+ c->controller = cppi;
+ c->is_rndis = 0;
+ c->freelist = NULL;
+
+ /* build the BD Free list for the channel */
+ for (j = 0; j < NUM_TXCHAN_BD + 1; j++) {
+ struct cppi_descriptor *bd;
+ dma_addr_t dma;
+
+ bd = dma_pool_alloc(cppi->pool, GFP_KERNEL, &dma);
+ bd->dma = dma;
+ cppi_bd_free(c, bd);
+ }
+}
+
+static int cppi_channel_abort(struct dma_channel *);
+
+static void cppi_pool_free(struct cppi_channel *c)
+{
+ struct cppi *cppi = c->controller;
+ struct cppi_descriptor *bd;
+
+ (void) cppi_channel_abort(&c->channel);
+ c->channel.status = MUSB_DMA_STATUS_UNKNOWN;
+ c->controller = NULL;
+
+ /* free all its bds */
+ bd = c->last_processed;
+ do {
+ if (bd)
+ dma_pool_free(cppi->pool, bd, bd->dma);
+ bd = cppi_bd_alloc(c);
+ } while (bd);
+ c->last_processed = NULL;
+}
+
+static int __init cppi_controller_start(struct dma_controller *c)
+{
+ struct cppi *controller;
+ void __iomem *tibase;
+ int i;
+
+ controller = container_of(c, struct cppi, controller);
+
+ /* do whatever is necessary to start controller */
+ for (i = 0; i < ARRAY_SIZE(controller->tx); i++) {
+ controller->tx[i].transmit = true;
+ controller->tx[i].index = i;
+ }
+ for (i = 0; i < ARRAY_SIZE(controller->rx); i++) {
+ controller->rx[i].transmit = false;
+ controller->rx[i].index = i;
+ }
+
+ /* setup BD list on a per channel basis */
+ for (i = 0; i < ARRAY_SIZE(controller->tx); i++)
+ cppi_pool_init(controller, controller->tx + i);
+ for (i = 0; i < ARRAY_SIZE(controller->rx); i++)
+ cppi_pool_init(controller, controller->rx + i);
+
+ tibase = controller->tibase;
+ INIT_LIST_HEAD(&controller->tx_complete);
+
+ /* initialise tx/rx channel head pointers to zero */
+ for (i = 0; i < ARRAY_SIZE(controller->tx); i++) {
+ struct cppi_channel *tx_ch = controller->tx + i;
+ struct cppi_tx_stateram __iomem *tx;
+
+ INIT_LIST_HEAD(&tx_ch->tx_complete);
+
+ tx = tibase + DAVINCI_TXCPPI_STATERAM_OFFSET(i);
+ tx_ch->state_ram = tx;
+ cppi_reset_tx(tx, 0);
+ }
+ for (i = 0; i < ARRAY_SIZE(controller->rx); i++) {
+ struct cppi_channel *rx_ch = controller->rx + i;
+ struct cppi_rx_stateram __iomem *rx;
+
+ INIT_LIST_HEAD(&rx_ch->tx_complete);
+
+ rx = tibase + DAVINCI_RXCPPI_STATERAM_OFFSET(i);
+ rx_ch->state_ram = rx;
+ cppi_reset_rx(rx);
+ }
+
+ /* enable individual cppi channels */
+ musb_writel(tibase, DAVINCI_TXCPPI_INTENAB_REG,
+ DAVINCI_DMA_ALL_CHANNELS_ENABLE);
+ musb_writel(tibase, DAVINCI_RXCPPI_INTENAB_REG,
+ DAVINCI_DMA_ALL_CHANNELS_ENABLE);
+
+ /* enable tx/rx CPPI control */
+ musb_writel(tibase, DAVINCI_TXCPPI_CTRL_REG, DAVINCI_DMA_CTRL_ENABLE);
+ musb_writel(tibase, DAVINCI_RXCPPI_CTRL_REG, DAVINCI_DMA_CTRL_ENABLE);
+
+ /* disable RNDIS mode, also host rx RNDIS autorequest */
+ musb_writel(tibase, DAVINCI_RNDIS_REG, 0);
+ musb_writel(tibase, DAVINCI_AUTOREQ_REG, 0);
+
+ return 0;
+}
+
+/*
+ * Stop DMA controller
+ *
+ * De-Init the DMA controller as necessary.
+ */
+
+static int cppi_controller_stop(struct dma_controller *c)
+{
+ struct cppi *controller;
+ void __iomem *tibase;
+ int i;
+
+ controller = container_of(c, struct cppi, controller);
+
+ tibase = controller->tibase;
+ /* DISABLE INDIVIDUAL CHANNEL Interrupts */
+ musb_writel(tibase, DAVINCI_TXCPPI_INTCLR_REG,
+ DAVINCI_DMA_ALL_CHANNELS_ENABLE);
+ musb_writel(tibase, DAVINCI_RXCPPI_INTCLR_REG,
+ DAVINCI_DMA_ALL_CHANNELS_ENABLE);
+
+ DBG(1, "Tearing down RX and TX Channels\n");
+ for (i = 0; i < ARRAY_SIZE(controller->tx); i++) {
+ /* FIXME restructure of txdma to use bds like rxdma */
+ controller->tx[i].last_processed = NULL;
+ cppi_pool_free(controller->tx + i);
+ }
+ for (i = 0; i < ARRAY_SIZE(controller->rx); i++)
+ cppi_pool_free(controller->rx + i);
+
+ /* in Tx Case proper teardown is supported. We resort to disabling
+ * Tx/Rx CPPI after cleanup of Tx channels. Before TX teardown is
+ * complete TX CPPI cannot be disabled.
+ */
+ /*disable tx/rx cppi */
+ musb_writel(tibase, DAVINCI_TXCPPI_CTRL_REG, DAVINCI_DMA_CTRL_DISABLE);
+ musb_writel(tibase, DAVINCI_RXCPPI_CTRL_REG, DAVINCI_DMA_CTRL_DISABLE);
+
+ return 0;
+}
+
+/* While dma channel is allocated, we only want the core irqs active
+ * for fault reports, otherwise we'd get irqs that we don't care about.
+ * Except for TX irqs, where dma done != fifo empty and reusable ...
+ *
+ * NOTE: docs don't say either way, but irq masking **enables** irqs.
+ *
+ * REVISIT same issue applies to pure PIO usage too, and non-cppi dma...
+ */
+static inline void core_rxirq_disable(void __iomem *tibase, unsigned epnum)
+{
+ musb_writel(tibase, DAVINCI_USB_INT_MASK_CLR_REG, 1 << (epnum + 8));
+}
+
+static inline void core_rxirq_enable(void __iomem *tibase, unsigned epnum)
+{
+ musb_writel(tibase, DAVINCI_USB_INT_MASK_SET_REG, 1 << (epnum + 8));
+}
+
+
+/*
+ * Allocate a CPPI Channel for DMA. With CPPI, channels are bound to
+ * each transfer direction of a non-control endpoint, so allocating
+ * (and deallocating) is mostly a way to notice bad housekeeping on
+ * the software side. We assume the irqs are always active.
+ */
+static struct dma_channel *
+cppi_channel_allocate(struct dma_controller *c,
+ struct musb_hw_ep *ep, u8 transmit)
+{
+ struct cppi *controller;
+ u8 index;
+ struct cppi_channel *cppi_ch;
+ void __iomem *tibase;
+
+ controller = container_of(c, struct cppi, controller);
+ tibase = controller->tibase;
+
+ /* ep0 doesn't use DMA; remember cppi indices are 0..N-1 */
+ index = ep->epnum - 1;
+
+ /* return the corresponding CPPI Channel Handle, and
+ * probably disable the non-CPPI irq until we need it.
+ */
+ if (transmit) {
+ if (index >= ARRAY_SIZE(controller->tx)) {
+ DBG(1, "no %cX%d CPPI channel\n", 'T', index);
+ return NULL;
+ }
+ cppi_ch = controller->tx + index;
+ } else {
+ if (index >= ARRAY_SIZE(controller->rx)) {
+ DBG(1, "no %cX%d CPPI channel\n", 'R', index);
+ return NULL;
+ }
+ cppi_ch = controller->rx + index;
+ core_rxirq_disable(tibase, ep->epnum);
+ }
+
+ /* REVISIT make this an error later once the same driver code works
+ * with the other DMA engine too
+ */
+ if (cppi_ch->hw_ep)
+ DBG(1, "re-allocating DMA%d %cX channel %p\n",
+ index, transmit ? 'T' : 'R', cppi_ch);
+ cppi_ch->hw_ep = ep;
+ cppi_ch->channel.status = MUSB_DMA_STATUS_FREE;
+
+ DBG(4, "Allocate CPPI%d %cX\n", index, transmit ? 'T' : 'R');
+ return &cppi_ch->channel;
+}
+
+/* Release a CPPI Channel. */
+static void cppi_channel_release(struct dma_channel *channel)
+{
+ struct cppi_channel *c;
+ void __iomem *tibase;
+
+ /* REVISIT: for paranoia, check state and abort if needed... */
+
+ c = container_of(channel, struct cppi_channel, channel);
+ tibase = c->controller->tibase;
+ if (!c->hw_ep)
+ DBG(1, "releasing idle DMA channel %p\n", c);
+ else if (!c->transmit)
+ core_rxirq_enable(tibase, c->index + 1);
+
+ /* for now, leave its cppi IRQ enabled (we won't trigger it) */
+ c->hw_ep = NULL;
+ channel->status = MUSB_DMA_STATUS_UNKNOWN;
+}
+
+/* Context: controller irqlocked */
+static void
+cppi_dump_rx(int level, struct cppi_channel *c, const char *tag)
+{
+ void __iomem *base = c->controller->mregs;
+ struct cppi_rx_stateram __iomem *rx = c->state_ram;
+
+ musb_ep_select(base, c->index + 1);
+
+ DBG(level, "RX DMA%d%s: %d left, csr %04x, "
+ "%08x H%08x S%08x C%08x, "
+ "B%08x L%08x %08x .. %08x"
+ "\n",
+ c->index, tag,
+ musb_readl(c->controller->tibase,
+ DAVINCI_RXCPPI_BUFCNT0_REG + 4 * c->index),
+ musb_readw(c->hw_ep->regs, MUSB_RXCSR),
+
+ musb_readl(&rx->rx_skipbytes, 0),
+ musb_readl(&rx->rx_head, 0),
+ musb_readl(&rx->rx_sop, 0),
+ musb_readl(&rx->rx_current, 0),
+
+ musb_readl(&rx->rx_buf_current, 0),
+ musb_readl(&rx->rx_len_len, 0),
+ musb_readl(&rx->rx_cnt_cnt, 0),
+ musb_readl(&rx->rx_complete, 0)
+ );
+}
+
+/* Context: controller irqlocked */
+static void
+cppi_dump_tx(int level, struct cppi_channel *c, const char *tag)
+{
+ void __iomem *base = c->controller->mregs;
+ struct cppi_tx_stateram __iomem *tx = c->state_ram;
+
+ musb_ep_select(base, c->index + 1);
+
+ DBG(level, "TX DMA%d%s: csr %04x, "
+ "H%08x S%08x C%08x %08x, "
+ "F%08x L%08x .. %08x"
+ "\n",
+ c->index, tag,
+ musb_readw(c->hw_ep->regs, MUSB_TXCSR),
+
+ musb_readl(&tx->tx_head, 0),
+ musb_readl(&tx->tx_buf, 0),
+ musb_readl(&tx->tx_current, 0),
+ musb_readl(&tx->tx_buf_current, 0),
+
+ musb_readl(&tx->tx_info, 0),
+ musb_readl(&tx->tx_rem_len, 0),
+ /* dummy/unused word 6 */
+ musb_readl(&tx->tx_complete, 0)
+ );
+}
+
+/* Context: controller irqlocked */
+static inline void
+cppi_rndis_update(struct cppi_channel *c, int is_rx,
+ void __iomem *tibase, int is_rndis)
+{
+ /* we may need to change the rndis flag for this cppi channel */
+ if (c->is_rndis != is_rndis) {
+ u32 value = musb_readl(tibase, DAVINCI_RNDIS_REG);
+ u32 temp = 1 << (c->index);
+
+ if (is_rx)
+ temp <<= 16;
+ if (is_rndis)
+ value |= temp;
+ else
+ value &= ~temp;
+ musb_writel(tibase, DAVINCI_RNDIS_REG, value);
+ c->is_rndis = is_rndis;
+ }
+}
+
+static void cppi_dump_rxbd(const char *tag, struct cppi_descriptor *bd)
+{
+ pr_debug("RXBD/%s %08x: "
+ "nxt %08x buf %08x off.blen %08x opt.plen %08x\n",
+ tag, bd->dma,
+ bd->hw_next, bd->hw_bufp, bd->hw_off_len,
+ bd->hw_options);
+}
+
+static void cppi_dump_rxq(int level, const char *tag, struct cppi_channel *rx)
+{
+#if MUSB_DEBUG > 0
+ struct cppi_descriptor *bd;
+
+ if (!_dbg_level(level))
+ return;
+ cppi_dump_rx(level, rx, tag);
+ if (rx->last_processed)
+ cppi_dump_rxbd("last", rx->last_processed);
+ for (bd = rx->head; bd; bd = bd->next)
+ cppi_dump_rxbd("active", bd);
+#endif
+}
+
+
+/* NOTE: DaVinci autoreq is ignored except for host side "RNDIS" mode RX;
+ * so we won't ever use it (see "CPPI RX Woes" below).
+ */
+static inline int cppi_autoreq_update(struct cppi_channel *rx,
+ void __iomem *tibase, int onepacket, unsigned n_bds)
+{
+ u32 val;
+
+#ifdef RNDIS_RX_IS_USABLE
+ u32 tmp;
+ /* assert(is_host_active(musb)) */
+
+ /* start from "AutoReq never" */
+ tmp = musb_readl(tibase, DAVINCI_AUTOREQ_REG);
+ val = tmp & ~((0x3) << (rx->index * 2));
+
+ /* HCD arranged reqpkt for packet #1. we arrange int
+ * for all but the last one, maybe in two segments.
+ */
+ if (!onepacket) {
+#if 0
+ /* use two segments, autoreq "all" then the last "never" */
+ val |= ((0x3) << (rx->index * 2));
+ n_bds--;
+#else
+ /* one segment, autoreq "all-but-last" */
+ val |= ((0x1) << (rx->index * 2));
+#endif
+ }
+
+ if (val != tmp) {
+ int n = 100;
+
+ /* make sure that autoreq is updated before continuing */
+ musb_writel(tibase, DAVINCI_AUTOREQ_REG, val);
+ do {
+ tmp = musb_readl(tibase, DAVINCI_AUTOREQ_REG);
+ if (tmp == val)
+ break;
+ cpu_relax();
+ } while (n-- > 0);
+ }
+#endif
+
+ /* REQPKT is turned off after each segment */
+ if (n_bds && rx->channel.actual_len) {
+ void __iomem *regs = rx->hw_ep->regs;
+
+ val = musb_readw(regs, MUSB_RXCSR);
+ if (!(val & MUSB_RXCSR_H_REQPKT)) {
+ val |= MUSB_RXCSR_H_REQPKT | MUSB_RXCSR_H_WZC_BITS;
+ musb_writew(regs, MUSB_RXCSR, val);
+ /* flush writebufer */
+ val = musb_readw(regs, MUSB_RXCSR);
+ }
+ }
+ return n_bds;
+}
+
+
+/* Buffer enqueuing Logic:
+ *
+ * - RX builds new queues each time, to help handle routine "early
+ * termination" cases (faults, including errors and short reads)
+ * more correctly.
+ *
+ * - for now, TX reuses the same queue of BDs every time
+ *
+ * REVISIT long term, we want a normal dynamic model.
+ * ... the goal will be to append to the
+ * existing queue, processing completed "dma buffers" (segments) on the fly.
+ *
+ * Otherwise we force an IRQ latency between requests, which slows us a lot
+ * (especially in "transparent" dma). Unfortunately that model seems to be
+ * inherent in the DMA model from the Mentor code, except in the rare case
+ * of transfers big enough (~128+ KB) that we could append "middle" segments
+ * in the TX paths. (RX can't do this, see below.)
+ *
+ * That's true even in the CPPI- friendly iso case, where most urbs have
+ * several small segments provided in a group and where the "packet at a time"
+ * "transparent" DMA model is always correct, even on the RX side.
+ */
+
+/*
+ * CPPI TX:
+ * ========
+ * TX is a lot more reasonable than RX; it doesn't need to run in
+ * irq-per-packet mode very often. RNDIS mode seems to behave too
+ * (except how it handles the exactly-N-packets case). Building a
+ * txdma queue with multiple requests (urb or usb_request) looks
+ * like it would work ... but fault handling would need much testing.
+ *
+ * The main issue with TX mode RNDIS relates to transfer lengths that
+ * are an exact multiple of the packet length. It appears that there's
+ * a hiccup in that case (maybe the DMA completes before the ZLP gets
+ * written?) boiling down to not being able to rely on CPPI writing any
+ * terminating zero length packet before the next transfer is written.
+ * So that's punted to PIO; better yet, gadget drivers can avoid it.
+ *
+ * Plus, there's allegedly an undocumented constraint that rndis transfer
+ * length be a multiple of 64 bytes ... but the chip doesn't act that
+ * way, and we really don't _want_ that behavior anyway.
+ *
+ * On TX, "transparent" mode works ... although experiments have shown
+ * problems trying to use the SOP/EOP bits in different USB packets.
+ *
+ * REVISIT try to handle terminating zero length packets using CPPI
+ * instead of doing it by PIO after an IRQ. (Meanwhile, make Ethernet
+ * links avoid that issue by forcing them to avoid zlps.)
+ */
+static void
+cppi_next_tx_segment(struct musb *musb, struct cppi_channel *tx)
+{
+ unsigned maxpacket = tx->maxpacket;
+ dma_addr_t addr = tx->buf_dma + tx->offset;
+ size_t length = tx->buf_len - tx->offset;
+ struct cppi_descriptor *bd;
+ unsigned n_bds;
+ unsigned i;
+ struct cppi_tx_stateram __iomem *tx_ram = tx->state_ram;
+ int rndis;
+
+ /* TX can use the CPPI "rndis" mode, where we can probably fit this
+ * transfer in one BD and one IRQ. The only time we would NOT want
+ * to use it is when hardware constraints prevent it, or if we'd
+ * trigger the "send a ZLP?" confusion.
+ */
+ rndis = (maxpacket & 0x3f) == 0
+ && length < 0xffff
+ && (length % maxpacket) != 0;
+
+ if (rndis) {
+ maxpacket = length;
+ n_bds = 1;
+ } else {
+ n_bds = length / maxpacket;
+ if (!length || (length % maxpacket))
+ n_bds++;
+ n_bds = min(n_bds, (unsigned) NUM_TXCHAN_BD);
+ length = min(n_bds * maxpacket, length);
+ }
+
+ DBG(4, "TX DMA%d, pktSz %d %s bds %d dma 0x%x len %u\n",
+ tx->index,
+ maxpacket,
+ rndis ? "rndis" : "transparent",
+ n_bds,
+ addr, length);
+
+ cppi_rndis_update(tx, 0, musb->ctrl_base, rndis);
+
+ /* assuming here that channel_program is called during
+ * transfer initiation ... current code maintains state
+ * for one outstanding request only (no queues, not even
+ * the implicit ones of an iso urb).
+ */
+
+ bd = tx->freelist;
+ tx->head = bd;
+ tx->last_processed = NULL;
+
+ /* FIXME use BD pool like RX side does, and just queue
+ * the minimum number for this request.
+ */
+
+ /* Prepare queue of BDs first, then hand it to hardware.
+ * All BDs except maybe the last should be of full packet
+ * size; for RNDIS there _is_ only that last packet.
+ */
+ for (i = 0; i < n_bds; ) {
+ if (++i < n_bds && bd->next)
+ bd->hw_next = bd->next->dma;
+ else
+ bd->hw_next = 0;
+
+ bd->hw_bufp = tx->buf_dma + tx->offset;
+
+ /* FIXME set EOP only on the last packet,
+ * SOP only on the first ... avoid IRQs
+ */
+ if ((tx->offset + maxpacket) <= tx->buf_len) {
+ tx->offset += maxpacket;
+ bd->hw_off_len = maxpacket;
+ bd->hw_options = CPPI_SOP_SET | CPPI_EOP_SET
+ | CPPI_OWN_SET | maxpacket;
+ } else {
+ /* only this one may be a partial USB Packet */
+ u32 partial_len;
+
+ partial_len = tx->buf_len - tx->offset;
+ tx->offset = tx->buf_len;
+ bd->hw_off_len = partial_len;
+
+ bd->hw_options = CPPI_SOP_SET | CPPI_EOP_SET
+ | CPPI_OWN_SET | partial_len;
+ if (partial_len == 0)
+ bd->hw_options |= CPPI_ZERO_SET;
+ }
+
+ DBG(5, "TXBD %p: nxt %08x buf %08x len %04x opt %08x\n",
+ bd, bd->hw_next, bd->hw_bufp,
+ bd->hw_off_len, bd->hw_options);
+
+ /* update the last BD enqueued to the list */
+ tx->tail = bd;
+ bd = bd->next;
+ }
+
+ /* BDs live in DMA-coherent memory, but writes might be pending */
+ cpu_drain_writebuffer();
+
+ /* Write to the HeadPtr in state RAM to trigger */
+ musb_writel(&tx_ram->tx_head, 0, (u32)tx->freelist->dma);
+
+ cppi_dump_tx(5, tx, "/S");
+}
+
+/*
+ * CPPI RX Woes:
+ * =============
+ * Consider a 1KB bulk RX buffer in two scenarios: (a) it's fed two 300 byte
+ * packets back-to-back, and (b) it's fed two 512 byte packets back-to-back.
+ * (Full speed transfers have similar scenarios.)
+ *
+ * The correct behavior for Linux is that (a) fills the buffer with 300 bytes,
+ * and the next packet goes into a buffer that's queued later; while (b) fills
+ * the buffer with 1024 bytes. How to do that with CPPI?
+ *
+ * - RX queues in "rndis" mode -- one single BD -- handle (a) correctly, but
+ * (b) loses **BADLY** because nothing (!) happens when that second packet
+ * fills the buffer, much less when a third one arrives. (Which makes this
+ * not a "true" RNDIS mode. In the RNDIS protocol short-packet termination
+ * is optional, and it's fine if peripherals -- not hosts! -- pad messages
+ * out to end-of-buffer. Standard PCI host controller DMA descriptors
+ * implement that mode by default ... which is no accident.)
+ *
+ * - RX queues in "transparent" mode -- two BDs with 512 bytes each -- have
+ * converse problems: (b) is handled right, but (a) loses badly. CPPI RX
+ * ignores SOP/EOP markings and processes both of those BDs; so both packets
+ * are loaded into the buffer (with a 212 byte gap between them), and the next
+ * buffer queued will NOT get its 300 bytes of data. (It seems like SOP/EOP
+ * are intended as outputs for RX queues, not inputs...)
+ *
+ * - A variant of "transparent" mode -- one BD at a time -- is the only way to
+ * reliably make both cases work, with software handling both cases correctly
+ * and at the significant penalty of needing an IRQ per packet. (The lack of
+ * I/O overlap can be slightly ameliorated by enabling double buffering.)
+ *
+ * So how to get rid of IRQ-per-packet? The transparent multi-BD case could
+ * be used in special cases like mass storage, which sets URB_SHORT_NOT_OK
+ * (or maybe its peripheral side counterpart) to flag (a) scenarios as errors
+ * with guaranteed driver level fault recovery and scrubbing out what's left
+ * of that garbaged datastream.
+ *
+ * But there seems to be no way to identify the cases where CPPI RNDIS mode
+ * is appropriate -- which do NOT include RNDIS host drivers, but do include
+ * the CDC Ethernet driver! -- and the documentation is incomplete/wrong.
+ * So we can't _ever_ use RX RNDIS mode ... except by using a heuristic
+ * that applies best on the peripheral side (and which could fail rudely).
+ *
+ * Leaving only "transparent" mode; we avoid multi-bd modes in almost all
+ * cases other than mass storage class. Otherwise we're correct but slow,
+ * since CPPI penalizes our need for a "true RNDIS" default mode.
+ */
+
+
+/* Heuristic, intended to kick in for ethernet/rndis peripheral ONLY
+ *
+ * IFF
+ * (a) peripheral mode ... since rndis peripherals could pad their
+ * writes to hosts, causing i/o failure; or we'd have to cope with
+ * a largely unknowable variety of host side protocol variants
+ * (b) and short reads are NOT errors ... since full reads would
+ * cause those same i/o failures
+ * (c) and read length is
+ * - less than 64KB (max per cppi descriptor)
+ * - not a multiple of 4096 (g_zero default, full reads typical)
+ * - N (>1) packets long, ditto (full reads not EXPECTED)
+ * THEN
+ * try rx rndis mode
+ *
+ * Cost of heuristic failing: RXDMA wedges at the end of transfers that
+ * fill out the whole buffer. Buggy host side usb network drivers could
+ * trigger that, but "in the field" such bugs seem to be all but unknown.
+ *
+ * So this module parameter lets the heuristic be disabled. When using
+ * gadgetfs, the heuristic will probably need to be disabled.
+ */
+static int cppi_rx_rndis = 1;
+
+module_param(cppi_rx_rndis, bool, 0);
+MODULE_PARM_DESC(cppi_rx_rndis, "enable/disable RX RNDIS heuristic");
+
+
+/**
+ * cppi_next_rx_segment - dma read for the next chunk of a buffer
+ * @musb: the controller
+ * @rx: dma channel
+ * @onepacket: true unless caller treats short reads as errors, and
+ * performs fault recovery above usbcore.
+ * Context: controller irqlocked
+ *
+ * See above notes about why we can't use multi-BD RX queues except in
+ * rare cases (mass storage class), and can never use the hardware "rndis"
+ * mode (since it's not a "true" RNDIS mode) with complete safety..
+ *
+ * It's ESSENTIAL that callers specify "onepacket" mode unless they kick in
+ * code to recover from corrupted datastreams after each short transfer.
+ */
+static void
+cppi_next_rx_segment(struct musb *musb, struct cppi_channel *rx, int onepacket)
+{
+ unsigned maxpacket = rx->maxpacket;
+ dma_addr_t addr = rx->buf_dma + rx->offset;
+ size_t length = rx->buf_len - rx->offset;
+ struct cppi_descriptor *bd, *tail;
+ unsigned n_bds;
+ unsigned i;
+ void __iomem *tibase = musb->ctrl_base;
+ int is_rndis = 0;
+ struct cppi_rx_stateram __iomem *rx_ram = rx->state_ram;
+
+ if (onepacket) {
+ /* almost every USB driver, host or peripheral side */
+ n_bds = 1;
+
+ /* maybe apply the heuristic above */
+ if (cppi_rx_rndis
+ && is_peripheral_active(musb)
+ && length > maxpacket
+ && (length & ~0xffff) == 0
+ && (length & 0x0fff) != 0
+ && (length & (maxpacket - 1)) == 0) {
+ maxpacket = length;
+ is_rndis = 1;
+ }
+ } else {
+ /* virtually nothing except mass storage class */
+ if (length > 0xffff) {
+ n_bds = 0xffff / maxpacket;
+ length = n_bds * maxpacket;
+ } else {
+ n_bds = length / maxpacket;
+ if (length % maxpacket)
+ n_bds++;
+ }
+ if (n_bds == 1)
+ onepacket = 1;
+ else
+ n_bds = min(n_bds, (unsigned) NUM_RXCHAN_BD);
+ }
+
+ /* In host mode, autorequest logic can generate some IN tokens; it's
+ * tricky since we can't leave REQPKT set in RXCSR after the transfer
+ * finishes. So: multipacket transfers involve two or more segments.
+ * And always at least two IRQs ... RNDIS mode is not an option.
+ */
+ if (is_host_active(musb))
+ n_bds = cppi_autoreq_update(rx, tibase, onepacket, n_bds);
+
+ cppi_rndis_update(rx, 1, musb->ctrl_base, is_rndis);
+
+ length = min(n_bds * maxpacket, length);
+
+ DBG(4, "RX DMA%d seg, maxp %d %s bds %d (cnt %d) "
+ "dma 0x%x len %u %u/%u\n",
+ rx->index, maxpacket,
+ onepacket
+ ? (is_rndis ? "rndis" : "onepacket")
+ : "multipacket",
+ n_bds,
+ musb_readl(tibase,
+ DAVINCI_RXCPPI_BUFCNT0_REG + (rx->index * 4))
+ & 0xffff,
+ addr, length, rx->channel.actual_len, rx->buf_len);
+
+ /* only queue one segment at a time, since the hardware prevents
+ * correct queue shutdown after unexpected short packets
+ */
+ bd = cppi_bd_alloc(rx);
+ rx->head = bd;
+
+ /* Build BDs for all packets in this segment */
+ for (i = 0, tail = NULL; bd && i < n_bds; i++, tail = bd) {
+ u32 bd_len;
+
+ if (i) {
+ bd = cppi_bd_alloc(rx);
+ if (!bd)
+ break;
+ tail->next = bd;
+ tail->hw_next = bd->dma;
+ }
+ bd->hw_next = 0;
+
+ /* all but the last packet will be maxpacket size */
+ if (maxpacket < length)
+ bd_len = maxpacket;
+ else
+ bd_len = length;
+
+ bd->hw_bufp = addr;
+ addr += bd_len;
+ rx->offset += bd_len;
+
+ bd->hw_off_len = (0 /*offset*/ << 16) + bd_len;
+ bd->buflen = bd_len;
+
+ bd->hw_options = CPPI_OWN_SET | (i == 0 ? length : 0);
+ length -= bd_len;
+ }
+
+ /* we always expect at least one reusable BD! */
+ if (!tail) {
+ WARN("rx dma%d -- no BDs? need %d\n", rx->index, n_bds);
+ return;
+ } else if (i < n_bds)
+ WARN("rx dma%d -- only %d of %d BDs\n", rx->index, i, n_bds);
+
+ tail->next = NULL;
+ tail->hw_next = 0;
+
+ bd = rx->head;
+ rx->tail = tail;
+
+ /* short reads and other faults should terminate this entire
+ * dma segment. we want one "dma packet" per dma segment, not
+ * one per USB packet, terminating the whole queue at once...
+ * NOTE that current hardware seems to ignore SOP and EOP.
+ */
+ bd->hw_options |= CPPI_SOP_SET;
+ tail->hw_options |= CPPI_EOP_SET;
+
+ if (debug >= 5) {
+ struct cppi_descriptor *d;
+
+ for (d = rx->head; d; d = d->next)
+ cppi_dump_rxbd("S", d);
+ }
+
+ /* in case the preceding transfer left some state... */
+ tail = rx->last_processed;
+ if (tail) {
+ tail->next = bd;
+ tail->hw_next = bd->dma;
+ }
+
+ core_rxirq_enable(tibase, rx->index + 1);
+
+ /* BDs live in DMA-coherent memory, but writes might be pending */
+ cpu_drain_writebuffer();
+
+ /* REVISIT specs say to write this AFTER the BUFCNT register
+ * below ... but that loses badly.
+ */
+ musb_writel(&rx_ram->rx_head, 0, bd->dma);
+
+ /* bufferCount must be at least 3, and zeroes on completion
+ * unless it underflows below zero, or stops at two, or keeps
+ * growing ... grr.
+ */
+ i = musb_readl(tibase,
+ DAVINCI_RXCPPI_BUFCNT0_REG + (rx->index * 4))
+ & 0xffff;
+
+ if (!i)
+ musb_writel(tibase,
+ DAVINCI_RXCPPI_BUFCNT0_REG + (rx->index * 4),
+ n_bds + 2);
+ else if (n_bds > (i - 3))
+ musb_writel(tibase,
+ DAVINCI_RXCPPI_BUFCNT0_REG + (rx->index * 4),
+ n_bds - (i - 3));
+
+ i = musb_readl(tibase,
+ DAVINCI_RXCPPI_BUFCNT0_REG + (rx->index * 4))
+ & 0xffff;
+ if (i < (2 + n_bds)) {
+ DBG(2, "bufcnt%d underrun - %d (for %d)\n",
+ rx->index, i, n_bds);
+ musb_writel(tibase,
+ DAVINCI_RXCPPI_BUFCNT0_REG + (rx->index * 4),
+ n_bds + 2);
+ }
+
+ cppi_dump_rx(4, rx, "/S");
+}
+
+/**
+ * cppi_channel_program - program channel for data transfer
+ * @ch: the channel
+ * @maxpacket: max packet size
+ * @mode: For RX, 1 unless the usb protocol driver promised to treat
+ * all short reads as errors and kick in high level fault recovery.
+ * For TX, ignored because of RNDIS mode races/glitches.
+ * @dma_addr: dma address of buffer
+ * @len: length of buffer
+ * Context: controller irqlocked
+ */
+static int cppi_channel_program(struct dma_channel *ch,
+ u16 maxpacket, u8 mode,
+ dma_addr_t dma_addr, u32 len)
+{
+ struct cppi_channel *cppi_ch;
+ struct cppi *controller;
+ struct musb *musb;
+
+ cppi_ch = container_of(ch, struct cppi_channel, channel);
+ controller = cppi_ch->controller;
+ musb = controller->musb;
+
+ switch (ch->status) {
+ case MUSB_DMA_STATUS_BUS_ABORT:
+ case MUSB_DMA_STATUS_CORE_ABORT:
+ /* fault irq handler should have handled cleanup */
+ WARN("%cX DMA%d not cleaned up after abort!\n",
+ cppi_ch->transmit ? 'T' : 'R',
+ cppi_ch->index);
+ /* WARN_ON(1); */
+ break;
+ case MUSB_DMA_STATUS_BUSY:
+ WARN("program active channel? %cX DMA%d\n",
+ cppi_ch->transmit ? 'T' : 'R',
+ cppi_ch->index);
+ /* WARN_ON(1); */
+ break;
+ case MUSB_DMA_STATUS_UNKNOWN:
+ DBG(1, "%cX DMA%d not allocated!\n",
+ cppi_ch->transmit ? 'T' : 'R',
+ cppi_ch->index);
+ /* FALLTHROUGH */
+ case MUSB_DMA_STATUS_FREE:
+ break;
+ }
+
+ ch->status = MUSB_DMA_STATUS_BUSY;
+
+ /* set transfer parameters, then queue up its first segment */
+ cppi_ch->buf_dma = dma_addr;
+ cppi_ch->offset = 0;
+ cppi_ch->maxpacket = maxpacket;
+ cppi_ch->buf_len = len;
+
+ /* TX channel? or RX? */
+ if (cppi_ch->transmit)
+ cppi_next_tx_segment(musb, cppi_ch);
+ else
+ cppi_next_rx_segment(musb, cppi_ch, mode);
+
+ return true;
+}
+
+static bool cppi_rx_scan(struct cppi *cppi, unsigned ch)
+{
+ struct cppi_channel *rx = &cppi->rx[ch];
+ struct cppi_rx_stateram __iomem *state = rx->state_ram;
+ struct cppi_descriptor *bd;
+ struct cppi_descriptor *last = rx->last_processed;
+ bool completed = false;
+ bool acked = false;
+ int i;
+ dma_addr_t safe2ack;
+ void __iomem *regs = rx->hw_ep->regs;
+
+ cppi_dump_rx(6, rx, "/K");
+
+ bd = last ? last->next : rx->head;
+ if (!bd)
+ return false;
+
+ /* run through all completed BDs */
+ for (i = 0, safe2ack = musb_readl(&state->rx_complete, 0);
+ (safe2ack || completed) && bd && i < NUM_RXCHAN_BD;
+ i++, bd = bd->next) {
+ u16 len;
+
+ rmb();
+ if (!completed && (bd->hw_options & CPPI_OWN_SET))
+ break;
+
+ DBG(5, "C/RXBD %08x: nxt %08x buf %08x "
+ "off.len %08x opt.len %08x (%d)\n",
+ bd->dma, bd->hw_next, bd->hw_bufp,
+ bd->hw_off_len, bd->hw_options,
+ rx->channel.actual_len);
+
+ /* actual packet received length */
+ if ((bd->hw_options & CPPI_SOP_SET) && !completed)
+ len = bd->hw_off_len & CPPI_RECV_PKTLEN_MASK;
+ else
+ len = 0;
+
+ if (bd->hw_options & CPPI_EOQ_MASK)
+ completed = true;
+
+ if (!completed && len < bd->buflen) {
+ /* NOTE: when we get a short packet, RXCSR_H_REQPKT
+ * must have been cleared, and no more DMA packets may
+ * active be in the queue... TI docs didn't say, but
+ * CPPI ignores those BDs even though OWN is still set.
+ */
+ completed = true;
+ DBG(3, "rx short %d/%d (%d)\n",
+ len, bd->buflen,
+ rx->channel.actual_len);
+ }
+
+ /* If we got here, we expect to ack at least one BD; meanwhile
+ * CPPI may completing other BDs while we scan this list...
+ *
+ * RACE: we can notice OWN cleared before CPPI raises the
+ * matching irq by writing that BD as the completion pointer.
+ * In such cases, stop scanning and wait for the irq, avoiding
+ * lost acks and states where BD ownership is unclear.
+ */
+ if (bd->dma == safe2ack) {
+ musb_writel(&state->rx_complete, 0, safe2ack);
+ safe2ack = musb_readl(&state->rx_complete, 0);
+ acked = true;
+ if (bd->dma == safe2ack)
+ safe2ack = 0;
+ }
+
+ rx->channel.actual_len += len;
+
+ cppi_bd_free(rx, last);
+ last = bd;
+
+ /* stop scanning on end-of-segment */
+ if (bd->hw_next == 0)
+ completed = true;
+ }
+ rx->last_processed = last;
+
+ /* dma abort, lost ack, or ... */
+ if (!acked && last) {
+ int csr;
+
+ if (safe2ack == 0 || safe2ack == rx->last_processed->dma)
+ musb_writel(&state->rx_complete, 0, safe2ack);
+ if (safe2ack == 0) {
+ cppi_bd_free(rx, last);
+ rx->last_processed = NULL;
+
+ /* if we land here on the host side, H_REQPKT will
+ * be clear and we need to restart the queue...
+ */
+ WARN_ON(rx->head);
+ }
+ musb_ep_select(cppi->mregs, rx->index + 1);
+ csr = musb_readw(regs, MUSB_RXCSR);
+ if (csr & MUSB_RXCSR_DMAENAB) {
+ DBG(4, "list%d %p/%p, last %08x%s, csr %04x\n",
+ rx->index,
+ rx->head, rx->tail,
+ rx->last_processed
+ ? rx->last_processed->dma
+ : 0,
+ completed ? ", completed" : "",
+ csr);
+ cppi_dump_rxq(4, "/what?", rx);
+ }
+ }
+ if (!completed) {
+ int csr;
+
+ rx->head = bd;
+
+ /* REVISIT seems like "autoreq all but EOP" doesn't...
+ * setting it here "should" be racey, but seems to work
+ */
+ csr = musb_readw(rx->hw_ep->regs, MUSB_RXCSR);
+ if (is_host_active(cppi->musb)
+ && bd
+ && !(csr & MUSB_RXCSR_H_REQPKT)) {
+ csr |= MUSB_RXCSR_H_REQPKT;
+ musb_writew(regs, MUSB_RXCSR,
+ MUSB_RXCSR_H_WZC_BITS | csr);
+ csr = musb_readw(rx->hw_ep->regs, MUSB_RXCSR);
+ }
+ } else {
+ rx->head = NULL;
+ rx->tail = NULL;
+ }
+
+ cppi_dump_rx(6, rx, completed ? "/completed" : "/cleaned");
+ return completed;
+}
+
+void cppi_completion(struct musb *musb, u32 rx, u32 tx)
+{
+ void __iomem *tibase;
+ int i, index;
+ struct cppi *cppi;
+ struct musb_hw_ep *hw_ep = NULL;
+
+ cppi = container_of(musb->dma_controller, struct cppi, controller);
+
+ tibase = musb->ctrl_base;
+
+ /* process TX channels */
+ for (index = 0; tx; tx = tx >> 1, index++) {
+ struct cppi_channel *tx_ch;
+ struct cppi_tx_stateram __iomem *tx_ram;
+ bool completed = false;
+ struct cppi_descriptor *bd;
+
+ if (!(tx & 1))
+ continue;
+
+ tx_ch = cppi->tx + index;
+ tx_ram = tx_ch->state_ram;
+
+ /* FIXME need a cppi_tx_scan() routine, which
+ * can also be called from abort code
+ */
+
+ cppi_dump_tx(5, tx_ch, "/E");
+
+ bd = tx_ch->head;
+
+ if (NULL == bd) {
+ DBG(1, "null BD\n");
+ continue;
+ }
+
+ /* run through all completed BDs */
+ for (i = 0; !completed && bd && i < NUM_TXCHAN_BD;
+ i++, bd = bd->next) {
+ u16 len;
+
+ rmb();
+ if (bd->hw_options & CPPI_OWN_SET)
+ break;
+
+ DBG(5, "C/TXBD %p n %x b %x off %x opt %x\n",
+ bd, bd->hw_next, bd->hw_bufp,
+ bd->hw_off_len, bd->hw_options);
+
+ len = bd->hw_off_len & CPPI_BUFFER_LEN_MASK;
+ tx_ch->channel.actual_len += len;
+
+ tx_ch->last_processed = bd;
+
+ /* write completion register to acknowledge
+ * processing of completed BDs, and possibly
+ * release the IRQ; EOQ might not be set ...
+ *
+ * REVISIT use the same ack strategy as rx
+ *
+ * REVISIT have observed bit 18 set; huh??
+ */
+ /* if ((bd->hw_options & CPPI_EOQ_MASK)) */
+ musb_writel(&tx_ram->tx_complete, 0, bd->dma);
+
+ /* stop scanning on end-of-segment */
+ if (bd->hw_next == 0)
+ completed = true;
+ }
+
+ /* on end of segment, maybe go to next one */
+ if (completed) {
+ /* cppi_dump_tx(4, tx_ch, "/complete"); */
+
+ /* transfer more, or report completion */
+ if (tx_ch->offset >= tx_ch->buf_len) {
+ tx_ch->head = NULL;
+ tx_ch->tail = NULL;
+ tx_ch->channel.status = MUSB_DMA_STATUS_FREE;
+
+ hw_ep = tx_ch->hw_ep;
+
+ /* Peripheral role never repurposes the
+ * endpoint, so immediate completion is
+ * safe. Host role waits for the fifo
+ * to empty (TXPKTRDY irq) before going
+ * to the next queued bulk transfer.
+ */
+ if (is_host_active(cppi->musb)) {
+#if 0
+ /* WORKAROUND because we may
+ * not always get TXKPTRDY ...
+ */
+ int csr;
+
+ csr = musb_readw(hw_ep->regs,
+ MUSB_TXCSR);
+ if (csr & MUSB_TXCSR_TXPKTRDY)
+#endif
+ completed = false;
+ }
+ if (completed)
+ musb_dma_completion(musb, index + 1, 1);
+
+ } else {
+ /* Bigger transfer than we could fit in
+ * that first batch of descriptors...
+ */
+ cppi_next_tx_segment(musb, tx_ch);
+ }
+ } else
+ tx_ch->head = bd;
+ }
+
+ /* Start processing the RX block */
+ for (index = 0; rx; rx = rx >> 1, index++) {
+
+ if (rx & 1) {
+ struct cppi_channel *rx_ch;
+
+ rx_ch = cppi->rx + index;
+
+ /* let incomplete dma segments finish */
+ if (!cppi_rx_scan(cppi, index))
+ continue;
+
+ /* start another dma segment if needed */
+ if (rx_ch->channel.actual_len != rx_ch->buf_len
+ && rx_ch->channel.actual_len
+ == rx_ch->offset) {
+ cppi_next_rx_segment(musb, rx_ch, 1);
+ continue;
+ }
+
+ /* all segments completed! */
+ rx_ch->channel.status = MUSB_DMA_STATUS_FREE;
+
+ hw_ep = rx_ch->hw_ep;
+
+ core_rxirq_disable(tibase, index + 1);
+ musb_dma_completion(musb, index + 1, 0);
+ }
+ }
+
+ /* write to CPPI EOI register to re-enable interrupts */
+ musb_writel(tibase, DAVINCI_CPPI_EOI_REG, 0);
+}
+
+/* Instantiate a software object representing a DMA controller. */
+struct dma_controller *__init
+dma_controller_create(struct musb *musb, void __iomem *mregs)
+{
+ struct cppi *controller;
+
+ controller = kzalloc(sizeof *controller, GFP_KERNEL);
+ if (!controller)
+ return NULL;
+
+ controller->mregs = mregs;
+ controller->tibase = mregs - DAVINCI_BASE_OFFSET;
+
+ controller->musb = musb;
+ controller->controller.start = cppi_controller_start;
+ controller->controller.stop = cppi_controller_stop;
+ controller->controller.channel_alloc = cppi_channel_allocate;
+ controller->controller.channel_release = cppi_channel_release;
+ controller->controller.channel_program = cppi_channel_program;
+ controller->controller.channel_abort = cppi_channel_abort;
+
+ /* NOTE: allocating from on-chip SRAM would give the least
+ * contention for memory access, if that ever matters here.
+ */
+
+ /* setup BufferPool */
+ controller->pool = dma_pool_create("cppi",
+ controller->musb->controller,
+ sizeof(struct cppi_descriptor),
+ CPPI_DESCRIPTOR_ALIGN, 0);
+ if (!controller->pool) {
+ kfree(controller);
+ return NULL;
+ }
+
+ return &controller->controller;
+}
+
+/*
+ * Destroy a previously-instantiated DMA controller.
+ */
+void dma_controller_destroy(struct dma_controller *c)
+{
+ struct cppi *cppi;
+
+ cppi = container_of(c, struct cppi, controller);
+
+ /* assert: caller stopped the controller first */
+ dma_pool_destroy(cppi->pool);
+
+ kfree(cppi);
+}
+
+/*
+ * Context: controller irqlocked, endpoint selected
+ */
+static int cppi_channel_abort(struct dma_channel *channel)
+{
+ struct cppi_channel *cppi_ch;
+ struct cppi *controller;
+ void __iomem *mbase;
+ void __iomem *tibase;
+ void __iomem *regs;
+ u32 value;
+ struct cppi_descriptor *queue;
+
+ cppi_ch = container_of(channel, struct cppi_channel, channel);
+
+ controller = cppi_ch->controller;
+
+ switch (channel->status) {
+ case MUSB_DMA_STATUS_BUS_ABORT:
+ case MUSB_DMA_STATUS_CORE_ABORT:
+ /* from RX or TX fault irq handler */
+ case MUSB_DMA_STATUS_BUSY:
+ /* the hardware needs shutting down */
+ regs = cppi_ch->hw_ep->regs;
+ break;
+ case MUSB_DMA_STATUS_UNKNOWN:
+ case MUSB_DMA_STATUS_FREE:
+ return 0;
+ default:
+ return -EINVAL;
+ }
+
+ if (!cppi_ch->transmit && cppi_ch->head)
+ cppi_dump_rxq(3, "/abort", cppi_ch);
+
+ mbase = controller->mregs;
+ tibase = controller->tibase;
+
+ queue = cppi_ch->head;
+ cppi_ch->head = NULL;
+ cppi_ch->tail = NULL;
+
+ /* REVISIT should rely on caller having done this,
+ * and caller should rely on us not changing it.
+ * peripheral code is safe ... check host too.
+ */
+ musb_ep_select(mbase, cppi_ch->index + 1);
+
+ if (cppi_ch->transmit) {
+ struct cppi_tx_stateram __iomem *tx_ram;
+ int enabled;
+
+ /* mask interrupts raised to signal teardown complete. */
+ enabled = musb_readl(tibase, DAVINCI_TXCPPI_INTENAB_REG)
+ & (1 << cppi_ch->index);
+ if (enabled)
+ musb_writel(tibase, DAVINCI_TXCPPI_INTCLR_REG,
+ (1 << cppi_ch->index));
+
+ /* REVISIT put timeouts on these controller handshakes */
+
+ cppi_dump_tx(6, cppi_ch, " (teardown)");
+
+ /* teardown DMA engine then usb core */
+ do {
+ value = musb_readl(tibase, DAVINCI_TXCPPI_TEAR_REG);
+ } while (!(value & CPPI_TEAR_READY));
+ musb_writel(tibase, DAVINCI_TXCPPI_TEAR_REG, cppi_ch->index);
+
+ tx_ram = cppi_ch->state_ram;
+ do {
+ value = musb_readl(&tx_ram->tx_complete, 0);
+ } while (0xFFFFFFFC != value);
+ musb_writel(&tx_ram->tx_complete, 0, 0xFFFFFFFC);
+
+ /* FIXME clean up the transfer state ... here?
+ * the completion routine should get called with
+ * an appropriate status code.
+ */
+
+ value = musb_readw(regs, MUSB_TXCSR);
+ value &= ~MUSB_TXCSR_DMAENAB;
+ value |= MUSB_TXCSR_FLUSHFIFO;
+ musb_writew(regs, MUSB_TXCSR, value);
+ musb_writew(regs, MUSB_TXCSR, value);
+
+ /* re-enable interrupt */
+ if (enabled)
+ musb_writel(tibase, DAVINCI_TXCPPI_INTENAB_REG,
+ (1 << cppi_ch->index));
+
+ /* While we scrub the TX state RAM, ensure that we clean
+ * up any interrupt that's currently asserted:
+ * 1. Write to completion Ptr value 0x1(bit 0 set)
+ * (write back mode)
+ * 2. Write to completion Ptr value 0x0(bit 0 cleared)
+ * (compare mode)
+ * Value written is compared(for bits 31:2) and when
+ * equal, interrupt is deasserted.
+ */
+ cppi_reset_tx(tx_ram, 1);
+ musb_writel(&tx_ram->tx_complete, 0, 0);
+
+ cppi_dump_tx(5, cppi_ch, " (done teardown)");
+
+ /* REVISIT tx side _should_ clean up the same way
+ * as the RX side ... this does no cleanup at all!
+ */
+
+ } else /* RX */ {
+ u16 csr;
+
+ /* NOTE: docs don't guarantee any of this works ... we
+ * expect that if the usb core stops telling the cppi core
+ * to pull more data from it, then it'll be safe to flush
+ * current RX DMA state iff any pending fifo transfer is done.
+ */
+
+ core_rxirq_disable(tibase, cppi_ch->index + 1);
+
+ /* for host, ensure ReqPkt is never set again */
+ if (is_host_active(cppi_ch->controller->musb)) {
+ value = musb_readl(tibase, DAVINCI_AUTOREQ_REG);
+ value &= ~((0x3) << (cppi_ch->index * 2));
+ musb_writel(tibase, DAVINCI_AUTOREQ_REG, value);
+ }
+
+ csr = musb_readw(regs, MUSB_RXCSR);
+
+ /* for host, clear (just) ReqPkt at end of current packet(s) */
+ if (is_host_active(cppi_ch->controller->musb)) {
+ csr |= MUSB_RXCSR_H_WZC_BITS;
+ csr &= ~MUSB_RXCSR_H_REQPKT;
+ } else
+ csr |= MUSB_RXCSR_P_WZC_BITS;
+
+ /* clear dma enable */
+ csr &= ~(MUSB_RXCSR_DMAENAB);
+ musb_writew(regs, MUSB_RXCSR, csr);
+ csr = musb_readw(regs, MUSB_RXCSR);
+
+ /* Quiesce: wait for current dma to finish (if not cleanup).
+ * We can't use bit zero of stateram->rx_sop, since that
+ * refers to an entire "DMA packet" not just emptying the
+ * current fifo. Most segments need multiple usb packets.
+ */
+ if (channel->status == MUSB_DMA_STATUS_BUSY)
+ udelay(50);
+
+ /* scan the current list, reporting any data that was
+ * transferred and acking any IRQ
+ */
+ cppi_rx_scan(controller, cppi_ch->index);
+
+ /* clobber the existing state once it's idle
+ *
+ * NOTE: arguably, we should also wait for all the other
+ * RX channels to quiesce (how??) and then temporarily
+ * disable RXCPPI_CTRL_REG ... but it seems that we can
+ * rely on the controller restarting from state ram, with
+ * only RXCPPI_BUFCNT state being bogus. BUFCNT will
+ * correct itself after the next DMA transfer though.
+ *
+ * REVISIT does using rndis mode change that?
+ */
+ cppi_reset_rx(cppi_ch->state_ram);
+
+ /* next DMA request _should_ load cppi head ptr */
+
+ /* ... we don't "free" that list, only mutate it in place. */
+ cppi_dump_rx(5, cppi_ch, " (done abort)");
+
+ /* clean up previously pending bds */
+ cppi_bd_free(cppi_ch, cppi_ch->last_processed);
+ cppi_ch->last_processed = NULL;
+
+ while (queue) {
+ struct cppi_descriptor *tmp = queue->next;
+
+ cppi_bd_free(cppi_ch, queue);
+ queue = tmp;
+ }
+ }
+
+ channel->status = MUSB_DMA_STATUS_FREE;
+ cppi_ch->buf_dma = 0;
+ cppi_ch->offset = 0;
+ cppi_ch->buf_len = 0;
+ cppi_ch->maxpacket = 0;
+ return 0;
+}
+
+/* TBD Queries:
+ *
+ * Power Management ... probably turn off cppi during suspend, restart;
+ * check state ram? Clocking is presumably shared with usb core.
+ */
--- /dev/null
+/* Copyright (C) 2005-2006 by Texas Instruments */
+
+#ifndef _CPPI_DMA_H_
+#define _CPPI_DMA_H_
+
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/dmapool.h>
+
+#include "musb_dma.h"
+#include "musb_core.h"
+
+
+/* FIXME fully isolate CPPI from DaVinci ... the "CPPI generic" registers
+ * would seem to be shared with the TUSB6020 (over VLYNQ).
+ */
+
+#include "davinci.h"
+
+
+/* CPPI RX/TX state RAM */
+
+struct cppi_tx_stateram {
+ u32 tx_head; /* "DMA packet" head descriptor */
+ u32 tx_buf;
+ u32 tx_current; /* current descriptor */
+ u32 tx_buf_current;
+ u32 tx_info; /* flags, remaining buflen */
+ u32 tx_rem_len;
+ u32 tx_dummy; /* unused */
+ u32 tx_complete;
+};
+
+struct cppi_rx_stateram {
+ u32 rx_skipbytes;
+ u32 rx_head;
+ u32 rx_sop; /* "DMA packet" head descriptor */
+ u32 rx_current; /* current descriptor */
+ u32 rx_buf_current;
+ u32 rx_len_len;
+ u32 rx_cnt_cnt;
+ u32 rx_complete;
+};
+
+/* hw_options bits in CPPI buffer descriptors */
+#define CPPI_SOP_SET ((u32)(1 << 31))
+#define CPPI_EOP_SET ((u32)(1 << 30))
+#define CPPI_OWN_SET ((u32)(1 << 29)) /* owned by cppi */
+#define CPPI_EOQ_MASK ((u32)(1 << 28))
+#define CPPI_ZERO_SET ((u32)(1 << 23)) /* rx saw zlp; tx issues one */
+#define CPPI_RXABT_MASK ((u32)(1 << 19)) /* need more rx buffers */
+
+#define CPPI_RECV_PKTLEN_MASK 0xFFFF
+#define CPPI_BUFFER_LEN_MASK 0xFFFF
+
+#define CPPI_TEAR_READY ((u32)(1 << 31))
+
+/* CPPI data structure definitions */
+
+#define CPPI_DESCRIPTOR_ALIGN 16 /* bytes; 5-dec docs say 4-byte align */
+
+struct cppi_descriptor {
+ /* hardware overlay */
+ u32 hw_next; /* next buffer descriptor Pointer */
+ u32 hw_bufp; /* i/o buffer pointer */
+ u32 hw_off_len; /* buffer_offset16, buffer_length16 */
+ u32 hw_options; /* flags: SOP, EOP etc*/
+
+ struct cppi_descriptor *next;
+ dma_addr_t dma; /* address of this descriptor */
+ u32 buflen; /* for RX: original buffer length */
+} __attribute__ ((aligned(CPPI_DESCRIPTOR_ALIGN)));
+
+
+struct cppi;
+
+/* CPPI Channel Control structure */
+struct cppi_channel {
+ struct dma_channel channel;
+
+ /* back pointer to the DMA controller structure */
+ struct cppi *controller;
+
+ /* which direction of which endpoint? */
+ struct musb_hw_ep *hw_ep;
+ bool transmit;
+ u8 index;
+
+ /* DMA modes: RNDIS or "transparent" */
+ u8 is_rndis;
+
+ /* book keeping for current transfer request */
+ dma_addr_t buf_dma;
+ u32 buf_len;
+ u32 maxpacket;
+ u32 offset; /* dma requested */
+
+ void __iomem *state_ram; /* CPPI state */
+
+ struct cppi_descriptor *freelist;
+
+ /* BD management fields */
+ struct cppi_descriptor *head;
+ struct cppi_descriptor *tail;
+ struct cppi_descriptor *last_processed;
+
+ /* use tx_complete in host role to track endpoints waiting for
+ * FIFONOTEMPTY to clear.
+ */
+ struct list_head tx_complete;
+};
+
+/* CPPI DMA controller object */
+struct cppi {
+ struct dma_controller controller;
+ struct musb *musb;
+ void __iomem *mregs; /* Mentor regs */
+ void __iomem *tibase; /* TI/CPPI regs */
+
+ struct cppi_channel tx[MUSB_C_NUM_EPT - 1];
+ struct cppi_channel rx[MUSB_C_NUM_EPR - 1];
+
+ struct dma_pool *pool;
+
+ struct list_head tx_complete;
+};
+
+/* irq handling hook */
+extern void cppi_completion(struct musb *, u32 rx, u32 tx);
+
+#endif /* end of ifndef _CPPI_DMA_H_ */
--- /dev/null
+/*
+ * Copyright (C) 2005-2006 by Texas Instruments
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * The Inventra Controller Driver for Linux is free software; you
+ * can redistribute it and/or modify it under the terms of the GNU
+ * General Public License version 2 as published by the Free Software
+ * Foundation.
+ *
+ * The Inventra Controller Driver for Linux is distributed in
+ * the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Inventra Controller Driver for Linux ; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/memory.h>
+#include <asm/arch/gpio.h>
+#include <asm/mach-types.h>
+
+#include "musb_core.h"
+
+#ifdef CONFIG_MACH_DAVINCI_EVM
+#include <asm/arch/i2c-client.h>
+#endif
+
+#include "davinci.h"
+#include "cppi_dma.h"
+
+
+/* REVISIT (PM) we should be able to keep the PHY in low power mode most
+ * of the time (24 MHZ oscillator and PLL off, etc) by setting POWER.D0
+ * and, when in host mode, autosuspending idle root ports... PHYPLLON
+ * (overriding SUSPENDM?) then likely needs to stay off.
+ */
+
+static inline void phy_on(void)
+{
+ /* start the on-chip PHY and its PLL */
+ __raw_writel(USBPHY_SESNDEN | USBPHY_VBDTCTEN | USBPHY_PHYPLLON,
+ (void __force __iomem *) IO_ADDRESS(USBPHY_CTL_PADDR));
+ while ((__raw_readl((void __force __iomem *)
+ IO_ADDRESS(USBPHY_CTL_PADDR))
+ & USBPHY_PHYCLKGD) == 0)
+ cpu_relax();
+}
+
+static inline void phy_off(void)
+{
+ /* powerdown the on-chip PHY and its oscillator */
+ __raw_writel(USBPHY_OSCPDWN | USBPHY_PHYPDWN, (void __force __iomem *)
+ IO_ADDRESS(USBPHY_CTL_PADDR));
+}
+
+static int dma_off = 1;
+
+void musb_platform_enable(struct musb *musb)
+{
+ u32 tmp, old, val;
+
+ /* workaround: setup irqs through both register sets */
+ tmp = (musb->epmask & DAVINCI_USB_TX_ENDPTS_MASK)
+ << DAVINCI_USB_TXINT_SHIFT;
+ musb_writel(musb->ctrl_base, DAVINCI_USB_INT_MASK_SET_REG, tmp);
+ old = tmp;
+ tmp = (musb->epmask & (0xfffe & DAVINCI_USB_RX_ENDPTS_MASK))
+ << DAVINCI_USB_RXINT_SHIFT;
+ musb_writel(musb->ctrl_base, DAVINCI_USB_INT_MASK_SET_REG, tmp);
+ tmp |= old;
+
+ val = ~MUSB_INTR_SOF;
+ tmp |= ((val & 0x01ff) << DAVINCI_USB_USBINT_SHIFT);
+ musb_writel(musb->ctrl_base, DAVINCI_USB_INT_MASK_SET_REG, tmp);
+
+ if (is_dma_capable() && !dma_off)
+ printk(KERN_WARNING "%s %s: dma not reactivated\n",
+ __FILE__, __func__);
+ else
+ dma_off = 0;
+
+ /* force a DRVVBUS irq so we can start polling for ID change */
+ if (is_otg_enabled(musb))
+ musb_writel(musb->ctrl_base, DAVINCI_USB_INT_SET_REG,
+ DAVINCI_INTR_DRVVBUS << DAVINCI_USB_USBINT_SHIFT);
+}
+
+/*
+ * Disable the HDRC and flush interrupts
+ */
+void musb_platform_disable(struct musb *musb)
+{
+ /* because we don't set CTRLR.UINT, "important" to:
+ * - not read/write INTRUSB/INTRUSBE
+ * - (except during initial setup, as workaround)
+ * - use INTSETR/INTCLRR instead
+ */
+ musb_writel(musb->ctrl_base, DAVINCI_USB_INT_MASK_CLR_REG,
+ DAVINCI_USB_USBINT_MASK
+ | DAVINCI_USB_TXINT_MASK
+ | DAVINCI_USB_RXINT_MASK);
+ musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
+ musb_writel(musb->ctrl_base, DAVINCI_USB_EOI_REG, 0);
+
+ if (is_dma_capable() && !dma_off)
+ WARN("dma still active\n");
+}
+
+
+/* REVISIT it's not clear whether DaVinci can support full OTG. */
+
+static int vbus_state = -1;
+
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+#define portstate(stmt) stmt
+#else
+#define portstate(stmt)
+#endif
+
+
+/* VBUS SWITCHING IS BOARD-SPECIFIC */
+
+#ifdef CONFIG_MACH_DAVINCI_EVM
+#ifndef CONFIG_MACH_DAVINCI_EVM_OTG
+
+/* I2C operations are always synchronous, and require a task context.
+ * With unloaded systems, using the shared workqueue seems to suffice
+ * to satisfy the 100msec A_WAIT_VRISE timeout...
+ */
+static void evm_deferred_drvvbus(struct work_struct *ignored)
+{
+ davinci_i2c_expander_op(0x3a, USB_DRVVBUS, vbus_state);
+ vbus_state = !vbus_state;
+}
+static DECLARE_WORK(evm_vbus_work, evm_deferred_drvvbus);
+
+#endif /* modified board */
+#endif /* EVM */
+
+static void davinci_source_power(struct musb *musb, int is_on, int immediate)
+{
+ if (is_on)
+ is_on = 1;
+
+ if (vbus_state == is_on)
+ return;
+ vbus_state = !is_on; /* 0/1 vs "-1 == unknown/init" */
+
+#ifdef CONFIG_MACH_DAVINCI_EVM
+ if (machine_is_davinci_evm()) {
+#ifdef CONFIG_MACH_DAVINCI_EVM_OTG
+ /* modified EVM board switching VBUS with GPIO(6) not I2C
+ * NOTE: PINMUX0.RGB888 (bit23) must be clear
+ */
+ if (is_on)
+ gpio_set(GPIO(6));
+ else
+ gpio_clear(GPIO(6));
+ immediate = 1;
+#else
+ if (immediate)
+ davinci_i2c_expander_op(0x3a, USB_DRVVBUS, !is_on);
+ else
+ schedule_work(&evm_vbus_work);
+#endif
+ }
+#endif
+ if (immediate)
+ vbus_state = is_on;
+}
+
+static void davinci_set_vbus(struct musb *musb, int is_on)
+{
+ WARN_ON(is_on && is_peripheral_active(musb));
+ davinci_source_power(musb, is_on, 0);
+}
+
+
+#define POLL_SECONDS 2
+
+static struct timer_list otg_workaround;
+
+static void otg_timer(unsigned long _musb)
+{
+ struct musb *musb = (void *)_musb;
+ void __iomem *mregs = musb->mregs;
+ u8 devctl;
+ unsigned long flags;
+
+ /* We poll because DaVinci's won't expose several OTG-critical
+ * status change events (from the transceiver) otherwise.
+ */
+ devctl = musb_readb(mregs, MUSB_DEVCTL);
+ DBG(7, "poll devctl %02x (%s)\n", devctl, otg_state_string(musb));
+
+ spin_lock_irqsave(&musb->lock, flags);
+ switch (musb->xceiv.state) {
+ case OTG_STATE_A_WAIT_VFALL:
+ /* Wait till VBUS falls below SessionEnd (~0.2V); the 1.3 RTL
+ * seems to mis-handle session "start" otherwise (or in our
+ * case "recover"), in routine "VBUS was valid by the time
+ * VBUSERR got reported during enumeration" cases.
+ */
+ if (devctl & MUSB_DEVCTL_VBUS) {
+ mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
+ break;
+ }
+ musb->xceiv.state = OTG_STATE_A_WAIT_VRISE;
+ musb_writel(musb->ctrl_base, DAVINCI_USB_INT_SET_REG,
+ MUSB_INTR_VBUSERROR << DAVINCI_USB_USBINT_SHIFT);
+ break;
+ case OTG_STATE_B_IDLE:
+ if (!is_peripheral_enabled(musb))
+ break;
+
+ /* There's no ID-changed IRQ, so we have no good way to tell
+ * when to switch to the A-Default state machine (by setting
+ * the DEVCTL.SESSION flag).
+ *
+ * Workaround: whenever we're in B_IDLE, try setting the
+ * session flag every few seconds. If it works, ID was
+ * grounded and we're now in the A-Default state machine.
+ *
+ * NOTE setting the session flag is _supposed_ to trigger
+ * SRP, but clearly it doesn't.
+ */
+ musb_writeb(mregs, MUSB_DEVCTL,
+ devctl | MUSB_DEVCTL_SESSION);
+ devctl = musb_readb(mregs, MUSB_DEVCTL);
+ if (devctl & MUSB_DEVCTL_BDEVICE)
+ mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
+ else
+ musb->xceiv.state = OTG_STATE_A_IDLE;
+ break;
+ default:
+ break;
+ }
+ spin_unlock_irqrestore(&musb->lock, flags);
+}
+
+static irqreturn_t davinci_interrupt(int irq, void *__hci)
+{
+ unsigned long flags;
+ irqreturn_t retval = IRQ_NONE;
+ struct musb *musb = __hci;
+ void __iomem *tibase = musb->ctrl_base;
+ u32 tmp;
+
+ spin_lock_irqsave(&musb->lock, flags);
+
+ /* NOTE: DaVinci shadows the Mentor IRQs. Don't manage them through
+ * the Mentor registers (except for setup), use the TI ones and EOI.
+ *
+ * Docs describe irq "vector" registers asociated with the CPPI and
+ * USB EOI registers. These hold a bitmask corresponding to the
+ * current IRQ, not an irq handler address. Would using those bits
+ * resolve some of the races observed in this dispatch code??
+ */
+
+ /* CPPI interrupts share the same IRQ line, but have their own
+ * mask, state, "vector", and EOI registers.
+ */
+ if (is_cppi_enabled()) {
+ u32 cppi_tx = musb_readl(tibase, DAVINCI_TXCPPI_MASKED_REG);
+ u32 cppi_rx = musb_readl(tibase, DAVINCI_RXCPPI_MASKED_REG);
+
+ if (cppi_tx || cppi_rx) {
+ DBG(4, "CPPI IRQ t%x r%x\n", cppi_tx, cppi_rx);
+ cppi_completion(musb, cppi_rx, cppi_tx);
+ retval = IRQ_HANDLED;
+ }
+ }
+
+ /* ack and handle non-CPPI interrupts */
+ tmp = musb_readl(tibase, DAVINCI_USB_INT_SRC_MASKED_REG);
+ musb_writel(tibase, DAVINCI_USB_INT_SRC_CLR_REG, tmp);
+ DBG(4, "IRQ %08x\n", tmp);
+
+ musb->int_rx = (tmp & DAVINCI_USB_RXINT_MASK)
+ >> DAVINCI_USB_RXINT_SHIFT;
+ musb->int_tx = (tmp & DAVINCI_USB_TXINT_MASK)
+ >> DAVINCI_USB_TXINT_SHIFT;
+ musb->int_usb = (tmp & DAVINCI_USB_USBINT_MASK)
+ >> DAVINCI_USB_USBINT_SHIFT;
+
+ /* DRVVBUS irqs are the only proxy we have (a very poor one!) for
+ * DaVinci's missing ID change IRQ. We need an ID change IRQ to
+ * switch appropriately between halves of the OTG state machine.
+ * Managing DEVCTL.SESSION per Mentor docs requires we know its
+ * value, but DEVCTL.BDEVICE is invalid without DEVCTL.SESSION set.
+ * Also, DRVVBUS pulses for SRP (but not at 5V) ...
+ */
+ if (tmp & (DAVINCI_INTR_DRVVBUS << DAVINCI_USB_USBINT_SHIFT)) {
+ int drvvbus = musb_readl(tibase, DAVINCI_USB_STAT_REG);
+ void __iomem *mregs = musb->mregs;
+ u8 devctl = musb_readb(mregs, MUSB_DEVCTL);
+ int err = musb->int_usb & MUSB_INTR_VBUSERROR;
+
+ err = is_host_enabled(musb)
+ && (musb->int_usb & MUSB_INTR_VBUSERROR);
+ if (err) {
+ /* The Mentor core doesn't debounce VBUS as needed
+ * to cope with device connect current spikes. This
+ * means it's not uncommon for bus-powered devices
+ * to get VBUS errors during enumeration.
+ *
+ * This is a workaround, but newer RTL from Mentor
+ * seems to allow a better one: "re"starting sessions
+ * without waiting (on EVM, a **long** time) for VBUS
+ * to stop registering in devctl.
+ */
+ musb->int_usb &= ~MUSB_INTR_VBUSERROR;
+ musb->xceiv.state = OTG_STATE_A_WAIT_VFALL;
+ mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
+ WARN("VBUS error workaround (delay coming)\n");
+ } else if (is_host_enabled(musb) && drvvbus) {
+ musb->is_active = 1;
+ MUSB_HST_MODE(musb);
+ musb->xceiv.default_a = 1;
+ musb->xceiv.state = OTG_STATE_A_WAIT_VRISE;
+ portstate(musb->port1_status |= USB_PORT_STAT_POWER);
+ del_timer(&otg_workaround);
+ } else {
+ musb->is_active = 0;
+ MUSB_DEV_MODE(musb);
+ musb->xceiv.default_a = 0;
+ musb->xceiv.state = OTG_STATE_B_IDLE;
+ portstate(musb->port1_status &= ~USB_PORT_STAT_POWER);
+ }
+
+ /* NOTE: this must complete poweron within 100 msec */
+ davinci_source_power(musb, drvvbus, 0);
+ DBG(2, "VBUS %s (%s)%s, devctl %02x\n",
+ drvvbus ? "on" : "off",
+ otg_state_string(musb),
+ err ? " ERROR" : "",
+ devctl);
+ retval = IRQ_HANDLED;
+ }
+
+ if (musb->int_tx || musb->int_rx || musb->int_usb)
+ retval |= musb_interrupt(musb);
+
+ /* irq stays asserted until EOI is written */
+ musb_writel(tibase, DAVINCI_USB_EOI_REG, 0);
+
+ /* poll for ID change */
+ if (is_otg_enabled(musb)
+ && musb->xceiv.state == OTG_STATE_B_IDLE)
+ mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
+
+ spin_unlock_irqrestore(&musb->lock, flags);
+
+ /* REVISIT we sometimes get unhandled IRQs
+ * (e.g. ep0). not clear why...
+ */
+ if (retval != IRQ_HANDLED)
+ DBG(5, "unhandled? %08x\n", tmp);
+ return IRQ_HANDLED;
+}
+
+int __init musb_platform_init(struct musb *musb)
+{
+ void __iomem *tibase = musb->ctrl_base;
+ u32 revision;
+
+ musb->mregs += DAVINCI_BASE_OFFSET;
+#if 0
+ /* REVISIT there's something odd about clocking, this
+ * didn't appear do the job ...
+ */
+ musb->clock = clk_get(pDevice, "usb");
+ if (IS_ERR(musb->clock))
+ return PTR_ERR(musb->clock);
+
+ status = clk_enable(musb->clock);
+ if (status < 0)
+ return -ENODEV;
+#endif
+
+ /* returns zero if e.g. not clocked */
+ revision = musb_readl(tibase, DAVINCI_USB_VERSION_REG);
+ if (revision == 0)
+ return -ENODEV;
+
+ if (is_host_enabled(musb))
+ setup_timer(&otg_workaround, otg_timer, (unsigned long) musb);
+
+ musb->board_set_vbus = davinci_set_vbus;
+ davinci_source_power(musb, 0, 1);
+
+ /* reset the controller */
+ musb_writel(tibase, DAVINCI_USB_CTRL_REG, 0x1);
+
+ /* start the on-chip PHY and its PLL */
+ phy_on();
+
+ msleep(5);
+
+ /* NOTE: irqs are in mixed mode, not bypass to pure-musb */
+ pr_debug("DaVinci OTG revision %08x phy %03x control %02x\n",
+ revision, __raw_readl((void __force __iomem *)
+ IO_ADDRESS(USBPHY_CTL_PADDR)),
+ musb_readb(tibase, DAVINCI_USB_CTRL_REG));
+
+ musb->isr = davinci_interrupt;
+ return 0;
+}
+
+int musb_platform_exit(struct musb *musb)
+{
+ if (is_host_enabled(musb))
+ del_timer_sync(&otg_workaround);
+
+ davinci_source_power(musb, 0 /*off*/, 1);
+
+ /* delay, to avoid problems with module reload */
+ if (is_host_enabled(musb) && musb->xceiv.default_a) {
+ int maxdelay = 30;
+ u8 devctl, warn = 0;
+
+ /* if there's no peripheral connected, this can take a
+ * long time to fall, especially on EVM with huge C133.
+ */
+ do {
+ devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+ if (!(devctl & MUSB_DEVCTL_VBUS))
+ break;
+ if ((devctl & MUSB_DEVCTL_VBUS) != warn) {
+ warn = devctl & MUSB_DEVCTL_VBUS;
+ DBG(1, "VBUS %d\n",
+ warn >> MUSB_DEVCTL_VBUS_SHIFT);
+ }
+ msleep(1000);
+ maxdelay--;
+ } while (maxdelay > 0);
+
+ /* in OTG mode, another host might be connected */
+ if (devctl & MUSB_DEVCTL_VBUS)
+ DBG(1, "VBUS off timeout (devctl %02x)\n", devctl);
+ }
+
+ phy_off();
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (C) 2005-2006 by Texas Instruments
+ *
+ * The Inventra Controller Driver for Linux is free software; you
+ * can redistribute it and/or modify it under the terms of the GNU
+ * General Public License version 2 as published by the Free Software
+ * Foundation.
+ */
+
+#ifndef __MUSB_HDRDF_H__
+#define __MUSB_HDRDF_H__
+
+/*
+ * DaVinci-specific definitions
+ */
+
+/* Integrated highspeed/otg PHY */
+#define USBPHY_CTL_PADDR (DAVINCI_SYSTEM_MODULE_BASE + 0x34)
+#define USBPHY_PHYCLKGD (1 << 8)
+#define USBPHY_SESNDEN (1 << 7) /* v(sess_end) comparator */
+#define USBPHY_VBDTCTEN (1 << 6) /* v(bus) comparator */
+#define USBPHY_PHYPLLON (1 << 4) /* override pll suspend */
+#define USBPHY_CLKO1SEL (1 << 3)
+#define USBPHY_OSCPDWN (1 << 2)
+#define USBPHY_PHYPDWN (1 << 0)
+
+/* For now include usb OTG module registers here */
+#define DAVINCI_USB_VERSION_REG 0x00
+#define DAVINCI_USB_CTRL_REG 0x04
+#define DAVINCI_USB_STAT_REG 0x08
+#define DAVINCI_RNDIS_REG 0x10
+#define DAVINCI_AUTOREQ_REG 0x14
+#define DAVINCI_USB_INT_SOURCE_REG 0x20
+#define DAVINCI_USB_INT_SET_REG 0x24
+#define DAVINCI_USB_INT_SRC_CLR_REG 0x28
+#define DAVINCI_USB_INT_MASK_REG 0x2c
+#define DAVINCI_USB_INT_MASK_SET_REG 0x30
+#define DAVINCI_USB_INT_MASK_CLR_REG 0x34
+#define DAVINCI_USB_INT_SRC_MASKED_REG 0x38
+#define DAVINCI_USB_EOI_REG 0x3c
+#define DAVINCI_USB_EOI_INTVEC 0x40
+
+/* BEGIN CPPI-generic (?) */
+
+/* CPPI related registers */
+#define DAVINCI_TXCPPI_CTRL_REG 0x80
+#define DAVINCI_TXCPPI_TEAR_REG 0x84
+#define DAVINCI_CPPI_EOI_REG 0x88
+#define DAVINCI_CPPI_INTVEC_REG 0x8c
+#define DAVINCI_TXCPPI_MASKED_REG 0x90
+#define DAVINCI_TXCPPI_RAW_REG 0x94
+#define DAVINCI_TXCPPI_INTENAB_REG 0x98
+#define DAVINCI_TXCPPI_INTCLR_REG 0x9c
+
+#define DAVINCI_RXCPPI_CTRL_REG 0xC0
+#define DAVINCI_RXCPPI_MASKED_REG 0xD0
+#define DAVINCI_RXCPPI_RAW_REG 0xD4
+#define DAVINCI_RXCPPI_INTENAB_REG 0xD8
+#define DAVINCI_RXCPPI_INTCLR_REG 0xDC
+
+#define DAVINCI_RXCPPI_BUFCNT0_REG 0xE0
+#define DAVINCI_RXCPPI_BUFCNT1_REG 0xE4
+#define DAVINCI_RXCPPI_BUFCNT2_REG 0xE8
+#define DAVINCI_RXCPPI_BUFCNT3_REG 0xEC
+
+/* CPPI state RAM entries */
+#define DAVINCI_CPPI_STATERAM_BASE_OFFSET 0x100
+
+#define DAVINCI_TXCPPI_STATERAM_OFFSET(chnum) \
+ (DAVINCI_CPPI_STATERAM_BASE_OFFSET + ((chnum) * 0x40))
+#define DAVINCI_RXCPPI_STATERAM_OFFSET(chnum) \
+ (DAVINCI_CPPI_STATERAM_BASE_OFFSET + 0x20 + ((chnum) * 0x40))
+
+/* CPPI masks */
+#define DAVINCI_DMA_CTRL_ENABLE 1
+#define DAVINCI_DMA_CTRL_DISABLE 0
+
+#define DAVINCI_DMA_ALL_CHANNELS_ENABLE 0xF
+#define DAVINCI_DMA_ALL_CHANNELS_DISABLE 0xF
+
+/* END CPPI-generic (?) */
+
+#define DAVINCI_USB_TX_ENDPTS_MASK 0x1f /* ep0 + 4 tx */
+#define DAVINCI_USB_RX_ENDPTS_MASK 0x1e /* 4 rx */
+
+#define DAVINCI_USB_USBINT_SHIFT 16
+#define DAVINCI_USB_TXINT_SHIFT 0
+#define DAVINCI_USB_RXINT_SHIFT 8
+
+#define DAVINCI_INTR_DRVVBUS 0x0100
+
+#define DAVINCI_USB_USBINT_MASK 0x01ff0000 /* 8 Mentor, DRVVBUS */
+#define DAVINCI_USB_TXINT_MASK \
+ (DAVINCI_USB_TX_ENDPTS_MASK << DAVINCI_USB_TXINT_SHIFT)
+#define DAVINCI_USB_RXINT_MASK \
+ (DAVINCI_USB_RX_ENDPTS_MASK << DAVINCI_USB_RXINT_SHIFT)
+
+#define DAVINCI_BASE_OFFSET 0x400
+
+#endif /* __MUSB_HDRDF_H__ */
--- /dev/null
+/*
+ * MUSB OTG driver core code
+ *
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ * Copyright (C) 2006-2007 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * 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 AUTHORS 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.
+ *
+ */
+
+/*
+ * Inventra (Multipoint) Dual-Role Controller Driver for Linux.
+ *
+ * This consists of a Host Controller Driver (HCD) and a peripheral
+ * controller driver implementing the "Gadget" API; OTG support is
+ * in the works. These are normal Linux-USB controller drivers which
+ * use IRQs and have no dedicated thread.
+ *
+ * This version of the driver has only been used with products from
+ * Texas Instruments. Those products integrate the Inventra logic
+ * with other DMA, IRQ, and bus modules, as well as other logic that
+ * needs to be reflected in this driver.
+ *
+ *
+ * NOTE: the original Mentor code here was pretty much a collection
+ * of mechanisms that don't seem to have been fully integrated/working
+ * for *any* Linux kernel version. This version aims at Linux 2.6.now,
+ * Key open issues include:
+ *
+ * - Lack of host-side transaction scheduling, for all transfer types.
+ * The hardware doesn't do it; instead, software must.
+ *
+ * This is not an issue for OTG devices that don't support external
+ * hubs, but for more "normal" USB hosts it's a user issue that the
+ * "multipoint" support doesn't scale in the expected ways. That
+ * includes DaVinci EVM in a common non-OTG mode.
+ *
+ * * Control and bulk use dedicated endpoints, and there's as
+ * yet no mechanism to either (a) reclaim the hardware when
+ * peripherals are NAKing, which gets complicated with bulk
+ * endpoints, or (b) use more than a single bulk endpoint in
+ * each direction.
+ *
+ * RESULT: one device may be perceived as blocking another one.
+ *
+ * * Interrupt and isochronous will dynamically allocate endpoint
+ * hardware, but (a) there's no record keeping for bandwidth;
+ * (b) in the common case that few endpoints are available, there
+ * is no mechanism to reuse endpoints to talk to multiple devices.
+ *
+ * RESULT: At one extreme, bandwidth can be overcommitted in
+ * some hardware configurations, no faults will be reported.
+ * At the other extreme, the bandwidth capabilities which do
+ * exist tend to be severely undercommitted. You can't yet hook
+ * up both a keyboard and a mouse to an external USB hub.
+ */
+
+/*
+ * This gets many kinds of configuration information:
+ * - Kconfig for everything user-configurable
+ * - <asm/arch/hdrc_cnf.h> for SOC or family details
+ * - platform_device for addressing, irq, and platform_data
+ * - platform_data is mostly for board-specific informarion
+ *
+ * Most of the conditional compilation will (someday) vanish.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/kobject.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#ifdef CONFIG_ARM
+#include <asm/arch/hardware.h>
+#include <asm/arch/memory.h>
+#include <asm/mach-types.h>
+#endif
+
+#include "musb_core.h"
+
+
+#ifdef CONFIG_ARCH_DAVINCI
+#include "davinci.h"
+#endif
+
+
+
+#if MUSB_DEBUG > 0
+unsigned debug = MUSB_DEBUG;
+module_param(debug, uint, 0);
+MODULE_PARM_DESC(debug, "initial debug message level");
+
+#define MUSB_VERSION_SUFFIX "/dbg"
+#endif
+
+#define DRIVER_AUTHOR "Mentor Graphics, Texas Instruments, Nokia"
+#define DRIVER_DESC "Inventra Dual-Role USB Controller Driver"
+
+#define MUSB_VERSION_BASE "6.0"
+
+#ifndef MUSB_VERSION_SUFFIX
+#define MUSB_VERSION_SUFFIX ""
+#endif
+#define MUSB_VERSION MUSB_VERSION_BASE MUSB_VERSION_SUFFIX
+
+#define DRIVER_INFO DRIVER_DESC ", v" MUSB_VERSION
+
+const char musb_driver_name[] = "musb_hdrc";
+
+MODULE_DESCRIPTION(DRIVER_INFO);
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_LICENSE("GPL");
+
+
+/*-------------------------------------------------------------------------*/
+
+static inline struct musb *dev_to_musb(struct device *dev)
+{
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+ /* usbcore insists dev->driver_data is a "struct hcd *" */
+ return hcd_to_musb(dev_get_drvdata(dev));
+#else
+ return dev_get_drvdata(dev);
+#endif
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifndef CONFIG_USB_TUSB6010
+/*
+ * Load an endpoint's FIFO
+ */
+void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)
+{
+ void __iomem *fifo = hw_ep->fifo;
+
+ prefetch((u8 *)src);
+
+ DBG(4, "%cX ep%d fifo %p count %d buf %p\n",
+ 'T', hw_ep->epnum, fifo, len, src);
+
+ /* we can't assume unaligned reads work */
+ if (likely((0x01 & (unsigned long) src) == 0)) {
+ u16 index = 0;
+
+ /* best case is 32bit-aligned source address */
+ if ((0x02 & (unsigned long) src) == 0) {
+ if (len >= 4) {
+ writesl(fifo, src + index, len >> 2);
+ index += len & ~0x03;
+ }
+ if (len & 0x02) {
+ musb_writew(fifo, 0, *(u16 *)&src[index]);
+ index += 2;
+ }
+ } else {
+ if (len >= 2) {
+ writesw(fifo, src + index, len >> 1);
+ index += len & ~0x01;
+ }
+ }
+ if (len & 0x01)
+ musb_writeb(fifo, 0, src[index]);
+ } else {
+ /* byte aligned */
+ writesb(fifo, src, len);
+ }
+}
+
+/*
+ * Unload an endpoint's FIFO
+ */
+void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
+{
+ void __iomem *fifo = hw_ep->fifo;
+
+ DBG(4, "%cX ep%d fifo %p count %d buf %p\n",
+ 'R', hw_ep->epnum, fifo, len, dst);
+
+ /* we can't assume unaligned writes work */
+ if (likely((0x01 & (unsigned long) dst) == 0)) {
+ u16 index = 0;
+
+ /* best case is 32bit-aligned destination address */
+ if ((0x02 & (unsigned long) dst) == 0) {
+ if (len >= 4) {
+ readsl(fifo, dst, len >> 2);
+ index = len & ~0x03;
+ }
+ if (len & 0x02) {
+ *(u16 *)&dst[index] = musb_readw(fifo, 0);
+ index += 2;
+ }
+ } else {
+ if (len >= 2) {
+ readsw(fifo, dst, len >> 1);
+ index = len & ~0x01;
+ }
+ }
+ if (len & 0x01)
+ dst[index] = musb_readb(fifo, 0);
+ } else {
+ /* byte aligned */
+ readsb(fifo, dst, len);
+ }
+}
+
+#endif /* normal PIO */
+
+
+/*-------------------------------------------------------------------------*/
+
+/* for high speed test mode; see USB 2.0 spec 7.1.20 */
+static const u8 musb_test_packet[53] = {
+ /* implicit SYNC then DATA0 to start */
+
+ /* JKJKJKJK x9 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* JJKKJJKK x8 */
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ /* JJJJKKKK x8 */
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ /* JJJJJJJKKKKKKK x8 */
+ 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* JJJJJJJK x8 */
+ 0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd,
+ /* JKKKKKKK x10, JK */
+ 0xfc, 0x7e, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0x7e
+
+ /* implicit CRC16 then EOP to end */
+};
+
+void musb_load_testpacket(struct musb *musb)
+{
+ void __iomem *regs = musb->endpoints[0].regs;
+
+ musb_ep_select(musb->mregs, 0);
+ musb_write_fifo(musb->control_ep,
+ sizeof(musb_test_packet), musb_test_packet);
+ musb_writew(regs, MUSB_CSR0, MUSB_CSR0_TXPKTRDY);
+}
+
+/*-------------------------------------------------------------------------*/
+
+const char *otg_state_string(struct musb *musb)
+{
+ switch (musb->xceiv.state) {
+ case OTG_STATE_A_IDLE: return "a_idle";
+ case OTG_STATE_A_WAIT_VRISE: return "a_wait_vrise";
+ case OTG_STATE_A_WAIT_BCON: return "a_wait_bcon";
+ case OTG_STATE_A_HOST: return "a_host";
+ case OTG_STATE_A_SUSPEND: return "a_suspend";
+ case OTG_STATE_A_PERIPHERAL: return "a_peripheral";
+ case OTG_STATE_A_WAIT_VFALL: return "a_wait_vfall";
+ case OTG_STATE_A_VBUS_ERR: return "a_vbus_err";
+ case OTG_STATE_B_IDLE: return "b_idle";
+ case OTG_STATE_B_SRP_INIT: return "b_srp_init";
+ case OTG_STATE_B_PERIPHERAL: return "b_peripheral";
+ case OTG_STATE_B_WAIT_ACON: return "b_wait_acon";
+ case OTG_STATE_B_HOST: return "b_host";
+ default: return "UNDEFINED";
+ }
+}
+
+#ifdef CONFIG_USB_MUSB_OTG
+
+/*
+ * See also USB_OTG_1-3.pdf 6.6.5 Timers
+ * REVISIT: Are the other timers done in the hardware?
+ */
+#define TB_ASE0_BRST 100 /* Min 3.125 ms */
+
+/*
+ * Handles OTG hnp timeouts, such as b_ase0_brst
+ */
+void musb_otg_timer_func(unsigned long data)
+{
+ struct musb *musb = (struct musb *)data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&musb->lock, flags);
+ switch (musb->xceiv.state) {
+ case OTG_STATE_B_WAIT_ACON:
+ DBG(1, "HNP: b_wait_acon timeout; back to b_peripheral\n");
+ musb_g_disconnect(musb);
+ musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
+ musb->is_active = 0;
+ break;
+ case OTG_STATE_A_WAIT_BCON:
+ DBG(1, "HNP: a_wait_bcon timeout; back to a_host\n");
+ musb_hnp_stop(musb);
+ break;
+ default:
+ DBG(1, "HNP: Unhandled mode %s\n", otg_state_string(musb));
+ }
+ musb->ignore_disconnect = 0;
+ spin_unlock_irqrestore(&musb->lock, flags);
+}
+
+static DEFINE_TIMER(musb_otg_timer, musb_otg_timer_func, 0, 0);
+
+/*
+ * Stops the B-device HNP state. Caller must take care of locking.
+ */
+void musb_hnp_stop(struct musb *musb)
+{
+ struct usb_hcd *hcd = musb_to_hcd(musb);
+ void __iomem *mbase = musb->mregs;
+ u8 reg;
+
+ switch (musb->xceiv.state) {
+ case OTG_STATE_A_PERIPHERAL:
+ case OTG_STATE_A_WAIT_VFALL:
+ case OTG_STATE_A_WAIT_BCON:
+ DBG(1, "HNP: Switching back to A-host\n");
+ musb_g_disconnect(musb);
+ musb->xceiv.state = OTG_STATE_A_IDLE;
+ MUSB_HST_MODE(musb);
+ musb->is_active = 0;
+ break;
+ case OTG_STATE_B_HOST:
+ DBG(1, "HNP: Disabling HR\n");
+ hcd->self.is_b_host = 0;
+ musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
+ MUSB_DEV_MODE(musb);
+ reg = musb_readb(mbase, MUSB_POWER);
+ reg |= MUSB_POWER_SUSPENDM;
+ musb_writeb(mbase, MUSB_POWER, reg);
+ /* REVISIT: Start SESSION_REQUEST here? */
+ break;
+ default:
+ DBG(1, "HNP: Stopping in unknown state %s\n",
+ otg_state_string(musb));
+ }
+
+ /*
+ * When returning to A state after HNP, avoid hub_port_rebounce(),
+ * which cause occasional OPT A "Did not receive reset after connect"
+ * errors.
+ */
+ musb->port1_status &=
+ ~(1 << USB_PORT_FEAT_C_CONNECTION);
+}
+
+#endif
+
+/*
+ * Interrupt Service Routine to record USB "global" interrupts.
+ * Since these do not happen often and signify things of
+ * paramount importance, it seems OK to check them individually;
+ * the order of the tests is specified in the manual
+ *
+ * @param musb instance pointer
+ * @param int_usb register contents
+ * @param devctl
+ * @param power
+ */
+
+#define STAGE0_MASK (MUSB_INTR_RESUME | MUSB_INTR_SESSREQ \
+ | MUSB_INTR_VBUSERROR | MUSB_INTR_CONNECT \
+ | MUSB_INTR_RESET)
+
+static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
+ u8 devctl, u8 power)
+{
+ irqreturn_t handled = IRQ_NONE;
+ void __iomem *mbase = musb->mregs;
+
+ DBG(3, "<== Power=%02x, DevCtl=%02x, int_usb=0x%x\n", power, devctl,
+ int_usb);
+
+ /* in host mode, the peripheral may issue remote wakeup.
+ * in peripheral mode, the host may resume the link.
+ * spurious RESUME irqs happen too, paired with SUSPEND.
+ */
+ if (int_usb & MUSB_INTR_RESUME) {
+ handled = IRQ_HANDLED;
+ DBG(3, "RESUME (%s)\n", otg_state_string(musb));
+
+ if (devctl & MUSB_DEVCTL_HM) {
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+ switch (musb->xceiv.state) {
+ case OTG_STATE_A_SUSPEND:
+ /* remote wakeup? later, GetPortStatus
+ * will stop RESUME signaling
+ */
+
+ if (power & MUSB_POWER_SUSPENDM) {
+ /* spurious */
+ musb->int_usb &= ~MUSB_INTR_SUSPEND;
+ DBG(2, "Spurious SUSPENDM\n");
+ break;
+ }
+
+ power &= ~MUSB_POWER_SUSPENDM;
+ musb_writeb(mbase, MUSB_POWER,
+ power | MUSB_POWER_RESUME);
+
+ musb->port1_status |=
+ (USB_PORT_STAT_C_SUSPEND << 16)
+ | MUSB_PORT_STAT_RESUME;
+ musb->rh_timer = jiffies
+ + msecs_to_jiffies(20);
+
+ musb->xceiv.state = OTG_STATE_A_HOST;
+ musb->is_active = 1;
+ usb_hcd_resume_root_hub(musb_to_hcd(musb));
+ break;
+ case OTG_STATE_B_WAIT_ACON:
+ musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
+ musb->is_active = 1;
+ MUSB_DEV_MODE(musb);
+ break;
+ default:
+ WARN("bogus %s RESUME (%s)\n",
+ "host",
+ otg_state_string(musb));
+ }
+#endif
+ } else {
+ switch (musb->xceiv.state) {
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+ case OTG_STATE_A_SUSPEND:
+ /* possibly DISCONNECT is upcoming */
+ musb->xceiv.state = OTG_STATE_A_HOST;
+ usb_hcd_resume_root_hub(musb_to_hcd(musb));
+ break;
+#endif
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+ case OTG_STATE_B_WAIT_ACON:
+ case OTG_STATE_B_PERIPHERAL:
+ /* disconnect while suspended? we may
+ * not get a disconnect irq...
+ */
+ if ((devctl & MUSB_DEVCTL_VBUS)
+ != (3 << MUSB_DEVCTL_VBUS_SHIFT)
+ ) {
+ musb->int_usb |= MUSB_INTR_DISCONNECT;
+ musb->int_usb &= ~MUSB_INTR_SUSPEND;
+ break;
+ }
+ musb_g_resume(musb);
+ break;
+ case OTG_STATE_B_IDLE:
+ musb->int_usb &= ~MUSB_INTR_SUSPEND;
+ break;
+#endif
+ default:
+ WARN("bogus %s RESUME (%s)\n",
+ "peripheral",
+ otg_state_string(musb));
+ }
+ }
+ }
+
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+ /* see manual for the order of the tests */
+ if (int_usb & MUSB_INTR_SESSREQ) {
+ DBG(1, "SESSION_REQUEST (%s)\n", otg_state_string(musb));
+
+ /* IRQ arrives from ID pin sense or (later, if VBUS power
+ * is removed) SRP. responses are time critical:
+ * - turn on VBUS (with silicon-specific mechanism)
+ * - go through A_WAIT_VRISE
+ * - ... to A_WAIT_BCON.
+ * a_wait_vrise_tmout triggers VBUS_ERROR transitions
+ */
+ musb_writeb(mbase, MUSB_DEVCTL, MUSB_DEVCTL_SESSION);
+ musb->ep0_stage = MUSB_EP0_START;
+ musb->xceiv.state = OTG_STATE_A_IDLE;
+ MUSB_HST_MODE(musb);
+ musb_set_vbus(musb, 1);
+
+ handled = IRQ_HANDLED;
+ }
+
+ if (int_usb & MUSB_INTR_VBUSERROR) {
+ int ignore = 0;
+
+ /* During connection as an A-Device, we may see a short
+ * current spikes causing voltage drop, because of cable
+ * and peripheral capacitance combined with vbus draw.
+ * (So: less common with truly self-powered devices, where
+ * vbus doesn't act like a power supply.)
+ *
+ * Such spikes are short; usually less than ~500 usec, max
+ * of ~2 msec. That is, they're not sustained overcurrent
+ * errors, though they're reported using VBUSERROR irqs.
+ *
+ * Workarounds: (a) hardware: use self powered devices.
+ * (b) software: ignore non-repeated VBUS errors.
+ *
+ * REVISIT: do delays from lots of DEBUG_KERNEL checks
+ * make trouble here, keeping VBUS < 4.4V ?
+ */
+ switch (musb->xceiv.state) {
+ case OTG_STATE_A_HOST:
+ /* recovery is dicey once we've gotten past the
+ * initial stages of enumeration, but if VBUS
+ * stayed ok at the other end of the link, and
+ * another reset is due (at least for high speed,
+ * to redo the chirp etc), it might work OK...
+ */
+ case OTG_STATE_A_WAIT_BCON:
+ case OTG_STATE_A_WAIT_VRISE:
+ if (musb->vbuserr_retry) {
+ musb->vbuserr_retry--;
+ ignore = 1;
+ devctl |= MUSB_DEVCTL_SESSION;
+ musb_writeb(mbase, MUSB_DEVCTL, devctl);
+ } else {
+ musb->port1_status |=
+ (1 << USB_PORT_FEAT_OVER_CURRENT)
+ | (1 << USB_PORT_FEAT_C_OVER_CURRENT);
+ }
+ break;
+ default:
+ break;
+ }
+
+ DBG(1, "VBUS_ERROR in %s (%02x, %s), retry #%d, port1 %08x\n",
+ otg_state_string(musb),
+ devctl,
+ ({ char *s;
+ switch (devctl & MUSB_DEVCTL_VBUS) {
+ case 0 << MUSB_DEVCTL_VBUS_SHIFT:
+ s = "<SessEnd"; break;
+ case 1 << MUSB_DEVCTL_VBUS_SHIFT:
+ s = "<AValid"; break;
+ case 2 << MUSB_DEVCTL_VBUS_SHIFT:
+ s = "<VBusValid"; break;
+ /* case 3 << MUSB_DEVCTL_VBUS_SHIFT: */
+ default:
+ s = "VALID"; break;
+ }; s; }),
+ VBUSERR_RETRY_COUNT - musb->vbuserr_retry,
+ musb->port1_status);
+
+ /* go through A_WAIT_VFALL then start a new session */
+ if (!ignore)
+ musb_set_vbus(musb, 0);
+ handled = IRQ_HANDLED;
+ }
+
+ if (int_usb & MUSB_INTR_CONNECT) {
+ struct usb_hcd *hcd = musb_to_hcd(musb);
+
+ handled = IRQ_HANDLED;
+ musb->is_active = 1;
+ set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
+
+ musb->ep0_stage = MUSB_EP0_START;
+
+#ifdef CONFIG_USB_MUSB_OTG
+ /* flush endpoints when transitioning from Device Mode */
+ if (is_peripheral_active(musb)) {
+ /* REVISIT HNP; just force disconnect */
+ }
+ musb_writew(mbase, MUSB_INTRTXE, musb->epmask);
+ musb_writew(mbase, MUSB_INTRRXE, musb->epmask & 0xfffe);
+ musb_writeb(mbase, MUSB_INTRUSBE, 0xf7);
+#endif
+ musb->port1_status &= ~(USB_PORT_STAT_LOW_SPEED
+ |USB_PORT_STAT_HIGH_SPEED
+ |USB_PORT_STAT_ENABLE
+ );
+ musb->port1_status |= USB_PORT_STAT_CONNECTION
+ |(USB_PORT_STAT_C_CONNECTION << 16);
+
+ /* high vs full speed is just a guess until after reset */
+ if (devctl & MUSB_DEVCTL_LSDEV)
+ musb->port1_status |= USB_PORT_STAT_LOW_SPEED;
+
+ if (hcd->status_urb)
+ usb_hcd_poll_rh_status(hcd);
+ else
+ usb_hcd_resume_root_hub(hcd);
+
+ MUSB_HST_MODE(musb);
+
+ /* indicate new connection to OTG machine */
+ switch (musb->xceiv.state) {
+ case OTG_STATE_B_PERIPHERAL:
+ if (int_usb & MUSB_INTR_SUSPEND) {
+ DBG(1, "HNP: SUSPEND+CONNECT, now b_host\n");
+ musb->xceiv.state = OTG_STATE_B_HOST;
+ hcd->self.is_b_host = 1;
+ int_usb &= ~MUSB_INTR_SUSPEND;
+ } else
+ DBG(1, "CONNECT as b_peripheral???\n");
+ break;
+ case OTG_STATE_B_WAIT_ACON:
+ DBG(1, "HNP: Waiting to switch to b_host state\n");
+ musb->xceiv.state = OTG_STATE_B_HOST;
+ hcd->self.is_b_host = 1;
+ break;
+ default:
+ if ((devctl & MUSB_DEVCTL_VBUS)
+ == (3 << MUSB_DEVCTL_VBUS_SHIFT)) {
+ musb->xceiv.state = OTG_STATE_A_HOST;
+ hcd->self.is_b_host = 0;
+ }
+ break;
+ }
+ DBG(1, "CONNECT (%s) devctl %02x\n",
+ otg_state_string(musb), devctl);
+ }
+#endif /* CONFIG_USB_MUSB_HDRC_HCD */
+
+ /* mentor saves a bit: bus reset and babble share the same irq.
+ * only host sees babble; only peripheral sees bus reset.
+ */
+ if (int_usb & MUSB_INTR_RESET) {
+ if (is_host_capable() && (devctl & MUSB_DEVCTL_HM) != 0) {
+ /*
+ * Looks like non-HS BABBLE can be ignored, but
+ * HS BABBLE is an error condition. For HS the solution
+ * is to avoid babble in the first place and fix what
+ * caused BABBLE. When HS BABBLE happens we can only
+ * stop the session.
+ */
+ if (devctl & (MUSB_DEVCTL_FSDEV | MUSB_DEVCTL_LSDEV))
+ DBG(1, "BABBLE devctl: %02x\n", devctl);
+ else {
+ ERR("Stopping host session -- babble\n");
+ musb_writeb(mbase, MUSB_DEVCTL, 0);
+ }
+ } else if (is_peripheral_capable()) {
+ DBG(1, "BUS RESET as %s\n", otg_state_string(musb));
+ switch (musb->xceiv.state) {
+#ifdef CONFIG_USB_OTG
+ case OTG_STATE_A_SUSPEND:
+ musb->ignore_disconnect = 1;
+ musb_g_reset(musb);
+ /* FALLTHROUGH */
+ case OTG_STATE_A_WAIT_BCON: /* OPT TD.4.7-900ms */
+ DBG(1, "HNP: Setting timer as %s\n",
+ otg_state_string(musb));
+ musb_otg_timer.data = (unsigned long)musb;
+ mod_timer(&musb_otg_timer, jiffies
+ + msecs_to_jiffies(100));
+ break;
+ case OTG_STATE_A_PERIPHERAL:
+ musb_hnp_stop(musb);
+ break;
+ case OTG_STATE_B_WAIT_ACON:
+ DBG(1, "HNP: RESET (%s), back to b_peripheral\n",
+ otg_state_string(musb));
+ musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
+ musb_g_reset(musb);
+ break;
+#endif
+ case OTG_STATE_B_IDLE:
+ musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
+ /* FALLTHROUGH */
+ case OTG_STATE_B_PERIPHERAL:
+ musb_g_reset(musb);
+ break;
+ default:
+ DBG(1, "Unhandled BUS RESET as %s\n",
+ otg_state_string(musb));
+ }
+ }
+
+ handled = IRQ_HANDLED;
+ }
+ schedule_work(&musb->irq_work);
+
+ return handled;
+}
+
+/*
+ * Interrupt Service Routine to record USB "global" interrupts.
+ * Since these do not happen often and signify things of
+ * paramount importance, it seems OK to check them individually;
+ * the order of the tests is specified in the manual
+ *
+ * @param musb instance pointer
+ * @param int_usb register contents
+ * @param devctl
+ * @param power
+ */
+static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb,
+ u8 devctl, u8 power)
+{
+ irqreturn_t handled = IRQ_NONE;
+
+#if 0
+/* REVISIT ... this would be for multiplexing periodic endpoints, or
+ * supporting transfer phasing to prevent exceeding ISO bandwidth
+ * limits of a given frame or microframe.
+ *
+ * It's not needed for peripheral side, which dedicates endpoints;
+ * though it _might_ use SOF irqs for other purposes.
+ *
+ * And it's not currently needed for host side, which also dedicates
+ * endpoints, relies on TX/RX interval registers, and isn't claimed
+ * to support ISO transfers yet.
+ */
+ if (int_usb & MUSB_INTR_SOF) {
+ void __iomem *mbase = musb->mregs;
+ struct musb_hw_ep *ep;
+ u8 epnum;
+ u16 frame;
+
+ DBG(6, "START_OF_FRAME\n");
+ handled = IRQ_HANDLED;
+
+ /* start any periodic Tx transfers waiting for current frame */
+ frame = musb_readw(mbase, MUSB_FRAME);
+ ep = musb->endpoints;
+ for (epnum = 1; (epnum < musb->nr_endpoints)
+ && (musb->epmask >= (1 << epnum));
+ epnum++, ep++) {
+ /*
+ * FIXME handle framecounter wraps (12 bits)
+ * eliminate duplicated StartUrb logic
+ */
+ if (ep->dwWaitFrame >= frame) {
+ ep->dwWaitFrame = 0;
+ printk("SOF --> periodic TX%s on %d\n",
+ ep->tx_channel ? " DMA" : "",
+ epnum);
+ if (!ep->tx_channel)
+ musb_h_tx_start(musb, epnum);
+ else
+ cppi_hostdma_start(musb, epnum);
+ }
+ } /* end of for loop */
+ }
+#endif
+
+ if ((int_usb & MUSB_INTR_DISCONNECT) && !musb->ignore_disconnect) {
+ DBG(1, "DISCONNECT (%s) as %s, devctl %02x\n",
+ otg_state_string(musb),
+ MUSB_MODE(musb), devctl);
+ handled = IRQ_HANDLED;
+
+ switch (musb->xceiv.state) {
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+ case OTG_STATE_A_HOST:
+ case OTG_STATE_A_SUSPEND:
+ musb_root_disconnect(musb);
+ if (musb->a_wait_bcon != 0)
+ musb_platform_try_idle(musb, jiffies
+ + msecs_to_jiffies(musb->a_wait_bcon));
+ break;
+#endif /* HOST */
+#ifdef CONFIG_USB_MUSB_OTG
+ case OTG_STATE_B_HOST:
+ musb_hnp_stop(musb);
+ break;
+ case OTG_STATE_A_PERIPHERAL:
+ musb_hnp_stop(musb);
+ musb_root_disconnect(musb);
+ /* FALLTHROUGH */
+ case OTG_STATE_B_WAIT_ACON:
+ /* FALLTHROUGH */
+#endif /* OTG */
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+ case OTG_STATE_B_PERIPHERAL:
+ case OTG_STATE_B_IDLE:
+ musb_g_disconnect(musb);
+ break;
+#endif /* GADGET */
+ default:
+ WARN("unhandled DISCONNECT transition (%s)\n",
+ otg_state_string(musb));
+ break;
+ }
+
+ schedule_work(&musb->irq_work);
+ }
+
+ if (int_usb & MUSB_INTR_SUSPEND) {
+ DBG(1, "SUSPEND (%s) devctl %02x power %02x\n",
+ otg_state_string(musb), devctl, power);
+ handled = IRQ_HANDLED;
+
+ switch (musb->xceiv.state) {
+#ifdef CONFIG_USB_MUSB_OTG
+ case OTG_STATE_A_PERIPHERAL:
+ /*
+ * We cannot stop HNP here, devctl BDEVICE might be
+ * still set.
+ */
+ break;
+#endif
+ case OTG_STATE_B_PERIPHERAL:
+ musb_g_suspend(musb);
+ musb->is_active = is_otg_enabled(musb)
+ && musb->xceiv.gadget->b_hnp_enable;
+ if (musb->is_active) {
+#ifdef CONFIG_USB_MUSB_OTG
+ musb->xceiv.state = OTG_STATE_B_WAIT_ACON;
+ DBG(1, "HNP: Setting timer for b_ase0_brst\n");
+ musb_otg_timer.data = (unsigned long)musb;
+ mod_timer(&musb_otg_timer, jiffies
+ + msecs_to_jiffies(TB_ASE0_BRST));
+#endif
+ }
+ break;
+ case OTG_STATE_A_WAIT_BCON:
+ if (musb->a_wait_bcon != 0)
+ musb_platform_try_idle(musb, jiffies
+ + msecs_to_jiffies(musb->a_wait_bcon));
+ break;
+ case OTG_STATE_A_HOST:
+ musb->xceiv.state = OTG_STATE_A_SUSPEND;
+ musb->is_active = is_otg_enabled(musb)
+ && musb->xceiv.host->b_hnp_enable;
+ break;
+ case OTG_STATE_B_HOST:
+ /* Transition to B_PERIPHERAL, see 6.8.2.6 p 44 */
+ DBG(1, "REVISIT: SUSPEND as B_HOST\n");
+ break;
+ default:
+ /* "should not happen" */
+ musb->is_active = 0;
+ break;
+ }
+ schedule_work(&musb->irq_work);
+ }
+
+
+ return handled;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+* Program the HDRC to start (enable interrupts, dma, etc.).
+*/
+void musb_start(struct musb *musb)
+{
+ void __iomem *regs = musb->mregs;
+ u8 devctl = musb_readb(regs, MUSB_DEVCTL);
+
+ DBG(2, "<== devctl %02x\n", devctl);
+
+ /* Set INT enable registers, enable interrupts */
+ musb_writew(regs, MUSB_INTRTXE, musb->epmask);
+ musb_writew(regs, MUSB_INTRRXE, musb->epmask & 0xfffe);
+ musb_writeb(regs, MUSB_INTRUSBE, 0xf7);
+
+ musb_writeb(regs, MUSB_TESTMODE, 0);
+
+ /* put into basic highspeed mode and start session */
+ musb_writeb(regs, MUSB_POWER, MUSB_POWER_ISOUPDATE
+ | MUSB_POWER_SOFTCONN
+ | MUSB_POWER_HSENAB
+ /* ENSUSPEND wedges tusb */
+ /* | MUSB_POWER_ENSUSPEND */
+ );
+
+ musb->is_active = 0;
+ devctl = musb_readb(regs, MUSB_DEVCTL);
+ devctl &= ~MUSB_DEVCTL_SESSION;
+
+ if (is_otg_enabled(musb)) {
+ /* session started after:
+ * (a) ID-grounded irq, host mode;
+ * (b) vbus present/connect IRQ, peripheral mode;
+ * (c) peripheral initiates, using SRP
+ */
+ if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS)
+ musb->is_active = 1;
+ else
+ devctl |= MUSB_DEVCTL_SESSION;
+
+ } else if (is_host_enabled(musb)) {
+ /* assume ID pin is hard-wired to ground */
+ devctl |= MUSB_DEVCTL_SESSION;
+
+ } else /* peripheral is enabled */ {
+ if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS)
+ musb->is_active = 1;
+ }
+ musb_platform_enable(musb);
+ musb_writeb(regs, MUSB_DEVCTL, devctl);
+}
+
+
+static void musb_generic_disable(struct musb *musb)
+{
+ void __iomem *mbase = musb->mregs;
+ u16 temp;
+
+ /* disable interrupts */
+ musb_writeb(mbase, MUSB_INTRUSBE, 0);
+ musb_writew(mbase, MUSB_INTRTXE, 0);
+ musb_writew(mbase, MUSB_INTRRXE, 0);
+
+ /* off */
+ musb_writeb(mbase, MUSB_DEVCTL, 0);
+
+ /* flush pending interrupts */
+ temp = musb_readb(mbase, MUSB_INTRUSB);
+ temp = musb_readw(mbase, MUSB_INTRTX);
+ temp = musb_readw(mbase, MUSB_INTRRX);
+
+}
+
+/*
+ * Make the HDRC stop (disable interrupts, etc.);
+ * reversible by musb_start
+ * called on gadget driver unregister
+ * with controller locked, irqs blocked
+ * acts as a NOP unless some role activated the hardware
+ */
+void musb_stop(struct musb *musb)
+{
+ /* stop IRQs, timers, ... */
+ musb_platform_disable(musb);
+ musb_generic_disable(musb);
+ DBG(3, "HDRC disabled\n");
+
+ /* FIXME
+ * - mark host and/or peripheral drivers unusable/inactive
+ * - disable DMA (and enable it in HdrcStart)
+ * - make sure we can musb_start() after musb_stop(); with
+ * OTG mode, gadget driver module rmmod/modprobe cycles that
+ * - ...
+ */
+ musb_platform_try_idle(musb, 0);
+}
+
+static void musb_shutdown(struct platform_device *pdev)
+{
+ struct musb *musb = dev_to_musb(&pdev->dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&musb->lock, flags);
+ musb_platform_disable(musb);
+ musb_generic_disable(musb);
+ if (musb->clock) {
+ clk_put(musb->clock);
+ musb->clock = NULL;
+ }
+ spin_unlock_irqrestore(&musb->lock, flags);
+
+ /* FIXME power down */
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * The silicon either has hard-wired endpoint configurations, or else
+ * "dynamic fifo" sizing. The driver has support for both, though at this
+ * writing only the dynamic sizing is very well tested. We use normal
+ * idioms to so both modes are compile-tested, but dead code elimination
+ * leaves only the relevant one in the object file.
+ *
+ * We don't currently use dynamic fifo setup capability to do anything
+ * more than selecting one of a bunch of predefined configurations.
+ */
+#ifdef MUSB_C_DYNFIFO_DEF
+#define can_dynfifo() 1
+#else
+#define can_dynfifo() 0
+#endif
+
+#if defined(CONFIG_USB_TUSB6010) || \
+ defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX)
+static ushort __initdata fifo_mode = 4;
+#else
+static ushort __initdata fifo_mode = 2;
+#endif
+
+/* "modprobe ... fifo_mode=1" etc */
+module_param(fifo_mode, ushort, 0);
+MODULE_PARM_DESC(fifo_mode, "initial endpoint configuration");
+
+
+#define DYN_FIFO_SIZE (1<<(MUSB_C_RAM_BITS+2))
+
+enum fifo_style { FIFO_RXTX, FIFO_TX, FIFO_RX } __attribute__ ((packed));
+enum buf_mode { BUF_SINGLE, BUF_DOUBLE } __attribute__ ((packed));
+
+struct fifo_cfg {
+ u8 hw_ep_num;
+ enum fifo_style style;
+ enum buf_mode mode;
+ u16 maxpacket;
+};
+
+/*
+ * tables defining fifo_mode values. define more if you like.
+ * for host side, make sure both halves of ep1 are set up.
+ */
+
+/* mode 0 - fits in 2KB */
+static struct fifo_cfg __initdata mode_0_cfg[] = {
+{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, },
+{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, },
+{ .hw_ep_num = 2, .style = FIFO_RXTX, .maxpacket = 512, },
+{ .hw_ep_num = 3, .style = FIFO_RXTX, .maxpacket = 256, },
+{ .hw_ep_num = 4, .style = FIFO_RXTX, .maxpacket = 256, },
+};
+
+/* mode 1 - fits in 4KB */
+static struct fifo_cfg __initdata mode_1_cfg[] = {
+{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, .mode = BUF_DOUBLE, },
+{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, .mode = BUF_DOUBLE, },
+{ .hw_ep_num = 2, .style = FIFO_RXTX, .maxpacket = 512, .mode = BUF_DOUBLE, },
+{ .hw_ep_num = 3, .style = FIFO_RXTX, .maxpacket = 256, },
+{ .hw_ep_num = 4, .style = FIFO_RXTX, .maxpacket = 256, },
+};
+
+/* mode 2 - fits in 4KB */
+static struct fifo_cfg __initdata mode_2_cfg[] = {
+{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, },
+{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, },
+{ .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, },
+{ .hw_ep_num = 2, .style = FIFO_RX, .maxpacket = 512, },
+{ .hw_ep_num = 3, .style = FIFO_RXTX, .maxpacket = 256, },
+{ .hw_ep_num = 4, .style = FIFO_RXTX, .maxpacket = 256, },
+};
+
+/* mode 3 - fits in 4KB */
+static struct fifo_cfg __initdata mode_3_cfg[] = {
+{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, .mode = BUF_DOUBLE, },
+{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, .mode = BUF_DOUBLE, },
+{ .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, },
+{ .hw_ep_num = 2, .style = FIFO_RX, .maxpacket = 512, },
+{ .hw_ep_num = 3, .style = FIFO_RXTX, .maxpacket = 256, },
+{ .hw_ep_num = 4, .style = FIFO_RXTX, .maxpacket = 256, },
+};
+
+/* mode 4 - fits in 16KB */
+static struct fifo_cfg __initdata mode_4_cfg[] = {
+{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, },
+{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, },
+{ .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, },
+{ .hw_ep_num = 2, .style = FIFO_RX, .maxpacket = 512, },
+{ .hw_ep_num = 3, .style = FIFO_TX, .maxpacket = 512, },
+{ .hw_ep_num = 3, .style = FIFO_RX, .maxpacket = 512, },
+{ .hw_ep_num = 4, .style = FIFO_TX, .maxpacket = 512, },
+{ .hw_ep_num = 4, .style = FIFO_RX, .maxpacket = 512, },
+{ .hw_ep_num = 5, .style = FIFO_TX, .maxpacket = 512, },
+{ .hw_ep_num = 5, .style = FIFO_RX, .maxpacket = 512, },
+{ .hw_ep_num = 6, .style = FIFO_TX, .maxpacket = 512, },
+{ .hw_ep_num = 6, .style = FIFO_RX, .maxpacket = 512, },
+{ .hw_ep_num = 7, .style = FIFO_TX, .maxpacket = 512, },
+{ .hw_ep_num = 7, .style = FIFO_RX, .maxpacket = 512, },
+{ .hw_ep_num = 8, .style = FIFO_TX, .maxpacket = 512, },
+{ .hw_ep_num = 8, .style = FIFO_RX, .maxpacket = 512, },
+{ .hw_ep_num = 9, .style = FIFO_TX, .maxpacket = 512, },
+{ .hw_ep_num = 9, .style = FIFO_RX, .maxpacket = 512, },
+{ .hw_ep_num = 10, .style = FIFO_TX, .maxpacket = 512, },
+{ .hw_ep_num = 10, .style = FIFO_RX, .maxpacket = 512, },
+{ .hw_ep_num = 11, .style = FIFO_TX, .maxpacket = 512, },
+{ .hw_ep_num = 11, .style = FIFO_RX, .maxpacket = 512, },
+{ .hw_ep_num = 12, .style = FIFO_TX, .maxpacket = 512, },
+{ .hw_ep_num = 12, .style = FIFO_RX, .maxpacket = 512, },
+{ .hw_ep_num = 13, .style = FIFO_TX, .maxpacket = 512, },
+{ .hw_ep_num = 13, .style = FIFO_RX, .maxpacket = 512, },
+{ .hw_ep_num = 14, .style = FIFO_RXTX, .maxpacket = 1024, },
+{ .hw_ep_num = 15, .style = FIFO_RXTX, .maxpacket = 1024, },
+};
+
+
+/*
+ * configure a fifo; for non-shared endpoints, this may be called
+ * once for a tx fifo and once for an rx fifo.
+ *
+ * returns negative errno or offset for next fifo.
+ */
+static int __init
+fifo_setup(struct musb *musb, struct musb_hw_ep *hw_ep,
+ const struct fifo_cfg *cfg, u16 offset)
+{
+ void __iomem *mbase = musb->mregs;
+ int size = 0;
+ u16 maxpacket = cfg->maxpacket;
+ u16 c_off = offset >> 3;
+ u8 c_size;
+
+ /* expect hw_ep has already been zero-initialized */
+
+ size = ffs(max(maxpacket, (u16) 8)) - 1;
+ maxpacket = 1 << size;
+
+ c_size = size - 3;
+ if (cfg->mode == BUF_DOUBLE) {
+ if ((offset + (maxpacket << 1)) > DYN_FIFO_SIZE)
+ return -EMSGSIZE;
+ c_size |= MUSB_FIFOSZ_DPB;
+ } else {
+ if ((offset + maxpacket) > DYN_FIFO_SIZE)
+ return -EMSGSIZE;
+ }
+
+ /* configure the FIFO */
+ musb_writeb(mbase, MUSB_INDEX, hw_ep->epnum);
+
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+ /* EP0 reserved endpoint for control, bidirectional;
+ * EP1 reserved for bulk, two unidirection halves.
+ */
+ if (hw_ep->epnum == 1)
+ musb->bulk_ep = hw_ep;
+ /* REVISIT error check: be sure ep0 can both rx and tx ... */
+#endif
+ switch (cfg->style) {
+ case FIFO_TX:
+ musb_writeb(mbase, MUSB_TXFIFOSZ, c_size);
+ musb_writew(mbase, MUSB_TXFIFOADD, c_off);
+ hw_ep->tx_double_buffered = !!(c_size & MUSB_FIFOSZ_DPB);
+ hw_ep->max_packet_sz_tx = maxpacket;
+ break;
+ case FIFO_RX:
+ musb_writeb(mbase, MUSB_RXFIFOSZ, c_size);
+ musb_writew(mbase, MUSB_RXFIFOADD, c_off);
+ hw_ep->rx_double_buffered = !!(c_size & MUSB_FIFOSZ_DPB);
+ hw_ep->max_packet_sz_rx = maxpacket;
+ break;
+ case FIFO_RXTX:
+ musb_writeb(mbase, MUSB_TXFIFOSZ, c_size);
+ musb_writew(mbase, MUSB_TXFIFOADD, c_off);
+ hw_ep->rx_double_buffered = !!(c_size & MUSB_FIFOSZ_DPB);
+ hw_ep->max_packet_sz_rx = maxpacket;
+
+ musb_writeb(mbase, MUSB_RXFIFOSZ, c_size);
+ musb_writew(mbase, MUSB_RXFIFOADD, c_off);
+ hw_ep->tx_double_buffered = hw_ep->rx_double_buffered;
+ hw_ep->max_packet_sz_tx = maxpacket;
+
+ hw_ep->is_shared_fifo = true;
+ break;
+ }
+
+ /* NOTE rx and tx endpoint irqs aren't managed separately,
+ * which happens to be ok
+ */
+ musb->epmask |= (1 << hw_ep->epnum);
+
+ return offset + (maxpacket << ((c_size & MUSB_FIFOSZ_DPB) ? 1 : 0));
+}
+
+static struct fifo_cfg __initdata ep0_cfg = {
+ .style = FIFO_RXTX, .maxpacket = 64,
+};
+
+static int __init ep_config_from_table(struct musb *musb)
+{
+ const struct fifo_cfg *cfg;
+ unsigned i, n;
+ int offset;
+ struct musb_hw_ep *hw_ep = musb->endpoints;
+
+ switch (fifo_mode) {
+ default:
+ fifo_mode = 0;
+ /* FALLTHROUGH */
+ case 0:
+ cfg = mode_0_cfg;
+ n = ARRAY_SIZE(mode_0_cfg);
+ break;
+ case 1:
+ cfg = mode_1_cfg;
+ n = ARRAY_SIZE(mode_1_cfg);
+ break;
+ case 2:
+ cfg = mode_2_cfg;
+ n = ARRAY_SIZE(mode_2_cfg);
+ break;
+ case 3:
+ cfg = mode_3_cfg;
+ n = ARRAY_SIZE(mode_3_cfg);
+ break;
+ case 4:
+ cfg = mode_4_cfg;
+ n = ARRAY_SIZE(mode_4_cfg);
+ break;
+ }
+
+ printk(KERN_DEBUG "%s: setup fifo_mode %d\n",
+ musb_driver_name, fifo_mode);
+
+
+ offset = fifo_setup(musb, hw_ep, &ep0_cfg, 0);
+ /* assert(offset > 0) */
+
+ /* NOTE: for RTL versions >= 1.400 EPINFO and RAMINFO would
+ * be better than static MUSB_C_NUM_EPS and DYN_FIFO_SIZE...
+ */
+
+ for (i = 0; i < n; i++) {
+ u8 epn = cfg->hw_ep_num;
+
+ if (epn >= MUSB_C_NUM_EPS) {
+ pr_debug("%s: invalid ep %d\n",
+ musb_driver_name, epn);
+ continue;
+ }
+ offset = fifo_setup(musb, hw_ep + epn, cfg++, offset);
+ if (offset < 0) {
+ pr_debug("%s: mem overrun, ep %d\n",
+ musb_driver_name, epn);
+ return -EINVAL;
+ }
+ epn++;
+ musb->nr_endpoints = max(epn, musb->nr_endpoints);
+ }
+
+ printk(KERN_DEBUG "%s: %d/%d max ep, %d/%d memory\n",
+ musb_driver_name,
+ n + 1, MUSB_C_NUM_EPS * 2 - 1,
+ offset, DYN_FIFO_SIZE);
+
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+ if (!musb->bulk_ep) {
+ pr_debug("%s: missing bulk\n", musb_driver_name);
+ return -EINVAL;
+ }
+#endif
+
+ return 0;
+}
+
+
+/*
+ * ep_config_from_hw - when MUSB_C_DYNFIFO_DEF is false
+ * @param musb the controller
+ */
+static int __init ep_config_from_hw(struct musb *musb)
+{
+ u8 epnum = 0, reg;
+ struct musb_hw_ep *hw_ep;
+ void *mbase = musb->mregs;
+
+ DBG(2, "<== static silicon ep config\n");
+
+ /* FIXME pick up ep0 maxpacket size */
+
+ for (epnum = 1; epnum < MUSB_C_NUM_EPS; epnum++) {
+ musb_ep_select(mbase, epnum);
+ hw_ep = musb->endpoints + epnum;
+
+ /* read from core using indexed model */
+ reg = musb_readb(hw_ep->regs, 0x10 + MUSB_FIFOSIZE);
+ if (!reg) {
+ /* 0's returned when no more endpoints */
+ break;
+ }
+ musb->nr_endpoints++;
+ musb->epmask |= (1 << epnum);
+
+ hw_ep->max_packet_sz_tx = 1 << (reg & 0x0f);
+
+ /* shared TX/RX FIFO? */
+ if ((reg & 0xf0) == 0xf0) {
+ hw_ep->max_packet_sz_rx = hw_ep->max_packet_sz_tx;
+ hw_ep->is_shared_fifo = true;
+ continue;
+ } else {
+ hw_ep->max_packet_sz_rx = 1 << ((reg & 0xf0) >> 4);
+ hw_ep->is_shared_fifo = false;
+ }
+
+ /* FIXME set up hw_ep->{rx,tx}_double_buffered */
+
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+ /* pick an RX/TX endpoint for bulk */
+ if (hw_ep->max_packet_sz_tx < 512
+ || hw_ep->max_packet_sz_rx < 512)
+ continue;
+
+ /* REVISIT: this algorithm is lazy, we should at least
+ * try to pick a double buffered endpoint.
+ */
+ if (musb->bulk_ep)
+ continue;
+ musb->bulk_ep = hw_ep;
+#endif
+ }
+
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+ if (!musb->bulk_ep) {
+ pr_debug("%s: missing bulk\n", musb_driver_name);
+ return -EINVAL;
+ }
+#endif
+
+ return 0;
+}
+
+enum { MUSB_CONTROLLER_MHDRC, MUSB_CONTROLLER_HDRC, };
+
+/* Initialize MUSB (M)HDRC part of the USB hardware subsystem;
+ * configure endpoints, or take their config from silicon
+ */
+static int __init musb_core_init(u16 musb_type, struct musb *musb)
+{
+#ifdef MUSB_AHB_ID
+ u32 data;
+#endif
+ u8 reg;
+ char *type;
+ u16 hwvers, rev_major, rev_minor;
+ char aInfo[78], aRevision[32], aDate[12];
+ void __iomem *mbase = musb->mregs;
+ int status = 0;
+ int i;
+
+ /* log core options (read using indexed model) */
+ musb_ep_select(mbase, 0);
+ reg = musb_readb(mbase, 0x10 + MUSB_CONFIGDATA);
+
+ strcpy(aInfo, (reg & MUSB_CONFIGDATA_UTMIDW) ? "UTMI-16" : "UTMI-8");
+ if (reg & MUSB_CONFIGDATA_DYNFIFO)
+ strcat(aInfo, ", dyn FIFOs");
+ if (reg & MUSB_CONFIGDATA_MPRXE) {
+ strcat(aInfo, ", bulk combine");
+#ifdef C_MP_RX
+ musb->bulk_combine = true;
+#else
+ strcat(aInfo, " (X)"); /* no driver support */
+#endif
+ }
+ if (reg & MUSB_CONFIGDATA_MPTXE) {
+ strcat(aInfo, ", bulk split");
+#ifdef C_MP_TX
+ musb->bulk_split = true;
+#else
+ strcat(aInfo, " (X)"); /* no driver support */
+#endif
+ }
+ if (reg & MUSB_CONFIGDATA_HBRXE) {
+ strcat(aInfo, ", HB-ISO Rx");
+ strcat(aInfo, " (X)"); /* no driver support */
+ }
+ if (reg & MUSB_CONFIGDATA_HBTXE) {
+ strcat(aInfo, ", HB-ISO Tx");
+ strcat(aInfo, " (X)"); /* no driver support */
+ }
+ if (reg & MUSB_CONFIGDATA_SOFTCONE)
+ strcat(aInfo, ", SoftConn");
+
+ printk(KERN_DEBUG "%s: ConfigData=0x%02x (%s)\n",
+ musb_driver_name, reg, aInfo);
+
+#ifdef MUSB_AHB_ID
+ data = musb_readl(mbase, 0x404);
+ sprintf(aDate, "%04d-%02x-%02x", (data & 0xffff),
+ (data >> 16) & 0xff, (data >> 24) & 0xff);
+ /* FIXME ID2 and ID3 are unused */
+ data = musb_readl(mbase, 0x408);
+ printk("ID2=%lx\n", (long unsigned)data);
+ data = musb_readl(mbase, 0x40c);
+ printk("ID3=%lx\n", (long unsigned)data);
+ reg = musb_readb(mbase, 0x400);
+ musb_type = ('M' == reg) ? MUSB_CONTROLLER_MHDRC : MUSB_CONTROLLER_HDRC;
+#else
+ aDate[0] = 0;
+#endif
+ if (MUSB_CONTROLLER_MHDRC == musb_type) {
+ musb->is_multipoint = 1;
+ type = "M";
+ } else {
+ musb->is_multipoint = 0;
+ type = "";
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+#ifndef CONFIG_USB_OTG_BLACKLIST_HUB
+ printk(KERN_ERR
+ "%s: kernel must blacklist external hubs\n",
+ musb_driver_name);
+#endif
+#endif
+ }
+
+ /* log release info */
+ hwvers = musb_readw(mbase, MUSB_HWVERS);
+ rev_major = (hwvers >> 10) & 0x1f;
+ rev_minor = hwvers & 0x3ff;
+ snprintf(aRevision, 32, "%d.%d%s", rev_major,
+ rev_minor, (hwvers & 0x8000) ? "RC" : "");
+ printk(KERN_DEBUG "%s: %sHDRC RTL version %s %s\n",
+ musb_driver_name, type, aRevision, aDate);
+
+ /* configure ep0 */
+ musb->endpoints[0].max_packet_sz_tx = MUSB_EP0_FIFOSIZE;
+ musb->endpoints[0].max_packet_sz_rx = MUSB_EP0_FIFOSIZE;
+
+ /* discover endpoint configuration */
+ musb->nr_endpoints = 1;
+ musb->epmask = 1;
+
+ if (reg & MUSB_CONFIGDATA_DYNFIFO) {
+ if (can_dynfifo())
+ status = ep_config_from_table(musb);
+ else {
+ ERR("reconfigure software for Dynamic FIFOs\n");
+ status = -ENODEV;
+ }
+ } else {
+ if (!can_dynfifo())
+ status = ep_config_from_hw(musb);
+ else {
+ ERR("reconfigure software for static FIFOs\n");
+ return -ENODEV;
+ }
+ }
+
+ if (status < 0)
+ return status;
+
+ /* finish init, and print endpoint config */
+ for (i = 0; i < musb->nr_endpoints; i++) {
+ struct musb_hw_ep *hw_ep = musb->endpoints + i;
+
+ hw_ep->fifo = MUSB_FIFO_OFFSET(i) + mbase;
+#ifdef CONFIG_USB_TUSB6010
+ hw_ep->fifo_async = musb->async + 0x400 + MUSB_FIFO_OFFSET(i);
+ hw_ep->fifo_sync = musb->sync + 0x400 + MUSB_FIFO_OFFSET(i);
+ hw_ep->fifo_sync_va =
+ musb->sync_va + 0x400 + MUSB_FIFO_OFFSET(i);
+
+ if (i == 0)
+ hw_ep->conf = mbase - 0x400 + TUSB_EP0_CONF;
+ else
+ hw_ep->conf = mbase + 0x400 + (((i - 1) & 0xf) << 2);
+#endif
+
+ hw_ep->regs = MUSB_EP_OFFSET(i, 0) + mbase;
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+ hw_ep->target_regs = MUSB_BUSCTL_OFFSET(i, 0) + mbase;
+ hw_ep->rx_reinit = 1;
+ hw_ep->tx_reinit = 1;
+#endif
+
+ if (hw_ep->max_packet_sz_tx) {
+ printk(KERN_DEBUG
+ "%s: hw_ep %d%s, %smax %d\n",
+ musb_driver_name, i,
+ hw_ep->is_shared_fifo ? "shared" : "tx",
+ hw_ep->tx_double_buffered
+ ? "doublebuffer, " : "",
+ hw_ep->max_packet_sz_tx);
+ }
+ if (hw_ep->max_packet_sz_rx && !hw_ep->is_shared_fifo) {
+ printk(KERN_DEBUG
+ "%s: hw_ep %d%s, %smax %d\n",
+ musb_driver_name, i,
+ "rx",
+ hw_ep->rx_double_buffered
+ ? "doublebuffer, " : "",
+ hw_ep->max_packet_sz_rx);
+ }
+ if (!(hw_ep->max_packet_sz_tx || hw_ep->max_packet_sz_rx))
+ DBG(1, "hw_ep %d not configured\n", i);
+ }
+
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430)
+
+static irqreturn_t generic_interrupt(int irq, void *__hci)
+{
+ unsigned long flags;
+ irqreturn_t retval = IRQ_NONE;
+ struct musb *musb = __hci;
+
+ spin_lock_irqsave(&musb->lock, flags);
+
+ musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB);
+ musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX);
+ musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX);
+
+ if (musb->int_usb || musb->int_tx || musb->int_rx)
+ retval = musb_interrupt(musb);
+
+ spin_unlock_irqrestore(&musb->lock, flags);
+
+ /* REVISIT we sometimes get spurious IRQs on g_ep0
+ * not clear why...
+ */
+ if (retval != IRQ_HANDLED)
+ DBG(5, "spurious?\n");
+
+ return IRQ_HANDLED;
+}
+
+#else
+#define generic_interrupt NULL
+#endif
+
+/*
+ * handle all the irqs defined by the HDRC core. for now we expect: other
+ * irq sources (phy, dma, etc) will be handled first, musb->int_* values
+ * will be assigned, and the irq will already have been acked.
+ *
+ * called in irq context with spinlock held, irqs blocked
+ */
+irqreturn_t musb_interrupt(struct musb *musb)
+{
+ irqreturn_t retval = IRQ_NONE;
+ u8 devctl, power;
+ int ep_num;
+ u32 reg;
+
+ devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+ power = musb_readb(musb->mregs, MUSB_POWER);
+
+ DBG(4, "** IRQ %s usb%04x tx%04x rx%04x\n",
+ (devctl & MUSB_DEVCTL_HM) ? "host" : "peripheral",
+ musb->int_usb, musb->int_tx, musb->int_rx);
+
+ /* the core can interrupt us for multiple reasons; docs have
+ * a generic interrupt flowchart to follow
+ */
+ if (musb->int_usb & STAGE0_MASK)
+ retval |= musb_stage0_irq(musb, musb->int_usb,
+ devctl, power);
+
+ /* "stage 1" is handling endpoint irqs */
+
+ /* handle endpoint 0 first */
+ if (musb->int_tx & 1) {
+ if (devctl & MUSB_DEVCTL_HM)
+ retval |= musb_h_ep0_irq(musb);
+ else
+ retval |= musb_g_ep0_irq(musb);
+ }
+
+ /* RX on endpoints 1-15 */
+ reg = musb->int_rx >> 1;
+ ep_num = 1;
+ while (reg) {
+ if (reg & 1) {
+ /* musb_ep_select(musb->mregs, ep_num); */
+ /* REVISIT just retval = ep->rx_irq(...) */
+ retval = IRQ_HANDLED;
+ if (devctl & MUSB_DEVCTL_HM) {
+ if (is_host_capable())
+ musb_host_rx(musb, ep_num);
+ } else {
+ if (is_peripheral_capable())
+ musb_g_rx(musb, ep_num);
+ }
+ }
+
+ reg >>= 1;
+ ep_num++;
+ }
+
+ /* TX on endpoints 1-15 */
+ reg = musb->int_tx >> 1;
+ ep_num = 1;
+ while (reg) {
+ if (reg & 1) {
+ /* musb_ep_select(musb->mregs, ep_num); */
+ /* REVISIT just retval |= ep->tx_irq(...) */
+ retval = IRQ_HANDLED;
+ if (devctl & MUSB_DEVCTL_HM) {
+ if (is_host_capable())
+ musb_host_tx(musb, ep_num);
+ } else {
+ if (is_peripheral_capable())
+ musb_g_tx(musb, ep_num);
+ }
+ }
+ reg >>= 1;
+ ep_num++;
+ }
+
+ /* finish handling "global" interrupts after handling fifos */
+ if (musb->int_usb)
+ retval |= musb_stage2_irq(musb,
+ musb->int_usb, devctl, power);
+
+ return retval;
+}
+
+
+#ifndef CONFIG_MUSB_PIO_ONLY
+static int __initdata use_dma = 1;
+
+/* "modprobe ... use_dma=0" etc */
+module_param(use_dma, bool, 0);
+MODULE_PARM_DESC(use_dma, "enable/disable use of DMA");
+
+void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit)
+{
+ u8 devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+
+ /* called with controller lock already held */
+
+ if (!epnum) {
+#ifndef CONFIG_USB_TUSB_OMAP_DMA
+ if (!is_cppi_enabled()) {
+ /* endpoint 0 */
+ if (devctl & MUSB_DEVCTL_HM)
+ musb_h_ep0_irq(musb);
+ else
+ musb_g_ep0_irq(musb);
+ }
+#endif
+ } else {
+ /* endpoints 1..15 */
+ if (transmit) {
+ if (devctl & MUSB_DEVCTL_HM) {
+ if (is_host_capable())
+ musb_host_tx(musb, epnum);
+ } else {
+ if (is_peripheral_capable())
+ musb_g_tx(musb, epnum);
+ }
+ } else {
+ /* receive */
+ if (devctl & MUSB_DEVCTL_HM) {
+ if (is_host_capable())
+ musb_host_rx(musb, epnum);
+ } else {
+ if (is_peripheral_capable())
+ musb_g_rx(musb, epnum);
+ }
+ }
+ }
+}
+
+#else
+#define use_dma 0
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_SYSFS
+
+static ssize_t
+musb_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct musb *musb = dev_to_musb(dev);
+ unsigned long flags;
+ int ret = -EINVAL;
+
+ spin_lock_irqsave(&musb->lock, flags);
+ ret = sprintf(buf, "%s\n", otg_state_string(musb));
+ spin_unlock_irqrestore(&musb->lock, flags);
+
+ return ret;
+}
+
+static ssize_t
+musb_mode_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t n)
+{
+ struct musb *musb = dev_to_musb(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&musb->lock, flags);
+ if (!strncmp(buf, "host", 4))
+ musb_platform_set_mode(musb, MUSB_HOST);
+ if (!strncmp(buf, "peripheral", 10))
+ musb_platform_set_mode(musb, MUSB_PERIPHERAL);
+ if (!strncmp(buf, "otg", 3))
+ musb_platform_set_mode(musb, MUSB_OTG);
+ spin_unlock_irqrestore(&musb->lock, flags);
+
+ return n;
+}
+static DEVICE_ATTR(mode, 0644, musb_mode_show, musb_mode_store);
+
+static ssize_t
+musb_vbus_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t n)
+{
+ struct musb *musb = dev_to_musb(dev);
+ unsigned long flags;
+ unsigned long val;
+
+ if (sscanf(buf, "%lu", &val) < 1) {
+ printk(KERN_ERR "Invalid VBUS timeout ms value\n");
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&musb->lock, flags);
+ musb->a_wait_bcon = val;
+ if (musb->xceiv.state == OTG_STATE_A_WAIT_BCON)
+ musb->is_active = 0;
+ musb_platform_try_idle(musb, jiffies + msecs_to_jiffies(val));
+ spin_unlock_irqrestore(&musb->lock, flags);
+
+ return n;
+}
+
+static ssize_t
+musb_vbus_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct musb *musb = dev_to_musb(dev);
+ unsigned long flags;
+ unsigned long val;
+ int vbus;
+
+ spin_lock_irqsave(&musb->lock, flags);
+ val = musb->a_wait_bcon;
+ vbus = musb_platform_get_vbus_status(musb);
+ spin_unlock_irqrestore(&musb->lock, flags);
+
+ return sprintf(buf, "Vbus %s, timeout %lu\n",
+ vbus ? "on" : "off", val);
+}
+static DEVICE_ATTR(vbus, 0644, musb_vbus_show, musb_vbus_store);
+
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+
+/* Gadget drivers can't know that a host is connected so they might want
+ * to start SRP, but users can. This allows userspace to trigger SRP.
+ */
+static ssize_t
+musb_srp_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t n)
+{
+ struct musb *musb = dev_to_musb(dev);
+ unsigned short srp;
+
+ if (sscanf(buf, "%hu", &srp) != 1
+ || (srp != 1)) {
+ printk(KERN_ERR "SRP: Value must be 1\n");
+ return -EINVAL;
+ }
+
+ if (srp == 1)
+ musb_g_wakeup(musb);
+
+ return n;
+}
+static DEVICE_ATTR(srp, 0644, NULL, musb_srp_store);
+
+#endif /* CONFIG_USB_GADGET_MUSB_HDRC */
+
+#endif /* sysfs */
+
+/* Only used to provide driver mode change events */
+static void musb_irq_work(struct work_struct *data)
+{
+ struct musb *musb = container_of(data, struct musb, irq_work);
+ static int old_state;
+
+ if (musb->xceiv.state != old_state) {
+ old_state = musb->xceiv.state;
+ sysfs_notify(&musb->controller->kobj, NULL, "mode");
+ }
+}
+
+/* --------------------------------------------------------------------------
+ * Init support
+ */
+
+static struct musb *__init
+allocate_instance(struct device *dev, void __iomem *mbase)
+{
+ struct musb *musb;
+ struct musb_hw_ep *ep;
+ int epnum;
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+ struct usb_hcd *hcd;
+
+ hcd = usb_create_hcd(&musb_hc_driver, dev, dev->bus_id);
+ if (!hcd)
+ return NULL;
+ /* usbcore sets dev->driver_data to hcd, and sometimes uses that... */
+
+ musb = hcd_to_musb(hcd);
+ INIT_LIST_HEAD(&musb->control);
+ INIT_LIST_HEAD(&musb->in_bulk);
+ INIT_LIST_HEAD(&musb->out_bulk);
+
+ hcd->uses_new_polling = 1;
+
+ musb->vbuserr_retry = VBUSERR_RETRY_COUNT;
+#else
+ musb = kzalloc(sizeof *musb, GFP_KERNEL);
+ if (!musb)
+ return NULL;
+ dev_set_drvdata(dev, musb);
+
+#endif
+
+ musb->mregs = mbase;
+ musb->ctrl_base = mbase;
+ musb->nIrq = -ENODEV;
+ for (epnum = 0, ep = musb->endpoints;
+ epnum < MUSB_C_NUM_EPS;
+ epnum++, ep++) {
+
+ ep->musb = musb;
+ ep->epnum = epnum;
+ }
+
+#ifdef CONFIG_USB_MUSB_OTG
+ otg_set_transceiver(&musb->xceiv);
+#endif
+ musb->controller = dev;
+ return musb;
+}
+
+static void musb_free(struct musb *musb)
+{
+ /* this has multiple entry modes. it handles fault cleanup after
+ * probe(), where things may be partially set up, as well as rmmod
+ * cleanup after everything's been de-activated.
+ */
+
+#ifdef CONFIG_SYSFS
+ device_remove_file(musb->controller, &dev_attr_mode);
+ device_remove_file(musb->controller, &dev_attr_vbus);
+#ifdef CONFIG_USB_MUSB_OTG
+ device_remove_file(musb->controller, &dev_attr_srp);
+#endif
+#endif
+
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+ musb_gadget_cleanup(musb);
+#endif
+
+ if (musb->nIrq >= 0) {
+ disable_irq_wake(musb->nIrq);
+ free_irq(musb->nIrq, musb);
+ }
+ if (is_dma_capable() && musb->dma_controller) {
+ struct dma_controller *c = musb->dma_controller;
+
+ (void) c->stop(c);
+ dma_controller_destroy(c);
+ }
+
+ musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
+ musb_platform_exit(musb);
+ musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
+
+ if (musb->clock) {
+ clk_disable(musb->clock);
+ clk_put(musb->clock);
+ }
+
+#ifdef CONFIG_USB_MUSB_OTG
+ put_device(musb->xceiv.dev);
+#endif
+
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+ usb_put_hcd(musb_to_hcd(musb));
+#else
+ kfree(musb);
+#endif
+}
+
+/*
+ * Perform generic per-controller initialization.
+ *
+ * @pDevice: the controller (already clocked, etc)
+ * @nIrq: irq
+ * @mregs: virtual address of controller registers,
+ * not yet corrected for platform-specific offsets
+ */
+static int __init
+musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
+{
+ int status;
+ struct musb *musb;
+ struct musb_hdrc_platform_data *plat = dev->platform_data;
+
+ /* The driver might handle more features than the board; OK.
+ * Fail when the board needs a feature that's not enabled.
+ */
+ if (!plat) {
+ dev_dbg(dev, "no platform_data?\n");
+ return -ENODEV;
+ }
+ switch (plat->mode) {
+ case MUSB_HOST:
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+ break;
+#else
+ goto bad_config;
+#endif
+ case MUSB_PERIPHERAL:
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+ break;
+#else
+ goto bad_config;
+#endif
+ case MUSB_OTG:
+#ifdef CONFIG_USB_MUSB_OTG
+ break;
+#else
+bad_config:
+#endif
+ default:
+ dev_err(dev, "incompatible Kconfig role setting\n");
+ return -EINVAL;
+ }
+
+ /* allocate */
+ musb = allocate_instance(dev, ctrl);
+ if (!musb)
+ return -ENOMEM;
+
+ spin_lock_init(&musb->lock);
+ musb->board_mode = plat->mode;
+ musb->board_set_power = plat->set_power;
+ musb->set_clock = plat->set_clock;
+ musb->min_power = plat->min_power;
+
+ /* Clock usage is chip-specific ... functional clock (DaVinci,
+ * OMAP2430), or PHY ref (some TUSB6010 boards). All this core
+ * code does is make sure a clock handle is available; platform
+ * code manages it during start/stop and suspend/resume.
+ */
+ if (plat->clock) {
+ musb->clock = clk_get(dev, plat->clock);
+ if (IS_ERR(musb->clock)) {
+ status = PTR_ERR(musb->clock);
+ musb->clock = NULL;
+ goto fail;
+ }
+ }
+
+ /* assume vbus is off */
+
+ /* platform adjusts musb->mregs and musb->isr if needed,
+ * and activates clocks
+ */
+ musb->isr = generic_interrupt;
+ status = musb_platform_init(musb);
+
+ if (status < 0)
+ goto fail;
+ if (!musb->isr) {
+ status = -ENODEV;
+ goto fail2;
+ }
+
+#ifndef CONFIG_MUSB_PIO_ONLY
+ if (use_dma && dev->dma_mask) {
+ struct dma_controller *c;
+
+ c = dma_controller_create(musb, musb->mregs);
+ musb->dma_controller = c;
+ if (c)
+ (void) c->start(c);
+ }
+#endif
+ /* ideally this would be abstracted in platform setup */
+ if (!is_dma_capable() || !musb->dma_controller)
+ dev->dma_mask = NULL;
+
+ /* be sure interrupts are disabled before connecting ISR */
+ musb_platform_disable(musb);
+ musb_generic_disable(musb);
+
+ /* setup musb parts of the core (especially endpoints) */
+ status = musb_core_init(plat->multipoint
+ ? MUSB_CONTROLLER_MHDRC
+ : MUSB_CONTROLLER_HDRC, musb);
+ if (status < 0)
+ goto fail2;
+
+ /* Init IRQ workqueue before request_irq */
+ INIT_WORK(&musb->irq_work, musb_irq_work);
+
+ /* attach to the IRQ */
+ if (request_irq(nIrq, musb->isr, 0, dev->bus_id, musb)) {
+ dev_err(dev, "request_irq %d failed!\n", nIrq);
+ status = -ENODEV;
+ goto fail2;
+ }
+ musb->nIrq = nIrq;
+/* FIXME this handles wakeup irqs wrong */
+ if (enable_irq_wake(nIrq) == 0)
+ device_init_wakeup(dev, 1);
+
+ pr_info("%s: USB %s mode controller at %p using %s, IRQ %d\n",
+ musb_driver_name,
+ ({char *s;
+ switch (musb->board_mode) {
+ case MUSB_HOST: s = "Host"; break;
+ case MUSB_PERIPHERAL: s = "Peripheral"; break;
+ default: s = "OTG"; break;
+ }; s; }),
+ ctrl,
+ (is_dma_capable() && musb->dma_controller)
+ ? "DMA" : "PIO",
+ musb->nIrq);
+
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+ /* host side needs more setup, except for no-host modes */
+ if (musb->board_mode != MUSB_PERIPHERAL) {
+ struct usb_hcd *hcd = musb_to_hcd(musb);
+
+ if (musb->board_mode == MUSB_OTG)
+ hcd->self.otg_port = 1;
+ musb->xceiv.host = &hcd->self;
+ hcd->power_budget = 2 * (plat->power ? : 250);
+ }
+#endif /* CONFIG_USB_MUSB_HDRC_HCD */
+
+ /* For the host-only role, we can activate right away.
+ * (We expect the ID pin to be forcibly grounded!!)
+ * Otherwise, wait till the gadget driver hooks up.
+ */
+ if (!is_otg_enabled(musb) && is_host_enabled(musb)) {
+ MUSB_HST_MODE(musb);
+ musb->xceiv.default_a = 1;
+ musb->xceiv.state = OTG_STATE_A_IDLE;
+
+ status = usb_add_hcd(musb_to_hcd(musb), -1, 0);
+
+ DBG(1, "%s mode, status %d, devctl %02x %c\n",
+ "HOST", status,
+ musb_readb(musb->mregs, MUSB_DEVCTL),
+ (musb_readb(musb->mregs, MUSB_DEVCTL)
+ & MUSB_DEVCTL_BDEVICE
+ ? 'B' : 'A'));
+
+ } else /* peripheral is enabled */ {
+ MUSB_DEV_MODE(musb);
+ musb->xceiv.default_a = 0;
+ musb->xceiv.state = OTG_STATE_B_IDLE;
+
+ status = musb_gadget_setup(musb);
+
+ DBG(1, "%s mode, status %d, dev%02x\n",
+ is_otg_enabled(musb) ? "OTG" : "PERIPHERAL",
+ status,
+ musb_readb(musb->mregs, MUSB_DEVCTL));
+
+ }
+
+ if (status == 0)
+ musb_debug_create("driver/musb_hdrc", musb);
+ else {
+fail:
+ if (musb->clock)
+ clk_put(musb->clock);
+ device_init_wakeup(dev, 0);
+ musb_free(musb);
+ return status;
+ }
+
+#ifdef CONFIG_SYSFS
+ status = device_create_file(dev, &dev_attr_mode);
+ status = device_create_file(dev, &dev_attr_vbus);
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+ status = device_create_file(dev, &dev_attr_srp);
+#endif /* CONFIG_USB_GADGET_MUSB_HDRC */
+ status = 0;
+#endif
+
+ return status;
+
+fail2:
+ musb_platform_exit(musb);
+ goto fail;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* all implementations (PCI bridge to FPGA, VLYNQ, etc) should just
+ * bridge to a platform device; this driver then suffices.
+ */
+
+#ifndef CONFIG_MUSB_PIO_ONLY
+static u64 *orig_dma_mask;
+#endif
+
+static int __init musb_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ int irq = platform_get_irq(pdev, 0);
+ struct resource *iomem;
+ void __iomem *base;
+
+ iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!iomem || irq == 0)
+ return -ENODEV;
+
+ base = ioremap(iomem->start, iomem->end - iomem->start + 1);
+ if (!base) {
+ dev_err(dev, "ioremap failed\n");
+ return -ENOMEM;
+ }
+
+#ifndef CONFIG_MUSB_PIO_ONLY
+ /* clobbered by use_dma=n */
+ orig_dma_mask = dev->dma_mask;
+#endif
+ return musb_init_controller(dev, irq, base);
+}
+
+static int __devexit musb_remove(struct platform_device *pdev)
+{
+ struct musb *musb = dev_to_musb(&pdev->dev);
+ void __iomem *ctrl_base = musb->ctrl_base;
+
+ /* this gets called on rmmod.
+ * - Host mode: host may still be active
+ * - Peripheral mode: peripheral is deactivated (or never-activated)
+ * - OTG mode: both roles are deactivated (or never-activated)
+ */
+ musb_shutdown(pdev);
+ musb_debug_delete("driver/musb_hdrc", musb);
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+ if (musb->board_mode == MUSB_HOST)
+ usb_remove_hcd(musb_to_hcd(musb));
+#endif
+ musb_free(musb);
+ iounmap(ctrl_base);
+ device_init_wakeup(&pdev->dev, 0);
+#ifndef CONFIG_MUSB_PIO_ONLY
+ pdev->dev.dma_mask = orig_dma_mask;
+#endif
+ return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int musb_suspend(struct platform_device *pdev, pm_message_t message)
+{
+ unsigned long flags;
+ struct musb *musb = dev_to_musb(&pdev->dev);
+
+ if (!musb->clock)
+ return 0;
+
+ spin_lock_irqsave(&musb->lock, flags);
+
+ if (is_peripheral_active(musb)) {
+ /* FIXME force disconnect unless we know USB will wake
+ * the system up quickly enough to respond ...
+ */
+ } else if (is_host_active(musb)) {
+ /* we know all the children are suspended; sometimes
+ * they will even be wakeup-enabled.
+ */
+ }
+
+ if (musb->set_clock)
+ musb->set_clock(musb->clock, 0);
+ else
+ clk_disable(musb->clock);
+ spin_unlock_irqrestore(&musb->lock, flags);
+ return 0;
+}
+
+static int musb_resume(struct platform_device *pdev)
+{
+ unsigned long flags;
+ struct musb *musb = dev_to_musb(&pdev->dev);
+
+ if (!musb->clock)
+ return 0;
+
+ spin_lock_irqsave(&musb->lock, flags);
+
+ if (musb->set_clock)
+ musb->set_clock(musb->clock, 1);
+ else
+ clk_enable(musb->clock);
+
+ /* for static cmos like DaVinci, register values were preserved
+ * unless for some reason the whole soc powered down and we're
+ * not treating that as a whole-system restart (e.g. swsusp)
+ */
+ spin_unlock_irqrestore(&musb->lock, flags);
+ return 0;
+}
+
+#else
+#define musb_suspend NULL
+#define musb_resume NULL
+#endif
+
+static struct platform_driver musb_driver = {
+ .driver = {
+ .name = (char *)musb_driver_name,
+ .bus = &platform_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .remove = __devexit_p(musb_remove),
+ .shutdown = musb_shutdown,
+ .suspend = musb_suspend,
+ .resume = musb_resume,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int __init musb_init(void)
+{
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+ if (usb_disabled())
+ return 0;
+#endif
+
+ pr_info("%s: version " MUSB_VERSION ", "
+#ifdef CONFIG_MUSB_PIO_ONLY
+ "pio"
+#elif defined(CONFIG_USB_TI_CPPI_DMA)
+ "cppi-dma"
+#elif defined(CONFIG_USB_INVENTRA_DMA)
+ "musb-dma"
+#elif defined(CONFIG_USB_TUSB_OMAP_DMA)
+ "tusb-omap-dma"
+#else
+ "?dma?"
+#endif
+ ", "
+#ifdef CONFIG_USB_MUSB_OTG
+ "otg (peripheral+host)"
+#elif defined(CONFIG_USB_GADGET_MUSB_HDRC)
+ "peripheral"
+#elif defined(CONFIG_USB_MUSB_HDRC_HCD)
+ "host"
+#endif
+ ", debug=%d\n",
+ musb_driver_name, debug);
+ return platform_driver_probe(&musb_driver, musb_probe);
+}
+
+/* make us init after usbcore and before usb
+ * gadget and host-side drivers start to register
+ */
+subsys_initcall(musb_init);
+
+static void __exit musb_cleanup(void)
+{
+ platform_driver_unregister(&musb_driver);
+}
+module_exit(musb_cleanup);
--- /dev/null
+/*
+ * MUSB OTG driver defines
+ *
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ * Copyright (C) 2006-2007 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * 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 AUTHORS 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.
+ *
+ */
+
+#ifndef __MUSB_CORE_H__
+#define __MUSB_CORE_H__
+
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/musb.h>
+
+struct musb;
+struct musb_hw_ep;
+struct musb_ep;
+
+
+#include "musb_debug.h"
+#include "musb_dma.h"
+
+#ifdef CONFIG_USB_MUSB_SOC
+/*
+ * Get core configuration from a header converted (by cfg_conv)
+ * from the Verilog config file generated by the core config utility
+ *
+ * For now we assume that header is provided along with other
+ * arch-specific files. Discrete chips will need a build tweak.
+ * So will using AHB IDs from silicon that provides them.
+ */
+#include <asm/arch/hdrc_cnf.h>
+#endif
+
+#include "musb_io.h"
+#include "musb_regs.h"
+
+#include "musb_gadget.h"
+#include "../core/hcd.h"
+#include "musb_host.h"
+
+
+
+#ifdef CONFIG_USB_MUSB_OTG
+
+#define is_peripheral_enabled(musb) ((musb)->board_mode != MUSB_HOST)
+#define is_host_enabled(musb) ((musb)->board_mode != MUSB_PERIPHERAL)
+#define is_otg_enabled(musb) ((musb)->board_mode == MUSB_OTG)
+
+/* NOTE: otg and peripheral-only state machines start at B_IDLE.
+ * OTG or host-only go to A_IDLE when ID is sensed.
+ */
+#define is_peripheral_active(m) (!(m)->is_host)
+#define is_host_active(m) ((m)->is_host)
+
+#else
+#define is_peripheral_enabled(musb) is_peripheral_capable()
+#define is_host_enabled(musb) is_host_capable()
+#define is_otg_enabled(musb) 0
+
+#define is_peripheral_active(musb) is_peripheral_capable()
+#define is_host_active(musb) is_host_capable()
+#endif
+
+#if defined(CONFIG_USB_MUSB_OTG) || defined(CONFIG_USB_MUSB_PERIPHERAL)
+/* for some reason, the "select USB_GADGET_MUSB_HDRC" doesn't always
+ * override that choice selection (often USB_GADGET_DUMMY_HCD).
+ */
+#ifndef CONFIG_USB_GADGET_MUSB_HDRC
+#error bogus Kconfig output ... select CONFIG_USB_GADGET_MUSB_HDRC
+#endif
+#endif /* need MUSB gadget selection */
+
+
+#ifdef CONFIG_PROC_FS
+#include <linux/fs.h>
+#define MUSB_CONFIG_PROC_FS
+#endif
+
+/****************************** PERIPHERAL ROLE *****************************/
+
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+
+#define is_peripheral_capable() (1)
+
+extern irqreturn_t musb_g_ep0_irq(struct musb *);
+extern void musb_g_tx(struct musb *, u8);
+extern void musb_g_rx(struct musb *, u8);
+extern void musb_g_reset(struct musb *);
+extern void musb_g_suspend(struct musb *);
+extern void musb_g_resume(struct musb *);
+extern void musb_g_wakeup(struct musb *);
+extern void musb_g_disconnect(struct musb *);
+
+#else
+
+#define is_peripheral_capable() (0)
+
+static inline irqreturn_t musb_g_ep0_irq(struct musb *m) { return IRQ_NONE; }
+static inline void musb_g_reset(struct musb *m) {}
+static inline void musb_g_suspend(struct musb *m) {}
+static inline void musb_g_resume(struct musb *m) {}
+static inline void musb_g_wakeup(struct musb *m) {}
+static inline void musb_g_disconnect(struct musb *m) {}
+
+#endif
+
+/****************************** HOST ROLE ***********************************/
+
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+
+#define is_host_capable() (1)
+
+extern irqreturn_t musb_h_ep0_irq(struct musb *);
+extern void musb_host_tx(struct musb *, u8);
+extern void musb_host_rx(struct musb *, u8);
+
+#else
+
+#define is_host_capable() (0)
+
+static inline irqreturn_t musb_h_ep0_irq(struct musb *m) { return IRQ_NONE; }
+static inline void musb_host_tx(struct musb *m, u8 e) {}
+static inline void musb_host_rx(struct musb *m, u8 e) {}
+
+#endif
+
+
+/****************************** CONSTANTS ********************************/
+
+#ifndef MUSB_C_NUM_EPS
+#define MUSB_C_NUM_EPS ((u8)16)
+#endif
+
+#ifndef MUSB_MAX_END0_PACKET
+#define MUSB_MAX_END0_PACKET ((u16)MUSB_EP0_FIFOSIZE)
+#endif
+
+/* host side ep0 states */
+enum musb_h_ep0_state {
+ MUSB_EP0_IDLE,
+ MUSB_EP0_START, /* expect ack of setup */
+ MUSB_EP0_IN, /* expect IN DATA */
+ MUSB_EP0_OUT, /* expect ack of OUT DATA */
+ MUSB_EP0_STATUS, /* expect ack of STATUS */
+} __attribute__ ((packed));
+
+/* peripheral side ep0 states */
+enum musb_g_ep0_state {
+ MUSB_EP0_STAGE_SETUP, /* idle, waiting for setup */
+ MUSB_EP0_STAGE_TX, /* IN data */
+ MUSB_EP0_STAGE_RX, /* OUT data */
+ MUSB_EP0_STAGE_STATUSIN, /* (after OUT data) */
+ MUSB_EP0_STAGE_STATUSOUT, /* (after IN data) */
+ MUSB_EP0_STAGE_ACKWAIT, /* after zlp, before statusin */
+} __attribute__ ((packed));
+
+/* OTG protocol constants */
+#define OTG_TIME_A_WAIT_VRISE 100 /* msec (max) */
+#define OTG_TIME_A_WAIT_BCON 0 /* 0=infinite; min 1000 msec */
+#define OTG_TIME_A_IDLE_BDIS 200 /* msec (min) */
+
+/*************************** REGISTER ACCESS ********************************/
+
+/* Endpoint registers (other than dynfifo setup) can be accessed either
+ * directly with the "flat" model, or after setting up an index register.
+ */
+
+#if defined(CONFIG_ARCH_DAVINCI) || defined(CONFIG_ARCH_OMAP2430) \
+ || defined(CONFIG_ARCH_OMAP3430)
+/* REVISIT indexed access seemed to
+ * misbehave (on DaVinci) for at least peripheral IN ...
+ */
+#define MUSB_FLAT_REG
+#endif
+
+/* TUSB mapping: "flat" plus ep0 special cases */
+#if defined(CONFIG_USB_TUSB6010)
+#define musb_ep_select(_mbase, _epnum) \
+ musb_writeb((_mbase), MUSB_INDEX, (_epnum))
+#define MUSB_EP_OFFSET MUSB_TUSB_OFFSET
+
+/* "flat" mapping: each endpoint has its own i/o address */
+#elif defined(MUSB_FLAT_REG)
+#define musb_ep_select(_mbase, _epnum) (((void)(_mbase)), ((void)(_epnum)))
+#define MUSB_EP_OFFSET MUSB_FLAT_OFFSET
+
+/* "indexed" mapping: INDEX register controls register bank select */
+#else
+#define musb_ep_select(_mbase, _epnum) \
+ musb_writeb((_mbase), MUSB_INDEX, (_epnum))
+#define MUSB_EP_OFFSET MUSB_INDEXED_OFFSET
+#endif
+
+/****************************** FUNCTIONS ********************************/
+
+#define MUSB_HST_MODE(_musb)\
+ { (_musb)->is_host = true; }
+#define MUSB_DEV_MODE(_musb) \
+ { (_musb)->is_host = false; }
+
+#define test_devctl_hst_mode(_x) \
+ (musb_readb((_x)->mregs, MUSB_DEVCTL)&MUSB_DEVCTL_HM)
+
+#define MUSB_MODE(musb) ((musb)->is_host ? "Host" : "Peripheral")
+
+/******************************** TYPES *************************************/
+
+/*
+ * struct musb_hw_ep - endpoint hardware (bidirectional)
+ *
+ * Ordered slightly for better cacheline locality.
+ */
+struct musb_hw_ep {
+ struct musb *musb;
+ void __iomem *fifo;
+ void __iomem *regs;
+
+#ifdef CONFIG_USB_TUSB6010
+ void __iomem *conf;
+#endif
+
+ /* index in musb->endpoints[] */
+ u8 epnum;
+
+ /* hardware configuration, possibly dynamic */
+ bool is_shared_fifo;
+ bool tx_double_buffered;
+ bool rx_double_buffered;
+ u16 max_packet_sz_tx;
+ u16 max_packet_sz_rx;
+
+ struct dma_channel *tx_channel;
+ struct dma_channel *rx_channel;
+
+#ifdef CONFIG_USB_TUSB6010
+ /* TUSB has "asynchronous" and "synchronous" dma modes */
+ dma_addr_t fifo_async;
+ dma_addr_t fifo_sync;
+ void __iomem *fifo_sync_va;
+#endif
+
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+ void __iomem *target_regs;
+
+ /* currently scheduled peripheral endpoint */
+ struct musb_qh *in_qh;
+ struct musb_qh *out_qh;
+
+ u8 rx_reinit;
+ u8 tx_reinit;
+#endif
+
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+ /* peripheral side */
+ struct musb_ep ep_in; /* TX */
+ struct musb_ep ep_out; /* RX */
+#endif
+};
+
+static inline struct usb_request *next_in_request(struct musb_hw_ep *hw_ep)
+{
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+ return next_request(&hw_ep->ep_in);
+#else
+ return NULL;
+#endif
+}
+
+static inline struct usb_request *next_out_request(struct musb_hw_ep *hw_ep)
+{
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+ return next_request(&hw_ep->ep_out);
+#else
+ return NULL;
+#endif
+}
+
+/*
+ * struct musb - Driver instance data.
+ */
+struct musb {
+ spinlock_t lock;
+ struct clk *clock;
+ irqreturn_t (*isr)(int, void *);
+ struct work_struct irq_work;
+
+/* this hub status bit is reserved by USB 2.0 and not seen by usbcore */
+#define MUSB_PORT_STAT_RESUME (1 << 31)
+
+ u32 port1_status;
+
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+ unsigned long rh_timer;
+
+ enum musb_h_ep0_state ep0_stage;
+
+ /* bulk traffic normally dedicates endpoint hardware, and each
+ * direction has its own ring of host side endpoints.
+ * we try to progress the transfer at the head of each endpoint's
+ * queue until it completes or NAKs too much; then we try the next
+ * endpoint.
+ */
+ struct musb_hw_ep *bulk_ep;
+
+ struct list_head control; /* of musb_qh */
+ struct list_head in_bulk; /* of musb_qh */
+ struct list_head out_bulk; /* of musb_qh */
+ struct musb_qh *periodic[32]; /* tree of interrupt+iso */
+#endif
+
+ /* called with IRQs blocked; ON/nonzero implies starting a session,
+ * and waiting at least a_wait_vrise_tmout.
+ */
+ void (*board_set_vbus)(struct musb *, int is_on);
+
+ struct dma_controller *dma_controller;
+
+ struct device *controller;
+ void __iomem *ctrl_base;
+ void __iomem *mregs;
+
+#ifdef CONFIG_USB_TUSB6010
+ dma_addr_t async;
+ dma_addr_t sync;
+ void __iomem *sync_va;
+#endif
+
+ /* passed down from chip/board specific irq handlers */
+ u8 int_usb;
+ u16 int_rx;
+ u16 int_tx;
+
+ struct otg_transceiver xceiv;
+
+ int nIrq;
+
+ struct musb_hw_ep endpoints[MUSB_C_NUM_EPS];
+#define control_ep endpoints
+
+#define VBUSERR_RETRY_COUNT 3
+ u16 vbuserr_retry;
+ u16 epmask;
+ u8 nr_endpoints;
+
+ u8 board_mode; /* enum musb_mode */
+ int (*board_set_power)(int state);
+
+ int (*set_clock)(struct clk *clk, int is_active);
+
+ u8 min_power; /* vbus for periph, in mA/2 */
+
+ bool is_host;
+
+ int a_wait_bcon; /* VBUS timeout in msecs */
+ unsigned long idle_timeout; /* Next timeout in jiffies */
+
+ /* active means connected and not suspended */
+ unsigned is_active:1;
+
+ unsigned is_multipoint:1;
+ unsigned ignore_disconnect:1; /* during bus resets */
+
+#ifdef C_MP_TX
+ unsigned bulk_split:1;
+#define can_bulk_split(musb,type) \
+ (((type) == USB_ENDPOINT_XFER_BULK) && (musb)->bulk_split)
+#else
+#define can_bulk_split(musb, type) 0
+#endif
+
+#ifdef C_MP_RX
+ unsigned bulk_combine:1;
+#define can_bulk_combine(musb,type) \
+ (((type) == USB_ENDPOINT_XFER_BULK) && (musb)->bulk_combine)
+#else
+#define can_bulk_combine(musb, type) 0
+#endif
+
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+ /* is_suspended means USB B_PERIPHERAL suspend */
+ unsigned is_suspended:1;
+
+ /* may_wakeup means remote wakeup is enabled */
+ unsigned may_wakeup:1;
+
+ /* is_self_powered is reported in device status and the
+ * config descriptor. is_bus_powered means B_PERIPHERAL
+ * draws some VBUS current; both can be true.
+ */
+ unsigned is_self_powered:1;
+ unsigned is_bus_powered:1;
+
+ unsigned set_address:1;
+ unsigned test_mode:1;
+ unsigned softconnect:1;
+
+ u8 address;
+ u8 test_mode_nr;
+ u16 ackpend; /* ep0 */
+ enum musb_g_ep0_state ep0_state;
+ struct usb_gadget g; /* the gadget */
+ struct usb_gadget_driver *gadget_driver; /* its driver */
+#endif
+
+#ifdef MUSB_CONFIG_PROC_FS
+ struct proc_dir_entry *proc_entry;
+#endif
+};
+
+static inline void musb_set_vbus(struct musb *musb, int is_on)
+{
+ musb->board_set_vbus(musb, is_on);
+}
+
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+static inline struct musb *gadget_to_musb(struct usb_gadget *g)
+{
+ return container_of(g, struct musb, g);
+}
+#endif
+
+
+/***************************** Glue it together *****************************/
+
+extern const char musb_driver_name[];
+
+extern void musb_start(struct musb *musb);
+extern void musb_stop(struct musb *musb);
+
+extern void musb_write_fifo(struct musb_hw_ep *ep, u16 len, const u8 *src);
+extern void musb_read_fifo(struct musb_hw_ep *ep, u16 len, u8 *dst);
+
+extern void musb_load_testpacket(struct musb *);
+
+extern irqreturn_t musb_interrupt(struct musb *);
+
+extern void musb_platform_enable(struct musb *musb);
+extern void musb_platform_disable(struct musb *musb);
+
+extern void musb_hnp_stop(struct musb *musb);
+
+extern void musb_platform_set_mode(struct musb *musb, u8 musb_mode);
+
+#if defined(CONFIG_USB_TUSB6010) || \
+ defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX)
+extern void musb_platform_try_idle(struct musb *musb, unsigned long timeout);
+#else
+#define musb_platform_try_idle(x, y) do {} while (0)
+#endif
+
+#ifdef CONFIG_USB_TUSB6010
+extern int musb_platform_get_vbus_status(struct musb *musb);
+#else
+#define musb_platform_get_vbus_status(x) 0
+#endif
+
+extern int __init musb_platform_init(struct musb *musb);
+extern int musb_platform_exit(struct musb *musb);
+
+/*-------------------------- ProcFS definitions ---------------------*/
+
+struct proc_dir_entry;
+
+#if (MUSB_DEBUG > 0) && defined(MUSB_CONFIG_PROC_FS)
+extern struct proc_dir_entry *musb_debug_create(char *name, struct musb *data);
+extern void musb_debug_delete(char *name, struct musb *data);
+
+#else
+static inline struct proc_dir_entry *
+musb_debug_create(char *name, struct musb *data)
+{
+ return NULL;
+}
+static inline void musb_debug_delete(char *name, struct musb *data)
+{
+}
+#endif
+
+#endif /* __MUSB_CORE_H__ */
--- /dev/null
+/*
+ * MUSB OTG driver debug defines
+ *
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ * Copyright (C) 2006-2007 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * 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 AUTHORS 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.
+ *
+ */
+
+#ifndef __MUSB_LINUX_DEBUG_H__
+#define __MUSB_LINUX_DEBUG_H__
+
+#define yprintk(facility, format, args...) \
+ do { printk(facility "%s %d: " format , \
+ __func__, __LINE__ , ## args); } while (0)
+#define WARN(fmt, args...) yprintk(KERN_WARNING, fmt, ## args)
+#define INFO(fmt, args...) yprintk(KERN_INFO, fmt, ## args)
+#define ERR(fmt, args...) yprintk(KERN_ERR, fmt, ## args)
+
+#define xprintk(level, facility, format, args...) do { \
+ if (_dbg_level(level)) { \
+ printk(facility "%s %d: " format , \
+ __func__, __LINE__ , ## args); \
+ } } while (0)
+
+#if MUSB_DEBUG > 0
+extern unsigned debug;
+#else
+#define debug 0
+#endif
+
+static inline int _dbg_level(unsigned l)
+{
+ return debug >= l;
+}
+
+#define DBG(level, fmt, args...) xprintk(level, KERN_DEBUG, fmt, ## args)
+
+extern const char *otg_state_string(struct musb *);
+
+#endif /* __MUSB_LINUX_DEBUG_H__ */
--- /dev/null
+/*
+ * MUSB OTG driver DMA controller abstraction
+ *
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ * Copyright (C) 2006-2007 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * 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 AUTHORS 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.
+ *
+ */
+
+#ifndef __MUSB_DMA_H__
+#define __MUSB_DMA_H__
+
+struct musb_hw_ep;
+
+/*
+ * DMA Controller Abstraction
+ *
+ * DMA Controllers are abstracted to allow use of a variety of different
+ * implementations of DMA, as allowed by the Inventra USB cores. On the
+ * host side, usbcore sets up the DMA mappings and flushes caches; on the
+ * peripheral side, the gadget controller driver does. Responsibilities
+ * of a DMA controller driver include:
+ *
+ * - Handling the details of moving multiple USB packets
+ * in cooperation with the Inventra USB core, including especially
+ * the correct RX side treatment of short packets and buffer-full
+ * states (both of which terminate transfers).
+ *
+ * - Knowing the correlation between dma channels and the
+ * Inventra core's local endpoint resources and data direction.
+ *
+ * - Maintaining a list of allocated/available channels.
+ *
+ * - Updating channel status on interrupts,
+ * whether shared with the Inventra core or separate.
+ */
+
+#define DMA_ADDR_INVALID (~(dma_addr_t)0)
+
+#ifndef CONFIG_MUSB_PIO_ONLY
+#define is_dma_capable() (1)
+#else
+#define is_dma_capable() (0)
+#endif
+
+#ifdef CONFIG_USB_TI_CPPI_DMA
+#define is_cppi_enabled() 1
+#else
+#define is_cppi_enabled() 0
+#endif
+
+#ifdef CONFIG_USB_TUSB_OMAP_DMA
+#define tusb_dma_omap() 1
+#else
+#define tusb_dma_omap() 0
+#endif
+
+/*
+ * DMA channel status ... updated by the dma controller driver whenever that
+ * status changes, and protected by the overall controller spinlock.
+ */
+enum dma_channel_status {
+ /* unallocated */
+ MUSB_DMA_STATUS_UNKNOWN,
+ /* allocated ... but not busy, no errors */
+ MUSB_DMA_STATUS_FREE,
+ /* busy ... transactions are active */
+ MUSB_DMA_STATUS_BUSY,
+ /* transaction(s) aborted due to ... dma or memory bus error */
+ MUSB_DMA_STATUS_BUS_ABORT,
+ /* transaction(s) aborted due to ... core error or USB fault */
+ MUSB_DMA_STATUS_CORE_ABORT
+};
+
+struct dma_controller;
+
+/**
+ * struct dma_channel - A DMA channel.
+ * @private_data: channel-private data
+ * @max_len: the maximum number of bytes the channel can move in one
+ * transaction (typically representing many USB maximum-sized packets)
+ * @actual_len: how many bytes have been transferred
+ * @status: current channel status (updated e.g. on interrupt)
+ * @desired_mode: true if mode 1 is desired; false if mode 0 is desired
+ *
+ * channels are associated with an endpoint for the duration of at least
+ * one usb transfer.
+ */
+struct dma_channel {
+ void *private_data;
+ /* FIXME not void* private_data, but a dma_controller * */
+ size_t max_len;
+ size_t actual_len;
+ enum dma_channel_status status;
+ bool desired_mode;
+};
+
+/*
+ * dma_channel_status - return status of dma channel
+ * @c: the channel
+ *
+ * Returns the software's view of the channel status. If that status is BUSY
+ * then it's possible that the hardware has completed (or aborted) a transfer,
+ * so the driver needs to update that status.
+ */
+static inline enum dma_channel_status
+dma_channel_status(struct dma_channel *c)
+{
+ return (is_dma_capable() && c) ? c->status : MUSB_DMA_STATUS_UNKNOWN;
+}
+
+/**
+ * struct dma_controller - A DMA Controller.
+ * @start: call this to start a DMA controller;
+ * return 0 on success, else negative errno
+ * @stop: call this to stop a DMA controller
+ * return 0 on success, else negative errno
+ * @channel_alloc: call this to allocate a DMA channel
+ * @channel_release: call this to release a DMA channel
+ * @channel_abort: call this to abort a pending DMA transaction,
+ * returning it to FREE (but allocated) state
+ *
+ * Controllers manage dma channels.
+ */
+struct dma_controller {
+ int (*start)(struct dma_controller *);
+ int (*stop)(struct dma_controller *);
+ struct dma_channel *(*channel_alloc)(struct dma_controller *,
+ struct musb_hw_ep *, u8 is_tx);
+ void (*channel_release)(struct dma_channel *);
+ int (*channel_program)(struct dma_channel *channel,
+ u16 maxpacket, u8 mode,
+ dma_addr_t dma_addr,
+ u32 length);
+ int (*channel_abort)(struct dma_channel *);
+};
+
+/* called after channel_program(), may indicate a fault */
+extern void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit);
+
+
+extern struct dma_controller *__init
+dma_controller_create(struct musb *, void __iomem *);
+
+extern void dma_controller_destroy(struct dma_controller *);
+
+#endif /* __MUSB_DMA_H__ */
--- /dev/null
+/*
+ * MUSB OTG driver peripheral support
+ *
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ * Copyright (C) 2006-2007 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * 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 AUTHORS 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/module.h>
+#include <linux/smp.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/moduleparam.h>
+#include <linux/stat.h>
+#include <linux/dma-mapping.h>
+
+#include "musb_core.h"
+
+
+/* MUSB PERIPHERAL status 3-mar-2006:
+ *
+ * - EP0 seems solid. It passes both USBCV and usbtest control cases.
+ * Minor glitches:
+ *
+ * + remote wakeup to Linux hosts work, but saw USBCV failures;
+ * in one test run (operator error?)
+ * + endpoint halt tests -- in both usbtest and usbcv -- seem
+ * to break when dma is enabled ... is something wrongly
+ * clearing SENDSTALL?
+ *
+ * - Mass storage behaved ok when last tested. Network traffic patterns
+ * (with lots of short transfers etc) need retesting; they turn up the
+ * worst cases of the DMA, since short packets are typical but are not
+ * required.
+ *
+ * - TX/IN
+ * + both pio and dma behave in with network and g_zero tests
+ * + no cppi throughput issues other than no-hw-queueing
+ * + failed with FLAT_REG (DaVinci)
+ * + seems to behave with double buffering, PIO -and- CPPI
+ * + with gadgetfs + AIO, requests got lost?
+ *
+ * - RX/OUT
+ * + both pio and dma behave in with network and g_zero tests
+ * + dma is slow in typical case (short_not_ok is clear)
+ * + double buffering ok with PIO
+ * + double buffering *FAILS* with CPPI, wrong data bytes sometimes
+ * + request lossage observed with gadgetfs
+ *
+ * - ISO not tested ... might work, but only weakly isochronous
+ *
+ * - Gadget driver disabling of softconnect during bind() is ignored; so
+ * drivers can't hold off host requests until userspace is ready.
+ * (Workaround: they can turn it off later.)
+ *
+ * - PORTABILITY (assumes PIO works):
+ * + DaVinci, basically works with cppi dma
+ * + OMAP 2430, ditto with mentor dma
+ * + TUSB 6010, platform-specific dma in the works
+ */
+
+/* ----------------------------------------------------------------------- */
+
+/*
+ * Immediately complete a request.
+ *
+ * @param request the request to complete
+ * @param status the status to complete the request with
+ * Context: controller locked, IRQs blocked.
+ */
+void musb_g_giveback(
+ struct musb_ep *ep,
+ struct usb_request *request,
+ int status)
+__releases(ep->musb->lock)
+__acquires(ep->musb->lock)
+{
+ struct musb_request *req;
+ struct musb *musb;
+ int busy = ep->busy;
+
+ req = to_musb_request(request);
+
+ list_del(&request->list);
+ if (req->request.status == -EINPROGRESS)
+ req->request.status = status;
+ musb = req->musb;
+
+ ep->busy = 1;
+ spin_unlock(&musb->lock);
+ if (is_dma_capable()) {
+ if (req->mapped) {
+ dma_unmap_single(musb->controller,
+ req->request.dma,
+ req->request.length,
+ req->tx
+ ? DMA_TO_DEVICE
+ : DMA_FROM_DEVICE);
+ req->request.dma = DMA_ADDR_INVALID;
+ req->mapped = 0;
+ } else if (req->request.dma != DMA_ADDR_INVALID)
+ dma_sync_single_for_cpu(musb->controller,
+ req->request.dma,
+ req->request.length,
+ req->tx
+ ? DMA_TO_DEVICE
+ : DMA_FROM_DEVICE);
+ }
+ if (request->status == 0)
+ DBG(5, "%s done request %p, %d/%d\n",
+ ep->end_point.name, request,
+ req->request.actual, req->request.length);
+ else
+ DBG(2, "%s request %p, %d/%d fault %d\n",
+ ep->end_point.name, request,
+ req->request.actual, req->request.length,
+ request->status);
+ req->request.complete(&req->ep->end_point, &req->request);
+ spin_lock(&musb->lock);
+ ep->busy = busy;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/*
+ * Abort requests queued to an endpoint using the status. Synchronous.
+ * caller locked controller and blocked irqs, and selected this ep.
+ */
+static void nuke(struct musb_ep *ep, const int status)
+{
+ struct musb_request *req = NULL;
+ void __iomem *epio = ep->musb->endpoints[ep->current_epnum].regs;
+
+ ep->busy = 1;
+
+ if (is_dma_capable() && ep->dma) {
+ struct dma_controller *c = ep->musb->dma_controller;
+ int value;
+ if (ep->is_in) {
+ musb_writew(epio, MUSB_TXCSR,
+ 0 | MUSB_TXCSR_FLUSHFIFO);
+ musb_writew(epio, MUSB_TXCSR,
+ 0 | MUSB_TXCSR_FLUSHFIFO);
+ } else {
+ musb_writew(epio, MUSB_RXCSR,
+ 0 | MUSB_RXCSR_FLUSHFIFO);
+ musb_writew(epio, MUSB_RXCSR,
+ 0 | MUSB_RXCSR_FLUSHFIFO);
+ }
+
+ value = c->channel_abort(ep->dma);
+ DBG(value ? 1 : 6, "%s: abort DMA --> %d\n", ep->name, value);
+ c->channel_release(ep->dma);
+ ep->dma = NULL;
+ }
+
+ while (!list_empty(&(ep->req_list))) {
+ req = container_of(ep->req_list.next, struct musb_request,
+ request.list);
+ musb_g_giveback(ep, &req->request, status);
+ }
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* Data transfers - pure PIO, pure DMA, or mixed mode */
+
+/*
+ * This assumes the separate CPPI engine is responding to DMA requests
+ * from the usb core ... sequenced a bit differently from mentor dma.
+ */
+
+static inline int max_ep_writesize(struct musb *musb, struct musb_ep *ep)
+{
+ if (can_bulk_split(musb, ep->type))
+ return ep->hw_ep->max_packet_sz_tx;
+ else
+ return ep->packet_sz;
+}
+
+
+#ifdef CONFIG_USB_INVENTRA_DMA
+
+/* Peripheral tx (IN) using Mentor DMA works as follows:
+ Only mode 0 is used for transfers <= wPktSize,
+ mode 1 is used for larger transfers,
+
+ One of the following happens:
+ - Host sends IN token which causes an endpoint interrupt
+ -> TxAvail
+ -> if DMA is currently busy, exit.
+ -> if queue is non-empty, txstate().
+
+ - Request is queued by the gadget driver.
+ -> if queue was previously empty, txstate()
+
+ txstate()
+ -> start
+ /\ -> setup DMA
+ | (data is transferred to the FIFO, then sent out when
+ | IN token(s) are recd from Host.
+ | -> DMA interrupt on completion
+ | calls TxAvail.
+ | -> stop DMA, ~DmaEenab,
+ | -> set TxPktRdy for last short pkt or zlp
+ | -> Complete Request
+ | -> Continue next request (call txstate)
+ |___________________________________|
+
+ * Non-Mentor DMA engines can of course work differently, such as by
+ * upleveling from irq-per-packet to irq-per-buffer.
+ */
+
+#endif
+
+/*
+ * An endpoint is transmitting data. This can be called either from
+ * the IRQ routine or from ep.queue() to kickstart a request on an
+ * endpoint.
+ *
+ * Context: controller locked, IRQs blocked, endpoint selected
+ */
+static void txstate(struct musb *musb, struct musb_request *req)
+{
+ u8 epnum = req->epnum;
+ struct musb_ep *musb_ep;
+ void __iomem *epio = musb->endpoints[epnum].regs;
+ struct usb_request *request;
+ u16 fifo_count = 0, csr;
+ int use_dma = 0;
+
+ musb_ep = req->ep;
+
+ /* we shouldn't get here while DMA is active ... but we do ... */
+ if (dma_channel_status(musb_ep->dma) == MUSB_DMA_STATUS_BUSY) {
+ DBG(4, "dma pending...\n");
+ return;
+ }
+
+ /* read TXCSR before */
+ csr = musb_readw(epio, MUSB_TXCSR);
+
+ request = &req->request;
+ fifo_count = min(max_ep_writesize(musb, musb_ep),
+ (int)(request->length - request->actual));
+
+ if (csr & MUSB_TXCSR_TXPKTRDY) {
+ DBG(5, "%s old packet still ready , txcsr %03x\n",
+ musb_ep->end_point.name, csr);
+ return;
+ }
+
+ if (csr & MUSB_TXCSR_P_SENDSTALL) {
+ DBG(5, "%s stalling, txcsr %03x\n",
+ musb_ep->end_point.name, csr);
+ return;
+ }
+
+ DBG(4, "hw_ep%d, maxpacket %d, fifo count %d, txcsr %03x\n",
+ epnum, musb_ep->packet_sz, fifo_count,
+ csr);
+
+#ifndef CONFIG_MUSB_PIO_ONLY
+ if (is_dma_capable() && musb_ep->dma) {
+ struct dma_controller *c = musb->dma_controller;
+
+ use_dma = (request->dma != DMA_ADDR_INVALID);
+
+ /* MUSB_TXCSR_P_ISO is still set correctly */
+
+#ifdef CONFIG_USB_INVENTRA_DMA
+ {
+ size_t request_size;
+
+ /* setup DMA, then program endpoint CSR */
+ request_size = min(request->length,
+ musb_ep->dma->max_len);
+ if (request_size <= musb_ep->packet_sz)
+ musb_ep->dma->desired_mode = 0;
+ else
+ musb_ep->dma->desired_mode = 1;
+
+ use_dma = use_dma && c->channel_program(
+ musb_ep->dma, musb_ep->packet_sz,
+ musb_ep->dma->desired_mode,
+ request->dma, request_size);
+ if (use_dma) {
+ if (musb_ep->dma->desired_mode == 0) {
+ /* ASSERT: DMAENAB is clear */
+ csr &= ~(MUSB_TXCSR_AUTOSET |
+ MUSB_TXCSR_DMAMODE);
+ csr |= (MUSB_TXCSR_DMAENAB |
+ MUSB_TXCSR_MODE);
+ /* against programming guide */
+ } else
+ csr |= (MUSB_TXCSR_AUTOSET
+ | MUSB_TXCSR_DMAENAB
+ | MUSB_TXCSR_DMAMODE
+ | MUSB_TXCSR_MODE);
+
+ csr &= ~MUSB_TXCSR_P_UNDERRUN;
+ musb_writew(epio, MUSB_TXCSR, csr);
+ }
+ }
+
+#elif defined(CONFIG_USB_TI_CPPI_DMA)
+ /* program endpoint CSR first, then setup DMA */
+ csr &= ~(MUSB_TXCSR_AUTOSET
+ | MUSB_TXCSR_DMAMODE
+ | MUSB_TXCSR_P_UNDERRUN
+ | MUSB_TXCSR_TXPKTRDY);
+ csr |= MUSB_TXCSR_MODE | MUSB_TXCSR_DMAENAB;
+ musb_writew(epio, MUSB_TXCSR,
+ (MUSB_TXCSR_P_WZC_BITS & ~MUSB_TXCSR_P_UNDERRUN)
+ | csr);
+
+ /* ensure writebuffer is empty */
+ csr = musb_readw(epio, MUSB_TXCSR);
+
+ /* NOTE host side sets DMAENAB later than this; both are
+ * OK since the transfer dma glue (between CPPI and Mentor
+ * fifos) just tells CPPI it could start. Data only moves
+ * to the USB TX fifo when both fifos are ready.
+ */
+
+ /* "mode" is irrelevant here; handle terminating ZLPs like
+ * PIO does, since the hardware RNDIS mode seems unreliable
+ * except for the last-packet-is-already-short case.
+ */
+ use_dma = use_dma && c->channel_program(
+ musb_ep->dma, musb_ep->packet_sz,
+ 0,
+ request->dma,
+ request->length);
+ if (!use_dma) {
+ c->channel_release(musb_ep->dma);
+ musb_ep->dma = NULL;
+ /* ASSERT: DMAENAB clear */
+ csr &= ~(MUSB_TXCSR_DMAMODE | MUSB_TXCSR_MODE);
+ /* invariant: prequest->buf is non-null */
+ }
+#elif defined(CONFIG_USB_TUSB_OMAP_DMA)
+ use_dma = use_dma && c->channel_program(
+ musb_ep->dma, musb_ep->packet_sz,
+ request->zero,
+ request->dma,
+ request->length);
+#endif
+ }
+#endif
+
+ if (!use_dma) {
+ musb_write_fifo(musb_ep->hw_ep, fifo_count,
+ (u8 *) (request->buf + request->actual));
+ request->actual += fifo_count;
+ csr |= MUSB_TXCSR_TXPKTRDY;
+ csr &= ~MUSB_TXCSR_P_UNDERRUN;
+ musb_writew(epio, MUSB_TXCSR, csr);
+ }
+
+ /* host may already have the data when this message shows... */
+ DBG(3, "%s TX/IN %s len %d/%d, txcsr %04x, fifo %d/%d\n",
+ musb_ep->end_point.name, use_dma ? "dma" : "pio",
+ request->actual, request->length,
+ musb_readw(epio, MUSB_TXCSR),
+ fifo_count,
+ musb_readw(epio, MUSB_TXMAXP));
+}
+
+/*
+ * FIFO state update (e.g. data ready).
+ * Called from IRQ, with controller locked.
+ */
+void musb_g_tx(struct musb *musb, u8 epnum)
+{
+ u16 csr;
+ struct usb_request *request;
+ u8 __iomem *mbase = musb->mregs;
+ struct musb_ep *musb_ep = &musb->endpoints[epnum].ep_in;
+ void __iomem *epio = musb->endpoints[epnum].regs;
+ struct dma_channel *dma;
+
+ musb_ep_select(mbase, epnum);
+ request = next_request(musb_ep);
+
+ csr = musb_readw(epio, MUSB_TXCSR);
+ DBG(4, "<== %s, txcsr %04x\n", musb_ep->end_point.name, csr);
+
+ dma = is_dma_capable() ? musb_ep->dma : NULL;
+ do {
+ /* REVISIT for high bandwidth, MUSB_TXCSR_P_INCOMPTX
+ * probably rates reporting as a host error
+ */
+ if (csr & MUSB_TXCSR_P_SENTSTALL) {
+ csr |= MUSB_TXCSR_P_WZC_BITS;
+ csr &= ~MUSB_TXCSR_P_SENTSTALL;
+ musb_writew(epio, MUSB_TXCSR, csr);
+ if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
+ dma->status = MUSB_DMA_STATUS_CORE_ABORT;
+ musb->dma_controller->channel_abort(dma);
+ }
+
+ if (request)
+ musb_g_giveback(musb_ep, request, -EPIPE);
+
+ break;
+ }
+
+ if (csr & MUSB_TXCSR_P_UNDERRUN) {
+ /* we NAKed, no big deal ... little reason to care */
+ csr |= MUSB_TXCSR_P_WZC_BITS;
+ csr &= ~(MUSB_TXCSR_P_UNDERRUN
+ | MUSB_TXCSR_TXPKTRDY);
+ musb_writew(epio, MUSB_TXCSR, csr);
+ DBG(20, "underrun on ep%d, req %p\n", epnum, request);
+ }
+
+ if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
+ /* SHOULD NOT HAPPEN ... has with cppi though, after
+ * changing SENDSTALL (and other cases); harmless?
+ */
+ DBG(5, "%s dma still busy?\n", musb_ep->end_point.name);
+ break;
+ }
+
+ if (request) {
+ u8 is_dma = 0;
+
+ if (dma && (csr & MUSB_TXCSR_DMAENAB)) {
+ is_dma = 1;
+ csr |= MUSB_TXCSR_P_WZC_BITS;
+ csr &= ~(MUSB_TXCSR_DMAENAB
+ | MUSB_TXCSR_P_UNDERRUN
+ | MUSB_TXCSR_TXPKTRDY);
+ musb_writew(epio, MUSB_TXCSR, csr);
+ /* ensure writebuffer is empty */
+ csr = musb_readw(epio, MUSB_TXCSR);
+ request->actual += musb_ep->dma->actual_len;
+ DBG(4, "TXCSR%d %04x, dma off, "
+ "len %Zd, req %p\n",
+ epnum, csr,
+ musb_ep->dma->actual_len,
+ request);
+ }
+
+ if (is_dma || request->actual == request->length) {
+
+ /* First, maybe a terminating short packet.
+ * Some DMA engines might handle this by
+ * themselves.
+ */
+ if ((request->zero
+ && request->length
+ && (request->length
+ % musb_ep->packet_sz)
+ == 0)
+#ifdef CONFIG_USB_INVENTRA_DMA
+ || (is_dma &&
+ ((!dma->desired_mode) ||
+ (request->actual &
+ (musb_ep->packet_sz - 1))))
+#endif
+ ) {
+ /* on dma completion, fifo may not
+ * be available yet ...
+ */
+ if (csr & MUSB_TXCSR_TXPKTRDY)
+ break;
+
+ DBG(4, "sending zero pkt\n");
+ musb_writew(epio, MUSB_TXCSR,
+ MUSB_TXCSR_MODE
+ | MUSB_TXCSR_TXPKTRDY);
+ request->zero = 0;
+ }
+
+ /* ... or if not, then complete it */
+ musb_g_giveback(musb_ep, request, 0);
+
+ /* kickstart next transfer if appropriate;
+ * the packet that just completed might not
+ * be transmitted for hours or days.
+ * REVISIT for double buffering...
+ * FIXME revisit for stalls too...
+ */
+ musb_ep_select(mbase, epnum);
+ csr = musb_readw(epio, MUSB_TXCSR);
+ if (csr & MUSB_TXCSR_FIFONOTEMPTY)
+ break;
+ request = musb_ep->desc
+ ? next_request(musb_ep)
+ : NULL;
+ if (!request) {
+ DBG(4, "%s idle now\n",
+ musb_ep->end_point.name);
+ break;
+ }
+ }
+
+ txstate(musb, to_musb_request(request));
+ }
+
+ } while (0);
+}
+
+/* ------------------------------------------------------------ */
+
+#ifdef CONFIG_USB_INVENTRA_DMA
+
+/* Peripheral rx (OUT) using Mentor DMA works as follows:
+ - Only mode 0 is used.
+
+ - Request is queued by the gadget class driver.
+ -> if queue was previously empty, rxstate()
+
+ - Host sends OUT token which causes an endpoint interrupt
+ /\ -> RxReady
+ | -> if request queued, call rxstate
+ | /\ -> setup DMA
+ | | -> DMA interrupt on completion
+ | | -> RxReady
+ | | -> stop DMA
+ | | -> ack the read
+ | | -> if data recd = max expected
+ | | by the request, or host
+ | | sent a short packet,
+ | | complete the request,
+ | | and start the next one.
+ | |_____________________________________|
+ | else just wait for the host
+ | to send the next OUT token.
+ |__________________________________________________|
+
+ * Non-Mentor DMA engines can of course work differently.
+ */
+
+#endif
+
+/*
+ * Context: controller locked, IRQs blocked, endpoint selected
+ */
+static void rxstate(struct musb *musb, struct musb_request *req)
+{
+ u16 csr = 0;
+ const u8 epnum = req->epnum;
+ struct usb_request *request = &req->request;
+ struct musb_ep *musb_ep = &musb->endpoints[epnum].ep_out;
+ void __iomem *epio = musb->endpoints[epnum].regs;
+ u16 fifo_count = 0;
+ u16 len = musb_ep->packet_sz;
+
+ csr = musb_readw(epio, MUSB_RXCSR);
+
+ if (is_cppi_enabled() && musb_ep->dma) {
+ struct dma_controller *c = musb->dma_controller;
+ struct dma_channel *channel = musb_ep->dma;
+
+ /* NOTE: CPPI won't actually stop advancing the DMA
+ * queue after short packet transfers, so this is almost
+ * always going to run as IRQ-per-packet DMA so that
+ * faults will be handled correctly.
+ */
+ if (c->channel_program(channel,
+ musb_ep->packet_sz,
+ !request->short_not_ok,
+ request->dma + request->actual,
+ request->length - request->actual)) {
+
+ /* make sure that if an rxpkt arrived after the irq,
+ * the cppi engine will be ready to take it as soon
+ * as DMA is enabled
+ */
+ csr &= ~(MUSB_RXCSR_AUTOCLEAR
+ | MUSB_RXCSR_DMAMODE);
+ csr |= MUSB_RXCSR_DMAENAB | MUSB_RXCSR_P_WZC_BITS;
+ musb_writew(epio, MUSB_RXCSR, csr);
+ return;
+ }
+ }
+
+ if (csr & MUSB_RXCSR_RXPKTRDY) {
+ len = musb_readw(epio, MUSB_RXCOUNT);
+ if (request->actual < request->length) {
+#ifdef CONFIG_USB_INVENTRA_DMA
+ if (is_dma_capable() && musb_ep->dma) {
+ struct dma_controller *c;
+ struct dma_channel *channel;
+ int use_dma = 0;
+
+ c = musb->dma_controller;
+ channel = musb_ep->dma;
+
+ /* We use DMA Req mode 0 in rx_csr, and DMA controller operates in
+ * mode 0 only. So we do not get endpoint interrupts due to DMA
+ * completion. We only get interrupts from DMA controller.
+ *
+ * We could operate in DMA mode 1 if we knew the size of the tranfer
+ * in advance. For mass storage class, request->length = what the host
+ * sends, so that'd work. But for pretty much everything else,
+ * request->length is routinely more than what the host sends. For
+ * most these gadgets, end of is signified either by a short packet,
+ * or filling the last byte of the buffer. (Sending extra data in
+ * that last pckate should trigger an overflow fault.) But in mode 1,
+ * we don't get DMA completion interrrupt for short packets.
+ *
+ * Theoretically, we could enable DMAReq irq (MUSB_RXCSR_DMAMODE = 1),
+ * to get endpoint interrupt on every DMA req, but that didn't seem
+ * to work reliably.
+ *
+ * REVISIT an updated g_file_storage can set req->short_not_ok, which
+ * then becomes usable as a runtime "use mode 1" hint...
+ */
+
+ csr |= MUSB_RXCSR_DMAENAB;
+#ifdef USE_MODE1
+ csr |= MUSB_RXCSR_AUTOCLEAR;
+ /* csr |= MUSB_RXCSR_DMAMODE; */
+
+ /* this special sequence (enabling and then
+ * disabling MUSB_RXCSR_DMAMODE) is required
+ * to get DMAReq to activate
+ */
+ musb_writew(epio, MUSB_RXCSR,
+ csr | MUSB_RXCSR_DMAMODE);
+#endif
+ musb_writew(epio, MUSB_RXCSR, csr);
+
+ if (request->actual < request->length) {
+ int transfer_size = 0;
+#ifdef USE_MODE1
+ transfer_size = min(request->length,
+ channel->max_len);
+#else
+ transfer_size = len;
+#endif
+ if (transfer_size <= musb_ep->packet_sz)
+ musb_ep->dma->desired_mode = 0;
+ else
+ musb_ep->dma->desired_mode = 1;
+
+ use_dma = c->channel_program(
+ channel,
+ musb_ep->packet_sz,
+ channel->desired_mode,
+ request->dma
+ + request->actual,
+ transfer_size);
+ }
+
+ if (use_dma)
+ return;
+ }
+#endif /* Mentor's DMA */
+
+ fifo_count = request->length - request->actual;
+ DBG(3, "%s OUT/RX pio fifo %d/%d, maxpacket %d\n",
+ musb_ep->end_point.name,
+ len, fifo_count,
+ musb_ep->packet_sz);
+
+ fifo_count = min(len, fifo_count);
+
+#ifdef CONFIG_USB_TUSB_OMAP_DMA
+ if (tusb_dma_omap() && musb_ep->dma) {
+ struct dma_controller *c = musb->dma_controller;
+ struct dma_channel *channel = musb_ep->dma;
+ u32 dma_addr = request->dma + request->actual;
+ int ret;
+
+ ret = c->channel_program(channel,
+ musb_ep->packet_sz,
+ channel->desired_mode,
+ dma_addr,
+ fifo_count);
+ if (ret)
+ return;
+ }
+#endif
+
+ musb_read_fifo(musb_ep->hw_ep, fifo_count, (u8 *)
+ (request->buf + request->actual));
+ request->actual += fifo_count;
+
+ /* REVISIT if we left anything in the fifo, flush
+ * it and report -EOVERFLOW
+ */
+
+ /* ack the read! */
+ csr |= MUSB_RXCSR_P_WZC_BITS;
+ csr &= ~MUSB_RXCSR_RXPKTRDY;
+ musb_writew(epio, MUSB_RXCSR, csr);
+ }
+ }
+
+ /* reach the end or short packet detected */
+ if (request->actual == request->length || len < musb_ep->packet_sz)
+ musb_g_giveback(musb_ep, request, 0);
+}
+
+/*
+ * Data ready for a request; called from IRQ
+ */
+void musb_g_rx(struct musb *musb, u8 epnum)
+{
+ u16 csr;
+ struct usb_request *request;
+ void __iomem *mbase = musb->mregs;
+ struct musb_ep *musb_ep = &musb->endpoints[epnum].ep_out;
+ void __iomem *epio = musb->endpoints[epnum].regs;
+ struct dma_channel *dma;
+
+ musb_ep_select(mbase, epnum);
+
+ request = next_request(musb_ep);
+
+ csr = musb_readw(epio, MUSB_RXCSR);
+ dma = is_dma_capable() ? musb_ep->dma : NULL;
+
+ DBG(4, "<== %s, rxcsr %04x%s %p\n", musb_ep->end_point.name,
+ csr, dma ? " (dma)" : "", request);
+
+ if (csr & MUSB_RXCSR_P_SENTSTALL) {
+ if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
+ dma->status = MUSB_DMA_STATUS_CORE_ABORT;
+ (void) musb->dma_controller->channel_abort(dma);
+ request->actual += musb_ep->dma->actual_len;
+ }
+
+ csr |= MUSB_RXCSR_P_WZC_BITS;
+ csr &= ~MUSB_RXCSR_P_SENTSTALL;
+ musb_writew(epio, MUSB_RXCSR, csr);
+
+ if (request)
+ musb_g_giveback(musb_ep, request, -EPIPE);
+ goto done;
+ }
+
+ if (csr & MUSB_RXCSR_P_OVERRUN) {
+ /* csr |= MUSB_RXCSR_P_WZC_BITS; */
+ csr &= ~MUSB_RXCSR_P_OVERRUN;
+ musb_writew(epio, MUSB_RXCSR, csr);
+
+ DBG(3, "%s iso overrun on %p\n", musb_ep->name, request);
+ if (request && request->status == -EINPROGRESS)
+ request->status = -EOVERFLOW;
+ }
+ if (csr & MUSB_RXCSR_INCOMPRX) {
+ /* REVISIT not necessarily an error */
+ DBG(4, "%s, incomprx\n", musb_ep->end_point.name);
+ }
+
+ if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
+ /* "should not happen"; likely RXPKTRDY pending for DMA */
+ DBG((csr & MUSB_RXCSR_DMAENAB) ? 4 : 1,
+ "%s busy, csr %04x\n",
+ musb_ep->end_point.name, csr);
+ goto done;
+ }
+
+ if (dma && (csr & MUSB_RXCSR_DMAENAB)) {
+ csr &= ~(MUSB_RXCSR_AUTOCLEAR
+ | MUSB_RXCSR_DMAENAB
+ | MUSB_RXCSR_DMAMODE);
+ musb_writew(epio, MUSB_RXCSR,
+ MUSB_RXCSR_P_WZC_BITS | csr);
+
+ request->actual += musb_ep->dma->actual_len;
+
+ DBG(4, "RXCSR%d %04x, dma off, %04x, len %Zd, req %p\n",
+ epnum, csr,
+ musb_readw(epio, MUSB_RXCSR),
+ musb_ep->dma->actual_len, request);
+
+#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_TUSB_OMAP_DMA)
+ /* Autoclear doesn't clear RxPktRdy for short packets */
+ if ((dma->desired_mode == 0)
+ || (dma->actual_len
+ & (musb_ep->packet_sz - 1))) {
+ /* ack the read! */
+ csr &= ~MUSB_RXCSR_RXPKTRDY;
+ musb_writew(epio, MUSB_RXCSR, csr);
+ }
+
+ /* incomplete, and not short? wait for next IN packet */
+ if ((request->actual < request->length)
+ && (musb_ep->dma->actual_len
+ == musb_ep->packet_sz))
+ goto done;
+#endif
+ musb_g_giveback(musb_ep, request, 0);
+
+ request = next_request(musb_ep);
+ if (!request)
+ goto done;
+
+ /* don't start more i/o till the stall clears */
+ musb_ep_select(mbase, epnum);
+ csr = musb_readw(epio, MUSB_RXCSR);
+ if (csr & MUSB_RXCSR_P_SENDSTALL)
+ goto done;
+ }
+
+
+ /* analyze request if the ep is hot */
+ if (request)
+ rxstate(musb, to_musb_request(request));
+ else
+ DBG(3, "packet waiting for %s%s request\n",
+ musb_ep->desc ? "" : "inactive ",
+ musb_ep->end_point.name);
+
+done:
+ return;
+}
+
+/* ------------------------------------------------------------ */
+
+static int musb_gadget_enable(struct usb_ep *ep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ unsigned long flags;
+ struct musb_ep *musb_ep;
+ struct musb_hw_ep *hw_ep;
+ void __iomem *regs;
+ struct musb *musb;
+ void __iomem *mbase;
+ u8 epnum;
+ u16 csr;
+ unsigned tmp;
+ int status = -EINVAL;
+
+ if (!ep || !desc)
+ return -EINVAL;
+
+ musb_ep = to_musb_ep(ep);
+ hw_ep = musb_ep->hw_ep;
+ regs = hw_ep->regs;
+ musb = musb_ep->musb;
+ mbase = musb->mregs;
+ epnum = musb_ep->current_epnum;
+
+ spin_lock_irqsave(&musb->lock, flags);
+
+ if (musb_ep->desc) {
+ status = -EBUSY;
+ goto fail;
+ }
+ musb_ep->type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+
+ /* check direction and (later) maxpacket size against endpoint */
+ if ((desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) != epnum)
+ goto fail;
+
+ /* REVISIT this rules out high bandwidth periodic transfers */
+ tmp = le16_to_cpu(desc->wMaxPacketSize);
+ if (tmp & ~0x07ff)
+ goto fail;
+ musb_ep->packet_sz = tmp;
+
+ /* enable the interrupts for the endpoint, set the endpoint
+ * packet size (or fail), set the mode, clear the fifo
+ */
+ musb_ep_select(mbase, epnum);
+ if (desc->bEndpointAddress & USB_DIR_IN) {
+ u16 int_txe = musb_readw(mbase, MUSB_INTRTXE);
+
+ if (hw_ep->is_shared_fifo)
+ musb_ep->is_in = 1;
+ if (!musb_ep->is_in)
+ goto fail;
+ if (tmp > hw_ep->max_packet_sz_tx)
+ goto fail;
+
+ int_txe |= (1 << epnum);
+ musb_writew(mbase, MUSB_INTRTXE, int_txe);
+
+ /* REVISIT if can_bulk_split(), use by updating "tmp";
+ * likewise high bandwidth periodic tx
+ */
+ musb_writew(regs, MUSB_TXMAXP, tmp);
+
+ csr = MUSB_TXCSR_MODE | MUSB_TXCSR_CLRDATATOG;
+ if (musb_readw(regs, MUSB_TXCSR)
+ & MUSB_TXCSR_FIFONOTEMPTY)
+ csr |= MUSB_TXCSR_FLUSHFIFO;
+ if (musb_ep->type == USB_ENDPOINT_XFER_ISOC)
+ csr |= MUSB_TXCSR_P_ISO;
+
+ /* set twice in case of double buffering */
+ musb_writew(regs, MUSB_TXCSR, csr);
+ /* REVISIT may be inappropriate w/o FIFONOTEMPTY ... */
+ musb_writew(regs, MUSB_TXCSR, csr);
+
+ } else {
+ u16 int_rxe = musb_readw(mbase, MUSB_INTRRXE);
+
+ if (hw_ep->is_shared_fifo)
+ musb_ep->is_in = 0;
+ if (musb_ep->is_in)
+ goto fail;
+ if (tmp > hw_ep->max_packet_sz_rx)
+ goto fail;
+
+ int_rxe |= (1 << epnum);
+ musb_writew(mbase, MUSB_INTRRXE, int_rxe);
+
+ /* REVISIT if can_bulk_combine() use by updating "tmp"
+ * likewise high bandwidth periodic rx
+ */
+ musb_writew(regs, MUSB_RXMAXP, tmp);
+
+ /* force shared fifo to OUT-only mode */
+ if (hw_ep->is_shared_fifo) {
+ csr = musb_readw(regs, MUSB_TXCSR);
+ csr &= ~(MUSB_TXCSR_MODE | MUSB_TXCSR_TXPKTRDY);
+ musb_writew(regs, MUSB_TXCSR, csr);
+ }
+
+ csr = MUSB_RXCSR_FLUSHFIFO | MUSB_RXCSR_CLRDATATOG;
+ if (musb_ep->type == USB_ENDPOINT_XFER_ISOC)
+ csr |= MUSB_RXCSR_P_ISO;
+ else if (musb_ep->type == USB_ENDPOINT_XFER_INT)
+ csr |= MUSB_RXCSR_DISNYET;
+
+ /* set twice in case of double buffering */
+ musb_writew(regs, MUSB_RXCSR, csr);
+ musb_writew(regs, MUSB_RXCSR, csr);
+ }
+
+ /* NOTE: all the I/O code _should_ work fine without DMA, in case
+ * for some reason you run out of channels here.
+ */
+ if (is_dma_capable() && musb->dma_controller) {
+ struct dma_controller *c = musb->dma_controller;
+
+ musb_ep->dma = c->channel_alloc(c, hw_ep,
+ (desc->bEndpointAddress & USB_DIR_IN));
+ } else
+ musb_ep->dma = NULL;
+
+ musb_ep->desc = desc;
+ musb_ep->busy = 0;
+ status = 0;
+
+ pr_debug("%s periph: enabled %s for %s %s, %smaxpacket %d\n",
+ musb_driver_name, musb_ep->end_point.name,
+ ({ char *s; switch (musb_ep->type) {
+ case USB_ENDPOINT_XFER_BULK: s = "bulk"; break;
+ case USB_ENDPOINT_XFER_INT: s = "int"; break;
+ default: s = "iso"; break;
+ }; s; }),
+ musb_ep->is_in ? "IN" : "OUT",
+ musb_ep->dma ? "dma, " : "",
+ musb_ep->packet_sz);
+
+ schedule_work(&musb->irq_work);
+
+fail:
+ spin_unlock_irqrestore(&musb->lock, flags);
+ return status;
+}
+
+/*
+ * Disable an endpoint flushing all requests queued.
+ */
+static int musb_gadget_disable(struct usb_ep *ep)
+{
+ unsigned long flags;
+ struct musb *musb;
+ u8 epnum;
+ struct musb_ep *musb_ep;
+ void __iomem *epio;
+ int status = 0;
+
+ musb_ep = to_musb_ep(ep);
+ musb = musb_ep->musb;
+ epnum = musb_ep->current_epnum;
+ epio = musb->endpoints[epnum].regs;
+
+ spin_lock_irqsave(&musb->lock, flags);
+ musb_ep_select(musb->mregs, epnum);
+
+ /* zero the endpoint sizes */
+ if (musb_ep->is_in) {
+ u16 int_txe = musb_readw(musb->mregs, MUSB_INTRTXE);
+ int_txe &= ~(1 << epnum);
+ musb_writew(musb->mregs, MUSB_INTRTXE, int_txe);
+ musb_writew(epio, MUSB_TXMAXP, 0);
+ } else {
+ u16 int_rxe = musb_readw(musb->mregs, MUSB_INTRRXE);
+ int_rxe &= ~(1 << epnum);
+ musb_writew(musb->mregs, MUSB_INTRRXE, int_rxe);
+ musb_writew(epio, MUSB_RXMAXP, 0);
+ }
+
+ musb_ep->desc = NULL;
+
+ /* abort all pending DMA and requests */
+ nuke(musb_ep, -ESHUTDOWN);
+
+ schedule_work(&musb->irq_work);
+
+ spin_unlock_irqrestore(&(musb->lock), flags);
+
+ DBG(2, "%s\n", musb_ep->end_point.name);
+
+ return status;
+}
+
+/*
+ * Allocate a request for an endpoint.
+ * Reused by ep0 code.
+ */
+struct usb_request *musb_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
+{
+ struct musb_ep *musb_ep = to_musb_ep(ep);
+ struct musb_request *request = NULL;
+
+ request = kzalloc(sizeof *request, gfp_flags);
+ if (request) {
+ INIT_LIST_HEAD(&request->request.list);
+ request->request.dma = DMA_ADDR_INVALID;
+ request->epnum = musb_ep->current_epnum;
+ request->ep = musb_ep;
+ }
+
+ return &request->request;
+}
+
+/*
+ * Free a request
+ * Reused by ep0 code.
+ */
+void musb_free_request(struct usb_ep *ep, struct usb_request *req)
+{
+ kfree(to_musb_request(req));
+}
+
+static LIST_HEAD(buffers);
+
+struct free_record {
+ struct list_head list;
+ struct device *dev;
+ unsigned bytes;
+ dma_addr_t dma;
+};
+
+/*
+ * Context: controller locked, IRQs blocked.
+ */
+static void musb_ep_restart(struct musb *musb, struct musb_request *req)
+{
+ DBG(3, "<== %s request %p len %u on hw_ep%d\n",
+ req->tx ? "TX/IN" : "RX/OUT",
+ &req->request, req->request.length, req->epnum);
+
+ musb_ep_select(musb->mregs, req->epnum);
+ if (req->tx)
+ txstate(musb, req);
+ else
+ rxstate(musb, req);
+}
+
+static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req,
+ gfp_t gfp_flags)
+{
+ struct musb_ep *musb_ep;
+ struct musb_request *request;
+ struct musb *musb;
+ int status = 0;
+ unsigned long lockflags;
+
+ if (!ep || !req)
+ return -EINVAL;
+ if (!req->buf)
+ return -ENODATA;
+
+ musb_ep = to_musb_ep(ep);
+ musb = musb_ep->musb;
+
+ request = to_musb_request(req);
+ request->musb = musb;
+
+ if (request->ep != musb_ep)
+ return -EINVAL;
+
+ DBG(4, "<== to %s request=%p\n", ep->name, req);
+
+ /* request is mine now... */
+ request->request.actual = 0;
+ request->request.status = -EINPROGRESS;
+ request->epnum = musb_ep->current_epnum;
+ request->tx = musb_ep->is_in;
+
+ if (is_dma_capable() && musb_ep->dma) {
+ if (request->request.dma == DMA_ADDR_INVALID) {
+ request->request.dma = dma_map_single(
+ musb->controller,
+ request->request.buf,
+ request->request.length,
+ request->tx
+ ? DMA_TO_DEVICE
+ : DMA_FROM_DEVICE);
+ request->mapped = 1;
+ } else {
+ dma_sync_single_for_device(musb->controller,
+ request->request.dma,
+ request->request.length,
+ request->tx
+ ? DMA_TO_DEVICE
+ : DMA_FROM_DEVICE);
+ request->mapped = 0;
+ }
+ } else if (!req->buf) {
+ return -ENODATA;
+ } else
+ request->mapped = 0;
+
+ spin_lock_irqsave(&musb->lock, lockflags);
+
+ /* don't queue if the ep is down */
+ if (!musb_ep->desc) {
+ DBG(4, "req %p queued to %s while ep %s\n",
+ req, ep->name, "disabled");
+ status = -ESHUTDOWN;
+ goto cleanup;
+ }
+
+ /* add request to the list */
+ list_add_tail(&(request->request.list), &(musb_ep->req_list));
+
+ /* it this is the head of the queue, start i/o ... */
+ if (!musb_ep->busy && &request->request.list == musb_ep->req_list.next)
+ musb_ep_restart(musb, request);
+
+cleanup:
+ spin_unlock_irqrestore(&musb->lock, lockflags);
+ return status;
+}
+
+static int musb_gadget_dequeue(struct usb_ep *ep, struct usb_request *request)
+{
+ struct musb_ep *musb_ep = to_musb_ep(ep);
+ struct usb_request *r;
+ unsigned long flags;
+ int status = 0;
+ struct musb *musb = musb_ep->musb;
+
+ if (!ep || !request || to_musb_request(request)->ep != musb_ep)
+ return -EINVAL;
+
+ spin_lock_irqsave(&musb->lock, flags);
+
+ list_for_each_entry(r, &musb_ep->req_list, list) {
+ if (r == request)
+ break;
+ }
+ if (r != request) {
+ DBG(3, "request %p not queued to %s\n", request, ep->name);
+ status = -EINVAL;
+ goto done;
+ }
+
+ /* if the hardware doesn't have the request, easy ... */
+ if (musb_ep->req_list.next != &request->list || musb_ep->busy)
+ musb_g_giveback(musb_ep, request, -ECONNRESET);
+
+ /* ... else abort the dma transfer ... */
+ else if (is_dma_capable() && musb_ep->dma) {
+ struct dma_controller *c = musb->dma_controller;
+
+ musb_ep_select(musb->mregs, musb_ep->current_epnum);
+ if (c->channel_abort)
+ status = c->channel_abort(musb_ep->dma);
+ else
+ status = -EBUSY;
+ if (status == 0)
+ musb_g_giveback(musb_ep, request, -ECONNRESET);
+ } else {
+ /* NOTE: by sticking to easily tested hardware/driver states,
+ * we leave counting of in-flight packets imprecise.
+ */
+ musb_g_giveback(musb_ep, request, -ECONNRESET);
+ }
+
+done:
+ spin_unlock_irqrestore(&musb->lock, flags);
+ return status;
+}
+
+/*
+ * Set or clear the halt bit of an endpoint. A halted enpoint won't tx/rx any
+ * data but will queue requests.
+ *
+ * exported to ep0 code
+ */
+int musb_gadget_set_halt(struct usb_ep *ep, int value)
+{
+ struct musb_ep *musb_ep = to_musb_ep(ep);
+ u8 epnum = musb_ep->current_epnum;
+ struct musb *musb = musb_ep->musb;
+ void __iomem *epio = musb->endpoints[epnum].regs;
+ void __iomem *mbase;
+ unsigned long flags;
+ u16 csr;
+ struct musb_request *request = NULL;
+ int status = 0;
+
+ if (!ep)
+ return -EINVAL;
+ mbase = musb->mregs;
+
+ spin_lock_irqsave(&musb->lock, flags);
+
+ if ((USB_ENDPOINT_XFER_ISOC == musb_ep->type)) {
+ status = -EINVAL;
+ goto done;
+ }
+
+ musb_ep_select(mbase, epnum);
+
+ /* cannot portably stall with non-empty FIFO */
+ request = to_musb_request(next_request(musb_ep));
+ if (value && musb_ep->is_in) {
+ csr = musb_readw(epio, MUSB_TXCSR);
+ if (csr & MUSB_TXCSR_FIFONOTEMPTY) {
+ DBG(3, "%s fifo busy, cannot halt\n", ep->name);
+ spin_unlock_irqrestore(&musb->lock, flags);
+ return -EAGAIN;
+ }
+
+ }
+
+ /* set/clear the stall and toggle bits */
+ DBG(2, "%s: %s stall\n", ep->name, value ? "set" : "clear");
+ if (musb_ep->is_in) {
+ csr = musb_readw(epio, MUSB_TXCSR);
+ if (csr & MUSB_TXCSR_FIFONOTEMPTY)
+ csr |= MUSB_TXCSR_FLUSHFIFO;
+ csr |= MUSB_TXCSR_P_WZC_BITS
+ | MUSB_TXCSR_CLRDATATOG;
+ if (value)
+ csr |= MUSB_TXCSR_P_SENDSTALL;
+ else
+ csr &= ~(MUSB_TXCSR_P_SENDSTALL
+ | MUSB_TXCSR_P_SENTSTALL);
+ csr &= ~MUSB_TXCSR_TXPKTRDY;
+ musb_writew(epio, MUSB_TXCSR, csr);
+ } else {
+ csr = musb_readw(epio, MUSB_RXCSR);
+ csr |= MUSB_RXCSR_P_WZC_BITS
+ | MUSB_RXCSR_FLUSHFIFO
+ | MUSB_RXCSR_CLRDATATOG;
+ if (value)
+ csr |= MUSB_RXCSR_P_SENDSTALL;
+ else
+ csr &= ~(MUSB_RXCSR_P_SENDSTALL
+ | MUSB_RXCSR_P_SENTSTALL);
+ musb_writew(epio, MUSB_RXCSR, csr);
+ }
+
+done:
+
+ /* maybe start the first request in the queue */
+ if (!musb_ep->busy && !value && request) {
+ DBG(3, "restarting the request\n");
+ musb_ep_restart(musb, request);
+ }
+
+ spin_unlock_irqrestore(&musb->lock, flags);
+ return status;
+}
+
+static int musb_gadget_fifo_status(struct usb_ep *ep)
+{
+ struct musb_ep *musb_ep = to_musb_ep(ep);
+ void __iomem *epio = musb_ep->hw_ep->regs;
+ int retval = -EINVAL;
+
+ if (musb_ep->desc && !musb_ep->is_in) {
+ struct musb *musb = musb_ep->musb;
+ int epnum = musb_ep->current_epnum;
+ void __iomem *mbase = musb->mregs;
+ unsigned long flags;
+
+ spin_lock_irqsave(&musb->lock, flags);
+
+ musb_ep_select(mbase, epnum);
+ /* FIXME return zero unless RXPKTRDY is set */
+ retval = musb_readw(epio, MUSB_RXCOUNT);
+
+ spin_unlock_irqrestore(&musb->lock, flags);
+ }
+ return retval;
+}
+
+static void musb_gadget_fifo_flush(struct usb_ep *ep)
+{
+ struct musb_ep *musb_ep = to_musb_ep(ep);
+ struct musb *musb = musb_ep->musb;
+ u8 epnum = musb_ep->current_epnum;
+ void __iomem *epio = musb->endpoints[epnum].regs;
+ void __iomem *mbase;
+ unsigned long flags;
+ u16 csr, int_txe;
+
+ mbase = musb->mregs;
+
+ spin_lock_irqsave(&musb->lock, flags);
+ musb_ep_select(mbase, (u8) epnum);
+
+ /* disable interrupts */
+ int_txe = musb_readw(mbase, MUSB_INTRTXE);
+ musb_writew(mbase, MUSB_INTRTXE, int_txe & ~(1 << epnum));
+
+ if (musb_ep->is_in) {
+ csr = musb_readw(epio, MUSB_TXCSR);
+ if (csr & MUSB_TXCSR_FIFONOTEMPTY) {
+ csr |= MUSB_TXCSR_FLUSHFIFO | MUSB_TXCSR_P_WZC_BITS;
+ musb_writew(epio, MUSB_TXCSR, csr);
+ /* REVISIT may be inappropriate w/o FIFONOTEMPTY ... */
+ musb_writew(epio, MUSB_TXCSR, csr);
+ }
+ } else {
+ csr = musb_readw(epio, MUSB_RXCSR);
+ csr |= MUSB_RXCSR_FLUSHFIFO | MUSB_RXCSR_P_WZC_BITS;
+ musb_writew(epio, MUSB_RXCSR, csr);
+ musb_writew(epio, MUSB_RXCSR, csr);
+ }
+
+ /* re-enable interrupt */
+ musb_writew(mbase, MUSB_INTRTXE, int_txe);
+ spin_unlock_irqrestore(&musb->lock, flags);
+}
+
+static const struct usb_ep_ops musb_ep_ops = {
+ .enable = musb_gadget_enable,
+ .disable = musb_gadget_disable,
+ .alloc_request = musb_alloc_request,
+ .free_request = musb_free_request,
+ .queue = musb_gadget_queue,
+ .dequeue = musb_gadget_dequeue,
+ .set_halt = musb_gadget_set_halt,
+ .fifo_status = musb_gadget_fifo_status,
+ .fifo_flush = musb_gadget_fifo_flush
+};
+
+/* ----------------------------------------------------------------------- */
+
+static int musb_gadget_get_frame(struct usb_gadget *gadget)
+{
+ struct musb *musb = gadget_to_musb(gadget);
+
+ return (int)musb_readw(musb->mregs, MUSB_FRAME);
+}
+
+static int musb_gadget_wakeup(struct usb_gadget *gadget)
+{
+ struct musb *musb = gadget_to_musb(gadget);
+ void __iomem *mregs = musb->mregs;
+ unsigned long flags;
+ int status = -EINVAL;
+ u8 power, devctl;
+ int retries;
+
+ spin_lock_irqsave(&musb->lock, flags);
+
+ switch (musb->xceiv.state) {
+ case OTG_STATE_B_PERIPHERAL:
+ /* NOTE: OTG state machine doesn't include B_SUSPENDED;
+ * that's part of the standard usb 1.1 state machine, and
+ * doesn't affect OTG transitions.
+ */
+ if (musb->may_wakeup && musb->is_suspended)
+ break;
+ goto done;
+ case OTG_STATE_B_IDLE:
+ /* Start SRP ... OTG not required. */
+ devctl = musb_readb(mregs, MUSB_DEVCTL);
+ DBG(2, "Sending SRP: devctl: %02x\n", devctl);
+ devctl |= MUSB_DEVCTL_SESSION;
+ musb_writeb(mregs, MUSB_DEVCTL, devctl);
+ devctl = musb_readb(mregs, MUSB_DEVCTL);
+ retries = 100;
+ while (!(devctl & MUSB_DEVCTL_SESSION)) {
+ devctl = musb_readb(mregs, MUSB_DEVCTL);
+ if (retries-- < 1)
+ break;
+ }
+ retries = 10000;
+ while (devctl & MUSB_DEVCTL_SESSION) {
+ devctl = musb_readb(mregs, MUSB_DEVCTL);
+ if (retries-- < 1)
+ break;
+ }
+
+ /* Block idling for at least 1s */
+ musb_platform_try_idle(musb,
+ jiffies + msecs_to_jiffies(1 * HZ));
+
+ status = 0;
+ goto done;
+ default:
+ DBG(2, "Unhandled wake: %s\n", otg_state_string(musb));
+ goto done;
+ }
+
+ status = 0;
+
+ power = musb_readb(mregs, MUSB_POWER);
+ power |= MUSB_POWER_RESUME;
+ musb_writeb(mregs, MUSB_POWER, power);
+ DBG(2, "issue wakeup\n");
+
+ /* FIXME do this next chunk in a timer callback, no udelay */
+ mdelay(2);
+
+ power = musb_readb(mregs, MUSB_POWER);
+ power &= ~MUSB_POWER_RESUME;
+ musb_writeb(mregs, MUSB_POWER, power);
+done:
+ spin_unlock_irqrestore(&musb->lock, flags);
+ return status;
+}
+
+static int
+musb_gadget_set_self_powered(struct usb_gadget *gadget, int is_selfpowered)
+{
+ struct musb *musb = gadget_to_musb(gadget);
+
+ musb->is_self_powered = !!is_selfpowered;
+ return 0;
+}
+
+static void musb_pullup(struct musb *musb, int is_on)
+{
+ u8 power;
+
+ power = musb_readb(musb->mregs, MUSB_POWER);
+ if (is_on)
+ power |= MUSB_POWER_SOFTCONN;
+ else
+ power &= ~MUSB_POWER_SOFTCONN;
+
+ /* FIXME if on, HdrcStart; if off, HdrcStop */
+
+ DBG(3, "gadget %s D+ pullup %s\n",
+ musb->gadget_driver->function, is_on ? "on" : "off");
+ musb_writeb(musb->mregs, MUSB_POWER, power);
+}
+
+#if 0
+static int musb_gadget_vbus_session(struct usb_gadget *gadget, int is_active)
+{
+ DBG(2, "<= %s =>\n", __func__);
+
+ /*
+ * FIXME iff driver's softconnect flag is set (as it is during probe,
+ * though that can clear it), just musb_pullup().
+ */
+
+ return -EINVAL;
+}
+#endif
+
+static int musb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA)
+{
+ struct musb *musb = gadget_to_musb(gadget);
+
+ if (!musb->xceiv.set_power)
+ return -EOPNOTSUPP;
+ return otg_set_power(&musb->xceiv, mA);
+}
+
+static int musb_gadget_pullup(struct usb_gadget *gadget, int is_on)
+{
+ struct musb *musb = gadget_to_musb(gadget);
+ unsigned long flags;
+
+ is_on = !!is_on;
+
+ /* NOTE: this assumes we are sensing vbus; we'd rather
+ * not pullup unless the B-session is active.
+ */
+ spin_lock_irqsave(&musb->lock, flags);
+ if (is_on != musb->softconnect) {
+ musb->softconnect = is_on;
+ musb_pullup(musb, is_on);
+ }
+ spin_unlock_irqrestore(&musb->lock, flags);
+ return 0;
+}
+
+static const struct usb_gadget_ops musb_gadget_operations = {
+ .get_frame = musb_gadget_get_frame,
+ .wakeup = musb_gadget_wakeup,
+ .set_selfpowered = musb_gadget_set_self_powered,
+ /* .vbus_session = musb_gadget_vbus_session, */
+ .vbus_draw = musb_gadget_vbus_draw,
+ .pullup = musb_gadget_pullup,
+};
+
+/* ----------------------------------------------------------------------- */
+
+/* Registration */
+
+/* Only this registration code "knows" the rule (from USB standards)
+ * about there being only one external upstream port. It assumes
+ * all peripheral ports are external...
+ */
+static struct musb *the_gadget;
+
+static void musb_gadget_release(struct device *dev)
+{
+ /* kref_put(WHAT) */
+ dev_dbg(dev, "%s\n", __func__);
+}
+
+
+static void __init
+init_peripheral_ep(struct musb *musb, struct musb_ep *ep, u8 epnum, int is_in)
+{
+ struct musb_hw_ep *hw_ep = musb->endpoints + epnum;
+
+ memset(ep, 0, sizeof *ep);
+
+ ep->current_epnum = epnum;
+ ep->musb = musb;
+ ep->hw_ep = hw_ep;
+ ep->is_in = is_in;
+
+ INIT_LIST_HEAD(&ep->req_list);
+
+ sprintf(ep->name, "ep%d%s", epnum,
+ (!epnum || hw_ep->is_shared_fifo) ? "" : (
+ is_in ? "in" : "out"));
+ ep->end_point.name = ep->name;
+ INIT_LIST_HEAD(&ep->end_point.ep_list);
+ if (!epnum) {
+ ep->end_point.maxpacket = 64;
+ ep->end_point.ops = &musb_g_ep0_ops;
+ musb->g.ep0 = &ep->end_point;
+ } else {
+ if (is_in)
+ ep->end_point.maxpacket = hw_ep->max_packet_sz_tx;
+ else
+ ep->end_point.maxpacket = hw_ep->max_packet_sz_rx;
+ ep->end_point.ops = &musb_ep_ops;
+ list_add_tail(&ep->end_point.ep_list, &musb->g.ep_list);
+ }
+}
+
+/*
+ * Initialize the endpoints exposed to peripheral drivers, with backlinks
+ * to the rest of the driver state.
+ */
+static inline void __init musb_g_init_endpoints(struct musb *musb)
+{
+ u8 epnum;
+ struct musb_hw_ep *hw_ep;
+ unsigned count = 0;
+
+ /* intialize endpoint list just once */
+ INIT_LIST_HEAD(&(musb->g.ep_list));
+
+ for (epnum = 0, hw_ep = musb->endpoints;
+ epnum < musb->nr_endpoints;
+ epnum++, hw_ep++) {
+ if (hw_ep->is_shared_fifo /* || !epnum */) {
+ init_peripheral_ep(musb, &hw_ep->ep_in, epnum, 0);
+ count++;
+ } else {
+ if (hw_ep->max_packet_sz_tx) {
+ init_peripheral_ep(musb, &hw_ep->ep_in,
+ epnum, 1);
+ count++;
+ }
+ if (hw_ep->max_packet_sz_rx) {
+ init_peripheral_ep(musb, &hw_ep->ep_out,
+ epnum, 0);
+ count++;
+ }
+ }
+ }
+}
+
+/* called once during driver setup to initialize and link into
+ * the driver model; memory is zeroed.
+ */
+int __init musb_gadget_setup(struct musb *musb)
+{
+ int status;
+
+ /* REVISIT minor race: if (erroneously) setting up two
+ * musb peripherals at the same time, only the bus lock
+ * is probably held.
+ */
+ if (the_gadget)
+ return -EBUSY;
+ the_gadget = musb;
+
+ musb->g.ops = &musb_gadget_operations;
+ musb->g.is_dualspeed = 1;
+ musb->g.speed = USB_SPEED_UNKNOWN;
+
+ /* this "gadget" abstracts/virtualizes the controller */
+ strcpy(musb->g.dev.bus_id, "gadget");
+ musb->g.dev.parent = musb->controller;
+ musb->g.dev.dma_mask = musb->controller->dma_mask;
+ musb->g.dev.release = musb_gadget_release;
+ musb->g.name = musb_driver_name;
+
+ if (is_otg_enabled(musb))
+ musb->g.is_otg = 1;
+
+ musb_g_init_endpoints(musb);
+
+ musb->is_active = 0;
+ musb_platform_try_idle(musb, 0);
+
+ status = device_register(&musb->g.dev);
+ if (status != 0)
+ the_gadget = NULL;
+ return status;
+}
+
+void musb_gadget_cleanup(struct musb *musb)
+{
+ if (musb != the_gadget)
+ return;
+
+ device_unregister(&musb->g.dev);
+ the_gadget = NULL;
+}
+
+/*
+ * Register the gadget driver. Used by gadget drivers when
+ * registering themselves with the controller.
+ *
+ * -EINVAL something went wrong (not driver)
+ * -EBUSY another gadget is already using the controller
+ * -ENOMEM no memeory to perform the operation
+ *
+ * @param driver the gadget driver
+ * @return <0 if error, 0 if everything is fine
+ */
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+ int retval;
+ unsigned long flags;
+ struct musb *musb = the_gadget;
+
+ if (!driver
+ || driver->speed != USB_SPEED_HIGH
+ || !driver->bind
+ || !driver->setup)
+ return -EINVAL;
+
+ /* driver must be initialized to support peripheral mode */
+ if (!musb || !(musb->board_mode == MUSB_OTG
+ || musb->board_mode != MUSB_OTG)) {
+ DBG(1, "%s, no dev??\n", __func__);
+ return -ENODEV;
+ }
+
+ DBG(3, "registering driver %s\n", driver->function);
+ spin_lock_irqsave(&musb->lock, flags);
+
+ if (musb->gadget_driver) {
+ DBG(1, "%s is already bound to %s\n",
+ musb_driver_name,
+ musb->gadget_driver->driver.name);
+ retval = -EBUSY;
+ } else {
+ musb->gadget_driver = driver;
+ musb->g.dev.driver = &driver->driver;
+ driver->driver.bus = NULL;
+ musb->softconnect = 1;
+ retval = 0;
+ }
+
+ spin_unlock_irqrestore(&musb->lock, flags);
+
+ if (retval == 0)
+ retval = driver->bind(&musb->g);
+ if (retval != 0) {
+ DBG(3, "bind to driver %s failed --> %d\n",
+ driver->driver.name, retval);
+ musb->gadget_driver = NULL;
+ musb->g.dev.driver = NULL;
+ }
+
+ /* start peripheral and/or OTG engines */
+ if (retval == 0) {
+ spin_lock_irqsave(&musb->lock, flags);
+
+ /* REVISIT always use otg_set_peripheral(), handling
+ * issues including the root hub one below ...
+ */
+ musb->xceiv.gadget = &musb->g;
+ musb->xceiv.state = OTG_STATE_B_IDLE;
+ musb->is_active = 1;
+
+ /* FIXME this ignores the softconnect flag. Drivers are
+ * allowed hold the peripheral inactive until for example
+ * userspace hooks up printer hardware or DSP codecs, so
+ * hosts only see fully functional devices.
+ */
+
+ if (!is_otg_enabled(musb))
+ musb_start(musb);
+
+ spin_unlock_irqrestore(&musb->lock, flags);
+
+ if (is_otg_enabled(musb)) {
+ DBG(3, "OTG startup...\n");
+
+ /* REVISIT: funcall to other code, which also
+ * handles power budgeting ... this way also
+ * ensures HdrcStart is indirectly called.
+ */
+ retval = usb_add_hcd(musb_to_hcd(musb), -1, 0);
+ if (retval < 0) {
+ DBG(1, "add_hcd failed, %d\n", retval);
+ spin_lock_irqsave(&musb->lock, flags);
+ musb->xceiv.gadget = NULL;
+ musb->xceiv.state = OTG_STATE_UNDEFINED;
+ musb->gadget_driver = NULL;
+ musb->g.dev.driver = NULL;
+ spin_unlock_irqrestore(&musb->lock, flags);
+ }
+ }
+ }
+
+ return retval;
+}
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+static void stop_activity(struct musb *musb, struct usb_gadget_driver *driver)
+{
+ int i;
+ struct musb_hw_ep *hw_ep;
+
+ /* don't disconnect if it's not connected */
+ if (musb->g.speed == USB_SPEED_UNKNOWN)
+ driver = NULL;
+ else
+ musb->g.speed = USB_SPEED_UNKNOWN;
+
+ /* deactivate the hardware */
+ if (musb->softconnect) {
+ musb->softconnect = 0;
+ musb_pullup(musb, 0);
+ }
+ musb_stop(musb);
+
+ /* killing any outstanding requests will quiesce the driver;
+ * then report disconnect
+ */
+ if (driver) {
+ for (i = 0, hw_ep = musb->endpoints;
+ i < musb->nr_endpoints;
+ i++, hw_ep++) {
+ musb_ep_select(musb->mregs, i);
+ if (hw_ep->is_shared_fifo /* || !epnum */) {
+ nuke(&hw_ep->ep_in, -ESHUTDOWN);
+ } else {
+ if (hw_ep->max_packet_sz_tx)
+ nuke(&hw_ep->ep_in, -ESHUTDOWN);
+ if (hw_ep->max_packet_sz_rx)
+ nuke(&hw_ep->ep_out, -ESHUTDOWN);
+ }
+ }
+
+ spin_unlock(&musb->lock);
+ driver->disconnect(&musb->g);
+ spin_lock(&musb->lock);
+ }
+}
+
+/*
+ * Unregister the gadget driver. Used by gadget drivers when
+ * unregistering themselves from the controller.
+ *
+ * @param driver the gadget driver to unregister
+ */
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+ unsigned long flags;
+ int retval = 0;
+ struct musb *musb = the_gadget;
+
+ if (!driver || !driver->unbind || !musb)
+ return -EINVAL;
+
+ /* REVISIT always use otg_set_peripheral() here too;
+ * this needs to shut down the OTG engine.
+ */
+
+ spin_lock_irqsave(&musb->lock, flags);
+
+#ifdef CONFIG_USB_MUSB_OTG
+ musb_hnp_stop(musb);
+#endif
+
+ if (musb->gadget_driver == driver) {
+
+ (void) musb_gadget_vbus_draw(&musb->g, 0);
+
+ musb->xceiv.state = OTG_STATE_UNDEFINED;
+ stop_activity(musb, driver);
+
+ DBG(3, "unregistering driver %s\n", driver->function);
+ spin_unlock_irqrestore(&musb->lock, flags);
+ driver->unbind(&musb->g);
+ spin_lock_irqsave(&musb->lock, flags);
+
+ musb->gadget_driver = NULL;
+ musb->g.dev.driver = NULL;
+
+ musb->is_active = 0;
+ musb_platform_try_idle(musb, 0);
+ } else
+ retval = -EINVAL;
+ spin_unlock_irqrestore(&musb->lock, flags);
+
+ if (is_otg_enabled(musb) && retval == 0) {
+ usb_remove_hcd(musb_to_hcd(musb));
+ /* FIXME we need to be able to register another
+ * gadget driver here and have everything work;
+ * that currently misbehaves.
+ */
+ }
+
+ return retval;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+
+/* ----------------------------------------------------------------------- */
+
+/* lifecycle operations called through plat_uds.c */
+
+void musb_g_resume(struct musb *musb)
+{
+ musb->is_suspended = 0;
+ switch (musb->xceiv.state) {
+ case OTG_STATE_B_IDLE:
+ break;
+ case OTG_STATE_B_WAIT_ACON:
+ case OTG_STATE_B_PERIPHERAL:
+ musb->is_active = 1;
+ if (musb->gadget_driver && musb->gadget_driver->resume) {
+ spin_unlock(&musb->lock);
+ musb->gadget_driver->resume(&musb->g);
+ spin_lock(&musb->lock);
+ }
+ break;
+ default:
+ WARN("unhandled RESUME transition (%s)\n",
+ otg_state_string(musb));
+ }
+}
+
+/* called when SOF packets stop for 3+ msec */
+void musb_g_suspend(struct musb *musb)
+{
+ u8 devctl;
+
+ devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+ DBG(3, "devctl %02x\n", devctl);
+
+ switch (musb->xceiv.state) {
+ case OTG_STATE_B_IDLE:
+ if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS)
+ musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
+ break;
+ case OTG_STATE_B_PERIPHERAL:
+ musb->is_suspended = 1;
+ if (musb->gadget_driver && musb->gadget_driver->suspend) {
+ spin_unlock(&musb->lock);
+ musb->gadget_driver->suspend(&musb->g);
+ spin_lock(&musb->lock);
+ }
+ break;
+ default:
+ /* REVISIT if B_HOST, clear DEVCTL.HOSTREQ;
+ * A_PERIPHERAL may need care too
+ */
+ WARN("unhandled SUSPEND transition (%s)\n",
+ otg_state_string(musb));
+ }
+}
+
+/* Called during SRP */
+void musb_g_wakeup(struct musb *musb)
+{
+ musb_gadget_wakeup(&musb->g);
+}
+
+/* called when VBUS drops below session threshold, and in other cases */
+void musb_g_disconnect(struct musb *musb)
+{
+ void __iomem *mregs = musb->mregs;
+ u8 devctl = musb_readb(mregs, MUSB_DEVCTL);
+
+ DBG(3, "devctl %02x\n", devctl);
+
+ /* clear HR */
+ musb_writeb(mregs, MUSB_DEVCTL, devctl & MUSB_DEVCTL_SESSION);
+
+ /* don't draw vbus until new b-default session */
+ (void) musb_gadget_vbus_draw(&musb->g, 0);
+
+ musb->g.speed = USB_SPEED_UNKNOWN;
+ if (musb->gadget_driver && musb->gadget_driver->disconnect) {
+ spin_unlock(&musb->lock);
+ musb->gadget_driver->disconnect(&musb->g);
+ spin_lock(&musb->lock);
+ }
+
+ switch (musb->xceiv.state) {
+ default:
+#ifdef CONFIG_USB_MUSB_OTG
+ DBG(2, "Unhandled disconnect %s, setting a_idle\n",
+ otg_state_string(musb));
+ musb->xceiv.state = OTG_STATE_A_IDLE;
+ break;
+ case OTG_STATE_A_PERIPHERAL:
+ musb->xceiv.state = OTG_STATE_A_WAIT_VFALL;
+ break;
+ case OTG_STATE_B_WAIT_ACON:
+ case OTG_STATE_B_HOST:
+#endif
+ case OTG_STATE_B_PERIPHERAL:
+ case OTG_STATE_B_IDLE:
+ musb->xceiv.state = OTG_STATE_B_IDLE;
+ break;
+ case OTG_STATE_B_SRP_INIT:
+ break;
+ }
+
+ musb->is_active = 0;
+}
+
+void musb_g_reset(struct musb *musb)
+__releases(musb->lock)
+__acquires(musb->lock)
+{
+ void __iomem *mbase = musb->mregs;
+ u8 devctl = musb_readb(mbase, MUSB_DEVCTL);
+ u8 power;
+
+ DBG(3, "<== %s addr=%x driver '%s'\n",
+ (devctl & MUSB_DEVCTL_BDEVICE)
+ ? "B-Device" : "A-Device",
+ musb_readb(mbase, MUSB_FADDR),
+ musb->gadget_driver
+ ? musb->gadget_driver->driver.name
+ : NULL
+ );
+
+ /* report disconnect, if we didn't already (flushing EP state) */
+ if (musb->g.speed != USB_SPEED_UNKNOWN)
+ musb_g_disconnect(musb);
+
+ /* clear HR */
+ else if (devctl & MUSB_DEVCTL_HR)
+ musb_writeb(mbase, MUSB_DEVCTL, MUSB_DEVCTL_SESSION);
+
+
+ /* what speed did we negotiate? */
+ power = musb_readb(mbase, MUSB_POWER);
+ musb->g.speed = (power & MUSB_POWER_HSMODE)
+ ? USB_SPEED_HIGH : USB_SPEED_FULL;
+
+ /* start in USB_STATE_DEFAULT */
+ musb->is_active = 1;
+ musb->is_suspended = 0;
+ MUSB_DEV_MODE(musb);
+ musb->address = 0;
+ musb->ep0_state = MUSB_EP0_STAGE_SETUP;
+
+ musb->may_wakeup = 0;
+ musb->g.b_hnp_enable = 0;
+ musb->g.a_alt_hnp_support = 0;
+ musb->g.a_hnp_support = 0;
+
+ /* Normal reset, as B-Device;
+ * or else after HNP, as A-Device
+ */
+ if (devctl & MUSB_DEVCTL_BDEVICE) {
+ musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
+ musb->g.is_a_peripheral = 0;
+ } else if (is_otg_enabled(musb)) {
+ musb->xceiv.state = OTG_STATE_A_PERIPHERAL;
+ musb->g.is_a_peripheral = 1;
+ } else
+ WARN_ON(1);
+
+ /* start with default limits on VBUS power draw */
+ (void) musb_gadget_vbus_draw(&musb->g,
+ is_otg_enabled(musb) ? 8 : 100);
+}
--- /dev/null
+/*
+ * MUSB OTG driver peripheral defines
+ *
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ * Copyright (C) 2006-2007 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * 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 AUTHORS 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.
+ *
+ */
+
+#ifndef __MUSB_GADGET_H
+#define __MUSB_GADGET_H
+
+struct musb_request {
+ struct usb_request request;
+ struct musb_ep *ep;
+ struct musb *musb;
+ u8 tx; /* endpoint direction */
+ u8 epnum;
+ u8 mapped;
+};
+
+static inline struct musb_request *to_musb_request(struct usb_request *req)
+{
+ return req ? container_of(req, struct musb_request, request) : NULL;
+}
+
+extern struct usb_request *
+musb_alloc_request(struct usb_ep *ep, gfp_t gfp_flags);
+extern void musb_free_request(struct usb_ep *ep, struct usb_request *req);
+
+
+/*
+ * struct musb_ep - peripheral side view of endpoint rx or tx side
+ */
+struct musb_ep {
+ /* stuff towards the head is basically write-once. */
+ struct usb_ep end_point;
+ char name[12];
+ struct musb_hw_ep *hw_ep;
+ struct musb *musb;
+ u8 current_epnum;
+
+ /* ... when enabled/disabled ... */
+ u8 type;
+ u8 is_in;
+ u16 packet_sz;
+ const struct usb_endpoint_descriptor *desc;
+ struct dma_channel *dma;
+
+ /* later things are modified based on usage */
+ struct list_head req_list;
+
+ /* true if lock must be dropped but req_list may not be advanced */
+ u8 busy;
+};
+
+static inline struct musb_ep *to_musb_ep(struct usb_ep *ep)
+{
+ return ep ? container_of(ep, struct musb_ep, end_point) : NULL;
+}
+
+static inline struct usb_request *next_request(struct musb_ep *ep)
+{
+ struct list_head *queue = &ep->req_list;
+
+ if (list_empty(queue))
+ return NULL;
+ return container_of(queue->next, struct usb_request, list);
+}
+
+extern void musb_g_tx(struct musb *musb, u8 epnum);
+extern void musb_g_rx(struct musb *musb, u8 epnum);
+
+extern const struct usb_ep_ops musb_g_ep0_ops;
+
+extern int musb_gadget_setup(struct musb *);
+extern void musb_gadget_cleanup(struct musb *);
+
+extern void musb_g_giveback(struct musb_ep *, struct usb_request *, int);
+
+extern int musb_gadget_set_halt(struct usb_ep *ep, int value);
+
+#endif /* __MUSB_GADGET_H */
--- /dev/null
+/*
+ * MUSB OTG peripheral driver ep0 handling
+ *
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ * Copyright (C) 2006-2007 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * 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 AUTHORS 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+
+#include "musb_core.h"
+
+/* ep0 is always musb->endpoints[0].ep_in */
+#define next_ep0_request(musb) next_in_request(&(musb)->endpoints[0])
+
+/*
+ * locking note: we use only the controller lock, for simpler correctness.
+ * It's always held with IRQs blocked.
+ *
+ * It protects the ep0 request queue as well as ep0_state, not just the
+ * controller and indexed registers. And that lock stays held unless it
+ * needs to be dropped to allow reentering this driver ... like upcalls to
+ * the gadget driver, or adjusting endpoint halt status.
+ */
+
+static char *decode_ep0stage(u8 stage)
+{
+ switch (stage) {
+ case MUSB_EP0_STAGE_SETUP: return "idle";
+ case MUSB_EP0_STAGE_TX: return "in";
+ case MUSB_EP0_STAGE_RX: return "out";
+ case MUSB_EP0_STAGE_ACKWAIT: return "wait";
+ case MUSB_EP0_STAGE_STATUSIN: return "in/status";
+ case MUSB_EP0_STAGE_STATUSOUT: return "out/status";
+ default: return "?";
+ }
+}
+
+/* handle a standard GET_STATUS request
+ * Context: caller holds controller lock
+ */
+static int service_tx_status_request(
+ struct musb *musb,
+ const struct usb_ctrlrequest *ctrlrequest)
+{
+ void __iomem *mbase = musb->mregs;
+ int handled = 1;
+ u8 result[2], epnum = 0;
+ const u8 recip = ctrlrequest->bRequestType & USB_RECIP_MASK;
+
+ result[1] = 0;
+
+ switch (recip) {
+ case USB_RECIP_DEVICE:
+ result[0] = musb->is_self_powered << USB_DEVICE_SELF_POWERED;
+ result[0] |= musb->may_wakeup << USB_DEVICE_REMOTE_WAKEUP;
+#ifdef CONFIG_USB_MUSB_OTG
+ if (musb->g.is_otg) {
+ result[0] |= musb->g.b_hnp_enable
+ << USB_DEVICE_B_HNP_ENABLE;
+ result[0] |= musb->g.a_alt_hnp_support
+ << USB_DEVICE_A_ALT_HNP_SUPPORT;
+ result[0] |= musb->g.a_hnp_support
+ << USB_DEVICE_A_HNP_SUPPORT;
+ }
+#endif
+ break;
+
+ case USB_RECIP_INTERFACE:
+ result[0] = 0;
+ break;
+
+ case USB_RECIP_ENDPOINT: {
+ int is_in;
+ struct musb_ep *ep;
+ u16 tmp;
+ void __iomem *regs;
+
+ epnum = (u8) ctrlrequest->wIndex;
+ if (!epnum) {
+ result[0] = 0;
+ break;
+ }
+
+ is_in = epnum & USB_DIR_IN;
+ if (is_in) {
+ epnum &= 0x0f;
+ ep = &musb->endpoints[epnum].ep_in;
+ } else {
+ ep = &musb->endpoints[epnum].ep_out;
+ }
+ regs = musb->endpoints[epnum].regs;
+
+ if (epnum >= MUSB_C_NUM_EPS || !ep->desc) {
+ handled = -EINVAL;
+ break;
+ }
+
+ musb_ep_select(mbase, epnum);
+ if (is_in)
+ tmp = musb_readw(regs, MUSB_TXCSR)
+ & MUSB_TXCSR_P_SENDSTALL;
+ else
+ tmp = musb_readw(regs, MUSB_RXCSR)
+ & MUSB_RXCSR_P_SENDSTALL;
+ musb_ep_select(mbase, 0);
+
+ result[0] = tmp ? 1 : 0;
+ } break;
+
+ default:
+ /* class, vendor, etc ... delegate */
+ handled = 0;
+ break;
+ }
+
+ /* fill up the fifo; caller updates csr0 */
+ if (handled > 0) {
+ u16 len = le16_to_cpu(ctrlrequest->wLength);
+
+ if (len > 2)
+ len = 2;
+ musb_write_fifo(&musb->endpoints[0], len, result);
+ }
+
+ return handled;
+}
+
+/*
+ * handle a control-IN request, the end0 buffer contains the current request
+ * that is supposed to be a standard control request. Assumes the fifo to
+ * be at least 2 bytes long.
+ *
+ * @return 0 if the request was NOT HANDLED,
+ * < 0 when error
+ * > 0 when the request is processed
+ *
+ * Context: caller holds controller lock
+ */
+static int
+service_in_request(struct musb *musb, const struct usb_ctrlrequest *ctrlrequest)
+{
+ int handled = 0; /* not handled */
+
+ if ((ctrlrequest->bRequestType & USB_TYPE_MASK)
+ == USB_TYPE_STANDARD) {
+ switch (ctrlrequest->bRequest) {
+ case USB_REQ_GET_STATUS:
+ handled = service_tx_status_request(musb,
+ ctrlrequest);
+ break;
+
+ /* case USB_REQ_SYNC_FRAME: */
+
+ default:
+ break;
+ }
+ }
+ return handled;
+}
+
+/*
+ * Context: caller holds controller lock
+ */
+static void musb_g_ep0_giveback(struct musb *musb, struct usb_request *req)
+{
+ musb_g_giveback(&musb->endpoints[0].ep_in, req, 0);
+ musb->ep0_state = MUSB_EP0_STAGE_SETUP;
+}
+
+/*
+ * Tries to start B-device HNP negotiation if enabled via sysfs
+ */
+static inline void musb_try_b_hnp_enable(struct musb *musb)
+{
+ void __iomem *mbase = musb->mregs;
+ u8 devctl;
+
+ DBG(1, "HNP: Setting HR\n");
+ devctl = musb_readb(mbase, MUSB_DEVCTL);
+ musb_writeb(mbase, MUSB_DEVCTL, devctl | MUSB_DEVCTL_HR);
+}
+
+/*
+ * Handle all control requests with no DATA stage, including standard
+ * requests such as:
+ * USB_REQ_SET_CONFIGURATION, USB_REQ_SET_INTERFACE, unrecognized
+ * always delegated to the gadget driver
+ * USB_REQ_SET_ADDRESS, USB_REQ_CLEAR_FEATURE, USB_REQ_SET_FEATURE
+ * always handled here, except for class/vendor/... features
+ *
+ * Context: caller holds controller lock
+ */
+static int
+service_zero_data_request(struct musb *musb,
+ struct usb_ctrlrequest *ctrlrequest)
+__releases(musb->lock)
+__acquires(musb->lock)
+{
+ int handled = -EINVAL;
+ void __iomem *mbase = musb->mregs;
+ const u8 recip = ctrlrequest->bRequestType & USB_RECIP_MASK;
+
+ /* the gadget driver handles everything except what we MUST handle */
+ if ((ctrlrequest->bRequestType & USB_TYPE_MASK)
+ == USB_TYPE_STANDARD) {
+ switch (ctrlrequest->bRequest) {
+ case USB_REQ_SET_ADDRESS:
+ /* change it after the status stage */
+ musb->set_address = true;
+ musb->address = (u8) (ctrlrequest->wValue & 0x7f);
+ handled = 1;
+ break;
+
+ case USB_REQ_CLEAR_FEATURE:
+ switch (recip) {
+ case USB_RECIP_DEVICE:
+ if (ctrlrequest->wValue
+ != USB_DEVICE_REMOTE_WAKEUP)
+ break;
+ musb->may_wakeup = 0;
+ handled = 1;
+ break;
+ case USB_RECIP_INTERFACE:
+ break;
+ case USB_RECIP_ENDPOINT:{
+ const u8 epnum = ctrlrequest->wIndex & 0x0f;
+ struct musb_ep *musb_ep;
+
+ if (epnum == 0
+ || epnum >= MUSB_C_NUM_EPS
+ || ctrlrequest->wValue
+ != USB_ENDPOINT_HALT)
+ break;
+
+ if (ctrlrequest->wIndex & USB_DIR_IN)
+ musb_ep = &musb->endpoints[epnum].ep_in;
+ else
+ musb_ep = &musb->endpoints[epnum].ep_out;
+ if (!musb_ep->desc)
+ break;
+
+ /* REVISIT do it directly, no locking games */
+ spin_unlock(&musb->lock);
+ musb_gadget_set_halt(&musb_ep->end_point, 0);
+ spin_lock(&musb->lock);
+
+ /* select ep0 again */
+ musb_ep_select(mbase, 0);
+ handled = 1;
+ } break;
+ default:
+ /* class, vendor, etc ... delegate */
+ handled = 0;
+ break;
+ }
+ break;
+
+ case USB_REQ_SET_FEATURE:
+ switch (recip) {
+ case USB_RECIP_DEVICE:
+ handled = 1;
+ switch (ctrlrequest->wValue) {
+ case USB_DEVICE_REMOTE_WAKEUP:
+ musb->may_wakeup = 1;
+ break;
+ case USB_DEVICE_TEST_MODE:
+ if (musb->g.speed != USB_SPEED_HIGH)
+ goto stall;
+ if (ctrlrequest->wIndex & 0xff)
+ goto stall;
+
+ switch (ctrlrequest->wIndex >> 8) {
+ case 1:
+ pr_debug("TEST_J\n");
+ /* TEST_J */
+ musb->test_mode_nr =
+ MUSB_TEST_J;
+ break;
+ case 2:
+ /* TEST_K */
+ pr_debug("TEST_K\n");
+ musb->test_mode_nr =
+ MUSB_TEST_K;
+ break;
+ case 3:
+ /* TEST_SE0_NAK */
+ pr_debug("TEST_SE0_NAK\n");
+ musb->test_mode_nr =
+ MUSB_TEST_SE0_NAK;
+ break;
+ case 4:
+ /* TEST_PACKET */
+ pr_debug("TEST_PACKET\n");
+ musb->test_mode_nr =
+ MUSB_TEST_PACKET;
+ break;
+ default:
+ goto stall;
+ }
+
+ /* enter test mode after irq */
+ if (handled > 0)
+ musb->test_mode = true;
+ break;
+#ifdef CONFIG_USB_MUSB_OTG
+ case USB_DEVICE_B_HNP_ENABLE:
+ if (!musb->g.is_otg)
+ goto stall;
+ musb->g.b_hnp_enable = 1;
+ musb_try_b_hnp_enable(musb);
+ break;
+ case USB_DEVICE_A_HNP_SUPPORT:
+ if (!musb->g.is_otg)
+ goto stall;
+ musb->g.a_hnp_support = 1;
+ break;
+ case USB_DEVICE_A_ALT_HNP_SUPPORT:
+ if (!musb->g.is_otg)
+ goto stall;
+ musb->g.a_alt_hnp_support = 1;
+ break;
+#endif
+stall:
+ default:
+ handled = -EINVAL;
+ break;
+ }
+ break;
+
+ case USB_RECIP_INTERFACE:
+ break;
+
+ case USB_RECIP_ENDPOINT:{
+ const u8 epnum =
+ ctrlrequest->wIndex & 0x0f;
+ struct musb_ep *musb_ep;
+ struct musb_hw_ep *ep;
+ void __iomem *regs;
+ int is_in;
+ u16 csr;
+
+ if (epnum == 0
+ || epnum >= MUSB_C_NUM_EPS
+ || ctrlrequest->wValue
+ != USB_ENDPOINT_HALT)
+ break;
+
+ ep = musb->endpoints + epnum;
+ regs = ep->regs;
+ is_in = ctrlrequest->wIndex & USB_DIR_IN;
+ if (is_in)
+ musb_ep = &ep->ep_in;
+ else
+ musb_ep = &ep->ep_out;
+ if (!musb_ep->desc)
+ break;
+
+ musb_ep_select(mbase, epnum);
+ if (is_in) {
+ csr = musb_readw(regs,
+ MUSB_TXCSR);
+ if (csr & MUSB_TXCSR_FIFONOTEMPTY)
+ csr |= MUSB_TXCSR_FLUSHFIFO;
+ csr |= MUSB_TXCSR_P_SENDSTALL
+ | MUSB_TXCSR_CLRDATATOG
+ | MUSB_TXCSR_P_WZC_BITS;
+ musb_writew(regs, MUSB_TXCSR,
+ csr);
+ } else {
+ csr = musb_readw(regs,
+ MUSB_RXCSR);
+ csr |= MUSB_RXCSR_P_SENDSTALL
+ | MUSB_RXCSR_FLUSHFIFO
+ | MUSB_RXCSR_CLRDATATOG
+ | MUSB_TXCSR_P_WZC_BITS;
+ musb_writew(regs, MUSB_RXCSR,
+ csr);
+ }
+
+ /* select ep0 again */
+ musb_ep_select(mbase, 0);
+ handled = 1;
+ } break;
+
+ default:
+ /* class, vendor, etc ... delegate */
+ handled = 0;
+ break;
+ }
+ break;
+ default:
+ /* delegate SET_CONFIGURATION, etc */
+ handled = 0;
+ }
+ } else
+ handled = 0;
+ return handled;
+}
+
+/* we have an ep0out data packet
+ * Context: caller holds controller lock
+ */
+static void ep0_rxstate(struct musb *musb)
+{
+ void __iomem *regs = musb->control_ep->regs;
+ struct usb_request *req;
+ u16 tmp;
+
+ req = next_ep0_request(musb);
+
+ /* read packet and ack; or stall because of gadget driver bug:
+ * should have provided the rx buffer before setup() returned.
+ */
+ if (req) {
+ void *buf = req->buf + req->actual;
+ unsigned len = req->length - req->actual;
+
+ /* read the buffer */
+ tmp = musb_readb(regs, MUSB_COUNT0);
+ if (tmp > len) {
+ req->status = -EOVERFLOW;
+ tmp = len;
+ }
+ musb_read_fifo(&musb->endpoints[0], tmp, buf);
+ req->actual += tmp;
+ tmp = MUSB_CSR0_P_SVDRXPKTRDY;
+ if (tmp < 64 || req->actual == req->length) {
+ musb->ep0_state = MUSB_EP0_STAGE_STATUSIN;
+ tmp |= MUSB_CSR0_P_DATAEND;
+ } else
+ req = NULL;
+ } else
+ tmp = MUSB_CSR0_P_SVDRXPKTRDY | MUSB_CSR0_P_SENDSTALL;
+
+
+ /* Completion handler may choose to stall, e.g. because the
+ * message just received holds invalid data.
+ */
+ if (req) {
+ musb->ackpend = tmp;
+ musb_g_ep0_giveback(musb, req);
+ if (!musb->ackpend)
+ return;
+ musb->ackpend = 0;
+ }
+ musb_writew(regs, MUSB_CSR0, tmp);
+}
+
+/*
+ * transmitting to the host (IN), this code might be called from IRQ
+ * and from kernel thread.
+ *
+ * Context: caller holds controller lock
+ */
+static void ep0_txstate(struct musb *musb)
+{
+ void __iomem *regs = musb->control_ep->regs;
+ struct usb_request *request = next_ep0_request(musb);
+ u16 csr = MUSB_CSR0_TXPKTRDY;
+ u8 *fifo_src;
+ u8 fifo_count;
+
+ if (!request) {
+ /* WARN_ON(1); */
+ DBG(2, "odd; csr0 %04x\n", musb_readw(regs, MUSB_CSR0));
+ return;
+ }
+
+ /* load the data */
+ fifo_src = (u8 *) request->buf + request->actual;
+ fifo_count = min((unsigned) MUSB_EP0_FIFOSIZE,
+ request->length - request->actual);
+ musb_write_fifo(&musb->endpoints[0], fifo_count, fifo_src);
+ request->actual += fifo_count;
+
+ /* update the flags */
+ if (fifo_count < MUSB_MAX_END0_PACKET
+ || request->actual == request->length) {
+ musb->ep0_state = MUSB_EP0_STAGE_STATUSOUT;
+ csr |= MUSB_CSR0_P_DATAEND;
+ } else
+ request = NULL;
+
+ /* report completions as soon as the fifo's loaded; there's no
+ * win in waiting till this last packet gets acked. (other than
+ * very precise fault reporting, needed by USB TMC; possible with
+ * this hardware, but not usable from portable gadget drivers.)
+ */
+ if (request) {
+ musb->ackpend = csr;
+ musb_g_ep0_giveback(musb, request);
+ if (!musb->ackpend)
+ return;
+ musb->ackpend = 0;
+ }
+
+ /* send it out, triggering a "txpktrdy cleared" irq */
+ musb_writew(regs, MUSB_CSR0, csr);
+}
+
+/*
+ * Read a SETUP packet (struct usb_ctrlrequest) from the hardware.
+ * Fields are left in USB byte-order.
+ *
+ * Context: caller holds controller lock.
+ */
+static void
+musb_read_setup(struct musb *musb, struct usb_ctrlrequest *req)
+{
+ struct usb_request *r;
+ void __iomem *regs = musb->control_ep->regs;
+
+ musb_read_fifo(&musb->endpoints[0], sizeof *req, (u8 *)req);
+
+ /* NOTE: earlier 2.6 versions changed setup packets to host
+ * order, but now USB packets always stay in USB byte order.
+ */
+ DBG(3, "SETUP req%02x.%02x v%04x i%04x l%d\n",
+ req->bRequestType,
+ req->bRequest,
+ le16_to_cpu(req->wValue),
+ le16_to_cpu(req->wIndex),
+ le16_to_cpu(req->wLength));
+
+ /* clean up any leftover transfers */
+ r = next_ep0_request(musb);
+ if (r)
+ musb_g_ep0_giveback(musb, r);
+
+ /* For zero-data requests we want to delay the STATUS stage to
+ * avoid SETUPEND errors. If we read data (OUT), delay accepting
+ * packets until there's a buffer to store them in.
+ *
+ * If we write data, the controller acts happier if we enable
+ * the TX FIFO right away, and give the controller a moment
+ * to switch modes...
+ */
+ musb->set_address = false;
+ musb->ackpend = MUSB_CSR0_P_SVDRXPKTRDY;
+ if (req->wLength == 0) {
+ if (req->bRequestType & USB_DIR_IN)
+ musb->ackpend |= MUSB_CSR0_TXPKTRDY;
+ musb->ep0_state = MUSB_EP0_STAGE_ACKWAIT;
+ } else if (req->bRequestType & USB_DIR_IN) {
+ musb->ep0_state = MUSB_EP0_STAGE_TX;
+ musb_writew(regs, MUSB_CSR0, MUSB_CSR0_P_SVDRXPKTRDY);
+ while ((musb_readw(regs, MUSB_CSR0)
+ & MUSB_CSR0_RXPKTRDY) != 0)
+ cpu_relax();
+ musb->ackpend = 0;
+ } else
+ musb->ep0_state = MUSB_EP0_STAGE_RX;
+}
+
+static int
+forward_to_driver(struct musb *musb, const struct usb_ctrlrequest *ctrlrequest)
+__releases(musb->lock)
+__acquires(musb->lock)
+{
+ int retval;
+ if (!musb->gadget_driver)
+ return -EOPNOTSUPP;
+ spin_unlock(&musb->lock);
+ retval = musb->gadget_driver->setup(&musb->g, ctrlrequest);
+ spin_lock(&musb->lock);
+ return retval;
+}
+
+/*
+ * Handle peripheral ep0 interrupt
+ *
+ * Context: irq handler; we won't re-enter the driver that way.
+ */
+irqreturn_t musb_g_ep0_irq(struct musb *musb)
+{
+ u16 csr;
+ u16 len;
+ void __iomem *mbase = musb->mregs;
+ void __iomem *regs = musb->endpoints[0].regs;
+ irqreturn_t retval = IRQ_NONE;
+
+ musb_ep_select(mbase, 0); /* select ep0 */
+ csr = musb_readw(regs, MUSB_CSR0);
+ len = musb_readb(regs, MUSB_COUNT0);
+
+ DBG(4, "csr %04x, count %d, myaddr %d, ep0stage %s\n",
+ csr, len,
+ musb_readb(mbase, MUSB_FADDR),
+ decode_ep0stage(musb->ep0_state));
+
+ /* I sent a stall.. need to acknowledge it now.. */
+ if (csr & MUSB_CSR0_P_SENTSTALL) {
+ musb_writew(regs, MUSB_CSR0,
+ csr & ~MUSB_CSR0_P_SENTSTALL);
+ retval = IRQ_HANDLED;
+ musb->ep0_state = MUSB_EP0_STAGE_SETUP;
+ csr = musb_readw(regs, MUSB_CSR0);
+ }
+
+ /* request ended "early" */
+ if (csr & MUSB_CSR0_P_SETUPEND) {
+ musb_writew(regs, MUSB_CSR0, MUSB_CSR0_P_SVDSETUPEND);
+ retval = IRQ_HANDLED;
+ musb->ep0_state = MUSB_EP0_STAGE_SETUP;
+ csr = musb_readw(regs, MUSB_CSR0);
+ /* NOTE: request may need completion */
+ }
+
+ /* docs from Mentor only describe tx, rx, and idle/setup states.
+ * we need to handle nuances around status stages, and also the
+ * case where status and setup stages come back-to-back ...
+ */
+ switch (musb->ep0_state) {
+
+ case MUSB_EP0_STAGE_TX:
+ /* irq on clearing txpktrdy */
+ if ((csr & MUSB_CSR0_TXPKTRDY) == 0) {
+ ep0_txstate(musb);
+ retval = IRQ_HANDLED;
+ }
+ break;
+
+ case MUSB_EP0_STAGE_RX:
+ /* irq on set rxpktrdy */
+ if (csr & MUSB_CSR0_RXPKTRDY) {
+ ep0_rxstate(musb);
+ retval = IRQ_HANDLED;
+ }
+ break;
+
+ case MUSB_EP0_STAGE_STATUSIN:
+ /* end of sequence #2 (OUT/RX state) or #3 (no data) */
+
+ /* update address (if needed) only @ the end of the
+ * status phase per usb spec, which also guarantees
+ * we get 10 msec to receive this irq... until this
+ * is done we won't see the next packet.
+ */
+ if (musb->set_address) {
+ musb->set_address = false;
+ musb_writeb(mbase, MUSB_FADDR, musb->address);
+ }
+
+ /* enter test mode if needed (exit by reset) */
+ else if (musb->test_mode) {
+ DBG(1, "entering TESTMODE\n");
+
+ if (MUSB_TEST_PACKET == musb->test_mode_nr)
+ musb_load_testpacket(musb);
+
+ musb_writeb(mbase, MUSB_TESTMODE,
+ musb->test_mode_nr);
+ }
+ /* FALLTHROUGH */
+
+ case MUSB_EP0_STAGE_STATUSOUT:
+ /* end of sequence #1: write to host (TX state) */
+ {
+ struct usb_request *req;
+
+ req = next_ep0_request(musb);
+ if (req)
+ musb_g_ep0_giveback(musb, req);
+ }
+ retval = IRQ_HANDLED;
+ musb->ep0_state = MUSB_EP0_STAGE_SETUP;
+ /* FALLTHROUGH */
+
+ case MUSB_EP0_STAGE_SETUP:
+ if (csr & MUSB_CSR0_RXPKTRDY) {
+ struct usb_ctrlrequest setup;
+ int handled = 0;
+
+ if (len != 8) {
+ ERR("SETUP packet len %d != 8 ?\n", len);
+ break;
+ }
+ musb_read_setup(musb, &setup);
+ retval = IRQ_HANDLED;
+
+ /* sometimes the RESET won't be reported */
+ if (unlikely(musb->g.speed == USB_SPEED_UNKNOWN)) {
+ u8 power;
+
+ printk(KERN_NOTICE "%s: peripheral reset "
+ "irq lost!\n",
+ musb_driver_name);
+ power = musb_readb(mbase, MUSB_POWER);
+ musb->g.speed = (power & MUSB_POWER_HSMODE)
+ ? USB_SPEED_HIGH : USB_SPEED_FULL;
+
+ }
+
+ switch (musb->ep0_state) {
+
+ /* sequence #3 (no data stage), includes requests
+ * we can't forward (notably SET_ADDRESS and the
+ * device/endpoint feature set/clear operations)
+ * plus SET_CONFIGURATION and others we must
+ */
+ case MUSB_EP0_STAGE_ACKWAIT:
+ handled = service_zero_data_request(
+ musb, &setup);
+
+ /* status stage might be immediate */
+ if (handled > 0) {
+ musb->ackpend |= MUSB_CSR0_P_DATAEND;
+ musb->ep0_state =
+ MUSB_EP0_STAGE_STATUSIN;
+ }
+ break;
+
+ /* sequence #1 (IN to host), includes GET_STATUS
+ * requests that we can't forward, GET_DESCRIPTOR
+ * and others that we must
+ */
+ case MUSB_EP0_STAGE_TX:
+ handled = service_in_request(musb, &setup);
+ if (handled > 0) {
+ musb->ackpend = MUSB_CSR0_TXPKTRDY
+ | MUSB_CSR0_P_DATAEND;
+ musb->ep0_state =
+ MUSB_EP0_STAGE_STATUSOUT;
+ }
+ break;
+
+ /* sequence #2 (OUT from host), always forward */
+ default: /* MUSB_EP0_STAGE_RX */
+ break;
+ }
+
+ DBG(3, "handled %d, csr %04x, ep0stage %s\n",
+ handled, csr,
+ decode_ep0stage(musb->ep0_state));
+
+ /* unless we need to delegate this to the gadget
+ * driver, we know how to wrap this up: csr0 has
+ * not yet been written.
+ */
+ if (handled < 0)
+ goto stall;
+ else if (handled > 0)
+ goto finish;
+
+ handled = forward_to_driver(musb, &setup);
+ if (handled < 0) {
+ musb_ep_select(mbase, 0);
+stall:
+ DBG(3, "stall (%d)\n", handled);
+ musb->ackpend |= MUSB_CSR0_P_SENDSTALL;
+ musb->ep0_state = MUSB_EP0_STAGE_SETUP;
+finish:
+ musb_writew(regs, MUSB_CSR0,
+ musb->ackpend);
+ musb->ackpend = 0;
+ }
+ }
+ break;
+
+ case MUSB_EP0_STAGE_ACKWAIT:
+ /* This should not happen. But happens with tusb6010 with
+ * g_file_storage and high speed. Do nothing.
+ */
+ retval = IRQ_HANDLED;
+ break;
+
+ default:
+ /* "can't happen" */
+ WARN_ON(1);
+ musb_writew(regs, MUSB_CSR0, MUSB_CSR0_P_SENDSTALL);
+ musb->ep0_state = MUSB_EP0_STAGE_SETUP;
+ break;
+ }
+
+ return retval;
+}
+
+
+static int
+musb_g_ep0_enable(struct usb_ep *ep, const struct usb_endpoint_descriptor *desc)
+{
+ /* always enabled */
+ return -EINVAL;
+}
+
+static int musb_g_ep0_disable(struct usb_ep *e)
+{
+ /* always enabled */
+ return -EINVAL;
+}
+
+static int
+musb_g_ep0_queue(struct usb_ep *e, struct usb_request *r, gfp_t gfp_flags)
+{
+ struct musb_ep *ep;
+ struct musb_request *req;
+ struct musb *musb;
+ int status;
+ unsigned long lockflags;
+ void __iomem *regs;
+
+ if (!e || !r)
+ return -EINVAL;
+
+ ep = to_musb_ep(e);
+ musb = ep->musb;
+ regs = musb->control_ep->regs;
+
+ req = to_musb_request(r);
+ req->musb = musb;
+ req->request.actual = 0;
+ req->request.status = -EINPROGRESS;
+ req->tx = ep->is_in;
+
+ spin_lock_irqsave(&musb->lock, lockflags);
+
+ if (!list_empty(&ep->req_list)) {
+ status = -EBUSY;
+ goto cleanup;
+ }
+
+ switch (musb->ep0_state) {
+ case MUSB_EP0_STAGE_RX: /* control-OUT data */
+ case MUSB_EP0_STAGE_TX: /* control-IN data */
+ case MUSB_EP0_STAGE_ACKWAIT: /* zero-length data */
+ status = 0;
+ break;
+ default:
+ DBG(1, "ep0 request queued in state %d\n",
+ musb->ep0_state);
+ status = -EINVAL;
+ goto cleanup;
+ }
+
+ /* add request to the list */
+ list_add_tail(&(req->request.list), &(ep->req_list));
+
+ DBG(3, "queue to %s (%s), length=%d\n",
+ ep->name, ep->is_in ? "IN/TX" : "OUT/RX",
+ req->request.length);
+
+ musb_ep_select(musb->mregs, 0);
+
+ /* sequence #1, IN ... start writing the data */
+ if (musb->ep0_state == MUSB_EP0_STAGE_TX)
+ ep0_txstate(musb);
+
+ /* sequence #3, no-data ... issue IN status */
+ else if (musb->ep0_state == MUSB_EP0_STAGE_ACKWAIT) {
+ if (req->request.length)
+ status = -EINVAL;
+ else {
+ musb->ep0_state = MUSB_EP0_STAGE_STATUSIN;
+ musb_writew(regs, MUSB_CSR0,
+ musb->ackpend | MUSB_CSR0_P_DATAEND);
+ musb->ackpend = 0;
+ musb_g_ep0_giveback(ep->musb, r);
+ }
+
+ /* else for sequence #2 (OUT), caller provides a buffer
+ * before the next packet arrives. deferred responses
+ * (after SETUP is acked) are racey.
+ */
+ } else if (musb->ackpend) {
+ musb_writew(regs, MUSB_CSR0, musb->ackpend);
+ musb->ackpend = 0;
+ }
+
+cleanup:
+ spin_unlock_irqrestore(&musb->lock, lockflags);
+ return status;
+}
+
+static int musb_g_ep0_dequeue(struct usb_ep *ep, struct usb_request *req)
+{
+ /* we just won't support this */
+ return -EINVAL;
+}
+
+static int musb_g_ep0_halt(struct usb_ep *e, int value)
+{
+ struct musb_ep *ep;
+ struct musb *musb;
+ void __iomem *base, *regs;
+ unsigned long flags;
+ int status;
+ u16 csr;
+
+ if (!e || !value)
+ return -EINVAL;
+
+ ep = to_musb_ep(e);
+ musb = ep->musb;
+ base = musb->mregs;
+ regs = musb->control_ep->regs;
+ status = 0;
+
+ spin_lock_irqsave(&musb->lock, flags);
+
+ if (!list_empty(&ep->req_list)) {
+ status = -EBUSY;
+ goto cleanup;
+ }
+
+ musb_ep_select(base, 0);
+ csr = musb->ackpend;
+
+ switch (musb->ep0_state) {
+
+ /* Stalls are usually issued after parsing SETUP packet, either
+ * directly in irq context from setup() or else later.
+ */
+ case MUSB_EP0_STAGE_TX: /* control-IN data */
+ case MUSB_EP0_STAGE_ACKWAIT: /* STALL for zero-length data */
+ case MUSB_EP0_STAGE_RX: /* control-OUT data */
+ csr = musb_readw(regs, MUSB_CSR0);
+ /* FALLTHROUGH */
+
+ /* It's also OK to issue stalls during callbacks when a non-empty
+ * DATA stage buffer has been read (or even written).
+ */
+ case MUSB_EP0_STAGE_STATUSIN: /* control-OUT status */
+ case MUSB_EP0_STAGE_STATUSOUT: /* control-IN status */
+
+ csr |= MUSB_CSR0_P_SENDSTALL;
+ musb_writew(regs, MUSB_CSR0, csr);
+ musb->ep0_state = MUSB_EP0_STAGE_SETUP;
+ musb->ackpend = 0;
+ break;
+ default:
+ DBG(1, "ep0 can't halt in state %d\n", musb->ep0_state);
+ status = -EINVAL;
+ }
+
+cleanup:
+ spin_unlock_irqrestore(&musb->lock, flags);
+ return status;
+}
+
+const struct usb_ep_ops musb_g_ep0_ops = {
+ .enable = musb_g_ep0_enable,
+ .disable = musb_g_ep0_disable,
+ .alloc_request = musb_alloc_request,
+ .free_request = musb_free_request,
+ .queue = musb_g_ep0_queue,
+ .dequeue = musb_g_ep0_dequeue,
+ .set_halt = musb_g_ep0_halt,
+};
--- /dev/null
+/*
+ * MUSB OTG driver host support
+ *
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ * Copyright (C) 2006-2007 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * 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 AUTHORS 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/list.h>
+
+#include "musb_core.h"
+#include "musb_host.h"
+
+
+/* MUSB HOST status 22-mar-2006
+ *
+ * - There's still lots of partial code duplication for fault paths, so
+ * they aren't handled as consistently as they need to be.
+ *
+ * - PIO mostly behaved when last tested.
+ * + including ep0, with all usbtest cases 9, 10
+ * + usbtest 14 (ep0out) doesn't seem to run at all
+ * + double buffered OUT/TX endpoints saw stalls(!) with certain usbtest
+ * configurations, but otherwise double buffering passes basic tests.
+ * + for 2.6.N, for N > ~10, needs API changes for hcd framework.
+ *
+ * - DMA (CPPI) ... partially behaves, not currently recommended
+ * + about 1/15 the speed of typical EHCI implementations (PCI)
+ * + RX, all too often reqpkt seems to misbehave after tx
+ * + TX, no known issues (other than evident silicon issue)
+ *
+ * - DMA (Mentor/OMAP) ...has at least toggle update problems
+ *
+ * - Still no traffic scheduling code to make NAKing for bulk or control
+ * transfers unable to starve other requests; or to make efficient use
+ * of hardware with periodic transfers. (Note that network drivers
+ * commonly post bulk reads that stay pending for a long time; these
+ * would make very visible trouble.)
+ *
+ * - Not tested with HNP, but some SRP paths seem to behave.
+ *
+ * NOTE 24-August-2006:
+ *
+ * - Bulk traffic finally uses both sides of hardware ep1, freeing up an
+ * extra endpoint for periodic use enabling hub + keybd + mouse. That
+ * mostly works, except that with "usbnet" it's easy to trigger cases
+ * with "ping" where RX loses. (a) ping to davinci, even "ping -f",
+ * fine; but (b) ping _from_ davinci, even "ping -c 1", ICMP RX loses
+ * although ARP RX wins. (That test was done with a full speed link.)
+ */
+
+
+/*
+ * NOTE on endpoint usage:
+ *
+ * CONTROL transfers all go through ep0. BULK ones go through dedicated IN
+ * and OUT endpoints ... hardware is dedicated for those "async" queue(s).
+ *
+ * (Yes, bulk _could_ use more of the endpoints than that, and would even
+ * benefit from it ... one remote device may easily be NAKing while others
+ * need to perform transfers in that same direction. The same thing could
+ * be done in software though, assuming dma cooperates.)
+ *
+ * INTERUPPT and ISOCHRONOUS transfers are scheduled to the other endpoints.
+ * So far that scheduling is both dumb and optimistic: the endpoint will be
+ * "claimed" until its software queue is no longer refilled. No multiplexing
+ * of transfers between endpoints, or anything clever.
+ */
+
+
+static void musb_ep_program(struct musb *musb, u8 epnum,
+ struct urb *urb, unsigned int nOut,
+ u8 *buf, u32 len);
+
+/*
+ * Clear TX fifo. Needed to avoid BABBLE errors.
+ */
+static inline void musb_h_tx_flush_fifo(struct musb_hw_ep *ep)
+{
+ void __iomem *epio = ep->regs;
+ u16 csr;
+ int retries = 1000;
+
+ csr = musb_readw(epio, MUSB_TXCSR);
+ while (csr & MUSB_TXCSR_FIFONOTEMPTY) {
+ DBG(5, "Host TX FIFONOTEMPTY csr: %02x\n", csr);
+ csr |= MUSB_TXCSR_FLUSHFIFO;
+ musb_writew(epio, MUSB_TXCSR, csr);
+ csr = musb_readw(epio, MUSB_TXCSR);
+ if (retries-- < 1) {
+ ERR("Could not flush host TX fifo: csr: %04x\n", csr);
+ return;
+ }
+ mdelay(1);
+ }
+}
+
+/*
+ * Start transmit. Caller is responsible for locking shared resources.
+ * musb must be locked.
+ */
+static inline void musb_h_tx_start(struct musb_hw_ep *ep)
+{
+ u16 txcsr;
+
+ /* NOTE: no locks here; caller should lock and select EP */
+ if (ep->epnum) {
+ txcsr = musb_readw(ep->regs, MUSB_TXCSR);
+ txcsr |= MUSB_TXCSR_TXPKTRDY | MUSB_TXCSR_H_WZC_BITS;
+ musb_writew(ep->regs, MUSB_TXCSR, txcsr);
+ } else {
+ txcsr = MUSB_CSR0_H_SETUPPKT | MUSB_CSR0_TXPKTRDY;
+ musb_writew(ep->regs, MUSB_CSR0, txcsr);
+ }
+
+}
+
+static inline void cppi_host_txdma_start(struct musb_hw_ep *ep)
+{
+ u16 txcsr;
+
+ /* NOTE: no locks here; caller should lock and select EP */
+ txcsr = musb_readw(ep->regs, MUSB_TXCSR);
+ txcsr |= MUSB_TXCSR_DMAENAB | MUSB_TXCSR_H_WZC_BITS;
+ musb_writew(ep->regs, MUSB_TXCSR, txcsr);
+}
+
+/*
+ * Start the URB at the front of an endpoint's queue
+ * end must be claimed from the caller.
+ *
+ * Context: controller locked, irqs blocked
+ */
+static void
+musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh)
+{
+ u16 frame;
+ u32 len;
+ void *buf;
+ void __iomem *mbase = musb->mregs;
+ struct urb *urb = next_urb(qh);
+ struct musb_hw_ep *hw_ep = qh->hw_ep;
+ unsigned pipe = urb->pipe;
+ u8 address = usb_pipedevice(pipe);
+ int epnum = hw_ep->epnum;
+
+ /* initialize software qh state */
+ qh->offset = 0;
+ qh->segsize = 0;
+
+ /* gather right source of data */
+ switch (qh->type) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ /* control transfers always start with SETUP */
+ is_in = 0;
+ hw_ep->out_qh = qh;
+ musb->ep0_stage = MUSB_EP0_START;
+ buf = urb->setup_packet;
+ len = 8;
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ qh->iso_idx = 0;
+ qh->frame = 0;
+ buf = urb->transfer_buffer + urb->iso_frame_desc[0].offset;
+ len = urb->iso_frame_desc[0].length;
+ break;
+ default: /* bulk, interrupt */
+ buf = urb->transfer_buffer;
+ len = urb->transfer_buffer_length;
+ }
+
+ DBG(4, "qh %p urb %p dev%d ep%d%s%s, hw_ep %d, %p/%d\n",
+ qh, urb, address, qh->epnum,
+ is_in ? "in" : "out",
+ ({char *s; switch (qh->type) {
+ case USB_ENDPOINT_XFER_CONTROL: s = ""; break;
+ case USB_ENDPOINT_XFER_BULK: s = "-bulk"; break;
+ case USB_ENDPOINT_XFER_ISOC: s = "-iso"; break;
+ default: s = "-intr"; break;
+ }; s; }),
+ epnum, buf, len);
+
+ /* Configure endpoint */
+ if (is_in || hw_ep->is_shared_fifo)
+ hw_ep->in_qh = qh;
+ else
+ hw_ep->out_qh = qh;
+ musb_ep_program(musb, epnum, urb, !is_in, buf, len);
+
+ /* transmit may have more work: start it when it is time */
+ if (is_in)
+ return;
+
+ /* determine if the time is right for a periodic transfer */
+ switch (qh->type) {
+ case USB_ENDPOINT_XFER_ISOC:
+ case USB_ENDPOINT_XFER_INT:
+ DBG(3, "check whether there's still time for periodic Tx\n");
+ qh->iso_idx = 0;
+ frame = musb_readw(mbase, MUSB_FRAME);
+ /* FIXME this doesn't implement that scheduling policy ...
+ * or handle framecounter wrapping
+ */
+ if ((urb->transfer_flags & URB_ISO_ASAP)
+ || (frame >= urb->start_frame)) {
+ /* REVISIT the SOF irq handler shouldn't duplicate
+ * this code; and we don't init urb->start_frame...
+ */
+ qh->frame = 0;
+ goto start;
+ } else {
+ qh->frame = urb->start_frame;
+ /* enable SOF interrupt so we can count down */
+ DBG(1, "SOF for %d\n", epnum);
+#if 1 /* ifndef CONFIG_ARCH_DAVINCI */
+ musb_writeb(mbase, MUSB_INTRUSBE, 0xff);
+#endif
+ }
+ break;
+ default:
+start:
+ DBG(4, "Start TX%d %s\n", epnum,
+ hw_ep->tx_channel ? "dma" : "pio");
+
+ if (!hw_ep->tx_channel)
+ musb_h_tx_start(hw_ep);
+ else if (is_cppi_enabled() || tusb_dma_omap())
+ cppi_host_txdma_start(hw_ep);
+ }
+}
+
+/* caller owns controller lock, irqs are blocked */
+static void
+__musb_giveback(struct musb *musb, struct urb *urb, int status)
+__releases(musb->lock)
+__acquires(musb->lock)
+{
+ DBG(({ int level; switch (urb->status) {
+ case 0:
+ level = 4;
+ break;
+ /* common/boring faults */
+ case -EREMOTEIO:
+ case -ESHUTDOWN:
+ case -ECONNRESET:
+ case -EPIPE:
+ level = 3;
+ break;
+ default:
+ level = 2;
+ break;
+ }; level; }),
+ "complete %p (%d), dev%d ep%d%s, %d/%d\n",
+ urb, urb->status,
+ usb_pipedevice(urb->pipe),
+ usb_pipeendpoint(urb->pipe),
+ usb_pipein(urb->pipe) ? "in" : "out",
+ urb->actual_length, urb->transfer_buffer_length
+ );
+
+ spin_unlock(&musb->lock);
+ usb_hcd_giveback_urb(musb_to_hcd(musb), urb, status);
+ spin_lock(&musb->lock);
+}
+
+/* for bulk/interrupt endpoints only */
+static inline void
+musb_save_toggle(struct musb_hw_ep *ep, int is_in, struct urb *urb)
+{
+ struct usb_device *udev = urb->dev;
+ u16 csr;
+ void __iomem *epio = ep->regs;
+ struct musb_qh *qh;
+
+ /* FIXME: the current Mentor DMA code seems to have
+ * problems getting toggle correct.
+ */
+
+ if (is_in || ep->is_shared_fifo)
+ qh = ep->in_qh;
+ else
+ qh = ep->out_qh;
+
+ if (!is_in) {
+ csr = musb_readw(epio, MUSB_TXCSR);
+ usb_settoggle(udev, qh->epnum, 1,
+ (csr & MUSB_TXCSR_H_DATATOGGLE)
+ ? 1 : 0);
+ } else {
+ csr = musb_readw(epio, MUSB_RXCSR);
+ usb_settoggle(udev, qh->epnum, 0,
+ (csr & MUSB_RXCSR_H_DATATOGGLE)
+ ? 1 : 0);
+ }
+}
+
+/* caller owns controller lock, irqs are blocked */
+static struct musb_qh *
+musb_giveback(struct musb_qh *qh, struct urb *urb, int status)
+{
+ int is_in;
+ struct musb_hw_ep *ep = qh->hw_ep;
+ struct musb *musb = ep->musb;
+ int ready = qh->is_ready;
+
+ if (ep->is_shared_fifo)
+ is_in = 1;
+ else
+ is_in = usb_pipein(urb->pipe);
+
+ /* save toggle eagerly, for paranoia */
+ switch (qh->type) {
+ case USB_ENDPOINT_XFER_BULK:
+ case USB_ENDPOINT_XFER_INT:
+ musb_save_toggle(ep, is_in, urb);
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ if (status == 0 && urb->error_count)
+ status = -EXDEV;
+ break;
+ }
+
+ usb_hcd_unlink_urb_from_ep(musb_to_hcd(musb), urb);
+
+ qh->is_ready = 0;
+ __musb_giveback(musb, urb, status);
+ qh->is_ready = ready;
+
+ /* reclaim resources (and bandwidth) ASAP; deschedule it, and
+ * invalidate qh as soon as list_empty(&hep->urb_list)
+ */
+ if (list_empty(&qh->hep->urb_list)) {
+ struct list_head *head;
+
+ if (is_in)
+ ep->rx_reinit = 1;
+ else
+ ep->tx_reinit = 1;
+
+ /* clobber old pointers to this qh */
+ if (is_in || ep->is_shared_fifo)
+ ep->in_qh = NULL;
+ else
+ ep->out_qh = NULL;
+ qh->hep->hcpriv = NULL;
+
+ switch (qh->type) {
+
+ case USB_ENDPOINT_XFER_ISOC:
+ case USB_ENDPOINT_XFER_INT:
+ /* this is where periodic bandwidth should be
+ * de-allocated if it's tracked and allocated;
+ * and where we'd update the schedule tree...
+ */
+ musb->periodic[ep->epnum] = NULL;
+ kfree(qh);
+ qh = NULL;
+ break;
+
+ case USB_ENDPOINT_XFER_CONTROL:
+ case USB_ENDPOINT_XFER_BULK:
+ /* fifo policy for these lists, except that NAKing
+ * should rotate a qh to the end (for fairness).
+ */
+ head = qh->ring.prev;
+ list_del(&qh->ring);
+ kfree(qh);
+ qh = first_qh(head);
+ break;
+ }
+ }
+ return qh;
+}
+
+/*
+ * Advance this hardware endpoint's queue, completing the specified urb and
+ * advancing to either the next urb queued to that qh, or else invalidating
+ * that qh and advancing to the next qh scheduled after the current one.
+ *
+ * Context: caller owns controller lock, irqs are blocked
+ */
+static void
+musb_advance_schedule(struct musb *musb, struct urb *urb,
+ struct musb_hw_ep *hw_ep, int is_in)
+{
+ struct musb_qh *qh;
+
+ if (is_in || hw_ep->is_shared_fifo)
+ qh = hw_ep->in_qh;
+ else
+ qh = hw_ep->out_qh;
+ qh = musb_giveback(qh, urb, 0);
+
+ if (qh && qh->is_ready && !list_empty(&qh->hep->urb_list)) {
+ DBG(4, "... next ep%d %cX urb %p\n",
+ hw_ep->epnum, is_in ? 'R' : 'T',
+ next_urb(qh));
+ musb_start_urb(musb, is_in, qh);
+ }
+}
+
+static inline u16 musb_h_flush_rxfifo(struct musb_hw_ep *hw_ep, u16 csr)
+{
+ /* we don't want fifo to fill itself again;
+ * ignore dma (various models),
+ * leave toggle alone (may not have been saved yet)
+ */
+ csr |= MUSB_RXCSR_FLUSHFIFO | MUSB_RXCSR_RXPKTRDY;
+ csr &= ~(MUSB_RXCSR_H_REQPKT
+ | MUSB_RXCSR_H_AUTOREQ
+ | MUSB_RXCSR_AUTOCLEAR);
+
+ /* write 2x to allow double buffering */
+ musb_writew(hw_ep->regs, MUSB_RXCSR, csr);
+ musb_writew(hw_ep->regs, MUSB_RXCSR, csr);
+
+ /* flush writebuffer */
+ return musb_readw(hw_ep->regs, MUSB_RXCSR);
+}
+
+/*
+ * PIO RX for a packet (or part of it).
+ */
+static bool
+musb_host_packet_rx(struct musb *musb, struct urb *urb, u8 epnum, u8 iso_err)
+{
+ u16 rx_count;
+ u8 *buf;
+ u16 csr;
+ bool done = false;
+ u32 length;
+ int do_flush = 0;
+ struct musb_hw_ep *hw_ep = musb->endpoints + epnum;
+ void __iomem *epio = hw_ep->regs;
+ struct musb_qh *qh = hw_ep->in_qh;
+ int pipe = urb->pipe;
+ void *buffer = urb->transfer_buffer;
+
+ /* musb_ep_select(mbase, epnum); */
+ rx_count = musb_readw(epio, MUSB_RXCOUNT);
+ DBG(3, "RX%d count %d, buffer %p len %d/%d\n", epnum, rx_count,
+ urb->transfer_buffer, qh->offset,
+ urb->transfer_buffer_length);
+
+ /* unload FIFO */
+ if (usb_pipeisoc(pipe)) {
+ int status = 0;
+ struct usb_iso_packet_descriptor *d;
+
+ if (iso_err) {
+ status = -EILSEQ;
+ urb->error_count++;
+ }
+
+ d = urb->iso_frame_desc + qh->iso_idx;
+ buf = buffer + d->offset;
+ length = d->length;
+ if (rx_count > length) {
+ if (status == 0) {
+ status = -EOVERFLOW;
+ urb->error_count++;
+ }
+ DBG(2, "** OVERFLOW %d into %d\n", rx_count, length);
+ do_flush = 1;
+ } else
+ length = rx_count;
+ urb->actual_length += length;
+ d->actual_length = length;
+
+ d->status = status;
+
+ /* see if we are done */
+ done = (++qh->iso_idx >= urb->number_of_packets);
+ } else {
+ /* non-isoch */
+ buf = buffer + qh->offset;
+ length = urb->transfer_buffer_length - qh->offset;
+ if (rx_count > length) {
+ if (urb->status == -EINPROGRESS)
+ urb->status = -EOVERFLOW;
+ DBG(2, "** OVERFLOW %d into %d\n", rx_count, length);
+ do_flush = 1;
+ } else
+ length = rx_count;
+ urb->actual_length += length;
+ qh->offset += length;
+
+ /* see if we are done */
+ done = (urb->actual_length == urb->transfer_buffer_length)
+ || (rx_count < qh->maxpacket)
+ || (urb->status != -EINPROGRESS);
+ if (done
+ && (urb->status == -EINPROGRESS)
+ && (urb->transfer_flags & URB_SHORT_NOT_OK)
+ && (urb->actual_length
+ < urb->transfer_buffer_length))
+ urb->status = -EREMOTEIO;
+ }
+
+ musb_read_fifo(hw_ep, length, buf);
+
+ csr = musb_readw(epio, MUSB_RXCSR);
+ csr |= MUSB_RXCSR_H_WZC_BITS;
+ if (unlikely(do_flush))
+ musb_h_flush_rxfifo(hw_ep, csr);
+ else {
+ /* REVISIT this assumes AUTOCLEAR is never set */
+ csr &= ~(MUSB_RXCSR_RXPKTRDY | MUSB_RXCSR_H_REQPKT);
+ if (!done)
+ csr |= MUSB_RXCSR_H_REQPKT;
+ musb_writew(epio, MUSB_RXCSR, csr);
+ }
+
+ return done;
+}
+
+/* we don't always need to reinit a given side of an endpoint...
+ * when we do, use tx/rx reinit routine and then construct a new CSR
+ * to address data toggle, NYET, and DMA or PIO.
+ *
+ * it's possible that driver bugs (especially for DMA) or aborting a
+ * transfer might have left the endpoint busier than it should be.
+ * the busy/not-empty tests are basically paranoia.
+ */
+static void
+musb_rx_reinit(struct musb *musb, struct musb_qh *qh, struct musb_hw_ep *ep)
+{
+ u16 csr;
+
+ /* NOTE: we know the "rx" fifo reinit never triggers for ep0.
+ * That always uses tx_reinit since ep0 repurposes TX register
+ * offsets; the initial SETUP packet is also a kind of OUT.
+ */
+
+ /* if programmed for Tx, put it in RX mode */
+ if (ep->is_shared_fifo) {
+ csr = musb_readw(ep->regs, MUSB_TXCSR);
+ if (csr & MUSB_TXCSR_MODE) {
+ musb_h_tx_flush_fifo(ep);
+ musb_writew(ep->regs, MUSB_TXCSR,
+ MUSB_TXCSR_FRCDATATOG);
+ }
+ /* clear mode (and everything else) to enable Rx */
+ musb_writew(ep->regs, MUSB_TXCSR, 0);
+
+ /* scrub all previous state, clearing toggle */
+ } else {
+ csr = musb_readw(ep->regs, MUSB_RXCSR);
+ if (csr & MUSB_RXCSR_RXPKTRDY)
+ WARN("rx%d, packet/%d ready?\n", ep->epnum,
+ musb_readw(ep->regs, MUSB_RXCOUNT));
+
+ musb_h_flush_rxfifo(ep, MUSB_RXCSR_CLRDATATOG);
+ }
+
+ /* target addr and (for multipoint) hub addr/port */
+ if (musb->is_multipoint) {
+ musb_writeb(ep->target_regs, MUSB_RXFUNCADDR,
+ qh->addr_reg);
+ musb_writeb(ep->target_regs, MUSB_RXHUBADDR,
+ qh->h_addr_reg);
+ musb_writeb(ep->target_regs, MUSB_RXHUBPORT,
+ qh->h_port_reg);
+ } else
+ musb_writeb(musb->mregs, MUSB_FADDR, qh->addr_reg);
+
+ /* protocol/endpoint, interval/NAKlimit, i/o size */
+ musb_writeb(ep->regs, MUSB_RXTYPE, qh->type_reg);
+ musb_writeb(ep->regs, MUSB_RXINTERVAL, qh->intv_reg);
+ /* NOTE: bulk combining rewrites high bits of maxpacket */
+ musb_writew(ep->regs, MUSB_RXMAXP, qh->maxpacket);
+
+ ep->rx_reinit = 0;
+}
+
+
+/*
+ * Program an HDRC endpoint as per the given URB
+ * Context: irqs blocked, controller lock held
+ */
+static void musb_ep_program(struct musb *musb, u8 epnum,
+ struct urb *urb, unsigned int is_out,
+ u8 *buf, u32 len)
+{
+ struct dma_controller *dma_controller;
+ struct dma_channel *dma_channel;
+ u8 dma_ok;
+ void __iomem *mbase = musb->mregs;
+ struct musb_hw_ep *hw_ep = musb->endpoints + epnum;
+ void __iomem *epio = hw_ep->regs;
+ struct musb_qh *qh;
+ u16 packet_sz;
+
+ if (!is_out || hw_ep->is_shared_fifo)
+ qh = hw_ep->in_qh;
+ else
+ qh = hw_ep->out_qh;
+
+ packet_sz = qh->maxpacket;
+
+ DBG(3, "%s hw%d urb %p spd%d dev%d ep%d%s "
+ "h_addr%02x h_port%02x bytes %d\n",
+ is_out ? "-->" : "<--",
+ epnum, urb, urb->dev->speed,
+ qh->addr_reg, qh->epnum, is_out ? "out" : "in",
+ qh->h_addr_reg, qh->h_port_reg,
+ len);
+
+ musb_ep_select(mbase, epnum);
+
+ /* candidate for DMA? */
+ dma_controller = musb->dma_controller;
+ if (is_dma_capable() && epnum && dma_controller) {
+ dma_channel = is_out ? hw_ep->tx_channel : hw_ep->rx_channel;
+ if (!dma_channel) {
+ dma_channel = dma_controller->channel_alloc(
+ dma_controller, hw_ep, is_out);
+ if (is_out)
+ hw_ep->tx_channel = dma_channel;
+ else
+ hw_ep->rx_channel = dma_channel;
+ }
+ } else
+ dma_channel = NULL;
+
+ /* make sure we clear DMAEnab, autoSet bits from previous run */
+
+ /* OUT/transmit/EP0 or IN/receive? */
+ if (is_out) {
+ u16 csr;
+ u16 int_txe;
+ u16 load_count;
+
+ csr = musb_readw(epio, MUSB_TXCSR);
+
+ /* disable interrupt in case we flush */
+ int_txe = musb_readw(mbase, MUSB_INTRTXE);
+ musb_writew(mbase, MUSB_INTRTXE, int_txe & ~(1 << epnum));
+
+ /* general endpoint setup */
+ if (epnum) {
+ /* ASSERT: TXCSR_DMAENAB was already cleared */
+
+ /* flush all old state, set default */
+ musb_h_tx_flush_fifo(hw_ep);
+ csr &= ~(MUSB_TXCSR_H_NAKTIMEOUT
+ | MUSB_TXCSR_DMAMODE
+ | MUSB_TXCSR_FRCDATATOG
+ | MUSB_TXCSR_H_RXSTALL
+ | MUSB_TXCSR_H_ERROR
+ | MUSB_TXCSR_TXPKTRDY
+ );
+ csr |= MUSB_TXCSR_MODE;
+
+ if (usb_gettoggle(urb->dev,
+ qh->epnum, 1))
+ csr |= MUSB_TXCSR_H_WR_DATATOGGLE
+ | MUSB_TXCSR_H_DATATOGGLE;
+ else
+ csr |= MUSB_TXCSR_CLRDATATOG;
+
+ /* twice in case of double packet buffering */
+ musb_writew(epio, MUSB_TXCSR, csr);
+ /* REVISIT may need to clear FLUSHFIFO ... */
+ musb_writew(epio, MUSB_TXCSR, csr);
+ csr = musb_readw(epio, MUSB_TXCSR);
+ } else {
+ /* endpoint 0: just flush */
+ musb_writew(epio, MUSB_CSR0,
+ csr | MUSB_CSR0_FLUSHFIFO);
+ musb_writew(epio, MUSB_CSR0,
+ csr | MUSB_CSR0_FLUSHFIFO);
+ }
+
+ /* target addr and (for multipoint) hub addr/port */
+ if (musb->is_multipoint) {
+ musb_writeb(mbase,
+ MUSB_BUSCTL_OFFSET(epnum, MUSB_TXFUNCADDR),
+ qh->addr_reg);
+ musb_writeb(mbase,
+ MUSB_BUSCTL_OFFSET(epnum, MUSB_TXHUBADDR),
+ qh->h_addr_reg);
+ musb_writeb(mbase,
+ MUSB_BUSCTL_OFFSET(epnum, MUSB_TXHUBPORT),
+ qh->h_port_reg);
+/* FIXME if !epnum, do the same for RX ... */
+ } else
+ musb_writeb(mbase, MUSB_FADDR, qh->addr_reg);
+
+ /* protocol/endpoint/interval/NAKlimit */
+ if (epnum) {
+ musb_writeb(epio, MUSB_TXTYPE, qh->type_reg);
+ if (can_bulk_split(musb, qh->type))
+ musb_writew(epio, MUSB_TXMAXP,
+ packet_sz
+ | ((hw_ep->max_packet_sz_tx /
+ packet_sz) - 1) << 11);
+ else
+ musb_writew(epio, MUSB_TXMAXP,
+ packet_sz);
+ musb_writeb(epio, MUSB_TXINTERVAL, qh->intv_reg);
+ } else {
+ musb_writeb(epio, MUSB_NAKLIMIT0, qh->intv_reg);
+ if (musb->is_multipoint)
+ musb_writeb(epio, MUSB_TYPE0,
+ qh->type_reg);
+ }
+
+ if (can_bulk_split(musb, qh->type))
+ load_count = min((u32) hw_ep->max_packet_sz_tx,
+ len);
+ else
+ load_count = min((u32) packet_sz, len);
+
+#ifdef CONFIG_USB_INVENTRA_DMA
+ if (dma_channel) {
+
+ /* clear previous state */
+ csr = musb_readw(epio, MUSB_TXCSR);
+ csr &= ~(MUSB_TXCSR_AUTOSET
+ | MUSB_TXCSR_DMAMODE
+ | MUSB_TXCSR_DMAENAB);
+ csr |= MUSB_TXCSR_MODE;
+ musb_writew(epio, MUSB_TXCSR,
+ csr | MUSB_TXCSR_MODE);
+
+ qh->segsize = min(len, dma_channel->max_len);
+
+ if (qh->segsize <= packet_sz)
+ dma_channel->desired_mode = 0;
+ else
+ dma_channel->desired_mode = 1;
+
+
+ if (dma_channel->desired_mode == 0) {
+ csr &= ~(MUSB_TXCSR_AUTOSET
+ | MUSB_TXCSR_DMAMODE);
+ csr |= (MUSB_TXCSR_DMAENAB);
+ /* against programming guide */
+ } else
+ csr |= (MUSB_TXCSR_AUTOSET
+ | MUSB_TXCSR_DMAENAB
+ | MUSB_TXCSR_DMAMODE);
+
+ musb_writew(epio, MUSB_TXCSR, csr);
+
+ dma_ok = dma_controller->channel_program(
+ dma_channel, packet_sz,
+ dma_channel->desired_mode,
+ urb->transfer_dma,
+ qh->segsize);
+ if (dma_ok) {
+ load_count = 0;
+ } else {
+ dma_controller->channel_release(dma_channel);
+ if (is_out)
+ hw_ep->tx_channel = NULL;
+ else
+ hw_ep->rx_channel = NULL;
+ dma_channel = NULL;
+ }
+ }
+#endif
+
+ /* candidate for DMA */
+ if ((is_cppi_enabled() || tusb_dma_omap()) && dma_channel) {
+
+ /* program endpoint CSRs first, then setup DMA.
+ * assume CPPI setup succeeds.
+ * defer enabling dma.
+ */
+ csr = musb_readw(epio, MUSB_TXCSR);
+ csr &= ~(MUSB_TXCSR_AUTOSET
+ | MUSB_TXCSR_DMAMODE
+ | MUSB_TXCSR_DMAENAB);
+ csr |= MUSB_TXCSR_MODE;
+ musb_writew(epio, MUSB_TXCSR,
+ csr | MUSB_TXCSR_MODE);
+
+ dma_channel->actual_len = 0L;
+ qh->segsize = len;
+
+ /* TX uses "rndis" mode automatically, but needs help
+ * to identify the zero-length-final-packet case.
+ */
+ dma_ok = dma_controller->channel_program(
+ dma_channel, packet_sz,
+ (urb->transfer_flags
+ & URB_ZERO_PACKET)
+ == URB_ZERO_PACKET,
+ urb->transfer_dma,
+ qh->segsize);
+ if (dma_ok) {
+ load_count = 0;
+ } else {
+ dma_controller->channel_release(dma_channel);
+ dma_channel = hw_ep->tx_channel = NULL;
+
+ /* REVISIT there's an error path here that
+ * needs handling: can't do dma, but
+ * there's no pio buffer address...
+ */
+ }
+ }
+
+ if (load_count) {
+ /* ASSERT: TXCSR_DMAENAB was already cleared */
+
+ /* PIO to load FIFO */
+ qh->segsize = load_count;
+ musb_write_fifo(hw_ep, load_count, buf);
+ csr = musb_readw(epio, MUSB_TXCSR);
+ csr &= ~(MUSB_TXCSR_DMAENAB
+ | MUSB_TXCSR_DMAMODE
+ | MUSB_TXCSR_AUTOSET);
+ /* write CSR */
+ csr |= MUSB_TXCSR_MODE;
+
+ if (epnum)
+ musb_writew(epio, MUSB_TXCSR, csr);
+ }
+
+ /* re-enable interrupt */
+ musb_writew(mbase, MUSB_INTRTXE, int_txe);
+
+ /* IN/receive */
+ } else {
+ u16 csr;
+
+ if (hw_ep->rx_reinit) {
+ musb_rx_reinit(musb, qh, hw_ep);
+
+ /* init new state: toggle and NYET, maybe DMA later */
+ if (usb_gettoggle(urb->dev, qh->epnum, 0))
+ csr = MUSB_RXCSR_H_WR_DATATOGGLE
+ | MUSB_RXCSR_H_DATATOGGLE;
+ else
+ csr = 0;
+ if (qh->type == USB_ENDPOINT_XFER_INT)
+ csr |= MUSB_RXCSR_DISNYET;
+
+ } else {
+ csr = musb_readw(hw_ep->regs, MUSB_RXCSR);
+
+ if (csr & (MUSB_RXCSR_RXPKTRDY
+ | MUSB_RXCSR_DMAENAB
+ | MUSB_RXCSR_H_REQPKT))
+ ERR("broken !rx_reinit, ep%d csr %04x\n",
+ hw_ep->epnum, csr);
+
+ /* scrub any stale state, leaving toggle alone */
+ csr &= MUSB_RXCSR_DISNYET;
+ }
+
+ /* kick things off */
+
+ if ((is_cppi_enabled() || tusb_dma_omap()) && dma_channel) {
+ /* candidate for DMA */
+ if (dma_channel) {
+ dma_channel->actual_len = 0L;
+ qh->segsize = len;
+
+ /* AUTOREQ is in a DMA register */
+ musb_writew(hw_ep->regs, MUSB_RXCSR, csr);
+ csr = musb_readw(hw_ep->regs,
+ MUSB_RXCSR);
+
+ /* unless caller treats short rx transfers as
+ * errors, we dare not queue multiple transfers.
+ */
+ dma_ok = dma_controller->channel_program(
+ dma_channel, packet_sz,
+ !(urb->transfer_flags
+ & URB_SHORT_NOT_OK),
+ urb->transfer_dma,
+ qh->segsize);
+ if (!dma_ok) {
+ dma_controller->channel_release(
+ dma_channel);
+ dma_channel = hw_ep->rx_channel = NULL;
+ } else
+ csr |= MUSB_RXCSR_DMAENAB;
+ }
+ }
+
+ csr |= MUSB_RXCSR_H_REQPKT;
+ DBG(7, "RXCSR%d := %04x\n", epnum, csr);
+ musb_writew(hw_ep->regs, MUSB_RXCSR, csr);
+ csr = musb_readw(hw_ep->regs, MUSB_RXCSR);
+ }
+}
+
+
+/*
+ * Service the default endpoint (ep0) as host.
+ * Return true until it's time to start the status stage.
+ */
+static bool musb_h_ep0_continue(struct musb *musb, u16 len, struct urb *urb)
+{
+ bool more = false;
+ u8 *fifo_dest = NULL;
+ u16 fifo_count = 0;
+ struct musb_hw_ep *hw_ep = musb->control_ep;
+ struct musb_qh *qh = hw_ep->in_qh;
+ struct usb_ctrlrequest *request;
+
+ switch (musb->ep0_stage) {
+ case MUSB_EP0_IN:
+ fifo_dest = urb->transfer_buffer + urb->actual_length;
+ fifo_count = min(len, ((u16) (urb->transfer_buffer_length
+ - urb->actual_length)));
+ if (fifo_count < len)
+ urb->status = -EOVERFLOW;
+
+ musb_read_fifo(hw_ep, fifo_count, fifo_dest);
+
+ urb->actual_length += fifo_count;
+ if (len < qh->maxpacket) {
+ /* always terminate on short read; it's
+ * rarely reported as an error.
+ */
+ } else if (urb->actual_length <
+ urb->transfer_buffer_length)
+ more = true;
+ break;
+ case MUSB_EP0_START:
+ request = (struct usb_ctrlrequest *) urb->setup_packet;
+
+ if (!request->wLength) {
+ DBG(4, "start no-DATA\n");
+ break;
+ } else if (request->bRequestType & USB_DIR_IN) {
+ DBG(4, "start IN-DATA\n");
+ musb->ep0_stage = MUSB_EP0_IN;
+ more = true;
+ break;
+ } else {
+ DBG(4, "start OUT-DATA\n");
+ musb->ep0_stage = MUSB_EP0_OUT;
+ more = true;
+ }
+ /* FALLTHROUGH */
+ case MUSB_EP0_OUT:
+ fifo_count = min(qh->maxpacket, ((u16)
+ (urb->transfer_buffer_length
+ - urb->actual_length)));
+
+ if (fifo_count) {
+ fifo_dest = (u8 *) (urb->transfer_buffer
+ + urb->actual_length);
+ DBG(3, "Sending %d bytes to %p\n",
+ fifo_count, fifo_dest);
+ musb_write_fifo(hw_ep, fifo_count, fifo_dest);
+
+ urb->actual_length += fifo_count;
+ more = true;
+ }
+ break;
+ default:
+ ERR("bogus ep0 stage %d\n", musb->ep0_stage);
+ break;
+ }
+
+ return more;
+}
+
+/*
+ * Handle default endpoint interrupt as host. Only called in IRQ time
+ * from the LinuxIsr() interrupt service routine.
+ *
+ * called with controller irqlocked
+ */
+irqreturn_t musb_h_ep0_irq(struct musb *musb)
+{
+ struct urb *urb;
+ u16 csr, len;
+ int status = 0;
+ void __iomem *mbase = musb->mregs;
+ struct musb_hw_ep *hw_ep = musb->control_ep;
+ void __iomem *epio = hw_ep->regs;
+ struct musb_qh *qh = hw_ep->in_qh;
+ bool complete = false;
+ irqreturn_t retval = IRQ_NONE;
+
+ /* ep0 only has one queue, "in" */
+ urb = next_urb(qh);
+
+ musb_ep_select(mbase, 0);
+ csr = musb_readw(epio, MUSB_CSR0);
+ len = (csr & MUSB_CSR0_RXPKTRDY)
+ ? musb_readb(epio, MUSB_COUNT0)
+ : 0;
+
+ DBG(4, "<== csr0 %04x, qh %p, count %d, urb %p, stage %d\n",
+ csr, qh, len, urb, musb->ep0_stage);
+
+ /* if we just did status stage, we are done */
+ if (MUSB_EP0_STATUS == musb->ep0_stage) {
+ retval = IRQ_HANDLED;
+ complete = true;
+ }
+
+ /* prepare status */
+ if (csr & MUSB_CSR0_H_RXSTALL) {
+ DBG(6, "STALLING ENDPOINT\n");
+ status = -EPIPE;
+
+ } else if (csr & MUSB_CSR0_H_ERROR) {
+ DBG(2, "no response, csr0 %04x\n", csr);
+ status = -EPROTO;
+
+ } else if (csr & MUSB_CSR0_H_NAKTIMEOUT) {
+ DBG(2, "control NAK timeout\n");
+
+ /* NOTE: this code path would be a good place to PAUSE a
+ * control transfer, if another one is queued, so that
+ * ep0 is more likely to stay busy.
+ *
+ * if (qh->ring.next != &musb->control), then
+ * we have a candidate... NAKing is *NOT* an error
+ */
+ musb_writew(epio, MUSB_CSR0, 0);
+ retval = IRQ_HANDLED;
+ }
+
+ if (status) {
+ DBG(6, "aborting\n");
+ retval = IRQ_HANDLED;
+ if (urb)
+ urb->status = status;
+ complete = true;
+
+ /* use the proper sequence to abort the transfer */
+ if (csr & MUSB_CSR0_H_REQPKT) {
+ csr &= ~MUSB_CSR0_H_REQPKT;
+ musb_writew(epio, MUSB_CSR0, csr);
+ csr &= ~MUSB_CSR0_H_NAKTIMEOUT;
+ musb_writew(epio, MUSB_CSR0, csr);
+ } else {
+ csr |= MUSB_CSR0_FLUSHFIFO;
+ musb_writew(epio, MUSB_CSR0, csr);
+ musb_writew(epio, MUSB_CSR0, csr);
+ csr &= ~MUSB_CSR0_H_NAKTIMEOUT;
+ musb_writew(epio, MUSB_CSR0, csr);
+ }
+
+ musb_writeb(epio, MUSB_NAKLIMIT0, 0);
+
+ /* clear it */
+ musb_writew(epio, MUSB_CSR0, 0);
+ }
+
+ if (unlikely(!urb)) {
+ /* stop endpoint since we have no place for its data, this
+ * SHOULD NEVER HAPPEN! */
+ ERR("no URB for end 0\n");
+
+ musb_writew(epio, MUSB_CSR0, MUSB_CSR0_FLUSHFIFO);
+ musb_writew(epio, MUSB_CSR0, MUSB_CSR0_FLUSHFIFO);
+ musb_writew(epio, MUSB_CSR0, 0);
+
+ goto done;
+ }
+
+ if (!complete) {
+ /* call common logic and prepare response */
+ if (musb_h_ep0_continue(musb, len, urb)) {
+ /* more packets required */
+ csr = (MUSB_EP0_IN == musb->ep0_stage)
+ ? MUSB_CSR0_H_REQPKT : MUSB_CSR0_TXPKTRDY;
+ } else {
+ /* data transfer complete; perform status phase */
+ if (usb_pipeout(urb->pipe)
+ || !urb->transfer_buffer_length)
+ csr = MUSB_CSR0_H_STATUSPKT
+ | MUSB_CSR0_H_REQPKT;
+ else
+ csr = MUSB_CSR0_H_STATUSPKT
+ | MUSB_CSR0_TXPKTRDY;
+
+ /* flag status stage */
+ musb->ep0_stage = MUSB_EP0_STATUS;
+
+ DBG(5, "ep0 STATUS, csr %04x\n", csr);
+
+ }
+ musb_writew(epio, MUSB_CSR0, csr);
+ retval = IRQ_HANDLED;
+ } else
+ musb->ep0_stage = MUSB_EP0_IDLE;
+
+ /* call completion handler if done */
+ if (complete)
+ musb_advance_schedule(musb, urb, hw_ep, 1);
+done:
+ return retval;
+}
+
+
+#ifdef CONFIG_USB_INVENTRA_DMA
+
+/* Host side TX (OUT) using Mentor DMA works as follows:
+ submit_urb ->
+ - if queue was empty, Program Endpoint
+ - ... which starts DMA to fifo in mode 1 or 0
+
+ DMA Isr (transfer complete) -> TxAvail()
+ - Stop DMA (~DmaEnab) (<--- Alert ... currently happens
+ only in musb_cleanup_urb)
+ - TxPktRdy has to be set in mode 0 or for
+ short packets in mode 1.
+*/
+
+#endif
+
+/* Service a Tx-Available or dma completion irq for the endpoint */
+void musb_host_tx(struct musb *musb, u8 epnum)
+{
+ int pipe;
+ bool done = false;
+ u16 tx_csr;
+ size_t wLength = 0;
+ u8 *buf = NULL;
+ struct urb *urb;
+ struct musb_hw_ep *hw_ep = musb->endpoints + epnum;
+ void __iomem *epio = hw_ep->regs;
+ struct musb_qh *qh = hw_ep->out_qh;
+ u32 status = 0;
+ void __iomem *mbase = musb->mregs;
+ struct dma_channel *dma;
+
+ urb = next_urb(qh);
+
+ musb_ep_select(mbase, epnum);
+ tx_csr = musb_readw(epio, MUSB_TXCSR);
+
+ /* with CPPI, DMA sometimes triggers "extra" irqs */
+ if (!urb) {
+ DBG(4, "extra TX%d ready, csr %04x\n", epnum, tx_csr);
+ goto finish;
+ }
+
+ pipe = urb->pipe;
+ dma = is_dma_capable() ? hw_ep->tx_channel : NULL;
+ DBG(4, "OUT/TX%d end, csr %04x%s\n", epnum, tx_csr,
+ dma ? ", dma" : "");
+
+ /* check for errors */
+ if (tx_csr & MUSB_TXCSR_H_RXSTALL) {
+ /* dma was disabled, fifo flushed */
+ DBG(3, "TX end %d stall\n", epnum);
+
+ /* stall; record URB status */
+ status = -EPIPE;
+
+ } else if (tx_csr & MUSB_TXCSR_H_ERROR) {
+ /* (NON-ISO) dma was disabled, fifo flushed */
+ DBG(3, "TX 3strikes on ep=%d\n", epnum);
+
+ status = -ETIMEDOUT;
+
+ } else if (tx_csr & MUSB_TXCSR_H_NAKTIMEOUT) {
+ DBG(6, "TX end=%d device not responding\n", epnum);
+
+ /* NOTE: this code path would be a good place to PAUSE a
+ * transfer, if there's some other (nonperiodic) tx urb
+ * that could use this fifo. (dma complicates it...)
+ *
+ * if (bulk && qh->ring.next != &musb->out_bulk), then
+ * we have a candidate... NAKing is *NOT* an error
+ */
+ musb_ep_select(mbase, epnum);
+ musb_writew(epio, MUSB_TXCSR,
+ MUSB_TXCSR_H_WZC_BITS
+ | MUSB_TXCSR_TXPKTRDY);
+ goto finish;
+ }
+
+ if (status) {
+ if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
+ dma->status = MUSB_DMA_STATUS_CORE_ABORT;
+ (void) musb->dma_controller->channel_abort(dma);
+ }
+
+ /* do the proper sequence to abort the transfer in the
+ * usb core; the dma engine should already be stopped.
+ */
+ musb_h_tx_flush_fifo(hw_ep);
+ tx_csr &= ~(MUSB_TXCSR_AUTOSET
+ | MUSB_TXCSR_DMAENAB
+ | MUSB_TXCSR_H_ERROR
+ | MUSB_TXCSR_H_RXSTALL
+ | MUSB_TXCSR_H_NAKTIMEOUT
+ );
+
+ musb_ep_select(mbase, epnum);
+ musb_writew(epio, MUSB_TXCSR, tx_csr);
+ /* REVISIT may need to clear FLUSHFIFO ... */
+ musb_writew(epio, MUSB_TXCSR, tx_csr);
+ musb_writeb(epio, MUSB_TXINTERVAL, 0);
+
+ done = true;
+ }
+
+ /* second cppi case */
+ if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
+ DBG(4, "extra TX%d ready, csr %04x\n", epnum, tx_csr);
+ goto finish;
+
+ }
+
+ /* REVISIT this looks wrong... */
+ if (!status || dma || usb_pipeisoc(pipe)) {
+ if (dma)
+ wLength = dma->actual_len;
+ else
+ wLength = qh->segsize;
+ qh->offset += wLength;
+
+ if (usb_pipeisoc(pipe)) {
+ struct usb_iso_packet_descriptor *d;
+
+ d = urb->iso_frame_desc + qh->iso_idx;
+ d->actual_length = qh->segsize;
+ if (++qh->iso_idx >= urb->number_of_packets) {
+ done = true;
+ } else {
+ d++;
+ buf = urb->transfer_buffer + d->offset;
+ wLength = d->length;
+ }
+ } else if (dma) {
+ done = true;
+ } else {
+ /* see if we need to send more data, or ZLP */
+ if (qh->segsize < qh->maxpacket)
+ done = true;
+ else if (qh->offset == urb->transfer_buffer_length
+ && !(urb->transfer_flags
+ & URB_ZERO_PACKET))
+ done = true;
+ if (!done) {
+ buf = urb->transfer_buffer
+ + qh->offset;
+ wLength = urb->transfer_buffer_length
+ - qh->offset;
+ }
+ }
+ }
+
+ /* urb->status != -EINPROGRESS means request has been faulted,
+ * so we must abort this transfer after cleanup
+ */
+ if (urb->status != -EINPROGRESS) {
+ done = true;
+ if (status == 0)
+ status = urb->status;
+ }
+
+ if (done) {
+ /* set status */
+ urb->status = status;
+ urb->actual_length = qh->offset;
+ musb_advance_schedule(musb, urb, hw_ep, USB_DIR_OUT);
+
+ } else if (!(tx_csr & MUSB_TXCSR_DMAENAB)) {
+ /* WARN_ON(!buf); */
+
+ /* REVISIT: some docs say that when hw_ep->tx_double_buffered,
+ * (and presumably, fifo is not half-full) we should write TWO
+ * packets before updating TXCSR ... other docs disagree ...
+ */
+ /* PIO: start next packet in this URB */
+ wLength = min(qh->maxpacket, (u16) wLength);
+ musb_write_fifo(hw_ep, wLength, buf);
+ qh->segsize = wLength;
+
+ musb_ep_select(mbase, epnum);
+ musb_writew(epio, MUSB_TXCSR,
+ MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY);
+ } else
+ DBG(1, "not complete, but dma enabled?\n");
+
+finish:
+ return;
+}
+
+
+#ifdef CONFIG_USB_INVENTRA_DMA
+
+/* Host side RX (IN) using Mentor DMA works as follows:
+ submit_urb ->
+ - if queue was empty, ProgramEndpoint
+ - first IN token is sent out (by setting ReqPkt)
+ LinuxIsr -> RxReady()
+ /\ => first packet is received
+ | - Set in mode 0 (DmaEnab, ~ReqPkt)
+ | -> DMA Isr (transfer complete) -> RxReady()
+ | - Ack receive (~RxPktRdy), turn off DMA (~DmaEnab)
+ | - if urb not complete, send next IN token (ReqPkt)
+ | | else complete urb.
+ | |
+ ---------------------------
+ *
+ * Nuances of mode 1:
+ * For short packets, no ack (+RxPktRdy) is sent automatically
+ * (even if AutoClear is ON)
+ * For full packets, ack (~RxPktRdy) and next IN token (+ReqPkt) is sent
+ * automatically => major problem, as collecting the next packet becomes
+ * difficult. Hence mode 1 is not used.
+ *
+ * REVISIT
+ * All we care about at this driver level is that
+ * (a) all URBs terminate with REQPKT cleared and fifo(s) empty;
+ * (b) termination conditions are: short RX, or buffer full;
+ * (c) fault modes include
+ * - iff URB_SHORT_NOT_OK, short RX status is -EREMOTEIO.
+ * (and that endpoint's dma queue stops immediately)
+ * - overflow (full, PLUS more bytes in the terminal packet)
+ *
+ * So for example, usb-storage sets URB_SHORT_NOT_OK, and would
+ * thus be a great candidate for using mode 1 ... for all but the
+ * last packet of one URB's transfer.
+ */
+
+#endif
+
+/*
+ * Service an RX interrupt for the given IN endpoint; docs cover bulk, iso,
+ * and high-bandwidth IN transfer cases.
+ */
+void musb_host_rx(struct musb *musb, u8 epnum)
+{
+ struct urb *urb;
+ struct musb_hw_ep *hw_ep = musb->endpoints + epnum;
+ void __iomem *epio = hw_ep->regs;
+ struct musb_qh *qh = hw_ep->in_qh;
+ size_t xfer_len;
+ void __iomem *mbase = musb->mregs;
+ int pipe;
+ u16 rx_csr, val;
+ bool iso_err = false;
+ bool done = false;
+ u32 status;
+ struct dma_channel *dma;
+
+ musb_ep_select(mbase, epnum);
+
+ urb = next_urb(qh);
+ dma = is_dma_capable() ? hw_ep->rx_channel : NULL;
+ status = 0;
+ xfer_len = 0;
+
+ val = rx_csr = musb_readw(epio, MUSB_RXCSR);
+
+ if (unlikely(!urb)) {
+ /* REVISIT -- THIS SHOULD NEVER HAPPEN ... but, at least
+ * usbtest #11 (unlinks) triggers it regularly, sometimes
+ * with fifo full. (Only with DMA??)
+ */
+ DBG(3, "BOGUS RX%d ready, csr %04x, count %d\n", epnum, val,
+ musb_readw(epio, MUSB_RXCOUNT));
+ musb_h_flush_rxfifo(hw_ep, MUSB_RXCSR_CLRDATATOG);
+ return;
+ }
+
+ pipe = urb->pipe;
+
+ DBG(5, "<== hw %d rxcsr %04x, urb actual %d (+dma %zd)\n",
+ epnum, rx_csr, urb->actual_length,
+ dma ? dma->actual_len : 0);
+
+ /* check for errors, concurrent stall & unlink is not really
+ * handled yet! */
+ if (rx_csr & MUSB_RXCSR_H_RXSTALL) {
+ DBG(3, "RX end %d STALL\n", epnum);
+
+ /* stall; record URB status */
+ status = -EPIPE;
+
+ } else if (rx_csr & MUSB_RXCSR_H_ERROR) {
+ DBG(3, "end %d RX proto error\n", epnum);
+
+ status = -EPROTO;
+ musb_writeb(epio, MUSB_RXINTERVAL, 0);
+
+ } else if (rx_csr & MUSB_RXCSR_DATAERROR) {
+
+ if (USB_ENDPOINT_XFER_ISOC != qh->type) {
+ /* NOTE this code path would be a good place to PAUSE a
+ * transfer, if there's some other (nonperiodic) rx urb
+ * that could use this fifo. (dma complicates it...)
+ *
+ * if (bulk && qh->ring.next != &musb->in_bulk), then
+ * we have a candidate... NAKing is *NOT* an error
+ */
+ DBG(6, "RX end %d NAK timeout\n", epnum);
+ musb_ep_select(mbase, epnum);
+ musb_writew(epio, MUSB_RXCSR,
+ MUSB_RXCSR_H_WZC_BITS
+ | MUSB_RXCSR_H_REQPKT);
+
+ goto finish;
+ } else {
+ DBG(4, "RX end %d ISO data error\n", epnum);
+ /* packet error reported later */
+ iso_err = true;
+ }
+ }
+
+ /* faults abort the transfer */
+ if (status) {
+ /* clean up dma and collect transfer count */
+ if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
+ dma->status = MUSB_DMA_STATUS_CORE_ABORT;
+ (void) musb->dma_controller->channel_abort(dma);
+ xfer_len = dma->actual_len;
+ }
+ musb_h_flush_rxfifo(hw_ep, 0);
+ musb_writeb(epio, MUSB_RXINTERVAL, 0);
+ done = true;
+ goto finish;
+ }
+
+ if (unlikely(dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY)) {
+ /* SHOULD NEVER HAPPEN ... but at least DaVinci has done it */
+ ERR("RX%d dma busy, csr %04x\n", epnum, rx_csr);
+ goto finish;
+ }
+
+ /* thorough shutdown for now ... given more precise fault handling
+ * and better queueing support, we might keep a DMA pipeline going
+ * while processing this irq for earlier completions.
+ */
+
+ /* FIXME this is _way_ too much in-line logic for Mentor DMA */
+
+#ifndef CONFIG_USB_INVENTRA_DMA
+ if (rx_csr & MUSB_RXCSR_H_REQPKT) {
+ /* REVISIT this happened for a while on some short reads...
+ * the cleanup still needs investigation... looks bad...
+ * and also duplicates dma cleanup code above ... plus,
+ * shouldn't this be the "half full" double buffer case?
+ */
+ if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
+ dma->status = MUSB_DMA_STATUS_CORE_ABORT;
+ (void) musb->dma_controller->channel_abort(dma);
+ xfer_len = dma->actual_len;
+ done = true;
+ }
+
+ DBG(2, "RXCSR%d %04x, reqpkt, len %zd%s\n", epnum, rx_csr,
+ xfer_len, dma ? ", dma" : "");
+ rx_csr &= ~MUSB_RXCSR_H_REQPKT;
+
+ musb_ep_select(mbase, epnum);
+ musb_writew(epio, MUSB_RXCSR,
+ MUSB_RXCSR_H_WZC_BITS | rx_csr);
+ }
+#endif
+ if (dma && (rx_csr & MUSB_RXCSR_DMAENAB)) {
+ xfer_len = dma->actual_len;
+
+ val &= ~(MUSB_RXCSR_DMAENAB
+ | MUSB_RXCSR_H_AUTOREQ
+ | MUSB_RXCSR_AUTOCLEAR
+ | MUSB_RXCSR_RXPKTRDY);
+ musb_writew(hw_ep->regs, MUSB_RXCSR, val);
+
+#ifdef CONFIG_USB_INVENTRA_DMA
+ /* done if urb buffer is full or short packet is recd */
+ done = (urb->actual_length + xfer_len >=
+ urb->transfer_buffer_length
+ || dma->actual_len < qh->maxpacket);
+
+ /* send IN token for next packet, without AUTOREQ */
+ if (!done) {
+ val |= MUSB_RXCSR_H_REQPKT;
+ musb_writew(epio, MUSB_RXCSR,
+ MUSB_RXCSR_H_WZC_BITS | val);
+ }
+
+ DBG(4, "ep %d dma %s, rxcsr %04x, rxcount %d\n", epnum,
+ done ? "off" : "reset",
+ musb_readw(epio, MUSB_RXCSR),
+ musb_readw(epio, MUSB_RXCOUNT));
+#else
+ done = true;
+#endif
+ } else if (urb->status == -EINPROGRESS) {
+ /* if no errors, be sure a packet is ready for unloading */
+ if (unlikely(!(rx_csr & MUSB_RXCSR_RXPKTRDY))) {
+ status = -EPROTO;
+ ERR("Rx interrupt with no errors or packet!\n");
+
+ /* FIXME this is another "SHOULD NEVER HAPPEN" */
+
+/* SCRUB (RX) */
+ /* do the proper sequence to abort the transfer */
+ musb_ep_select(mbase, epnum);
+ val &= ~MUSB_RXCSR_H_REQPKT;
+ musb_writew(epio, MUSB_RXCSR, val);
+ goto finish;
+ }
+
+ /* we are expecting IN packets */
+#ifdef CONFIG_USB_INVENTRA_DMA
+ if (dma) {
+ struct dma_controller *c;
+ u16 rx_count;
+ int ret;
+
+ rx_count = musb_readw(epio, MUSB_RXCOUNT);
+
+ DBG(2, "RX%d count %d, buffer 0x%x len %d/%d\n",
+ epnum, rx_count,
+ urb->transfer_dma
+ + urb->actual_length,
+ qh->offset,
+ urb->transfer_buffer_length);
+
+ c = musb->dma_controller;
+
+ dma->desired_mode = 0;
+#ifdef USE_MODE1
+ /* because of the issue below, mode 1 will
+ * only rarely behave with correct semantics.
+ */
+ if ((urb->transfer_flags &
+ URB_SHORT_NOT_OK)
+ && (urb->transfer_buffer_length -
+ urb->actual_length)
+ > qh->maxpacket)
+ dma->desired_mode = 1;
+#endif
+
+/* Disadvantage of using mode 1:
+ * It's basically usable only for mass storage class; essentially all
+ * other protocols also terminate transfers on short packets.
+ *
+ * Details:
+ * An extra IN token is sent at the end of the transfer (due to AUTOREQ)
+ * If you try to use mode 1 for (transfer_buffer_length - 512), and try
+ * to use the extra IN token to grab the last packet using mode 0, then
+ * the problem is that you cannot be sure when the device will send the
+ * last packet and RxPktRdy set. Sometimes the packet is recd too soon
+ * such that it gets lost when RxCSR is re-set at the end of the mode 1
+ * transfer, while sometimes it is recd just a little late so that if you
+ * try to configure for mode 0 soon after the mode 1 transfer is
+ * completed, you will find rxcount 0. Okay, so you might think why not
+ * wait for an interrupt when the pkt is recd. Well, you won't get any!
+ */
+
+ val = musb_readw(epio, MUSB_RXCSR);
+ val &= ~MUSB_RXCSR_H_REQPKT;
+
+ if (dma->desired_mode == 0)
+ val &= ~MUSB_RXCSR_H_AUTOREQ;
+ else
+ val |= MUSB_RXCSR_H_AUTOREQ;
+ val |= MUSB_RXCSR_AUTOCLEAR | MUSB_RXCSR_DMAENAB;
+
+ musb_writew(epio, MUSB_RXCSR,
+ MUSB_RXCSR_H_WZC_BITS | val);
+
+ /* REVISIT if when actual_length != 0,
+ * transfer_buffer_length needs to be
+ * adjusted first...
+ */
+ ret = c->channel_program(
+ dma, qh->maxpacket,
+ dma->desired_mode,
+ urb->transfer_dma
+ + urb->actual_length,
+ (dma->desired_mode == 0)
+ ? rx_count
+ : urb->transfer_buffer_length);
+
+ if (!ret) {
+ c->channel_release(dma);
+ dma = hw_ep->rx_channel = NULL;
+ /* REVISIT reset CSR */
+ }
+ }
+#endif /* Mentor DMA */
+
+ if (!dma) {
+ done = musb_host_packet_rx(musb, urb,
+ epnum, iso_err);
+ DBG(6, "read %spacket\n", done ? "last " : "");
+ }
+ }
+
+ if (dma && usb_pipeisoc(pipe)) {
+ struct usb_iso_packet_descriptor *d;
+ int iso_stat = status;
+
+ d = urb->iso_frame_desc + qh->iso_idx;
+ d->actual_length += xfer_len;
+ if (iso_err) {
+ iso_stat = -EILSEQ;
+ urb->error_count++;
+ }
+ d->status = iso_stat;
+ }
+
+finish:
+ urb->actual_length += xfer_len;
+ qh->offset += xfer_len;
+ if (done) {
+ if (urb->status == -EINPROGRESS)
+ urb->status = status;
+ musb_advance_schedule(musb, urb, hw_ep, USB_DIR_IN);
+ }
+}
+
+/* schedule nodes correspond to peripheral endpoints, like an OHCI QH.
+ * the software schedule associates multiple such nodes with a given
+ * host side hardware endpoint + direction; scheduling may activate
+ * that hardware endpoint.
+ */
+static int musb_schedule(
+ struct musb *musb,
+ struct musb_qh *qh,
+ int is_in)
+{
+ int idle;
+ int best_diff;
+ int best_end, epnum;
+ struct musb_hw_ep *hw_ep = NULL;
+ struct list_head *head = NULL;
+
+ /* use fixed hardware for control and bulk */
+ switch (qh->type) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ head = &musb->control;
+ hw_ep = musb->control_ep;
+ break;
+ case USB_ENDPOINT_XFER_BULK:
+ hw_ep = musb->bulk_ep;
+ if (is_in)
+ head = &musb->in_bulk;
+ else
+ head = &musb->out_bulk;
+ break;
+ }
+ if (head) {
+ idle = list_empty(head);
+ list_add_tail(&qh->ring, head);
+ goto success;
+ }
+
+ /* else, periodic transfers get muxed to other endpoints */
+
+ /* FIXME this doesn't consider direction, so it can only
+ * work for one half of the endpoint hardware, and assumes
+ * the previous cases handled all non-shared endpoints...
+ */
+
+ /* we know this qh hasn't been scheduled, so all we need to do
+ * is choose which hardware endpoint to put it on ...
+ *
+ * REVISIT what we really want here is a regular schedule tree
+ * like e.g. OHCI uses, but for now musb->periodic is just an
+ * array of the _single_ logical endpoint associated with a
+ * given physical one (identity mapping logical->physical).
+ *
+ * that simplistic approach makes TT scheduling a lot simpler;
+ * there is none, and thus none of its complexity...
+ */
+ best_diff = 4096;
+ best_end = -1;
+
+ for (epnum = 1; epnum < musb->nr_endpoints; epnum++) {
+ int diff;
+
+ if (musb->periodic[epnum])
+ continue;
+ hw_ep = &musb->endpoints[epnum];
+ if (hw_ep == musb->bulk_ep)
+ continue;
+
+ if (is_in)
+ diff = hw_ep->max_packet_sz_rx - qh->maxpacket;
+ else
+ diff = hw_ep->max_packet_sz_tx - qh->maxpacket;
+
+ if (diff > 0 && best_diff > diff) {
+ best_diff = diff;
+ best_end = epnum;
+ }
+ }
+ if (best_end < 0)
+ return -ENOSPC;
+
+ idle = 1;
+ hw_ep = musb->endpoints + best_end;
+ musb->periodic[best_end] = qh;
+ DBG(4, "qh %p periodic slot %d\n", qh, best_end);
+success:
+ qh->hw_ep = hw_ep;
+ qh->hep->hcpriv = qh;
+ if (idle)
+ musb_start_urb(musb, is_in, qh);
+ return 0;
+}
+
+static int musb_urb_enqueue(
+ struct usb_hcd *hcd,
+ struct urb *urb,
+ gfp_t mem_flags)
+{
+ unsigned long flags;
+ struct musb *musb = hcd_to_musb(hcd);
+ struct usb_host_endpoint *hep = urb->ep;
+ struct musb_qh *qh = hep->hcpriv;
+ struct usb_endpoint_descriptor *epd = &hep->desc;
+ int ret;
+ unsigned type_reg;
+ unsigned interval;
+
+ /* host role must be active */
+ if (!is_host_active(musb) || !musb->is_active)
+ return -ENODEV;
+
+ spin_lock_irqsave(&musb->lock, flags);
+ ret = usb_hcd_link_urb_to_ep(hcd, urb);
+ spin_unlock_irqrestore(&musb->lock, flags);
+ if (ret)
+ return ret;
+
+ /* DMA mapping was already done, if needed, and this urb is on
+ * hep->urb_list ... so there's little to do unless hep wasn't
+ * yet scheduled onto a live qh.
+ *
+ * REVISIT best to keep hep->hcpriv valid until the endpoint gets
+ * disabled, testing for empty qh->ring and avoiding qh setup costs
+ * except for the first urb queued after a config change.
+ */
+ if (qh) {
+ urb->hcpriv = qh;
+ return 0;
+ }
+
+ /* Allocate and initialize qh, minimizing the work done each time
+ * hw_ep gets reprogrammed, or with irqs blocked. Then schedule it.
+ *
+ * REVISIT consider a dedicated qh kmem_cache, so it's harder
+ * for bugs in other kernel code to break this driver...
+ */
+ qh = kzalloc(sizeof *qh, mem_flags);
+ if (!qh) {
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+ return -ENOMEM;
+ }
+
+ qh->hep = hep;
+ qh->dev = urb->dev;
+ INIT_LIST_HEAD(&qh->ring);
+ qh->is_ready = 1;
+
+ qh->maxpacket = le16_to_cpu(epd->wMaxPacketSize);
+
+ /* no high bandwidth support yet */
+ if (qh->maxpacket & ~0x7ff) {
+ ret = -EMSGSIZE;
+ goto done;
+ }
+
+ qh->epnum = epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+ qh->type = epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+
+ /* NOTE: urb->dev->devnum is wrong during SET_ADDRESS */
+ qh->addr_reg = (u8) usb_pipedevice(urb->pipe);
+
+ /* precompute rxtype/txtype/type0 register */
+ type_reg = (qh->type << 4) | qh->epnum;
+ switch (urb->dev->speed) {
+ case USB_SPEED_LOW:
+ type_reg |= 0xc0;
+ break;
+ case USB_SPEED_FULL:
+ type_reg |= 0x80;
+ break;
+ default:
+ type_reg |= 0x40;
+ }
+ qh->type_reg = type_reg;
+
+ /* precompute rxinterval/txinterval register */
+ interval = min((u8)16, epd->bInterval); /* log encoding */
+ switch (qh->type) {
+ case USB_ENDPOINT_XFER_INT:
+ /* fullspeed uses linear encoding */
+ if (USB_SPEED_FULL == urb->dev->speed) {
+ interval = epd->bInterval;
+ if (!interval)
+ interval = 1;
+ }
+ /* FALLTHROUGH */
+ case USB_ENDPOINT_XFER_ISOC:
+ /* iso always uses log encoding */
+ break;
+ default:
+ /* REVISIT we actually want to use NAK limits, hinting to the
+ * transfer scheduling logic to try some other qh, e.g. try
+ * for 2 msec first:
+ *
+ * interval = (USB_SPEED_HIGH == urb->dev->speed) ? 16 : 2;
+ *
+ * The downside of disabling this is that transfer scheduling
+ * gets VERY unfair for nonperiodic transfers; a misbehaving
+ * peripheral could make that hurt. Or for reads, one that's
+ * perfectly normal: network and other drivers keep reads
+ * posted at all times, having one pending for a week should
+ * be perfectly safe.
+ *
+ * The upside of disabling it is avoidng transfer scheduling
+ * code to put this aside for while.
+ */
+ interval = 0;
+ }
+ qh->intv_reg = interval;
+
+ /* precompute addressing for external hub/tt ports */
+ if (musb->is_multipoint) {
+ struct usb_device *parent = urb->dev->parent;
+
+ if (parent != hcd->self.root_hub) {
+ qh->h_addr_reg = (u8) parent->devnum;
+
+ /* set up tt info if needed */
+ if (urb->dev->tt) {
+ qh->h_port_reg = (u8) urb->dev->ttport;
+ qh->h_addr_reg |= 0x80;
+ }
+ }
+ }
+
+ /* invariant: hep->hcpriv is null OR the qh that's already scheduled.
+ * until we get real dma queues (with an entry for each urb/buffer),
+ * we only have work to do in the former case.
+ */
+ spin_lock_irqsave(&musb->lock, flags);
+ if (hep->hcpriv) {
+ /* some concurrent activity submitted another urb to hep...
+ * odd, rare, error prone, but legal.
+ */
+ kfree(qh);
+ ret = 0;
+ } else
+ ret = musb_schedule(musb, qh,
+ epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK);
+
+ if (ret == 0) {
+ urb->hcpriv = qh;
+ /* FIXME set urb->start_frame for iso/intr, it's tested in
+ * musb_start_urb(), but otherwise only konicawc cares ...
+ */
+ }
+ spin_unlock_irqrestore(&musb->lock, flags);
+
+done:
+ if (ret != 0) {
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+ kfree(qh);
+ }
+ return ret;
+}
+
+
+/*
+ * abort a transfer that's at the head of a hardware queue.
+ * called with controller locked, irqs blocked
+ * that hardware queue advances to the next transfer, unless prevented
+ */
+static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh, int is_in)
+{
+ struct musb_hw_ep *ep = qh->hw_ep;
+ void __iomem *epio = ep->regs;
+ unsigned hw_end = ep->epnum;
+ void __iomem *regs = ep->musb->mregs;
+ u16 csr;
+ int status = 0;
+
+ musb_ep_select(regs, hw_end);
+
+ if (is_dma_capable()) {
+ struct dma_channel *dma;
+
+ dma = is_in ? ep->rx_channel : ep->tx_channel;
+ if (dma) {
+ status = ep->musb->dma_controller->channel_abort(dma);
+ DBG(status ? 1 : 3,
+ "abort %cX%d DMA for urb %p --> %d\n",
+ is_in ? 'R' : 'T', ep->epnum,
+ urb, status);
+ urb->actual_length += dma->actual_len;
+ }
+ }
+
+ /* turn off DMA requests, discard state, stop polling ... */
+ if (is_in) {
+ /* giveback saves bulk toggle */
+ csr = musb_h_flush_rxfifo(ep, 0);
+
+ /* REVISIT we still get an irq; should likely clear the
+ * endpoint's irq status here to avoid bogus irqs.
+ * clearing that status is platform-specific...
+ */
+ } else {
+ musb_h_tx_flush_fifo(ep);
+ csr = musb_readw(epio, MUSB_TXCSR);
+ csr &= ~(MUSB_TXCSR_AUTOSET
+ | MUSB_TXCSR_DMAENAB
+ | MUSB_TXCSR_H_RXSTALL
+ | MUSB_TXCSR_H_NAKTIMEOUT
+ | MUSB_TXCSR_H_ERROR
+ | MUSB_TXCSR_TXPKTRDY);
+ musb_writew(epio, MUSB_TXCSR, csr);
+ /* REVISIT may need to clear FLUSHFIFO ... */
+ musb_writew(epio, MUSB_TXCSR, csr);
+ /* flush cpu writebuffer */
+ csr = musb_readw(epio, MUSB_TXCSR);
+ }
+ if (status == 0)
+ musb_advance_schedule(ep->musb, urb, ep, is_in);
+ return status;
+}
+
+static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
+{
+ struct musb *musb = hcd_to_musb(hcd);
+ struct musb_qh *qh;
+ struct list_head *sched;
+ unsigned long flags;
+ int ret;
+
+ DBG(4, "urb=%p, dev%d ep%d%s\n", urb,
+ usb_pipedevice(urb->pipe),
+ usb_pipeendpoint(urb->pipe),
+ usb_pipein(urb->pipe) ? "in" : "out");
+
+ spin_lock_irqsave(&musb->lock, flags);
+ ret = usb_hcd_check_unlink_urb(hcd, urb, status);
+ if (ret)
+ goto done;
+
+ qh = urb->hcpriv;
+ if (!qh)
+ goto done;
+
+ /* Any URB not actively programmed into endpoint hardware can be
+ * immediately given back. Such an URB must be at the head of its
+ * endpoint queue, unless someday we get real DMA queues. And even
+ * then, it might not be known to the hardware...
+ *
+ * Otherwise abort current transfer, pending dma, etc.; urb->status
+ * has already been updated. This is a synchronous abort; it'd be
+ * OK to hold off until after some IRQ, though.
+ */
+ if (!qh->is_ready || urb->urb_list.prev != &qh->hep->urb_list)
+ ret = -EINPROGRESS;
+ else {
+ switch (qh->type) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ sched = &musb->control;
+ break;
+ case USB_ENDPOINT_XFER_BULK:
+ if (usb_pipein(urb->pipe))
+ sched = &musb->in_bulk;
+ else
+ sched = &musb->out_bulk;
+ break;
+ default:
+ /* REVISIT when we get a schedule tree, periodic
+ * transfers won't always be at the head of a
+ * singleton queue...
+ */
+ sched = NULL;
+ break;
+ }
+ }
+
+ /* NOTE: qh is invalid unless !list_empty(&hep->urb_list) */
+ if (ret < 0 || (sched && qh != first_qh(sched))) {
+ int ready = qh->is_ready;
+
+ ret = 0;
+ qh->is_ready = 0;
+ __musb_giveback(musb, urb, 0);
+ qh->is_ready = ready;
+ } else
+ ret = musb_cleanup_urb(urb, qh, urb->pipe & USB_DIR_IN);
+done:
+ spin_unlock_irqrestore(&musb->lock, flags);
+ return ret;
+}
+
+/* disable an endpoint */
+static void
+musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep)
+{
+ u8 epnum = hep->desc.bEndpointAddress;
+ unsigned long flags;
+ struct musb *musb = hcd_to_musb(hcd);
+ u8 is_in = epnum & USB_DIR_IN;
+ struct musb_qh *qh = hep->hcpriv;
+ struct urb *urb, *tmp;
+ struct list_head *sched;
+
+ if (!qh)
+ return;
+
+ spin_lock_irqsave(&musb->lock, flags);
+
+ switch (qh->type) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ sched = &musb->control;
+ break;
+ case USB_ENDPOINT_XFER_BULK:
+ if (is_in)
+ sched = &musb->in_bulk;
+ else
+ sched = &musb->out_bulk;
+ break;
+ default:
+ /* REVISIT when we get a schedule tree, periodic transfers
+ * won't always be at the head of a singleton queue...
+ */
+ sched = NULL;
+ break;
+ }
+
+ /* NOTE: qh is invalid unless !list_empty(&hep->urb_list) */
+
+ /* kick first urb off the hardware, if needed */
+ qh->is_ready = 0;
+ if (!sched || qh == first_qh(sched)) {
+ urb = next_urb(qh);
+
+ /* make software (then hardware) stop ASAP */
+ if (!urb->unlinked)
+ urb->status = -ESHUTDOWN;
+
+ /* cleanup */
+ musb_cleanup_urb(urb, qh, urb->pipe & USB_DIR_IN);
+ } else
+ urb = NULL;
+
+ /* then just nuke all the others */
+ list_for_each_entry_safe_from(urb, tmp, &hep->urb_list, urb_list)
+ musb_giveback(qh, urb, -ESHUTDOWN);
+
+ spin_unlock_irqrestore(&musb->lock, flags);
+}
+
+static int musb_h_get_frame_number(struct usb_hcd *hcd)
+{
+ struct musb *musb = hcd_to_musb(hcd);
+
+ return musb_readw(musb->mregs, MUSB_FRAME);
+}
+
+static int musb_h_start(struct usb_hcd *hcd)
+{
+ struct musb *musb = hcd_to_musb(hcd);
+
+ /* NOTE: musb_start() is called when the hub driver turns
+ * on port power, or when (OTG) peripheral starts.
+ */
+ hcd->state = HC_STATE_RUNNING;
+ musb->port1_status = 0;
+ return 0;
+}
+
+static void musb_h_stop(struct usb_hcd *hcd)
+{
+ musb_stop(hcd_to_musb(hcd));
+ hcd->state = HC_STATE_HALT;
+}
+
+static int musb_bus_suspend(struct usb_hcd *hcd)
+{
+ struct musb *musb = hcd_to_musb(hcd);
+
+ if (musb->xceiv.state == OTG_STATE_A_SUSPEND)
+ return 0;
+
+ if (is_host_active(musb) && musb->is_active) {
+ WARN("trying to suspend as %s is_active=%i\n",
+ otg_state_string(musb), musb->is_active);
+ return -EBUSY;
+ } else
+ return 0;
+}
+
+static int musb_bus_resume(struct usb_hcd *hcd)
+{
+ /* resuming child port does the work */
+ return 0;
+}
+
+const struct hc_driver musb_hc_driver = {
+ .description = "musb-hcd",
+ .product_desc = "MUSB HDRC host driver",
+ .hcd_priv_size = sizeof(struct musb),
+ .flags = HCD_USB2 | HCD_MEMORY,
+
+ /* not using irq handler or reset hooks from usbcore, since
+ * those must be shared with peripheral code for OTG configs
+ */
+
+ .start = musb_h_start,
+ .stop = musb_h_stop,
+
+ .get_frame_number = musb_h_get_frame_number,
+
+ .urb_enqueue = musb_urb_enqueue,
+ .urb_dequeue = musb_urb_dequeue,
+ .endpoint_disable = musb_h_disable,
+
+ .hub_status_data = musb_hub_status_data,
+ .hub_control = musb_hub_control,
+ .bus_suspend = musb_bus_suspend,
+ .bus_resume = musb_bus_resume,
+ /* .start_port_reset = NULL, */
+ /* .hub_irq_enable = NULL, */
+};
--- /dev/null
+/*
+ * MUSB OTG driver host defines
+ *
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ * Copyright (C) 2006-2007 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * 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 AUTHORS 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.
+ *
+ */
+
+#ifndef _MUSB_HOST_H
+#define _MUSB_HOST_H
+
+static inline struct usb_hcd *musb_to_hcd(struct musb *musb)
+{
+ return container_of((void *) musb, struct usb_hcd, hcd_priv);
+}
+
+static inline struct musb *hcd_to_musb(struct usb_hcd *hcd)
+{
+ return (struct musb *) (hcd->hcd_priv);
+}
+
+/* stored in "usb_host_endpoint.hcpriv" for scheduled endpoints */
+struct musb_qh {
+ struct usb_host_endpoint *hep; /* usbcore info */
+ struct usb_device *dev;
+ struct musb_hw_ep *hw_ep; /* current binding */
+
+ struct list_head ring; /* of musb_qh */
+ /* struct musb_qh *next; */ /* for periodic tree */
+
+ unsigned offset; /* in urb->transfer_buffer */
+ unsigned segsize; /* current xfer fragment */
+
+ u8 type_reg; /* {rx,tx} type register */
+ u8 intv_reg; /* {rx,tx} interval register */
+ u8 addr_reg; /* device address register */
+ u8 h_addr_reg; /* hub address register */
+ u8 h_port_reg; /* hub port register */
+
+ u8 is_ready; /* safe to modify hw_ep */
+ u8 type; /* XFERTYPE_* */
+ u8 epnum;
+ u16 maxpacket;
+ u16 frame; /* for periodic schedule */
+ unsigned iso_idx; /* in urb->iso_frame_desc[] */
+};
+
+/* map from control or bulk queue head to the first qh on that ring */
+static inline struct musb_qh *first_qh(struct list_head *q)
+{
+ if (list_empty(q))
+ return NULL;
+ return list_entry(q->next, struct musb_qh, ring);
+}
+
+
+extern void musb_root_disconnect(struct musb *musb);
+
+struct usb_hcd;
+
+extern int musb_hub_status_data(struct usb_hcd *hcd, char *buf);
+extern int musb_hub_control(struct usb_hcd *hcd,
+ u16 typeReq, u16 wValue, u16 wIndex,
+ char *buf, u16 wLength);
+
+extern const struct hc_driver musb_hc_driver;
+
+static inline struct urb *next_urb(struct musb_qh *qh)
+{
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+ struct list_head *queue;
+
+ if (!qh)
+ return NULL;
+ queue = &qh->hep->urb_list;
+ if (list_empty(queue))
+ return NULL;
+ return list_entry(queue->next, struct urb, urb_list);
+#else
+ return NULL;
+#endif
+}
+
+#endif /* _MUSB_HOST_H */
--- /dev/null
+/*
+ * MUSB OTG driver register I/O
+ *
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ * Copyright (C) 2006-2007 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * 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 AUTHORS 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.
+ *
+ */
+
+#ifndef __MUSB_LINUX_PLATFORM_ARCH_H__
+#define __MUSB_LINUX_PLATFORM_ARCH_H__
+
+#include <linux/io.h>
+
+#ifndef CONFIG_ARM
+static inline void readsl(const void __iomem *addr, void *buf, int len)
+ { insl((unsigned long)addr, buf, len); }
+static inline void readsw(const void __iomem *addr, void *buf, int len)
+ { insw((unsigned long)addr, buf, len); }
+static inline void readsb(const void __iomem *addr, void *buf, int len)
+ { insb((unsigned long)addr, buf, len); }
+
+static inline void writesl(const void __iomem *addr, const void *buf, int len)
+ { outsl((unsigned long)addr, buf, len); }
+static inline void writesw(const void __iomem *addr, const void *buf, int len)
+ { outsw((unsigned long)addr, buf, len); }
+static inline void writesb(const void __iomem *addr, const void *buf, int len)
+ { outsb((unsigned long)addr, buf, len); }
+
+#endif
+
+/* NOTE: these offsets are all in bytes */
+
+static inline u16 musb_readw(const void __iomem *addr, unsigned offset)
+ { return __raw_readw(addr + offset); }
+
+static inline u32 musb_readl(const void __iomem *addr, unsigned offset)
+ { return __raw_readl(addr + offset); }
+
+
+static inline void musb_writew(void __iomem *addr, unsigned offset, u16 data)
+ { __raw_writew(data, addr + offset); }
+
+static inline void musb_writel(void __iomem *addr, unsigned offset, u32 data)
+ { __raw_writel(data, addr + offset); }
+
+
+#ifdef CONFIG_USB_TUSB6010
+
+/*
+ * TUSB6010 doesn't allow 8-bit access; 16-bit access is the minimum.
+ */
+static inline u8 musb_readb(const void __iomem *addr, unsigned offset)
+{
+ u16 tmp;
+ u8 val;
+
+ tmp = __raw_readw(addr + (offset & ~1));
+ if (offset & 1)
+ val = (tmp >> 8);
+ else
+ val = tmp & 0xff;
+
+ return val;
+}
+
+static inline void musb_writeb(void __iomem *addr, unsigned offset, u8 data)
+{
+ u16 tmp;
+
+ tmp = __raw_readw(addr + (offset & ~1));
+ if (offset & 1)
+ tmp = (data << 8) | (tmp & 0xff);
+ else
+ tmp = (tmp & 0xff00) | data;
+
+ __raw_writew(tmp, addr + (offset & ~1));
+}
+
+#else
+
+static inline u8 musb_readb(const void __iomem *addr, unsigned offset)
+ { return __raw_readb(addr + offset); }
+
+static inline void musb_writeb(void __iomem *addr, unsigned offset, u8 data)
+ { __raw_writeb(data, addr + offset); }
+
+#endif /* CONFIG_USB_TUSB6010 */
+
+#endif
--- /dev/null
+/*
+ * MUSB OTG driver debug support
+ *
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ * Copyright (C) 2006-2007 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * 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 AUTHORS 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/uaccess.h> /* FIXME remove procfs writes */
+#include <asm/arch/hardware.h>
+
+#include "musb_core.h"
+
+#include "davinci.h"
+
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+
+static int dump_qh(struct musb_qh *qh, char *buf, unsigned max)
+{
+ int count;
+ int tmp;
+ struct usb_host_endpoint *hep = qh->hep;
+ struct urb *urb;
+
+ count = snprintf(buf, max, " qh %p dev%d ep%d%s max%d\n",
+ qh, qh->dev->devnum, qh->epnum,
+ ({ char *s; switch (qh->type) {
+ case USB_ENDPOINT_XFER_BULK:
+ s = "-bulk"; break;
+ case USB_ENDPOINT_XFER_INT:
+ s = "-int"; break;
+ case USB_ENDPOINT_XFER_CONTROL:
+ s = ""; break;
+ default:
+ s = "iso"; break;
+ }; s; }),
+ qh->maxpacket);
+ if (count <= 0)
+ return 0;
+ buf += count;
+ max -= count;
+
+ list_for_each_entry(urb, &hep->urb_list, urb_list) {
+ tmp = snprintf(buf, max, "\t%s urb %p %d/%d\n",
+ usb_pipein(urb->pipe) ? "in" : "out",
+ urb, urb->actual_length,
+ urb->transfer_buffer_length);
+ if (tmp <= 0)
+ break;
+ tmp = min(tmp, (int)max);
+ count += tmp;
+ buf += tmp;
+ max -= tmp;
+ }
+ return count;
+}
+
+static int
+dump_queue(struct list_head *q, char *buf, unsigned max)
+{
+ int count = 0;
+ struct musb_qh *qh;
+
+ list_for_each_entry(qh, q, ring) {
+ int tmp;
+
+ tmp = dump_qh(qh, buf, max);
+ if (tmp <= 0)
+ break;
+ tmp = min(tmp, (int)max);
+ count += tmp;
+ buf += tmp;
+ max -= tmp;
+ }
+ return count;
+}
+
+#endif /* HCD */
+
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+static int dump_ep(struct musb_ep *ep, char *buffer, unsigned max)
+{
+ char *buf = buffer;
+ int code = 0;
+ void __iomem *regs = ep->hw_ep->regs;
+ char *mode = "1buf";
+
+ if (ep->is_in) {
+ if (ep->hw_ep->tx_double_buffered)
+ mode = "2buf";
+ } else {
+ if (ep->hw_ep->rx_double_buffered)
+ mode = "2buf";
+ }
+
+ do {
+ struct usb_request *req;
+
+ code = snprintf(buf, max,
+ "\n%s (hw%d): %s%s, csr %04x maxp %04x\n",
+ ep->name, ep->current_epnum,
+ mode, ep->dma ? " dma" : "",
+ musb_readw(regs,
+ (ep->is_in || !ep->current_epnum)
+ ? MUSB_TXCSR
+ : MUSB_RXCSR),
+ musb_readw(regs, ep->is_in
+ ? MUSB_TXMAXP
+ : MUSB_RXMAXP)
+ );
+ if (code <= 0)
+ break;
+ code = min(code, (int) max);
+ buf += code;
+ max -= code;
+
+ if (is_cppi_enabled() && ep->current_epnum) {
+ unsigned cppi = ep->current_epnum - 1;
+ void __iomem *base = ep->musb->ctrl_base;
+ unsigned off1 = cppi << 2;
+ void __iomem *ram = base;
+ char tmp[16];
+
+ if (ep->is_in) {
+ ram += DAVINCI_TXCPPI_STATERAM_OFFSET(cppi);
+ tmp[0] = 0;
+ } else {
+ ram += DAVINCI_RXCPPI_STATERAM_OFFSET(cppi);
+ snprintf(tmp, sizeof tmp, "%d left, ",
+ musb_readl(base,
+ DAVINCI_RXCPPI_BUFCNT0_REG + off1));
+ }
+
+ code = snprintf(buf, max, "%cX DMA%d: %s"
+ "%08x %08x, %08x %08x; "
+ "%08x %08x %08x .. %08x\n",
+ ep->is_in ? 'T' : 'R',
+ ep->current_epnum - 1, tmp,
+ musb_readl(ram, 0 * 4),
+ musb_readl(ram, 1 * 4),
+ musb_readl(ram, 2 * 4),
+ musb_readl(ram, 3 * 4),
+ musb_readl(ram, 4 * 4),
+ musb_readl(ram, 5 * 4),
+ musb_readl(ram, 6 * 4),
+ musb_readl(ram, 7 * 4));
+ if (code <= 0)
+ break;
+ code = min(code, (int) max);
+ buf += code;
+ max -= code;
+ }
+
+ if (list_empty(&ep->req_list)) {
+ code = snprintf(buf, max, "\t(queue empty)\n");
+ if (code <= 0)
+ break;
+ code = min(code, (int) max);
+ buf += code;
+ max -= code;
+ break;
+ }
+ list_for_each_entry(req, &ep->req_list, list) {
+ code = snprintf(buf, max, "\treq %p, %s%s%d/%d\n",
+ req,
+ req->zero ? "zero, " : "",
+ req->short_not_ok ? "!short, " : "",
+ req->actual, req->length);
+ if (code <= 0)
+ break;
+ code = min(code, (int) max);
+ buf += code;
+ max -= code;
+ }
+ } while (0);
+ return buf - buffer;
+}
+#endif
+
+static int
+dump_end_info(struct musb *musb, u8 epnum, char *aBuffer, unsigned max)
+{
+ int code = 0;
+ char *buf = aBuffer;
+ struct musb_hw_ep *hw_ep = &musb->endpoints[epnum];
+
+ do {
+ musb_ep_select(musb->mregs, epnum);
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+ if (is_host_active(musb)) {
+ int dump_rx, dump_tx;
+ void __iomem *regs = hw_ep->regs;
+
+ /* TEMPORARY (!) until we have a real periodic
+ * schedule tree ...
+ */
+ if (!epnum) {
+ /* control is shared, uses RX queue
+ * but (mostly) shadowed tx registers
+ */
+ dump_tx = !list_empty(&musb->control);
+ dump_rx = 0;
+ } else if (hw_ep == musb->bulk_ep) {
+ dump_tx = !list_empty(&musb->out_bulk);
+ dump_rx = !list_empty(&musb->in_bulk);
+ } else if (musb->periodic[epnum]) {
+ struct usb_host_endpoint *hep;
+
+ hep = musb->periodic[epnum]->hep;
+ dump_rx = hep->desc.bEndpointAddress
+ & USB_ENDPOINT_DIR_MASK;
+ dump_tx = !dump_rx;
+ } else
+ break;
+ /* END TEMPORARY */
+
+
+ if (dump_rx) {
+ code = snprintf(buf, max,
+ "\nRX%d: %s rxcsr %04x interval %02x "
+ "max %04x type %02x; "
+ "dev %d hub %d port %d"
+ "\n",
+ epnum,
+ hw_ep->rx_double_buffered
+ ? "2buf" : "1buf",
+ musb_readw(regs, MUSB_RXCSR),
+ musb_readb(regs, MUSB_RXINTERVAL),
+ musb_readw(regs, MUSB_RXMAXP),
+ musb_readb(regs, MUSB_RXTYPE),
+ /* FIXME: assumes multipoint */
+ musb_readb(musb->mregs,
+ MUSB_BUSCTL_OFFSET(epnum,
+ MUSB_RXFUNCADDR)),
+ musb_readb(musb->mregs,
+ MUSB_BUSCTL_OFFSET(epnum,
+ MUSB_RXHUBADDR)),
+ musb_readb(musb->mregs,
+ MUSB_BUSCTL_OFFSET(epnum,
+ MUSB_RXHUBPORT))
+ );
+ if (code <= 0)
+ break;
+ code = min(code, (int) max);
+ buf += code;
+ max -= code;
+
+ if (is_cppi_enabled()
+ && epnum
+ && hw_ep->rx_channel) {
+ unsigned cppi = epnum - 1;
+ unsigned off1 = cppi << 2;
+ void __iomem *base;
+ void __iomem *ram;
+ char tmp[16];
+
+ base = musb->ctrl_base;
+ ram = DAVINCI_RXCPPI_STATERAM_OFFSET(
+ cppi) + base;
+ snprintf(tmp, sizeof tmp, "%d left, ",
+ musb_readl(base,
+ DAVINCI_RXCPPI_BUFCNT0_REG
+ + off1));
+
+ code = snprintf(buf, max,
+ " rx dma%d: %s"
+ "%08x %08x, %08x %08x; "
+ "%08x %08x %08x .. %08x\n",
+ cppi, tmp,
+ musb_readl(ram, 0 * 4),
+ musb_readl(ram, 1 * 4),
+ musb_readl(ram, 2 * 4),
+ musb_readl(ram, 3 * 4),
+ musb_readl(ram, 4 * 4),
+ musb_readl(ram, 5 * 4),
+ musb_readl(ram, 6 * 4),
+ musb_readl(ram, 7 * 4));
+ if (code <= 0)
+ break;
+ code = min(code, (int) max);
+ buf += code;
+ max -= code;
+ }
+
+ if (hw_ep == musb->bulk_ep
+ && !list_empty(
+ &musb->in_bulk)) {
+ code = dump_queue(&musb->in_bulk,
+ buf, max);
+ if (code <= 0)
+ break;
+ code = min(code, (int) max);
+ buf += code;
+ max -= code;
+ } else if (musb->periodic[epnum]) {
+ code = dump_qh(musb->periodic[epnum],
+ buf, max);
+ if (code <= 0)
+ break;
+ code = min(code, (int) max);
+ buf += code;
+ max -= code;
+ }
+ }
+
+ if (dump_tx) {
+ code = snprintf(buf, max,
+ "\nTX%d: %s txcsr %04x interval %02x "
+ "max %04x type %02x; "
+ "dev %d hub %d port %d"
+ "\n",
+ epnum,
+ hw_ep->tx_double_buffered
+ ? "2buf" : "1buf",
+ musb_readw(regs, MUSB_TXCSR),
+ musb_readb(regs, MUSB_TXINTERVAL),
+ musb_readw(regs, MUSB_TXMAXP),
+ musb_readb(regs, MUSB_TXTYPE),
+ /* FIXME: assumes multipoint */
+ musb_readb(musb->mregs,
+ MUSB_BUSCTL_OFFSET(epnum,
+ MUSB_TXFUNCADDR)),
+ musb_readb(musb->mregs,
+ MUSB_BUSCTL_OFFSET(epnum,
+ MUSB_TXHUBADDR)),
+ musb_readb(musb->mregs,
+ MUSB_BUSCTL_OFFSET(epnum,
+ MUSB_TXHUBPORT))
+ );
+ if (code <= 0)
+ break;
+ code = min(code, (int) max);
+ buf += code;
+ max -= code;
+
+ if (is_cppi_enabled()
+ && epnum
+ && hw_ep->tx_channel) {
+ unsigned cppi = epnum - 1;
+ void __iomem *base;
+ void __iomem *ram;
+
+ base = musb->ctrl_base;
+ ram = DAVINCI_RXCPPI_STATERAM_OFFSET(
+ cppi) + base;
+ code = snprintf(buf, max,
+ " tx dma%d: "
+ "%08x %08x, %08x %08x; "
+ "%08x %08x %08x .. %08x\n",
+ cppi,
+ musb_readl(ram, 0 * 4),
+ musb_readl(ram, 1 * 4),
+ musb_readl(ram, 2 * 4),
+ musb_readl(ram, 3 * 4),
+ musb_readl(ram, 4 * 4),
+ musb_readl(ram, 5 * 4),
+ musb_readl(ram, 6 * 4),
+ musb_readl(ram, 7 * 4));
+ if (code <= 0)
+ break;
+ code = min(code, (int) max);
+ buf += code;
+ max -= code;
+ }
+
+ if (hw_ep == musb->control_ep
+ && !list_empty(
+ &musb->control)) {
+ code = dump_queue(&musb->control,
+ buf, max);
+ if (code <= 0)
+ break;
+ code = min(code, (int) max);
+ buf += code;
+ max -= code;
+ } else if (hw_ep == musb->bulk_ep
+ && !list_empty(
+ &musb->out_bulk)) {
+ code = dump_queue(&musb->out_bulk,
+ buf, max);
+ if (code <= 0)
+ break;
+ code = min(code, (int) max);
+ buf += code;
+ max -= code;
+ } else if (musb->periodic[epnum]) {
+ code = dump_qh(musb->periodic[epnum],
+ buf, max);
+ if (code <= 0)
+ break;
+ code = min(code, (int) max);
+ buf += code;
+ max -= code;
+ }
+ }
+ }
+#endif
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+ if (is_peripheral_active(musb)) {
+ code = 0;
+
+ if (hw_ep->ep_in.desc || !epnum) {
+ code = dump_ep(&hw_ep->ep_in, buf, max);
+ if (code <= 0)
+ break;
+ code = min(code, (int) max);
+ buf += code;
+ max -= code;
+ }
+ if (hw_ep->ep_out.desc) {
+ code = dump_ep(&hw_ep->ep_out, buf, max);
+ if (code <= 0)
+ break;
+ code = min(code, (int) max);
+ buf += code;
+ max -= code;
+ }
+ }
+#endif
+ } while (0);
+
+ return buf - aBuffer;
+}
+
+/* Dump the current status and compile options.
+ * @param musb the device driver instance
+ * @param buffer where to dump the status; it must be big enough to hold the
+ * result otherwise "BAD THINGS HAPPENS(TM)".
+ */
+static int dump_header_stats(struct musb *musb, char *buffer)
+{
+ int code, count = 0;
+ const void __iomem *mbase = musb->mregs;
+
+ *buffer = 0;
+ count = sprintf(buffer, "Status: %sHDRC, Mode=%s "
+ "(Power=%02x, DevCtl=%02x)\n",
+ (musb->is_multipoint ? "M" : ""), MUSB_MODE(musb),
+ musb_readb(mbase, MUSB_POWER),
+ musb_readb(mbase, MUSB_DEVCTL));
+ if (count <= 0)
+ return 0;
+ buffer += count;
+
+ code = sprintf(buffer, "OTG state: %s; %sactive\n",
+ otg_state_string(musb),
+ musb->is_active ? "" : "in");
+ if (code <= 0)
+ goto done;
+ buffer += code;
+ count += code;
+
+ code = sprintf(buffer,
+ "Options: "
+#ifdef CONFIG_MUSB_PIO_ONLY
+ "pio"
+#elif defined(CONFIG_USB_TI_CPPI_DMA)
+ "cppi-dma"
+#elif defined(CONFIG_USB_INVENTRA_DMA)
+ "musb-dma"
+#elif defined(CONFIG_USB_TUSB_OMAP_DMA)
+ "tusb-omap-dma"
+#else
+ "?dma?"
+#endif
+ ", "
+#ifdef CONFIG_USB_MUSB_OTG
+ "otg (peripheral+host)"
+#elif defined(CONFIG_USB_GADGET_MUSB_HDRC)
+ "peripheral"
+#elif defined(CONFIG_USB_MUSB_HDRC_HCD)
+ "host"
+#endif
+ ", debug=%d [eps=%d]\n",
+ debug,
+ musb->nr_endpoints);
+ if (code <= 0)
+ goto done;
+ count += code;
+ buffer += code;
+
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+ code = sprintf(buffer, "Peripheral address: %02x\n",
+ musb_readb(musb->ctrl_base, MUSB_FADDR));
+ if (code <= 0)
+ goto done;
+ buffer += code;
+ count += code;
+#endif
+
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+ code = sprintf(buffer, "Root port status: %08x\n",
+ musb->port1_status);
+ if (code <= 0)
+ goto done;
+ buffer += code;
+ count += code;
+#endif
+
+#ifdef CONFIG_ARCH_DAVINCI
+ code = sprintf(buffer,
+ "DaVinci: ctrl=%02x stat=%1x phy=%03x\n"
+ "\trndis=%05x auto=%04x intsrc=%08x intmsk=%08x"
+ "\n",
+ musb_readl(musb->ctrl_base, DAVINCI_USB_CTRL_REG),
+ musb_readl(musb->ctrl_base, DAVINCI_USB_STAT_REG),
+ __raw_readl((void __force __iomem *)
+ IO_ADDRESS(USBPHY_CTL_PADDR)),
+ musb_readl(musb->ctrl_base, DAVINCI_RNDIS_REG),
+ musb_readl(musb->ctrl_base, DAVINCI_AUTOREQ_REG),
+ musb_readl(musb->ctrl_base,
+ DAVINCI_USB_INT_SOURCE_REG),
+ musb_readl(musb->ctrl_base,
+ DAVINCI_USB_INT_MASK_REG));
+ if (code <= 0)
+ goto done;
+ count += code;
+ buffer += code;
+#endif /* DAVINCI */
+
+#ifdef CONFIG_USB_TUSB6010
+ code = sprintf(buffer,
+ "TUSB6010: devconf %08x, phy enable %08x drive %08x"
+ "\n\totg %03x timer %08x"
+ "\n\tprcm conf %08x mgmt %08x; int src %08x mask %08x"
+ "\n",
+ musb_readl(musb->ctrl_base, TUSB_DEV_CONF),
+ musb_readl(musb->ctrl_base, TUSB_PHY_OTG_CTRL_ENABLE),
+ musb_readl(musb->ctrl_base, TUSB_PHY_OTG_CTRL),
+ musb_readl(musb->ctrl_base, TUSB_DEV_OTG_STAT),
+ musb_readl(musb->ctrl_base, TUSB_DEV_OTG_TIMER),
+ musb_readl(musb->ctrl_base, TUSB_PRCM_CONF),
+ musb_readl(musb->ctrl_base, TUSB_PRCM_MNGMT),
+ musb_readl(musb->ctrl_base, TUSB_INT_SRC),
+ musb_readl(musb->ctrl_base, TUSB_INT_MASK));
+ if (code <= 0)
+ goto done;
+ count += code;
+ buffer += code;
+#endif /* DAVINCI */
+
+ if (is_cppi_enabled() && musb->dma_controller) {
+ code = sprintf(buffer,
+ "CPPI: txcr=%d txsrc=%01x txena=%01x; "
+ "rxcr=%d rxsrc=%01x rxena=%01x "
+ "\n",
+ musb_readl(musb->ctrl_base,
+ DAVINCI_TXCPPI_CTRL_REG),
+ musb_readl(musb->ctrl_base,
+ DAVINCI_TXCPPI_RAW_REG),
+ musb_readl(musb->ctrl_base,
+ DAVINCI_TXCPPI_INTENAB_REG),
+ musb_readl(musb->ctrl_base,
+ DAVINCI_RXCPPI_CTRL_REG),
+ musb_readl(musb->ctrl_base,
+ DAVINCI_RXCPPI_RAW_REG),
+ musb_readl(musb->ctrl_base,
+ DAVINCI_RXCPPI_INTENAB_REG));
+ if (code <= 0)
+ goto done;
+ count += code;
+ buffer += code;
+ }
+
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+ if (is_peripheral_enabled(musb)) {
+ code = sprintf(buffer, "Gadget driver: %s\n",
+ musb->gadget_driver
+ ? musb->gadget_driver->driver.name
+ : "(none)");
+ if (code <= 0)
+ goto done;
+ count += code;
+ buffer += code;
+ }
+#endif
+
+done:
+ return count;
+}
+
+/* Write to ProcFS
+ *
+ * C soft-connect
+ * c soft-disconnect
+ * I enable HS
+ * i disable HS
+ * s stop session
+ * F force session (OTG-unfriendly)
+ * E rElinquish bus (OTG)
+ * H request host mode
+ * h cancel host request
+ * T start sending TEST_PACKET
+ * D<num> set/query the debug level
+ */
+static int musb_proc_write(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ char cmd;
+ u8 reg;
+ struct musb *musb = (struct musb *)data;
+ void __iomem *mbase = musb->mregs;
+
+ /* MOD_INC_USE_COUNT; */
+
+ if (unlikely(copy_from_user(&cmd, buffer, 1)))
+ return -EFAULT;
+
+ switch (cmd) {
+ case 'C':
+ if (mbase) {
+ reg = musb_readb(mbase, MUSB_POWER)
+ | MUSB_POWER_SOFTCONN;
+ musb_writeb(mbase, MUSB_POWER, reg);
+ }
+ break;
+
+ case 'c':
+ if (mbase) {
+ reg = musb_readb(mbase, MUSB_POWER)
+ & ~MUSB_POWER_SOFTCONN;
+ musb_writeb(mbase, MUSB_POWER, reg);
+ }
+ break;
+
+ case 'I':
+ if (mbase) {
+ reg = musb_readb(mbase, MUSB_POWER)
+ | MUSB_POWER_HSENAB;
+ musb_writeb(mbase, MUSB_POWER, reg);
+ }
+ break;
+
+ case 'i':
+ if (mbase) {
+ reg = musb_readb(mbase, MUSB_POWER)
+ & ~MUSB_POWER_HSENAB;
+ musb_writeb(mbase, MUSB_POWER, reg);
+ }
+ break;
+
+ case 'F':
+ reg = musb_readb(mbase, MUSB_DEVCTL);
+ reg |= MUSB_DEVCTL_SESSION;
+ musb_writeb(mbase, MUSB_DEVCTL, reg);
+ break;
+
+ case 'H':
+ if (mbase) {
+ reg = musb_readb(mbase, MUSB_DEVCTL);
+ reg |= MUSB_DEVCTL_HR;
+ musb_writeb(mbase, MUSB_DEVCTL, reg);
+ /* MUSB_HST_MODE( ((struct musb*)data) ); */
+ /* WARN("Host Mode\n"); */
+ }
+ break;
+
+ case 'h':
+ if (mbase) {
+ reg = musb_readb(mbase, MUSB_DEVCTL);
+ reg &= ~MUSB_DEVCTL_HR;
+ musb_writeb(mbase, MUSB_DEVCTL, reg);
+ }
+ break;
+
+ case 'T':
+ if (mbase) {
+ musb_load_testpacket(musb);
+ musb_writeb(mbase, MUSB_TESTMODE,
+ MUSB_TEST_PACKET);
+ }
+ break;
+
+#if (MUSB_DEBUG > 0)
+ /* set/read debug level */
+ case 'D':{
+ if (count > 1) {
+ char digits[8], *p = digits;
+ int i = 0, level = 0, sign = 1;
+ int len = min(count - 1, (unsigned long)8);
+
+ if (copy_from_user(&digits, &buffer[1], len))
+ return -EFAULT;
+
+ /* optional sign */
+ if (*p == '-') {
+ len -= 1;
+ sign = -sign;
+ p++;
+ }
+
+ /* read it */
+ while (i++ < len && *p > '0' && *p < '9') {
+ level = level * 10 + (*p - '0');
+ p++;
+ }
+
+ level *= sign;
+ DBG(1, "debug level %d\n", level);
+ debug = level;
+ }
+ }
+ break;
+
+
+ case '?':
+ INFO("?: you are seeing it\n");
+ INFO("C/c: soft connect enable/disable\n");
+ INFO("I/i: hispeed enable/disable\n");
+ INFO("F: force session start\n");
+ INFO("H: host mode\n");
+ INFO("T: start sending TEST_PACKET\n");
+ INFO("D: set/read dbug level\n");
+ break;
+#endif
+
+ default:
+ ERR("Command %c not implemented\n", cmd);
+ break;
+ }
+
+ musb_platform_try_idle(musb, 0);
+
+ return count;
+}
+
+static int musb_proc_read(char *page, char **start,
+ off_t off, int count, int *eof, void *data)
+{
+ char *buffer = page;
+ int code = 0;
+ unsigned long flags;
+ struct musb *musb = data;
+ unsigned epnum;
+
+ count -= off;
+ count -= 1; /* for NUL at end */
+ if (count <= 0)
+ return -EINVAL;
+
+ spin_lock_irqsave(&musb->lock, flags);
+
+ code = dump_header_stats(musb, buffer);
+ if (code > 0) {
+ buffer += code;
+ count -= code;
+ }
+
+ /* generate the report for the end points */
+ /* REVISIT ... not unless something's connected! */
+ for (epnum = 0; count >= 0 && epnum < musb->nr_endpoints;
+ epnum++) {
+ code = dump_end_info(musb, epnum, buffer, count);
+ if (code > 0) {
+ buffer += code;
+ count -= code;
+ }
+ }
+
+ musb_platform_try_idle(musb, 0);
+
+ spin_unlock_irqrestore(&musb->lock, flags);
+ *eof = 1;
+
+ return buffer - page;
+}
+
+void __devexit musb_debug_delete(char *name, struct musb *musb)
+{
+ if (musb->proc_entry)
+ remove_proc_entry(name, NULL);
+}
+
+struct proc_dir_entry *__init
+musb_debug_create(char *name, struct musb *data)
+{
+ struct proc_dir_entry *pde;
+
+ /* FIXME convert everything to seq_file; then later, debugfs */
+
+ if (!name)
+ return NULL;
+
+ data->proc_entry = pde = create_proc_entry(name,
+ S_IFREG | S_IRUGO | S_IWUSR, NULL);
+ if (pde) {
+ pde->data = data;
+ /* pde->owner = THIS_MODULE; */
+
+ pde->read_proc = musb_proc_read;
+ pde->write_proc = musb_proc_write;
+
+ pde->size = 0;
+
+ pr_debug("Registered /proc/%s\n", name);
+ } else {
+ pr_debug("Cannot create a valid proc file entry");
+ }
+
+ return pde;
+}
--- /dev/null
+/*
+ * MUSB OTG driver register defines
+ *
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ * Copyright (C) 2006-2007 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * 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 AUTHORS 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.
+ *
+ */
+
+#ifndef __MUSB_REGS_H__
+#define __MUSB_REGS_H__
+
+#define MUSB_EP0_FIFOSIZE 64 /* This is non-configurable */
+
+/*
+ * Common USB registers
+ */
+
+#define MUSB_FADDR 0x00 /* 8-bit */
+#define MUSB_POWER 0x01 /* 8-bit */
+
+#define MUSB_INTRTX 0x02 /* 16-bit */
+#define MUSB_INTRRX 0x04
+#define MUSB_INTRTXE 0x06
+#define MUSB_INTRRXE 0x08
+#define MUSB_INTRUSB 0x0A /* 8 bit */
+#define MUSB_INTRUSBE 0x0B /* 8 bit */
+#define MUSB_FRAME 0x0C
+#define MUSB_INDEX 0x0E /* 8 bit */
+#define MUSB_TESTMODE 0x0F /* 8 bit */
+
+/* Get offset for a given FIFO from musb->mregs */
+#ifdef CONFIG_USB_TUSB6010
+#define MUSB_FIFO_OFFSET(epnum) (0x200 + ((epnum) * 0x20))
+#else
+#define MUSB_FIFO_OFFSET(epnum) (0x20 + ((epnum) * 4))
+#endif
+
+/*
+ * Additional Control Registers
+ */
+
+#define MUSB_DEVCTL 0x60 /* 8 bit */
+
+/* These are always controlled through the INDEX register */
+#define MUSB_TXFIFOSZ 0x62 /* 8-bit (see masks) */
+#define MUSB_RXFIFOSZ 0x63 /* 8-bit (see masks) */
+#define MUSB_TXFIFOADD 0x64 /* 16-bit offset shifted right 3 */
+#define MUSB_RXFIFOADD 0x66 /* 16-bit offset shifted right 3 */
+
+/* REVISIT: vctrl/vstatus: optional vendor utmi+phy register at 0x68 */
+#define MUSB_HWVERS 0x6C /* 8 bit */
+
+#define MUSB_EPINFO 0x78 /* 8 bit */
+#define MUSB_RAMINFO 0x79 /* 8 bit */
+#define MUSB_LINKINFO 0x7a /* 8 bit */
+#define MUSB_VPLEN 0x7b /* 8 bit */
+#define MUSB_HS_EOF1 0x7c /* 8 bit */
+#define MUSB_FS_EOF1 0x7d /* 8 bit */
+#define MUSB_LS_EOF1 0x7e /* 8 bit */
+
+/* Offsets to endpoint registers */
+#define MUSB_TXMAXP 0x00
+#define MUSB_TXCSR 0x02
+#define MUSB_CSR0 MUSB_TXCSR /* Re-used for EP0 */
+#define MUSB_RXMAXP 0x04
+#define MUSB_RXCSR 0x06
+#define MUSB_RXCOUNT 0x08
+#define MUSB_COUNT0 MUSB_RXCOUNT /* Re-used for EP0 */
+#define MUSB_TXTYPE 0x0A
+#define MUSB_TYPE0 MUSB_TXTYPE /* Re-used for EP0 */
+#define MUSB_TXINTERVAL 0x0B
+#define MUSB_NAKLIMIT0 MUSB_TXINTERVAL /* Re-used for EP0 */
+#define MUSB_RXTYPE 0x0C
+#define MUSB_RXINTERVAL 0x0D
+#define MUSB_FIFOSIZE 0x0F
+#define MUSB_CONFIGDATA MUSB_FIFOSIZE /* Re-used for EP0 */
+
+/* Offsets to endpoint registers in indexed model (using INDEX register) */
+#define MUSB_INDEXED_OFFSET(_epnum, _offset) \
+ (0x10 + (_offset))
+
+/* Offsets to endpoint registers in flat models */
+#define MUSB_FLAT_OFFSET(_epnum, _offset) \
+ (0x100 + (0x10*(_epnum)) + (_offset))
+
+#ifdef CONFIG_USB_TUSB6010
+/* TUSB6010 EP0 configuration register is special */
+#define MUSB_TUSB_OFFSET(_epnum, _offset) \
+ (0x10 + _offset)
+#include "tusb6010.h" /* Needed "only" for TUSB_EP0_CONF */
+#endif
+
+/* "bus control"/target registers, for host side multipoint (external hubs) */
+#define MUSB_TXFUNCADDR 0x00
+#define MUSB_TXHUBADDR 0x02
+#define MUSB_TXHUBPORT 0x03
+
+#define MUSB_RXFUNCADDR 0x04
+#define MUSB_RXHUBADDR 0x06
+#define MUSB_RXHUBPORT 0x07
+
+#define MUSB_BUSCTL_OFFSET(_epnum, _offset) \
+ (0x80 + (8*(_epnum)) + (_offset))
+
+/*
+ * MUSB Register bits
+ */
+
+/* POWER */
+#define MUSB_POWER_ISOUPDATE 0x80
+#define MUSB_POWER_SOFTCONN 0x40
+#define MUSB_POWER_HSENAB 0x20
+#define MUSB_POWER_HSMODE 0x10
+#define MUSB_POWER_RESET 0x08
+#define MUSB_POWER_RESUME 0x04
+#define MUSB_POWER_SUSPENDM 0x02
+#define MUSB_POWER_ENSUSPEND 0x01
+
+/* INTRUSB */
+#define MUSB_INTR_SUSPEND 0x01
+#define MUSB_INTR_RESUME 0x02
+#define MUSB_INTR_RESET 0x04
+#define MUSB_INTR_BABBLE 0x04
+#define MUSB_INTR_SOF 0x08
+#define MUSB_INTR_CONNECT 0x10
+#define MUSB_INTR_DISCONNECT 0x20
+#define MUSB_INTR_SESSREQ 0x40
+#define MUSB_INTR_VBUSERROR 0x80 /* For SESSION end */
+
+/* DEVCTL */
+#define MUSB_DEVCTL_BDEVICE 0x80
+#define MUSB_DEVCTL_FSDEV 0x40
+#define MUSB_DEVCTL_LSDEV 0x20
+#define MUSB_DEVCTL_VBUS 0x18
+#define MUSB_DEVCTL_VBUS_SHIFT 3
+#define MUSB_DEVCTL_HM 0x04
+#define MUSB_DEVCTL_HR 0x02
+#define MUSB_DEVCTL_SESSION 0x01
+
+/* TESTMODE */
+#define MUSB_TEST_FORCE_HOST 0x80
+#define MUSB_TEST_FIFO_ACCESS 0x40
+#define MUSB_TEST_FORCE_FS 0x20
+#define MUSB_TEST_FORCE_HS 0x10
+#define MUSB_TEST_PACKET 0x08
+#define MUSB_TEST_K 0x04
+#define MUSB_TEST_J 0x02
+#define MUSB_TEST_SE0_NAK 0x01
+
+/* Allocate for double-packet buffering (effectively doubles assigned _SIZE) */
+#define MUSB_FIFOSZ_DPB 0x10
+/* Allocation size (8, 16, 32, ... 4096) */
+#define MUSB_FIFOSZ_SIZE 0x0f
+
+/* CSR0 */
+#define MUSB_CSR0_FLUSHFIFO 0x0100
+#define MUSB_CSR0_TXPKTRDY 0x0002
+#define MUSB_CSR0_RXPKTRDY 0x0001
+
+/* CSR0 in Peripheral mode */
+#define MUSB_CSR0_P_SVDSETUPEND 0x0080
+#define MUSB_CSR0_P_SVDRXPKTRDY 0x0040
+#define MUSB_CSR0_P_SENDSTALL 0x0020
+#define MUSB_CSR0_P_SETUPEND 0x0010
+#define MUSB_CSR0_P_DATAEND 0x0008
+#define MUSB_CSR0_P_SENTSTALL 0x0004
+
+/* CSR0 in Host mode */
+#define MUSB_CSR0_H_DIS_PING 0x0800
+#define MUSB_CSR0_H_WR_DATATOGGLE 0x0400 /* Set to allow setting: */
+#define MUSB_CSR0_H_DATATOGGLE 0x0200 /* Data toggle control */
+#define MUSB_CSR0_H_NAKTIMEOUT 0x0080
+#define MUSB_CSR0_H_STATUSPKT 0x0040
+#define MUSB_CSR0_H_REQPKT 0x0020
+#define MUSB_CSR0_H_ERROR 0x0010
+#define MUSB_CSR0_H_SETUPPKT 0x0008
+#define MUSB_CSR0_H_RXSTALL 0x0004
+
+/* CSR0 bits to avoid zeroing (write zero clears, write 1 ignored) */
+#define MUSB_CSR0_P_WZC_BITS \
+ (MUSB_CSR0_P_SENTSTALL)
+#define MUSB_CSR0_H_WZC_BITS \
+ (MUSB_CSR0_H_NAKTIMEOUT | MUSB_CSR0_H_RXSTALL \
+ | MUSB_CSR0_RXPKTRDY)
+
+/* TxType/RxType */
+#define MUSB_TYPE_SPEED 0xc0
+#define MUSB_TYPE_SPEED_SHIFT 6
+#define MUSB_TYPE_PROTO 0x30 /* Implicitly zero for ep0 */
+#define MUSB_TYPE_PROTO_SHIFT 4
+#define MUSB_TYPE_REMOTE_END 0xf /* Implicitly zero for ep0 */
+
+/* CONFIGDATA */
+#define MUSB_CONFIGDATA_MPRXE 0x80 /* Auto bulk pkt combining */
+#define MUSB_CONFIGDATA_MPTXE 0x40 /* Auto bulk pkt splitting */
+#define MUSB_CONFIGDATA_BIGENDIAN 0x20
+#define MUSB_CONFIGDATA_HBRXE 0x10 /* HB-ISO for RX */
+#define MUSB_CONFIGDATA_HBTXE 0x08 /* HB-ISO for TX */
+#define MUSB_CONFIGDATA_DYNFIFO 0x04 /* Dynamic FIFO sizing */
+#define MUSB_CONFIGDATA_SOFTCONE 0x02 /* SoftConnect */
+#define MUSB_CONFIGDATA_UTMIDW 0x01 /* Data width 0/1 => 8/16bits */
+
+/* TXCSR in Peripheral and Host mode */
+#define MUSB_TXCSR_AUTOSET 0x8000
+#define MUSB_TXCSR_MODE 0x2000
+#define MUSB_TXCSR_DMAENAB 0x1000
+#define MUSB_TXCSR_FRCDATATOG 0x0800
+#define MUSB_TXCSR_DMAMODE 0x0400
+#define MUSB_TXCSR_CLRDATATOG 0x0040
+#define MUSB_TXCSR_FLUSHFIFO 0x0008
+#define MUSB_TXCSR_FIFONOTEMPTY 0x0002
+#define MUSB_TXCSR_TXPKTRDY 0x0001
+
+/* TXCSR in Peripheral mode */
+#define MUSB_TXCSR_P_ISO 0x4000
+#define MUSB_TXCSR_P_INCOMPTX 0x0080
+#define MUSB_TXCSR_P_SENTSTALL 0x0020
+#define MUSB_TXCSR_P_SENDSTALL 0x0010
+#define MUSB_TXCSR_P_UNDERRUN 0x0004
+
+/* TXCSR in Host mode */
+#define MUSB_TXCSR_H_WR_DATATOGGLE 0x0200
+#define MUSB_TXCSR_H_DATATOGGLE 0x0100
+#define MUSB_TXCSR_H_NAKTIMEOUT 0x0080
+#define MUSB_TXCSR_H_RXSTALL 0x0020
+#define MUSB_TXCSR_H_ERROR 0x0004
+
+/* TXCSR bits to avoid zeroing (write zero clears, write 1 ignored) */
+#define MUSB_TXCSR_P_WZC_BITS \
+ (MUSB_TXCSR_P_INCOMPTX | MUSB_TXCSR_P_SENTSTALL \
+ | MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_FIFONOTEMPTY)
+#define MUSB_TXCSR_H_WZC_BITS \
+ (MUSB_TXCSR_H_NAKTIMEOUT | MUSB_TXCSR_H_RXSTALL \
+ | MUSB_TXCSR_H_ERROR | MUSB_TXCSR_FIFONOTEMPTY)
+
+/* RXCSR in Peripheral and Host mode */
+#define MUSB_RXCSR_AUTOCLEAR 0x8000
+#define MUSB_RXCSR_DMAENAB 0x2000
+#define MUSB_RXCSR_DISNYET 0x1000
+#define MUSB_RXCSR_PID_ERR 0x1000
+#define MUSB_RXCSR_DMAMODE 0x0800
+#define MUSB_RXCSR_INCOMPRX 0x0100
+#define MUSB_RXCSR_CLRDATATOG 0x0080
+#define MUSB_RXCSR_FLUSHFIFO 0x0010
+#define MUSB_RXCSR_DATAERROR 0x0008
+#define MUSB_RXCSR_FIFOFULL 0x0002
+#define MUSB_RXCSR_RXPKTRDY 0x0001
+
+/* RXCSR in Peripheral mode */
+#define MUSB_RXCSR_P_ISO 0x4000
+#define MUSB_RXCSR_P_SENTSTALL 0x0040
+#define MUSB_RXCSR_P_SENDSTALL 0x0020
+#define MUSB_RXCSR_P_OVERRUN 0x0004
+
+/* RXCSR in Host mode */
+#define MUSB_RXCSR_H_AUTOREQ 0x4000
+#define MUSB_RXCSR_H_WR_DATATOGGLE 0x0400
+#define MUSB_RXCSR_H_DATATOGGLE 0x0200
+#define MUSB_RXCSR_H_RXSTALL 0x0040
+#define MUSB_RXCSR_H_REQPKT 0x0020
+#define MUSB_RXCSR_H_ERROR 0x0004
+
+/* RXCSR bits to avoid zeroing (write zero clears, write 1 ignored) */
+#define MUSB_RXCSR_P_WZC_BITS \
+ (MUSB_RXCSR_P_SENTSTALL | MUSB_RXCSR_P_OVERRUN \
+ | MUSB_RXCSR_RXPKTRDY)
+#define MUSB_RXCSR_H_WZC_BITS \
+ (MUSB_RXCSR_H_RXSTALL | MUSB_RXCSR_H_ERROR \
+ | MUSB_RXCSR_DATAERROR | MUSB_RXCSR_RXPKTRDY)
+
+/* HUBADDR */
+#define MUSB_HUBADDR_MULTI_TT 0x80
+
+#endif /* __MUSB_REGS_H__ */
--- /dev/null
+/*
+ * MUSB OTG driver virtual root hub support
+ *
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ * Copyright (C) 2006-2007 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * 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 AUTHORS 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/timer.h>
+
+#include <asm/unaligned.h>
+
+#include "musb_core.h"
+
+
+static void musb_port_suspend(struct musb *musb, bool do_suspend)
+{
+ u8 power;
+ void __iomem *mbase = musb->mregs;
+
+ if (!is_host_active(musb))
+ return;
+
+ /* NOTE: this doesn't necessarily put PHY into low power mode,
+ * turning off its clock; that's a function of PHY integration and
+ * MUSB_POWER_ENSUSPEND. PHY may need a clock (sigh) to detect
+ * SE0 changing to connect (J) or wakeup (K) states.
+ */
+ power = musb_readb(mbase, MUSB_POWER);
+ if (do_suspend) {
+ int retries = 10000;
+
+ power &= ~MUSB_POWER_RESUME;
+ power |= MUSB_POWER_SUSPENDM;
+ musb_writeb(mbase, MUSB_POWER, power);
+
+ /* Needed for OPT A tests */
+ power = musb_readb(mbase, MUSB_POWER);
+ while (power & MUSB_POWER_SUSPENDM) {
+ power = musb_readb(mbase, MUSB_POWER);
+ if (retries-- < 1)
+ break;
+ }
+
+ DBG(3, "Root port suspended, power %02x\n", power);
+
+ musb->port1_status |= USB_PORT_STAT_SUSPEND;
+ switch (musb->xceiv.state) {
+ case OTG_STATE_A_HOST:
+ musb->xceiv.state = OTG_STATE_A_SUSPEND;
+ musb->is_active = is_otg_enabled(musb)
+ && musb->xceiv.host->b_hnp_enable;
+ musb_platform_try_idle(musb, 0);
+ break;
+#ifdef CONFIG_USB_MUSB_OTG
+ case OTG_STATE_B_HOST:
+ musb->xceiv.state = OTG_STATE_B_WAIT_ACON;
+ musb->is_active = is_otg_enabled(musb)
+ && musb->xceiv.host->b_hnp_enable;
+ musb_platform_try_idle(musb, 0);
+ break;
+#endif
+ default:
+ DBG(1, "bogus rh suspend? %s\n",
+ otg_state_string(musb));
+ }
+ } else if (power & MUSB_POWER_SUSPENDM) {
+ power &= ~MUSB_POWER_SUSPENDM;
+ power |= MUSB_POWER_RESUME;
+ musb_writeb(mbase, MUSB_POWER, power);
+
+ DBG(3, "Root port resuming, power %02x\n", power);
+
+ /* later, GetPortStatus will stop RESUME signaling */
+ musb->port1_status |= MUSB_PORT_STAT_RESUME;
+ musb->rh_timer = jiffies + msecs_to_jiffies(20);
+ }
+}
+
+static void musb_port_reset(struct musb *musb, bool do_reset)
+{
+ u8 power;
+ void __iomem *mbase = musb->mregs;
+
+#ifdef CONFIG_USB_MUSB_OTG
+ if (musb->xceiv.state == OTG_STATE_B_IDLE) {
+ DBG(2, "HNP: Returning from HNP; no hub reset from b_idle\n");
+ musb->port1_status &= ~USB_PORT_STAT_RESET;
+ return;
+ }
+#endif
+
+ if (!is_host_active(musb))
+ return;
+
+ /* NOTE: caller guarantees it will turn off the reset when
+ * the appropriate amount of time has passed
+ */
+ power = musb_readb(mbase, MUSB_POWER);
+ if (do_reset) {
+
+ /*
+ * If RESUME is set, we must make sure it stays minimum 20 ms.
+ * Then we must clear RESUME and wait a bit to let musb start
+ * generating SOFs. If we don't do this, OPT HS A 6.8 tests
+ * fail with "Error! Did not receive an SOF before suspend
+ * detected".
+ */
+ if (power & MUSB_POWER_RESUME) {
+ while (time_before(jiffies, musb->rh_timer))
+ msleep(1);
+ musb_writeb(mbase, MUSB_POWER,
+ power & ~MUSB_POWER_RESUME);
+ msleep(1);
+ }
+
+ musb->ignore_disconnect = true;
+ power &= 0xf0;
+ musb_writeb(mbase, MUSB_POWER,
+ power | MUSB_POWER_RESET);
+
+ musb->port1_status |= USB_PORT_STAT_RESET;
+ musb->port1_status &= ~USB_PORT_STAT_ENABLE;
+ musb->rh_timer = jiffies + msecs_to_jiffies(50);
+ } else {
+ DBG(4, "root port reset stopped\n");
+ musb_writeb(mbase, MUSB_POWER,
+ power & ~MUSB_POWER_RESET);
+
+ musb->ignore_disconnect = false;
+
+ power = musb_readb(mbase, MUSB_POWER);
+ if (power & MUSB_POWER_HSMODE) {
+ DBG(4, "high-speed device connected\n");
+ musb->port1_status |= USB_PORT_STAT_HIGH_SPEED;
+ }
+
+ musb->port1_status &= ~USB_PORT_STAT_RESET;
+ musb->port1_status |= USB_PORT_STAT_ENABLE
+ | (USB_PORT_STAT_C_RESET << 16)
+ | (USB_PORT_STAT_C_ENABLE << 16);
+ usb_hcd_poll_rh_status(musb_to_hcd(musb));
+
+ musb->vbuserr_retry = VBUSERR_RETRY_COUNT;
+ }
+}
+
+void musb_root_disconnect(struct musb *musb)
+{
+ musb->port1_status = (1 << USB_PORT_FEAT_POWER)
+ | (1 << USB_PORT_FEAT_C_CONNECTION);
+
+ usb_hcd_poll_rh_status(musb_to_hcd(musb));
+ musb->is_active = 0;
+
+ switch (musb->xceiv.state) {
+ case OTG_STATE_A_HOST:
+ case OTG_STATE_A_SUSPEND:
+ musb->xceiv.state = OTG_STATE_A_WAIT_BCON;
+ musb->is_active = 0;
+ break;
+ case OTG_STATE_A_WAIT_VFALL:
+ musb->xceiv.state = OTG_STATE_B_IDLE;
+ break;
+ default:
+ DBG(1, "host disconnect (%s)\n", otg_state_string(musb));
+ }
+}
+
+
+/*---------------------------------------------------------------------*/
+
+/* Caller may or may not hold musb->lock */
+int musb_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+ struct musb *musb = hcd_to_musb(hcd);
+ int retval = 0;
+
+ /* called in_irq() via usb_hcd_poll_rh_status() */
+ if (musb->port1_status & 0xffff0000) {
+ *buf = 0x02;
+ retval = 1;
+ }
+ return retval;
+}
+
+int musb_hub_control(
+ struct usb_hcd *hcd,
+ u16 typeReq,
+ u16 wValue,
+ u16 wIndex,
+ char *buf,
+ u16 wLength)
+{
+ struct musb *musb = hcd_to_musb(hcd);
+ u32 temp;
+ int retval = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&musb->lock, flags);
+
+ if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) {
+ spin_unlock_irqrestore(&musb->lock, flags);
+ return -ESHUTDOWN;
+ }
+
+ /* hub features: always zero, setting is a NOP
+ * port features: reported, sometimes updated when host is active
+ * no indicators
+ */
+ switch (typeReq) {
+ case ClearHubFeature:
+ case SetHubFeature:
+ switch (wValue) {
+ case C_HUB_OVER_CURRENT:
+ case C_HUB_LOCAL_POWER:
+ break;
+ default:
+ goto error;
+ }
+ break;
+ case ClearPortFeature:
+ if ((wIndex & 0xff) != 1)
+ goto error;
+
+ switch (wValue) {
+ case USB_PORT_FEAT_ENABLE:
+ break;
+ case USB_PORT_FEAT_SUSPEND:
+ musb_port_suspend(musb, false);
+ break;
+ case USB_PORT_FEAT_POWER:
+ if (!(is_otg_enabled(musb) && hcd->self.is_b_host))
+ musb_set_vbus(musb, 0);
+ break;
+ case USB_PORT_FEAT_C_CONNECTION:
+ case USB_PORT_FEAT_C_ENABLE:
+ case USB_PORT_FEAT_C_OVER_CURRENT:
+ case USB_PORT_FEAT_C_RESET:
+ case USB_PORT_FEAT_C_SUSPEND:
+ break;
+ default:
+ goto error;
+ }
+ DBG(5, "clear feature %d\n", wValue);
+ musb->port1_status &= ~(1 << wValue);
+ break;
+ case GetHubDescriptor:
+ {
+ struct usb_hub_descriptor *desc = (void *)buf;
+
+ desc->bDescLength = 9;
+ desc->bDescriptorType = 0x29;
+ desc->bNbrPorts = 1;
+ desc->wHubCharacteristics = __constant_cpu_to_le16(
+ 0x0001 /* per-port power switching */
+ | 0x0010 /* no overcurrent reporting */
+ );
+ desc->bPwrOn2PwrGood = 5; /* msec/2 */
+ desc->bHubContrCurrent = 0;
+
+ /* workaround bogus struct definition */
+ desc->DeviceRemovable[0] = 0x02; /* port 1 */
+ desc->DeviceRemovable[1] = 0xff;
+ }
+ break;
+ case GetHubStatus:
+ temp = 0;
+ *(__le32 *) buf = cpu_to_le32(temp);
+ break;
+ case GetPortStatus:
+ if (wIndex != 1)
+ goto error;
+
+ /* finish RESET signaling? */
+ if ((musb->port1_status & USB_PORT_STAT_RESET)
+ && time_after_eq(jiffies, musb->rh_timer))
+ musb_port_reset(musb, false);
+
+ /* finish RESUME signaling? */
+ if ((musb->port1_status & MUSB_PORT_STAT_RESUME)
+ && time_after_eq(jiffies, musb->rh_timer)) {
+ u8 power;
+
+ power = musb_readb(musb->mregs, MUSB_POWER);
+ power &= ~MUSB_POWER_RESUME;
+ DBG(4, "root port resume stopped, power %02x\n",
+ power);
+ musb_writeb(musb->mregs, MUSB_POWER, power);
+
+ /* ISSUE: DaVinci (RTL 1.300) disconnects after
+ * resume of high speed peripherals (but not full
+ * speed ones).
+ */
+
+ musb->is_active = 1;
+ musb->port1_status &= ~(USB_PORT_STAT_SUSPEND
+ | MUSB_PORT_STAT_RESUME);
+ musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16;
+ usb_hcd_poll_rh_status(musb_to_hcd(musb));
+ /* NOTE: it might really be A_WAIT_BCON ... */
+ musb->xceiv.state = OTG_STATE_A_HOST;
+ }
+
+ put_unaligned(cpu_to_le32(musb->port1_status
+ & ~MUSB_PORT_STAT_RESUME),
+ (__le32 *) buf);
+
+ /* port change status is more interesting */
+ DBG(get_unaligned((u16 *)(buf+2)) ? 2 : 5, "port status %08x\n",
+ musb->port1_status);
+ break;
+ case SetPortFeature:
+ if ((wIndex & 0xff) != 1)
+ goto error;
+
+ switch (wValue) {
+ case USB_PORT_FEAT_POWER:
+ /* NOTE: this controller has a strange state machine
+ * that involves "requesting sessions" according to
+ * magic side effects from incompletely-described
+ * rules about startup...
+ *
+ * This call is what really starts the host mode; be
+ * very careful about side effects if you reorder any
+ * initialization logic, e.g. for OTG, or change any
+ * logic relating to VBUS power-up.
+ */
+ if (!(is_otg_enabled(musb) && hcd->self.is_b_host))
+ musb_start(musb);
+ break;
+ case USB_PORT_FEAT_RESET:
+ musb_port_reset(musb, true);
+ break;
+ case USB_PORT_FEAT_SUSPEND:
+ musb_port_suspend(musb, true);
+ break;
+ case USB_PORT_FEAT_TEST:
+ if (unlikely(is_host_active(musb)))
+ goto error;
+
+ wIndex >>= 8;
+ switch (wIndex) {
+ case 1:
+ pr_debug("TEST_J\n");
+ temp = MUSB_TEST_J;
+ break;
+ case 2:
+ pr_debug("TEST_K\n");
+ temp = MUSB_TEST_K;
+ break;
+ case 3:
+ pr_debug("TEST_SE0_NAK\n");
+ temp = MUSB_TEST_SE0_NAK;
+ break;
+ case 4:
+ pr_debug("TEST_PACKET\n");
+ temp = MUSB_TEST_PACKET;
+ musb_load_testpacket(musb);
+ break;
+ case 5:
+ pr_debug("TEST_FORCE_ENABLE\n");
+ temp = MUSB_TEST_FORCE_HOST
+ | MUSB_TEST_FORCE_HS;
+
+ musb_writeb(musb->mregs, MUSB_DEVCTL,
+ MUSB_DEVCTL_SESSION);
+ break;
+ case 6:
+ pr_debug("TEST_FIFO_ACCESS\n");
+ temp = MUSB_TEST_FIFO_ACCESS;
+ break;
+ default:
+ goto error;
+ }
+ musb_writeb(musb->mregs, MUSB_TESTMODE, temp);
+ break;
+ default:
+ goto error;
+ }
+ DBG(5, "set feature %d\n", wValue);
+ musb->port1_status |= 1 << wValue;
+ break;
+
+ default:
+error:
+ /* "protocol stall" on error */
+ retval = -EPIPE;
+ }
+ spin_unlock_irqrestore(&musb->lock, flags);
+ return retval;
+}
--- /dev/null
+/*
+ * MUSB OTG driver - support for Mentor's DMA controller
+ *
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2007 by Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * 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 AUTHORS 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.
+ *
+ */
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include "musb_core.h"
+
+#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430)
+#include "omap2430.h"
+#endif
+
+#define MUSB_HSDMA_BASE 0x200
+#define MUSB_HSDMA_INTR (MUSB_HSDMA_BASE + 0)
+#define MUSB_HSDMA_CONTROL 0x4
+#define MUSB_HSDMA_ADDRESS 0x8
+#define MUSB_HSDMA_COUNT 0xc
+
+#define MUSB_HSDMA_CHANNEL_OFFSET(_bChannel, _offset) \
+ (MUSB_HSDMA_BASE + (_bChannel << 4) + _offset)
+
+/* control register (16-bit): */
+#define MUSB_HSDMA_ENABLE_SHIFT 0
+#define MUSB_HSDMA_TRANSMIT_SHIFT 1
+#define MUSB_HSDMA_MODE1_SHIFT 2
+#define MUSB_HSDMA_IRQENABLE_SHIFT 3
+#define MUSB_HSDMA_ENDPOINT_SHIFT 4
+#define MUSB_HSDMA_BUSERROR_SHIFT 8
+#define MUSB_HSDMA_BURSTMODE_SHIFT 9
+#define MUSB_HSDMA_BURSTMODE (3 << MUSB_HSDMA_BURSTMODE_SHIFT)
+#define MUSB_HSDMA_BURSTMODE_UNSPEC 0
+#define MUSB_HSDMA_BURSTMODE_INCR4 1
+#define MUSB_HSDMA_BURSTMODE_INCR8 2
+#define MUSB_HSDMA_BURSTMODE_INCR16 3
+
+#define MUSB_HSDMA_CHANNELS 8
+
+struct musb_dma_controller;
+
+struct musb_dma_channel {
+ struct dma_channel Channel;
+ struct musb_dma_controller *controller;
+ u32 dwStartAddress;
+ u32 len;
+ u16 wMaxPacketSize;
+ u8 bIndex;
+ u8 epnum;
+ u8 transmit;
+};
+
+struct musb_dma_controller {
+ struct dma_controller Controller;
+ struct musb_dma_channel aChannel[MUSB_HSDMA_CHANNELS];
+ void *pDmaPrivate;
+ void __iomem *pCoreBase;
+ u8 bChannelCount;
+ u8 bmUsedChannels;
+ u8 irq;
+};
+
+static int dma_controller_start(struct dma_controller *c)
+{
+ /* nothing to do */
+ return 0;
+}
+
+static void dma_channel_release(struct dma_channel *pChannel);
+
+static int dma_controller_stop(struct dma_controller *c)
+{
+ struct musb_dma_controller *controller =
+ container_of(c, struct musb_dma_controller, Controller);
+ struct musb *musb = (struct musb *) controller->pDmaPrivate;
+ struct dma_channel *pChannel;
+ u8 bBit;
+
+ if (controller->bmUsedChannels != 0) {
+ dev_err(musb->controller,
+ "Stopping DMA controller while channel active\n");
+
+ for (bBit = 0; bBit < MUSB_HSDMA_CHANNELS; bBit++) {
+ if (controller->bmUsedChannels & (1 << bBit)) {
+ pChannel = &controller->aChannel[bBit].Channel;
+ dma_channel_release(pChannel);
+
+ if (!controller->bmUsedChannels)
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+static struct dma_channel *dma_channel_allocate(struct dma_controller *c,
+ struct musb_hw_ep *hw_ep, u8 transmit)
+{
+ u8 bBit;
+ struct dma_channel *pChannel = NULL;
+ struct musb_dma_channel *pImplChannel = NULL;
+ struct musb_dma_controller *controller =
+ container_of(c, struct musb_dma_controller, Controller);
+
+ for (bBit = 0; bBit < MUSB_HSDMA_CHANNELS; bBit++) {
+ if (!(controller->bmUsedChannels & (1 << bBit))) {
+ controller->bmUsedChannels |= (1 << bBit);
+ pImplChannel = &(controller->aChannel[bBit]);
+ pImplChannel->controller = controller;
+ pImplChannel->bIndex = bBit;
+ pImplChannel->epnum = hw_ep->epnum;
+ pImplChannel->transmit = transmit;
+ pChannel = &(pImplChannel->Channel);
+ pChannel->private_data = pImplChannel;
+ pChannel->status = MUSB_DMA_STATUS_FREE;
+ pChannel->max_len = 0x10000;
+ /* Tx => mode 1; Rx => mode 0 */
+ pChannel->desired_mode = transmit;
+ pChannel->actual_len = 0;
+ break;
+ }
+ }
+ return pChannel;
+}
+
+static void dma_channel_release(struct dma_channel *pChannel)
+{
+ struct musb_dma_channel *pImplChannel =
+ (struct musb_dma_channel *) pChannel->private_data;
+
+ pChannel->actual_len = 0;
+ pImplChannel->dwStartAddress = 0;
+ pImplChannel->len = 0;
+
+ pImplChannel->controller->bmUsedChannels &=
+ ~(1 << pImplChannel->bIndex);
+
+ pChannel->status = MUSB_DMA_STATUS_UNKNOWN;
+}
+
+static void configure_channel(struct dma_channel *pChannel,
+ u16 packet_sz, u8 mode,
+ dma_addr_t dma_addr, u32 len)
+{
+ struct musb_dma_channel *pImplChannel =
+ (struct musb_dma_channel *) pChannel->private_data;
+ struct musb_dma_controller *controller = pImplChannel->controller;
+ void __iomem *mbase = controller->pCoreBase;
+ u8 bChannel = pImplChannel->bIndex;
+ u16 csr = 0;
+
+ DBG(4, "%p, pkt_sz %d, addr 0x%x, len %d, mode %d\n",
+ pChannel, packet_sz, dma_addr, len, mode);
+
+ if (mode) {
+ csr |= 1 << MUSB_HSDMA_MODE1_SHIFT;
+ BUG_ON(len < packet_sz);
+
+ if (packet_sz >= 64) {
+ csr |= MUSB_HSDMA_BURSTMODE_INCR16
+ << MUSB_HSDMA_BURSTMODE_SHIFT;
+ } else if (packet_sz >= 32) {
+ csr |= MUSB_HSDMA_BURSTMODE_INCR8
+ << MUSB_HSDMA_BURSTMODE_SHIFT;
+ } else if (packet_sz >= 16) {
+ csr |= MUSB_HSDMA_BURSTMODE_INCR4
+ << MUSB_HSDMA_BURSTMODE_SHIFT;
+ }
+ }
+
+ csr |= (pImplChannel->epnum << MUSB_HSDMA_ENDPOINT_SHIFT)
+ | (1 << MUSB_HSDMA_ENABLE_SHIFT)
+ | (1 << MUSB_HSDMA_IRQENABLE_SHIFT)
+ | (pImplChannel->transmit
+ ? (1 << MUSB_HSDMA_TRANSMIT_SHIFT)
+ : 0);
+
+ /* address/count */
+ musb_writel(mbase,
+ MUSB_HSDMA_CHANNEL_OFFSET(bChannel, MUSB_HSDMA_ADDRESS),
+ dma_addr);
+ musb_writel(mbase,
+ MUSB_HSDMA_CHANNEL_OFFSET(bChannel, MUSB_HSDMA_COUNT),
+ len);
+
+ /* control (this should start things) */
+ musb_writew(mbase,
+ MUSB_HSDMA_CHANNEL_OFFSET(bChannel, MUSB_HSDMA_CONTROL),
+ csr);
+}
+
+static int dma_channel_program(struct dma_channel *pChannel,
+ u16 packet_sz, u8 mode,
+ dma_addr_t dma_addr, u32 len)
+{
+ struct musb_dma_channel *pImplChannel =
+ (struct musb_dma_channel *) pChannel->private_data;
+
+ DBG(2, "ep%d-%s pkt_sz %d, dma_addr 0x%x length %d, mode %d\n",
+ pImplChannel->epnum,
+ pImplChannel->transmit ? "Tx" : "Rx",
+ packet_sz, dma_addr, len, mode);
+
+ BUG_ON(pChannel->status == MUSB_DMA_STATUS_UNKNOWN ||
+ pChannel->status == MUSB_DMA_STATUS_BUSY);
+
+ pChannel->actual_len = 0;
+ pImplChannel->dwStartAddress = dma_addr;
+ pImplChannel->len = len;
+ pImplChannel->wMaxPacketSize = packet_sz;
+ pChannel->status = MUSB_DMA_STATUS_BUSY;
+
+ if ((mode == 1) && (len >= packet_sz))
+ configure_channel(pChannel, packet_sz, 1, dma_addr, len);
+ else
+ configure_channel(pChannel, packet_sz, 0, dma_addr, len);
+
+ return true;
+}
+
+static int dma_channel_abort(struct dma_channel *pChannel)
+{
+ struct musb_dma_channel *pImplChannel =
+ (struct musb_dma_channel *) pChannel->private_data;
+ u8 bChannel = pImplChannel->bIndex;
+ void __iomem *mbase = pImplChannel->controller->pCoreBase;
+ u16 csr;
+
+ if (pChannel->status == MUSB_DMA_STATUS_BUSY) {
+ if (pImplChannel->transmit) {
+
+ csr = musb_readw(mbase,
+ MUSB_EP_OFFSET(pImplChannel->epnum, MUSB_TXCSR));
+ csr &= ~(MUSB_TXCSR_AUTOSET |
+ MUSB_TXCSR_DMAENAB |
+ MUSB_TXCSR_DMAMODE);
+ musb_writew(mbase,
+ MUSB_EP_OFFSET(pImplChannel->epnum, MUSB_TXCSR),
+ csr);
+ } else {
+ csr = musb_readw(mbase,
+ MUSB_EP_OFFSET(pImplChannel->epnum, MUSB_RXCSR));
+ csr &= ~(MUSB_RXCSR_AUTOCLEAR |
+ MUSB_RXCSR_DMAENAB |
+ MUSB_RXCSR_DMAMODE);
+ musb_writew(mbase,
+ MUSB_EP_OFFSET(pImplChannel->epnum, MUSB_RXCSR),
+ csr);
+ }
+
+ musb_writew(mbase,
+ MUSB_HSDMA_CHANNEL_OFFSET(bChannel, MUSB_HSDMA_CONTROL),
+ 0);
+ musb_writel(mbase,
+ MUSB_HSDMA_CHANNEL_OFFSET(bChannel, MUSB_HSDMA_ADDRESS),
+ 0);
+ musb_writel(mbase,
+ MUSB_HSDMA_CHANNEL_OFFSET(bChannel, MUSB_HSDMA_COUNT),
+ 0);
+
+ pChannel->status = MUSB_DMA_STATUS_FREE;
+ }
+ return 0;
+}
+
+static irqreturn_t dma_controller_irq(int irq, void *private_data)
+{
+ struct musb_dma_controller *controller =
+ (struct musb_dma_controller *)private_data;
+ struct musb_dma_channel *pImplChannel;
+ struct musb *musb = controller->pDmaPrivate;
+ void __iomem *mbase = controller->pCoreBase;
+ struct dma_channel *pChannel;
+ u8 bChannel;
+ u16 csr;
+ u32 dwAddress;
+ u8 int_hsdma;
+ irqreturn_t retval = IRQ_NONE;
+ unsigned long flags;
+
+ spin_lock_irqsave(&musb->lock, flags);
+
+ int_hsdma = musb_readb(mbase, MUSB_HSDMA_INTR);
+ if (!int_hsdma)
+ goto done;
+
+ for (bChannel = 0; bChannel < MUSB_HSDMA_CHANNELS; bChannel++) {
+ if (int_hsdma & (1 << bChannel)) {
+ pImplChannel = (struct musb_dma_channel *)
+ &(controller->aChannel[bChannel]);
+ pChannel = &pImplChannel->Channel;
+
+ csr = musb_readw(mbase,
+ MUSB_HSDMA_CHANNEL_OFFSET(bChannel,
+ MUSB_HSDMA_CONTROL));
+
+ if (csr & (1 << MUSB_HSDMA_BUSERROR_SHIFT))
+ pImplChannel->Channel.status =
+ MUSB_DMA_STATUS_BUS_ABORT;
+ else {
+ u8 devctl;
+
+ dwAddress = musb_readl(mbase,
+ MUSB_HSDMA_CHANNEL_OFFSET(
+ bChannel,
+ MUSB_HSDMA_ADDRESS));
+ pChannel->actual_len = dwAddress
+ - pImplChannel->dwStartAddress;
+
+ DBG(2, "ch %p, 0x%x -> 0x%x (%d / %d) %s\n",
+ pChannel, pImplChannel->dwStartAddress,
+ dwAddress, pChannel->actual_len,
+ pImplChannel->len,
+ (pChannel->actual_len
+ < pImplChannel->len) ?
+ "=> reconfig 0": "=> complete");
+
+ devctl = musb_readb(mbase, MUSB_DEVCTL);
+
+ pChannel->status = MUSB_DMA_STATUS_FREE;
+
+ /* completed */
+ if ((devctl & MUSB_DEVCTL_HM)
+ && (pImplChannel->transmit)
+ && ((pChannel->desired_mode == 0)
+ || (pChannel->actual_len &
+ (pImplChannel->wMaxPacketSize - 1)))
+ ) {
+ /* Send out the packet */
+ musb_ep_select(mbase,
+ pImplChannel->epnum);
+ musb_writew(mbase, MUSB_EP_OFFSET(
+ pImplChannel->epnum,
+ MUSB_TXCSR),
+ MUSB_TXCSR_TXPKTRDY);
+ } else
+ musb_dma_completion(
+ musb,
+ pImplChannel->epnum,
+ pImplChannel->transmit);
+ }
+ }
+ }
+ retval = IRQ_HANDLED;
+done:
+ spin_unlock_irqrestore(&musb->lock, flags);
+ return retval;
+}
+
+void dma_controller_destroy(struct dma_controller *c)
+{
+ struct musb_dma_controller *controller;
+
+ controller = container_of(c, struct musb_dma_controller, Controller);
+ if (!controller)
+ return;
+
+ if (controller->irq)
+ free_irq(controller->irq, c);
+
+ kfree(controller);
+}
+
+struct dma_controller *__init
+dma_controller_create(struct musb *musb, void __iomem *pCoreBase)
+{
+ struct musb_dma_controller *controller;
+ struct device *dev = musb->controller;
+ struct platform_device *pdev = to_platform_device(dev);
+ int irq = platform_get_irq(pdev, 1);
+
+ if (irq == 0) {
+ dev_err(dev, "No DMA interrupt line!\n");
+ return NULL;
+ }
+
+ controller = kzalloc(sizeof(struct musb_dma_controller), GFP_KERNEL);
+ if (!controller)
+ return NULL;
+
+ controller->bChannelCount = MUSB_HSDMA_CHANNELS;
+ controller->pDmaPrivate = musb;
+ controller->pCoreBase = pCoreBase;
+
+ controller->Controller.start = dma_controller_start;
+ controller->Controller.stop = dma_controller_stop;
+ controller->Controller.channel_alloc = dma_channel_allocate;
+ controller->Controller.channel_release = dma_channel_release;
+ controller->Controller.channel_program = dma_channel_program;
+ controller->Controller.channel_abort = dma_channel_abort;
+
+ if (request_irq(irq, dma_controller_irq, IRQF_DISABLED,
+ musb->controller->bus_id, &controller->Controller)) {
+ dev_err(dev, "request_irq %d failed!\n", irq);
+ dma_controller_destroy(&controller->Controller);
+ return NULL;
+ }
+
+ controller->irq = irq;
+
+ return &controller->Controller;
+}
--- /dev/null
+/*
+ * Copyright (C) 2005-2007 by Texas Instruments
+ * Some code has been taken from tusb6010.c
+ * Copyrights for that are attributable to:
+ * Copyright (C) 2006 Nokia Corporation
+ * Jarkko Nikula <jarkko.nikula@nokia.com>
+ * Tony Lindgren <tony@atomide.com>
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * The Inventra Controller Driver for Linux is free software; you
+ * can redistribute it and/or modify it under the terms of the GNU
+ * General Public License version 2 as published by the Free Software
+ * Foundation.
+ *
+ * The Inventra Controller Driver for Linux is distributed in
+ * the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Inventra Controller Driver for Linux ; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <asm/mach-types.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/mux.h>
+
+#include "musb_core.h"
+#include "omap2430.h"
+
+#ifdef CONFIG_ARCH_OMAP3430
+#define get_cpu_rev() 2
+#endif
+
+#define MUSB_TIMEOUT_A_WAIT_BCON 1100
+
+static struct timer_list musb_idle_timer;
+
+static void musb_do_idle(unsigned long _musb)
+{
+ struct musb *musb = (void *)_musb;
+ unsigned long flags;
+ u8 power;
+ u8 devctl;
+
+ devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+
+ spin_lock_irqsave(&musb->lock, flags);
+
+ switch (musb->xceiv.state) {
+ case OTG_STATE_A_WAIT_BCON:
+ devctl &= ~MUSB_DEVCTL_SESSION;
+ musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
+
+ devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+ if (devctl & MUSB_DEVCTL_BDEVICE) {
+ musb->xceiv.state = OTG_STATE_B_IDLE;
+ MUSB_DEV_MODE(musb);
+ } else {
+ musb->xceiv.state = OTG_STATE_A_IDLE;
+ MUSB_HST_MODE(musb);
+ }
+ break;
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+ case OTG_STATE_A_SUSPEND:
+ /* finish RESUME signaling? */
+ if (musb->port1_status & MUSB_PORT_STAT_RESUME) {
+ power = musb_readb(musb->mregs, MUSB_POWER);
+ power &= ~MUSB_POWER_RESUME;
+ DBG(1, "root port resume stopped, power %02x\n", power);
+ musb_writeb(musb->mregs, MUSB_POWER, power);
+ musb->is_active = 1;
+ musb->port1_status &= ~(USB_PORT_STAT_SUSPEND
+ | MUSB_PORT_STAT_RESUME);
+ musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16;
+ usb_hcd_poll_rh_status(musb_to_hcd(musb));
+ /* NOTE: it might really be A_WAIT_BCON ... */
+ musb->xceiv.state = OTG_STATE_A_HOST;
+ }
+ break;
+#endif
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+ case OTG_STATE_A_HOST:
+ devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+ if (devctl & MUSB_DEVCTL_BDEVICE)
+ musb->xceiv.state = OTG_STATE_B_IDLE;
+ else
+ musb->xceiv.state = OTG_STATE_A_WAIT_BCON;
+#endif
+ default:
+ break;
+ }
+ spin_unlock_irqrestore(&musb->lock, flags);
+}
+
+
+void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
+{
+ unsigned long default_timeout = jiffies + msecs_to_jiffies(3);
+ static unsigned long last_timer;
+
+ if (timeout == 0)
+ timeout = default_timeout;
+
+ /* Never idle if active, or when VBUS timeout is not set as host */
+ if (musb->is_active || ((musb->a_wait_bcon == 0)
+ && (musb->xceiv.state == OTG_STATE_A_WAIT_BCON))) {
+ DBG(4, "%s active, deleting timer\n", otg_state_string(musb));
+ del_timer(&musb_idle_timer);
+ last_timer = jiffies;
+ return;
+ }
+
+ if (time_after(last_timer, timeout)) {
+ if (!timer_pending(&musb_idle_timer))
+ last_timer = timeout;
+ else {
+ DBG(4, "Longer idle timer already pending, ignoring\n");
+ return;
+ }
+ }
+ last_timer = timeout;
+
+ DBG(4, "%s inactive, for idle timer for %lu ms\n",
+ otg_state_string(musb),
+ (unsigned long)jiffies_to_msecs(timeout - jiffies));
+ mod_timer(&musb_idle_timer, timeout);
+}
+
+void musb_platform_enable(struct musb *musb)
+{
+}
+void musb_platform_disable(struct musb *musb)
+{
+}
+static void omap_vbus_power(struct musb *musb, int is_on, int sleeping)
+{
+}
+
+static void omap_set_vbus(struct musb *musb, int is_on)
+{
+ u8 devctl;
+ /* HDRC controls CPEN, but beware current surges during device
+ * connect. They can trigger transient overcurrent conditions
+ * that must be ignored.
+ */
+
+ devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+
+ if (is_on) {
+ musb->is_active = 1;
+ musb->xceiv.default_a = 1;
+ musb->xceiv.state = OTG_STATE_A_WAIT_VRISE;
+ devctl |= MUSB_DEVCTL_SESSION;
+
+ MUSB_HST_MODE(musb);
+ } else {
+ musb->is_active = 0;
+
+ /* NOTE: we're skipping A_WAIT_VFALL -> A_IDLE and
+ * jumping right to B_IDLE...
+ */
+
+ musb->xceiv.default_a = 0;
+ musb->xceiv.state = OTG_STATE_B_IDLE;
+ devctl &= ~MUSB_DEVCTL_SESSION;
+
+ MUSB_DEV_MODE(musb);
+ }
+ musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
+
+ DBG(1, "VBUS %s, devctl %02x "
+ /* otg %3x conf %08x prcm %08x */ "\n",
+ otg_state_string(musb),
+ musb_readb(musb->mregs, MUSB_DEVCTL));
+}
+static int omap_set_power(struct otg_transceiver *x, unsigned mA)
+{
+ return 0;
+}
+
+int musb_platform_resume(struct musb *musb);
+
+void musb_platform_set_mode(struct musb *musb, u8 musb_mode)
+{
+ u8 devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+
+ devctl |= MUSB_DEVCTL_SESSION;
+ musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
+
+ switch (musb_mode) {
+ case MUSB_HOST:
+ otg_set_host(&musb->xceiv, musb->xceiv.host);
+ break;
+ case MUSB_PERIPHERAL:
+ otg_set_peripheral(&musb->xceiv, musb->xceiv.gadget);
+ break;
+ case MUSB_OTG:
+ break;
+ }
+}
+
+int __init musb_platform_init(struct musb *musb)
+{
+ struct otg_transceiver *xceiv = otg_get_transceiver();
+
+#if defined(CONFIG_ARCH_OMAP2430)
+ omap_cfg_reg(AE5_2430_USB0HS_STP);
+#endif
+
+ musb->xceiv = *xceiv;
+ musb_platform_resume(musb);
+
+ OTG_SYSCONFIG_REG &= ~ENABLEWAKEUP; /* disable wakeup */
+ OTG_SYSCONFIG_REG &= ~NOSTDBY; /* remove possible nostdby */
+ OTG_SYSCONFIG_REG |= SMARTSTDBY; /* enable smart standby */
+ OTG_SYSCONFIG_REG &= ~AUTOIDLE; /* disable auto idle */
+ OTG_SYSCONFIG_REG &= ~NOIDLE; /* remove possible noidle */
+ OTG_SYSCONFIG_REG |= SMARTIDLE; /* enable smart idle */
+ OTG_SYSCONFIG_REG |= AUTOIDLE; /* enable auto idle */
+
+ OTG_INTERFSEL_REG |= ULPI_12PIN;
+
+ pr_debug("HS USB OTG: revision 0x%x, sysconfig 0x%02x, "
+ "sysstatus 0x%x, intrfsel 0x%x, simenable 0x%x\n",
+ OTG_REVISION_REG, OTG_SYSCONFIG_REG, OTG_SYSSTATUS_REG,
+ OTG_INTERFSEL_REG, OTG_SIMENABLE_REG);
+
+ omap_vbus_power(musb, musb->board_mode == MUSB_HOST, 1);
+
+ if (is_host_enabled(musb))
+ musb->board_set_vbus = omap_set_vbus;
+ if (is_peripheral_enabled(musb))
+ musb->xceiv.set_power = omap_set_power;
+ musb->a_wait_bcon = MUSB_TIMEOUT_A_WAIT_BCON;
+
+ setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
+
+ return 0;
+}
+
+int musb_platform_suspend(struct musb *musb)
+{
+ if (!musb->clock)
+ return 0;
+
+ /* in any role */
+ OTG_FORCESTDBY_REG |= ENABLEFORCE; /* enable MSTANDBY */
+ OTG_SYSCONFIG_REG |= ENABLEWAKEUP; /* enable wakeup */
+
+ if (musb->xceiv.set_suspend)
+ musb->xceiv.set_suspend(&musb->xceiv, 1);
+
+ if (musb->set_clock)
+ musb->set_clock(musb->clock, 0);
+ else
+ clk_disable(musb->clock);
+
+ return 0;
+}
+
+int musb_platform_resume(struct musb *musb)
+{
+ if (!musb->clock)
+ return 0;
+
+ if (musb->xceiv.set_suspend)
+ musb->xceiv.set_suspend(&musb->xceiv, 0);
+
+ if (musb->set_clock)
+ musb->set_clock(musb->clock, 1);
+ else
+ clk_enable(musb->clock);
+
+ OTG_SYSCONFIG_REG &= ~ENABLEWAKEUP; /* disable wakeup */
+ OTG_FORCESTDBY_REG &= ~ENABLEFORCE; /* disable MSTANDBY */
+
+ return 0;
+}
+
+
+int musb_platform_exit(struct musb *musb)
+{
+
+ omap_vbus_power(musb, 0 /*off*/, 1);
+
+ musb_platform_suspend(musb);
+
+ clk_put(musb->clock);
+ musb->clock = 0;
+
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (C) 2005-2006 by Texas Instruments
+ *
+ * The Inventra Controller Driver for Linux is free software; you
+ * can redistribute it and/or modify it under the terms of the GNU
+ * General Public License version 2 as published by the Free Software
+ * Foundation.
+ */
+
+#ifndef __MUSB_OMAP243X_H__
+#define __MUSB_OMAP243X_H__
+
+#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430)
+#include <asm/arch/hardware.h>
+#include <asm/arch/usb.h>
+
+/*
+ * OMAP2430-specific definitions
+ */
+
+#define MENTOR_BASE_OFFSET 0
+#if defined(CONFIG_ARCH_OMAP2430)
+#define OMAP_HSOTG_BASE (OMAP243X_HS_BASE)
+#elif defined(CONFIG_ARCH_OMAP3430)
+#define OMAP_HSOTG_BASE (OMAP34XX_HSUSB_OTG_BASE)
+#endif
+#define OMAP_HSOTG(offset) __REG32(OMAP_HSOTG_BASE + 0x400 + (offset))
+#define OTG_REVISION_REG OMAP_HSOTG(0x0)
+#define OTG_SYSCONFIG_REG OMAP_HSOTG(0x4)
+# define MIDLEMODE 12 /* bit position */
+# define FORCESTDBY (0 << MIDLEMODE)
+# define NOSTDBY (1 << MIDLEMODE)
+# define SMARTSTDBY (2 << MIDLEMODE)
+# define SIDLEMODE 3 /* bit position */
+# define FORCEIDLE (0 << SIDLEMODE)
+# define NOIDLE (1 << SIDLEMODE)
+# define SMARTIDLE (2 << SIDLEMODE)
+# define ENABLEWAKEUP (1 << 2)
+# define SOFTRST (1 << 1)
+# define AUTOIDLE (1 << 0)
+#define OTG_SYSSTATUS_REG OMAP_HSOTG(0x8)
+# define RESETDONE (1 << 0)
+#define OTG_INTERFSEL_REG OMAP_HSOTG(0xc)
+# define EXTCP (1 << 2)
+# define PHYSEL 0 /* bit position */
+# define UTMI_8BIT (0 << PHYSEL)
+# define ULPI_12PIN (1 << PHYSEL)
+# define ULPI_8PIN (2 << PHYSEL)
+#define OTG_SIMENABLE_REG OMAP_HSOTG(0x10)
+# define TM1 (1 << 0)
+#define OTG_FORCESTDBY_REG OMAP_HSOTG(0x14)
+# define ENABLEFORCE (1 << 0)
+
+#endif /* CONFIG_ARCH_OMAP2430 */
+
+#endif /* __MUSB_OMAP243X_H__ */
--- /dev/null
+/*
+ * TUSB6010 USB 2.0 OTG Dual Role controller
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Jarkko Nikula <jarkko.nikula@nokia.com>
+ * Tony Lindgren <tony@atomide.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Notes:
+ * - Driver assumes that interface to external host (main CPU) is
+ * configured for NOR FLASH interface instead of VLYNQ serial
+ * interface.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/usb.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+
+#include "musb_core.h"
+
+static void tusb_source_power(struct musb *musb, int is_on);
+
+#define TUSB_REV_MAJOR(reg_val) ((reg_val >> 4) & 0xf)
+#define TUSB_REV_MINOR(reg_val) (reg_val & 0xf)
+
+/*
+ * Checks the revision. We need to use the DMA register as 3.0 does not
+ * have correct versions for TUSB_PRCM_REV or TUSB_INT_CTRL_REV.
+ */
+u8 tusb_get_revision(struct musb *musb)
+{
+ void __iomem *tbase = musb->ctrl_base;
+ u32 die_id;
+ u8 rev;
+
+ rev = musb_readl(tbase, TUSB_DMA_CTRL_REV) & 0xff;
+ if (TUSB_REV_MAJOR(rev) == 3) {
+ die_id = TUSB_DIDR1_HI_CHIP_REV(musb_readl(tbase,
+ TUSB_DIDR1_HI));
+ if (die_id >= TUSB_DIDR1_HI_REV_31)
+ rev |= 1;
+ }
+
+ return rev;
+}
+
+static int __init tusb_print_revision(struct musb *musb)
+{
+ void __iomem *tbase = musb->ctrl_base;
+ u8 rev;
+
+ rev = tusb_get_revision(musb);
+
+ pr_info("tusb: %s%i.%i %s%i.%i %s%i.%i %s%i.%i %s%i %s%i.%i\n",
+ "prcm",
+ TUSB_REV_MAJOR(musb_readl(tbase, TUSB_PRCM_REV)),
+ TUSB_REV_MINOR(musb_readl(tbase, TUSB_PRCM_REV)),
+ "int",
+ TUSB_REV_MAJOR(musb_readl(tbase, TUSB_INT_CTRL_REV)),
+ TUSB_REV_MINOR(musb_readl(tbase, TUSB_INT_CTRL_REV)),
+ "gpio",
+ TUSB_REV_MAJOR(musb_readl(tbase, TUSB_GPIO_REV)),
+ TUSB_REV_MINOR(musb_readl(tbase, TUSB_GPIO_REV)),
+ "dma",
+ TUSB_REV_MAJOR(musb_readl(tbase, TUSB_DMA_CTRL_REV)),
+ TUSB_REV_MINOR(musb_readl(tbase, TUSB_DMA_CTRL_REV)),
+ "dieid",
+ TUSB_DIDR1_HI_CHIP_REV(musb_readl(tbase, TUSB_DIDR1_HI)),
+ "rev",
+ TUSB_REV_MAJOR(rev), TUSB_REV_MINOR(rev));
+
+ return tusb_get_revision(musb);
+}
+
+#define WBUS_QUIRK_MASK (TUSB_PHY_OTG_CTRL_TESTM2 | TUSB_PHY_OTG_CTRL_TESTM1 \
+ | TUSB_PHY_OTG_CTRL_TESTM0)
+
+/*
+ * Workaround for spontaneous WBUS wake-up issue #2 for tusb3.0.
+ * Disables power detection in PHY for the duration of idle.
+ */
+static void tusb_wbus_quirk(struct musb *musb, int enabled)
+{
+ void __iomem *tbase = musb->ctrl_base;
+ static u32 phy_otg_ctrl, phy_otg_ena;
+ u32 tmp;
+
+ if (enabled) {
+ phy_otg_ctrl = musb_readl(tbase, TUSB_PHY_OTG_CTRL);
+ phy_otg_ena = musb_readl(tbase, TUSB_PHY_OTG_CTRL_ENABLE);
+ tmp = TUSB_PHY_OTG_CTRL_WRPROTECT
+ | phy_otg_ena | WBUS_QUIRK_MASK;
+ musb_writel(tbase, TUSB_PHY_OTG_CTRL, tmp);
+ tmp = phy_otg_ena & ~WBUS_QUIRK_MASK;
+ tmp |= TUSB_PHY_OTG_CTRL_WRPROTECT | TUSB_PHY_OTG_CTRL_TESTM2;
+ musb_writel(tbase, TUSB_PHY_OTG_CTRL_ENABLE, tmp);
+ DBG(2, "Enabled tusb wbus quirk ctrl %08x ena %08x\n",
+ musb_readl(tbase, TUSB_PHY_OTG_CTRL),
+ musb_readl(tbase, TUSB_PHY_OTG_CTRL_ENABLE));
+ } else if (musb_readl(tbase, TUSB_PHY_OTG_CTRL_ENABLE)
+ & TUSB_PHY_OTG_CTRL_TESTM2) {
+ tmp = TUSB_PHY_OTG_CTRL_WRPROTECT | phy_otg_ctrl;
+ musb_writel(tbase, TUSB_PHY_OTG_CTRL, tmp);
+ tmp = TUSB_PHY_OTG_CTRL_WRPROTECT | phy_otg_ena;
+ musb_writel(tbase, TUSB_PHY_OTG_CTRL_ENABLE, tmp);
+ DBG(2, "Disabled tusb wbus quirk ctrl %08x ena %08x\n",
+ musb_readl(tbase, TUSB_PHY_OTG_CTRL),
+ musb_readl(tbase, TUSB_PHY_OTG_CTRL_ENABLE));
+ phy_otg_ctrl = 0;
+ phy_otg_ena = 0;
+ }
+}
+
+/*
+ * TUSB 6010 may use a parallel bus that doesn't support byte ops;
+ * so both loading and unloading FIFOs need explicit byte counts.
+ */
+
+static inline void
+tusb_fifo_write_unaligned(void __iomem *fifo, const u8 *buf, u16 len)
+{
+ u32 val;
+ int i;
+
+ if (len > 4) {
+ for (i = 0; i < (len >> 2); i++) {
+ memcpy(&val, buf, 4);
+ musb_writel(fifo, 0, val);
+ buf += 4;
+ }
+ len %= 4;
+ }
+ if (len > 0) {
+ /* Write the rest 1 - 3 bytes to FIFO */
+ memcpy(&val, buf, len);
+ musb_writel(fifo, 0, val);
+ }
+}
+
+static inline void tusb_fifo_read_unaligned(void __iomem *fifo,
+ void __iomem *buf, u16 len)
+{
+ u32 val;
+ int i;
+
+ if (len > 4) {
+ for (i = 0; i < (len >> 2); i++) {
+ val = musb_readl(fifo, 0);
+ memcpy(buf, &val, 4);
+ buf += 4;
+ }
+ len %= 4;
+ }
+ if (len > 0) {
+ /* Read the rest 1 - 3 bytes from FIFO */
+ val = musb_readl(fifo, 0);
+ memcpy(buf, &val, len);
+ }
+}
+
+void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *buf)
+{
+ void __iomem *ep_conf = hw_ep->conf;
+ void __iomem *fifo = hw_ep->fifo;
+ u8 epnum = hw_ep->epnum;
+
+ prefetch(buf);
+
+ DBG(4, "%cX ep%d fifo %p count %d buf %p\n",
+ 'T', epnum, fifo, len, buf);
+
+ if (epnum)
+ musb_writel(ep_conf, TUSB_EP_TX_OFFSET,
+ TUSB_EP_CONFIG_XFR_SIZE(len));
+ else
+ musb_writel(ep_conf, 0, TUSB_EP0_CONFIG_DIR_TX |
+ TUSB_EP0_CONFIG_XFR_SIZE(len));
+
+ if (likely((0x01 & (unsigned long) buf) == 0)) {
+
+ /* Best case is 32bit-aligned destination address */
+ if ((0x02 & (unsigned long) buf) == 0) {
+ if (len >= 4) {
+ writesl(fifo, buf, len >> 2);
+ buf += (len & ~0x03);
+ len &= 0x03;
+ }
+ } else {
+ if (len >= 2) {
+ u32 val;
+ int i;
+
+ /* Cannot use writesw, fifo is 32-bit */
+ for (i = 0; i < (len >> 2); i++) {
+ val = (u32)(*(u16 *)buf);
+ buf += 2;
+ val |= (*(u16 *)buf) << 16;
+ buf += 2;
+ musb_writel(fifo, 0, val);
+ }
+ len &= 0x03;
+ }
+ }
+ }
+
+ if (len > 0)
+ tusb_fifo_write_unaligned(fifo, buf, len);
+}
+
+void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *buf)
+{
+ void __iomem *ep_conf = hw_ep->conf;
+ void __iomem *fifo = hw_ep->fifo;
+ u8 epnum = hw_ep->epnum;
+
+ DBG(4, "%cX ep%d fifo %p count %d buf %p\n",
+ 'R', epnum, fifo, len, buf);
+
+ if (epnum)
+ musb_writel(ep_conf, TUSB_EP_RX_OFFSET,
+ TUSB_EP_CONFIG_XFR_SIZE(len));
+ else
+ musb_writel(ep_conf, 0, TUSB_EP0_CONFIG_XFR_SIZE(len));
+
+ if (likely((0x01 & (unsigned long) buf) == 0)) {
+
+ /* Best case is 32bit-aligned destination address */
+ if ((0x02 & (unsigned long) buf) == 0) {
+ if (len >= 4) {
+ readsl(fifo, buf, len >> 2);
+ buf += (len & ~0x03);
+ len &= 0x03;
+ }
+ } else {
+ if (len >= 2) {
+ u32 val;
+ int i;
+
+ /* Cannot use readsw, fifo is 32-bit */
+ for (i = 0; i < (len >> 2); i++) {
+ val = musb_readl(fifo, 0);
+ *(u16 *)buf = (u16)(val & 0xffff);
+ buf += 2;
+ *(u16 *)buf = (u16)(val >> 16);
+ buf += 2;
+ }
+ len &= 0x03;
+ }
+ }
+ }
+
+ if (len > 0)
+ tusb_fifo_read_unaligned(fifo, buf, len);
+}
+
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+
+/* This is used by gadget drivers, and OTG transceiver logic, allowing
+ * at most mA current to be drawn from VBUS during a Default-B session
+ * (that is, while VBUS exceeds 4.4V). In Default-A (including pure host
+ * mode), or low power Default-B sessions, something else supplies power.
+ * Caller must take care of locking.
+ */
+static int tusb_draw_power(struct otg_transceiver *x, unsigned mA)
+{
+ struct musb *musb = container_of(x, struct musb, xceiv);
+ void __iomem *tbase = musb->ctrl_base;
+ u32 reg;
+
+ /*
+ * Keep clock active when enabled. Note that this is not tied to
+ * drawing VBUS, as with OTG mA can be less than musb->min_power.
+ */
+ if (musb->set_clock) {
+ if (mA)
+ musb->set_clock(musb->clock, 1);
+ else
+ musb->set_clock(musb->clock, 0);
+ }
+
+ /* tps65030 seems to consume max 100mA, with maybe 60mA available
+ * (measured on one board) for things other than tps and tusb.
+ *
+ * Boards sharing the CPU clock with CLKIN will need to prevent
+ * certain idle sleep states while the USB link is active.
+ *
+ * REVISIT we could use VBUS to supply only _one_ of { 1.5V, 3.3V }.
+ * The actual current usage would be very board-specific. For now,
+ * it's simpler to just use an aggregate (also board-specific).
+ */
+ if (x->default_a || mA < (musb->min_power << 1))
+ mA = 0;
+
+ reg = musb_readl(tbase, TUSB_PRCM_MNGMT);
+ if (mA) {
+ musb->is_bus_powered = 1;
+ reg |= TUSB_PRCM_MNGMT_15_SW_EN | TUSB_PRCM_MNGMT_33_SW_EN;
+ } else {
+ musb->is_bus_powered = 0;
+ reg &= ~(TUSB_PRCM_MNGMT_15_SW_EN | TUSB_PRCM_MNGMT_33_SW_EN);
+ }
+ musb_writel(tbase, TUSB_PRCM_MNGMT, reg);
+
+ DBG(2, "draw max %d mA VBUS\n", mA);
+ return 0;
+}
+
+#else
+#define tusb_draw_power NULL
+#endif
+
+/* workaround for issue 13: change clock during chip idle
+ * (to be fixed in rev3 silicon) ... symptoms include disconnect
+ * or looping suspend/resume cycles
+ */
+static void tusb_set_clock_source(struct musb *musb, unsigned mode)
+{
+ void __iomem *tbase = musb->ctrl_base;
+ u32 reg;
+
+ reg = musb_readl(tbase, TUSB_PRCM_CONF);
+ reg &= ~TUSB_PRCM_CONF_SYS_CLKSEL(0x3);
+
+ /* 0 = refclk (clkin, XI)
+ * 1 = PHY 60 MHz (internal PLL)
+ * 2 = not supported
+ * 3 = what?
+ */
+ if (mode > 0)
+ reg |= TUSB_PRCM_CONF_SYS_CLKSEL(mode & 0x3);
+
+ musb_writel(tbase, TUSB_PRCM_CONF, reg);
+
+ /* FIXME tusb6010_platform_retime(mode == 0); */
+}
+
+/*
+ * Idle TUSB6010 until next wake-up event; NOR access always wakes.
+ * Other code ensures that we idle unless we're connected _and_ the
+ * USB link is not suspended ... and tells us the relevant wakeup
+ * events. SW_EN for voltage is handled separately.
+ */
+void tusb_allow_idle(struct musb *musb, u32 wakeup_enables)
+{
+ void __iomem *tbase = musb->ctrl_base;
+ u32 reg;
+
+ if ((wakeup_enables & TUSB_PRCM_WBUS)
+ && (tusb_get_revision(musb) == TUSB_REV_30))
+ tusb_wbus_quirk(musb, 1);
+
+ tusb_set_clock_source(musb, 0);
+
+ wakeup_enables |= TUSB_PRCM_WNORCS;
+ musb_writel(tbase, TUSB_PRCM_WAKEUP_MASK, ~wakeup_enables);
+
+ /* REVISIT writeup of WID implies that if WID set and ID is grounded,
+ * TUSB_PHY_OTG_CTRL.TUSB_PHY_OTG_CTRL_OTG_ID_PULLUP must be cleared.
+ * Presumably that's mostly to save power, hence WID is immaterial ...
+ */
+
+ reg = musb_readl(tbase, TUSB_PRCM_MNGMT);
+ /* issue 4: when driving vbus, use hipower (vbus_det) comparator */
+ if (is_host_active(musb)) {
+ reg |= TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN;
+ reg &= ~TUSB_PRCM_MNGMT_OTG_SESS_END_EN;
+ } else {
+ reg |= TUSB_PRCM_MNGMT_OTG_SESS_END_EN;
+ reg &= ~TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN;
+ }
+ reg |= TUSB_PRCM_MNGMT_PM_IDLE | TUSB_PRCM_MNGMT_DEV_IDLE;
+ musb_writel(tbase, TUSB_PRCM_MNGMT, reg);
+
+ DBG(6, "idle, wake on %02x\n", wakeup_enables);
+}
+
+/*
+ * Updates cable VBUS status. Caller must take care of locking.
+ */
+int musb_platform_get_vbus_status(struct musb *musb)
+{
+ void __iomem *tbase = musb->ctrl_base;
+ u32 otg_stat, prcm_mngmt;
+ int ret = 0;
+
+ otg_stat = musb_readl(tbase, TUSB_DEV_OTG_STAT);
+ prcm_mngmt = musb_readl(tbase, TUSB_PRCM_MNGMT);
+
+ /* Temporarily enable VBUS detection if it was disabled for
+ * suspend mode. Unless it's enabled otg_stat and devctl will
+ * not show correct VBUS state.
+ */
+ if (!(prcm_mngmt & TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN)) {
+ u32 tmp = prcm_mngmt;
+ tmp |= TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN;
+ musb_writel(tbase, TUSB_PRCM_MNGMT, tmp);
+ otg_stat = musb_readl(tbase, TUSB_DEV_OTG_STAT);
+ musb_writel(tbase, TUSB_PRCM_MNGMT, prcm_mngmt);
+ }
+
+ if (otg_stat & TUSB_DEV_OTG_STAT_VBUS_VALID)
+ ret = 1;
+
+ return ret;
+}
+
+static struct timer_list musb_idle_timer;
+
+static void musb_do_idle(unsigned long _musb)
+{
+ struct musb *musb = (void *)_musb;
+ unsigned long flags;
+
+ spin_lock_irqsave(&musb->lock, flags);
+
+ switch (musb->xceiv.state) {
+ case OTG_STATE_A_WAIT_BCON:
+ if ((musb->a_wait_bcon != 0)
+ && (musb->idle_timeout == 0
+ || time_after(jiffies, musb->idle_timeout))) {
+ DBG(4, "Nothing connected %s, turning off VBUS\n",
+ otg_state_string(musb));
+ }
+ /* FALLTHROUGH */
+ case OTG_STATE_A_IDLE:
+ tusb_source_power(musb, 0);
+ default:
+ break;
+ }
+
+ if (!musb->is_active) {
+ u32 wakeups;
+
+ /* wait until khubd handles port change status */
+ if (is_host_active(musb) && (musb->port1_status >> 16))
+ goto done;
+
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+ if (is_peripheral_enabled(musb) && !musb->gadget_driver)
+ wakeups = 0;
+ else {
+ wakeups = TUSB_PRCM_WHOSTDISCON
+ | TUSB_PRCM_WBUS
+ | TUSB_PRCM_WVBUS;
+ if (is_otg_enabled(musb))
+ wakeups |= TUSB_PRCM_WID;
+ }
+#else
+ wakeups = TUSB_PRCM_WHOSTDISCON | TUSB_PRCM_WBUS;
+#endif
+ tusb_allow_idle(musb, wakeups);
+ }
+done:
+ spin_unlock_irqrestore(&musb->lock, flags);
+}
+
+/*
+ * Maybe put TUSB6010 into idle mode mode depending on USB link status,
+ * like "disconnected" or "suspended". We'll be woken out of it by
+ * connect, resume, or disconnect.
+ *
+ * Needs to be called as the last function everywhere where there is
+ * register access to TUSB6010 because of NOR flash wake-up.
+ * Caller should own controller spinlock.
+ *
+ * Delay because peripheral enables D+ pullup 3msec after SE0, and
+ * we don't want to treat that full speed J as a wakeup event.
+ * ... peripherals must draw only suspend current after 10 msec.
+ */
+void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
+{
+ unsigned long default_timeout = jiffies + msecs_to_jiffies(3);
+ static unsigned long last_timer;
+
+ if (timeout == 0)
+ timeout = default_timeout;
+
+ /* Never idle if active, or when VBUS timeout is not set as host */
+ if (musb->is_active || ((musb->a_wait_bcon == 0)
+ && (musb->xceiv.state == OTG_STATE_A_WAIT_BCON))) {
+ DBG(4, "%s active, deleting timer\n", otg_state_string(musb));
+ del_timer(&musb_idle_timer);
+ last_timer = jiffies;
+ return;
+ }
+
+ if (time_after(last_timer, timeout)) {
+ if (!timer_pending(&musb_idle_timer))
+ last_timer = timeout;
+ else {
+ DBG(4, "Longer idle timer already pending, ignoring\n");
+ return;
+ }
+ }
+ last_timer = timeout;
+
+ DBG(4, "%s inactive, for idle timer for %lu ms\n",
+ otg_state_string(musb),
+ (unsigned long)jiffies_to_msecs(timeout - jiffies));
+ mod_timer(&musb_idle_timer, timeout);
+}
+
+/* ticks of 60 MHz clock */
+#define DEVCLOCK 60000000
+#define OTG_TIMER_MS(msecs) ((msecs) \
+ ? (TUSB_DEV_OTG_TIMER_VAL((DEVCLOCK/1000)*(msecs)) \
+ | TUSB_DEV_OTG_TIMER_ENABLE) \
+ : 0)
+
+static void tusb_source_power(struct musb *musb, int is_on)
+{
+ void __iomem *tbase = musb->ctrl_base;
+ u32 conf, prcm, timer;
+ u8 devctl;
+
+ /* HDRC controls CPEN, but beware current surges during device
+ * connect. They can trigger transient overcurrent conditions
+ * that must be ignored.
+ */
+
+ prcm = musb_readl(tbase, TUSB_PRCM_MNGMT);
+ conf = musb_readl(tbase, TUSB_DEV_CONF);
+ devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+
+ if (is_on) {
+ if (musb->set_clock)
+ musb->set_clock(musb->clock, 1);
+ timer = OTG_TIMER_MS(OTG_TIME_A_WAIT_VRISE);
+ musb->xceiv.default_a = 1;
+ musb->xceiv.state = OTG_STATE_A_WAIT_VRISE;
+ devctl |= MUSB_DEVCTL_SESSION;
+
+ conf |= TUSB_DEV_CONF_USB_HOST_MODE;
+ MUSB_HST_MODE(musb);
+ } else {
+ u32 otg_stat;
+
+ timer = 0;
+
+ /* If ID pin is grounded, we want to be a_idle */
+ otg_stat = musb_readl(tbase, TUSB_DEV_OTG_STAT);
+ if (!(otg_stat & TUSB_DEV_OTG_STAT_ID_STATUS)) {
+ switch (musb->xceiv.state) {
+ case OTG_STATE_A_WAIT_VRISE:
+ case OTG_STATE_A_WAIT_BCON:
+ musb->xceiv.state = OTG_STATE_A_WAIT_VFALL;
+ break;
+ case OTG_STATE_A_WAIT_VFALL:
+ musb->xceiv.state = OTG_STATE_A_IDLE;
+ break;
+ default:
+ musb->xceiv.state = OTG_STATE_A_IDLE;
+ }
+ musb->is_active = 0;
+ musb->xceiv.default_a = 1;
+ MUSB_HST_MODE(musb);
+ } else {
+ musb->is_active = 0;
+ musb->xceiv.default_a = 0;
+ musb->xceiv.state = OTG_STATE_B_IDLE;
+ MUSB_DEV_MODE(musb);
+ }
+
+ devctl &= ~MUSB_DEVCTL_SESSION;
+ conf &= ~TUSB_DEV_CONF_USB_HOST_MODE;
+ if (musb->set_clock)
+ musb->set_clock(musb->clock, 0);
+ }
+ prcm &= ~(TUSB_PRCM_MNGMT_15_SW_EN | TUSB_PRCM_MNGMT_33_SW_EN);
+
+ musb_writel(tbase, TUSB_PRCM_MNGMT, prcm);
+ musb_writel(tbase, TUSB_DEV_OTG_TIMER, timer);
+ musb_writel(tbase, TUSB_DEV_CONF, conf);
+ musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
+
+ DBG(1, "VBUS %s, devctl %02x otg %3x conf %08x prcm %08x\n",
+ otg_state_string(musb),
+ musb_readb(musb->mregs, MUSB_DEVCTL),
+ musb_readl(tbase, TUSB_DEV_OTG_STAT),
+ conf, prcm);
+}
+
+/*
+ * Sets the mode to OTG, peripheral or host by changing the ID detection.
+ * Caller must take care of locking.
+ *
+ * Note that if a mini-A cable is plugged in the ID line will stay down as
+ * the weak ID pull-up is not able to pull the ID up.
+ *
+ * REVISIT: It would be possible to add support for changing between host
+ * and peripheral modes in non-OTG configurations by reconfiguring hardware
+ * and then setting musb->board_mode. For now, only support OTG mode.
+ */
+void musb_platform_set_mode(struct musb *musb, u8 musb_mode)
+{
+ void __iomem *tbase = musb->ctrl_base;
+ u32 otg_stat, phy_otg_ctrl, phy_otg_ena, dev_conf;
+
+ if (musb->board_mode != MUSB_OTG) {
+ ERR("Changing mode currently only supported in OTG mode\n");
+ return;
+ }
+
+ otg_stat = musb_readl(tbase, TUSB_DEV_OTG_STAT);
+ phy_otg_ctrl = musb_readl(tbase, TUSB_PHY_OTG_CTRL);
+ phy_otg_ena = musb_readl(tbase, TUSB_PHY_OTG_CTRL_ENABLE);
+ dev_conf = musb_readl(tbase, TUSB_DEV_CONF);
+
+ switch (musb_mode) {
+
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+ case MUSB_HOST: /* Disable PHY ID detect, ground ID */
+ phy_otg_ctrl &= ~TUSB_PHY_OTG_CTRL_OTG_ID_PULLUP;
+ phy_otg_ena |= TUSB_PHY_OTG_CTRL_OTG_ID_PULLUP;
+ dev_conf |= TUSB_DEV_CONF_ID_SEL;
+ dev_conf &= ~TUSB_DEV_CONF_SOFT_ID;
+ break;
+#endif
+
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+ case MUSB_PERIPHERAL: /* Disable PHY ID detect, keep ID pull-up on */
+ phy_otg_ctrl |= TUSB_PHY_OTG_CTRL_OTG_ID_PULLUP;
+ phy_otg_ena |= TUSB_PHY_OTG_CTRL_OTG_ID_PULLUP;
+ dev_conf |= (TUSB_DEV_CONF_ID_SEL | TUSB_DEV_CONF_SOFT_ID);
+ break;
+#endif
+
+#ifdef CONFIG_USB_MUSB_OTG
+ case MUSB_OTG: /* Use PHY ID detection */
+ phy_otg_ctrl |= TUSB_PHY_OTG_CTRL_OTG_ID_PULLUP;
+ phy_otg_ena |= TUSB_PHY_OTG_CTRL_OTG_ID_PULLUP;
+ dev_conf &= ~(TUSB_DEV_CONF_ID_SEL | TUSB_DEV_CONF_SOFT_ID);
+ break;
+#endif
+
+ default:
+ DBG(2, "Trying to set unknown mode %i\n", musb_mode);
+ }
+
+ musb_writel(tbase, TUSB_PHY_OTG_CTRL,
+ TUSB_PHY_OTG_CTRL_WRPROTECT | phy_otg_ctrl);
+ musb_writel(tbase, TUSB_PHY_OTG_CTRL_ENABLE,
+ TUSB_PHY_OTG_CTRL_WRPROTECT | phy_otg_ena);
+ musb_writel(tbase, TUSB_DEV_CONF, dev_conf);
+
+ otg_stat = musb_readl(tbase, TUSB_DEV_OTG_STAT);
+ if ((musb_mode == MUSB_PERIPHERAL) &&
+ !(otg_stat & TUSB_DEV_OTG_STAT_ID_STATUS))
+ INFO("Cannot be peripheral with mini-A cable "
+ "otg_stat: %08x\n", otg_stat);
+}
+
+static inline unsigned long
+tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
+{
+ u32 otg_stat = musb_readl(tbase, TUSB_DEV_OTG_STAT);
+ unsigned long idle_timeout = 0;
+
+ /* ID pin */
+ if ((int_src & TUSB_INT_SRC_ID_STATUS_CHNG)) {
+ int default_a;
+
+ if (is_otg_enabled(musb))
+ default_a = !(otg_stat & TUSB_DEV_OTG_STAT_ID_STATUS);
+ else
+ default_a = is_host_enabled(musb);
+ DBG(2, "Default-%c\n", default_a ? 'A' : 'B');
+ musb->xceiv.default_a = default_a;
+ tusb_source_power(musb, default_a);
+
+ /* Don't allow idling immediately */
+ if (default_a)
+ idle_timeout = jiffies + (HZ * 3);
+ }
+
+ /* VBUS state change */
+ if (int_src & TUSB_INT_SRC_VBUS_SENSE_CHNG) {
+
+ /* B-dev state machine: no vbus ~= disconnect */
+ if ((is_otg_enabled(musb) && !musb->xceiv.default_a)
+ || !is_host_enabled(musb)) {
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+ /* ? musb_root_disconnect(musb); */
+ musb->port1_status &=
+ ~(USB_PORT_STAT_CONNECTION
+ | USB_PORT_STAT_ENABLE
+ | USB_PORT_STAT_LOW_SPEED
+ | USB_PORT_STAT_HIGH_SPEED
+ | USB_PORT_STAT_TEST
+ );
+#endif
+
+ if (otg_stat & TUSB_DEV_OTG_STAT_SESS_END) {
+ DBG(1, "Forcing disconnect (no interrupt)\n");
+ if (musb->xceiv.state != OTG_STATE_B_IDLE) {
+ /* INTR_DISCONNECT can hide... */
+ musb->xceiv.state = OTG_STATE_B_IDLE;
+ musb->int_usb |= MUSB_INTR_DISCONNECT;
+ }
+ musb->is_active = 0;
+ }
+ DBG(2, "vbus change, %s, otg %03x\n",
+ otg_state_string(musb), otg_stat);
+ idle_timeout = jiffies + (1 * HZ);
+ schedule_work(&musb->irq_work);
+
+ } else /* A-dev state machine */ {
+ DBG(2, "vbus change, %s, otg %03x\n",
+ otg_state_string(musb), otg_stat);
+
+ switch (musb->xceiv.state) {
+ case OTG_STATE_A_IDLE:
+ DBG(2, "Got SRP, turning on VBUS\n");
+ musb_set_vbus(musb, 1);
+
+ /* CONNECT can wake if a_wait_bcon is set */
+ if (musb->a_wait_bcon != 0)
+ musb->is_active = 0;
+ else
+ musb->is_active = 1;
+
+ /*
+ * OPT FS A TD.4.6 needs few seconds for
+ * A_WAIT_VRISE
+ */
+ idle_timeout = jiffies + (2 * HZ);
+
+ break;
+ case OTG_STATE_A_WAIT_VRISE:
+ /* ignore; A-session-valid < VBUS_VALID/2,
+ * we monitor this with the timer
+ */
+ break;
+ case OTG_STATE_A_WAIT_VFALL:
+ /* REVISIT this irq triggers during short
+ * spikes caused by enumeration ...
+ */
+ if (musb->vbuserr_retry) {
+ musb->vbuserr_retry--;
+ tusb_source_power(musb, 1);
+ } else {
+ musb->vbuserr_retry
+ = VBUSERR_RETRY_COUNT;
+ tusb_source_power(musb, 0);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ /* OTG timer expiration */
+ if (int_src & TUSB_INT_SRC_OTG_TIMEOUT) {
+ u8 devctl;
+
+ DBG(4, "%s timer, %03x\n", otg_state_string(musb), otg_stat);
+
+ switch (musb->xceiv.state) {
+ case OTG_STATE_A_WAIT_VRISE:
+ /* VBUS has probably been valid for a while now,
+ * but may well have bounced out of range a bit
+ */
+ devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+ if (otg_stat & TUSB_DEV_OTG_STAT_VBUS_VALID) {
+ if ((devctl & MUSB_DEVCTL_VBUS)
+ != MUSB_DEVCTL_VBUS) {
+ DBG(2, "devctl %02x\n", devctl);
+ break;
+ }
+ musb->xceiv.state = OTG_STATE_A_WAIT_BCON;
+ musb->is_active = 0;
+ idle_timeout = jiffies
+ + msecs_to_jiffies(musb->a_wait_bcon);
+ } else {
+ /* REVISIT report overcurrent to hub? */
+ ERR("vbus too slow, devctl %02x\n", devctl);
+ tusb_source_power(musb, 0);
+ }
+ break;
+ case OTG_STATE_A_WAIT_BCON:
+ if (musb->a_wait_bcon != 0)
+ idle_timeout = jiffies
+ + msecs_to_jiffies(musb->a_wait_bcon);
+ break;
+ case OTG_STATE_A_SUSPEND:
+ break;
+ case OTG_STATE_B_WAIT_ACON:
+ break;
+ default:
+ break;
+ }
+ }
+ schedule_work(&musb->irq_work);
+
+ return idle_timeout;
+}
+
+static irqreturn_t tusb_interrupt(int irq, void *__hci)
+{
+ struct musb *musb = __hci;
+ void __iomem *tbase = musb->ctrl_base;
+ unsigned long flags, idle_timeout = 0;
+ u32 int_mask, int_src;
+
+ spin_lock_irqsave(&musb->lock, flags);
+
+ /* Mask all interrupts to allow using both edge and level GPIO irq */
+ int_mask = musb_readl(tbase, TUSB_INT_MASK);
+ musb_writel(tbase, TUSB_INT_MASK, ~TUSB_INT_MASK_RESERVED_BITS);
+
+ int_src = musb_readl(tbase, TUSB_INT_SRC) & ~TUSB_INT_SRC_RESERVED_BITS;
+ DBG(3, "TUSB IRQ %08x\n", int_src);
+
+ musb->int_usb = (u8) int_src;
+
+ /* Acknowledge wake-up source interrupts */
+ if (int_src & TUSB_INT_SRC_DEV_WAKEUP) {
+ u32 reg;
+ u32 i;
+
+ if (tusb_get_revision(musb) == TUSB_REV_30)
+ tusb_wbus_quirk(musb, 0);
+
+ /* there are issues re-locking the PLL on wakeup ... */
+
+ /* work around issue 8 */
+ for (i = 0xf7f7f7; i > 0xf7f7f7 - 1000; i--) {
+ musb_writel(tbase, TUSB_SCRATCH_PAD, 0);
+ musb_writel(tbase, TUSB_SCRATCH_PAD, i);
+ reg = musb_readl(tbase, TUSB_SCRATCH_PAD);
+ if (reg == i)
+ break;
+ DBG(6, "TUSB NOR not ready\n");
+ }
+
+ /* work around issue 13 (2nd half) */
+ tusb_set_clock_source(musb, 1);
+
+ reg = musb_readl(tbase, TUSB_PRCM_WAKEUP_SOURCE);
+ musb_writel(tbase, TUSB_PRCM_WAKEUP_CLEAR, reg);
+ if (reg & ~TUSB_PRCM_WNORCS) {
+ musb->is_active = 1;
+ schedule_work(&musb->irq_work);
+ }
+ DBG(3, "wake %sactive %02x\n",
+ musb->is_active ? "" : "in", reg);
+
+ /* REVISIT host side TUSB_PRCM_WHOSTDISCON, TUSB_PRCM_WBUS */
+ }
+
+ if (int_src & TUSB_INT_SRC_USB_IP_CONN)
+ del_timer(&musb_idle_timer);
+
+ /* OTG state change reports (annoyingly) not issued by Mentor core */
+ if (int_src & (TUSB_INT_SRC_VBUS_SENSE_CHNG
+ | TUSB_INT_SRC_OTG_TIMEOUT
+ | TUSB_INT_SRC_ID_STATUS_CHNG))
+ idle_timeout = tusb_otg_ints(musb, int_src, tbase);
+
+ /* TX dma callback must be handled here, RX dma callback is
+ * handled in tusb_omap_dma_cb.
+ */
+ if ((int_src & TUSB_INT_SRC_TXRX_DMA_DONE)) {
+ u32 dma_src = musb_readl(tbase, TUSB_DMA_INT_SRC);
+ u32 real_dma_src = musb_readl(tbase, TUSB_DMA_INT_MASK);
+
+ DBG(3, "DMA IRQ %08x\n", dma_src);
+ real_dma_src = ~real_dma_src & dma_src;
+ if (tusb_dma_omap() && real_dma_src) {
+ int tx_source = (real_dma_src & 0xffff);
+ int i;
+
+ for (i = 1; i <= 15; i++) {
+ if (tx_source & (1 << i)) {
+ DBG(3, "completing ep%i %s\n", i, "tx");
+ musb_dma_completion(musb, i, 1);
+ }
+ }
+ }
+ musb_writel(tbase, TUSB_DMA_INT_CLEAR, dma_src);
+ }
+
+ /* EP interrupts. In OCP mode tusb6010 mirrors the MUSB interrupts */
+ if (int_src & (TUSB_INT_SRC_USB_IP_TX | TUSB_INT_SRC_USB_IP_RX)) {
+ u32 musb_src = musb_readl(tbase, TUSB_USBIP_INT_SRC);
+
+ musb_writel(tbase, TUSB_USBIP_INT_CLEAR, musb_src);
+ musb->int_rx = (((musb_src >> 16) & 0xffff) << 1);
+ musb->int_tx = (musb_src & 0xffff);
+ } else
+ musb->int_rx = musb->int_tx = 0;
+
+ if (int_src & (TUSB_INT_SRC_USB_IP_TX | TUSB_INT_SRC_USB_IP_RX | 0xff))
+ musb_interrupt(musb);
+
+ /* Acknowledge TUSB interrupts. Clear only non-reserved bits */
+ musb_writel(tbase, TUSB_INT_SRC_CLEAR,
+ int_src & ~TUSB_INT_MASK_RESERVED_BITS);
+
+ musb_platform_try_idle(musb, idle_timeout);
+
+ musb_writel(tbase, TUSB_INT_MASK, int_mask);
+ spin_unlock_irqrestore(&musb->lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+static int dma_off;
+
+/*
+ * Enables TUSB6010. Caller must take care of locking.
+ * REVISIT:
+ * - Check what is unnecessary in MGC_HdrcStart()
+ */
+void musb_platform_enable(struct musb *musb)
+{
+ void __iomem *tbase = musb->ctrl_base;
+
+ /* Setup TUSB6010 main interrupt mask. Enable all interrupts except SOF.
+ * REVISIT: Enable and deal with TUSB_INT_SRC_USB_IP_SOF */
+ musb_writel(tbase, TUSB_INT_MASK, TUSB_INT_SRC_USB_IP_SOF);
+
+ /* Setup TUSB interrupt, disable DMA and GPIO interrupts */
+ musb_writel(tbase, TUSB_USBIP_INT_MASK, 0);
+ musb_writel(tbase, TUSB_DMA_INT_MASK, 0x7fffffff);
+ musb_writel(tbase, TUSB_GPIO_INT_MASK, 0x1ff);
+
+ /* Clear all subsystem interrups */
+ musb_writel(tbase, TUSB_USBIP_INT_CLEAR, 0x7fffffff);
+ musb_writel(tbase, TUSB_DMA_INT_CLEAR, 0x7fffffff);
+ musb_writel(tbase, TUSB_GPIO_INT_CLEAR, 0x1ff);
+
+ /* Acknowledge pending interrupt(s) */
+ musb_writel(tbase, TUSB_INT_SRC_CLEAR, ~TUSB_INT_MASK_RESERVED_BITS);
+
+ /* Only 0 clock cycles for minimum interrupt de-assertion time and
+ * interrupt polarity active low seems to work reliably here */
+ musb_writel(tbase, TUSB_INT_CTRL_CONF,
+ TUSB_INT_CTRL_CONF_INT_RELCYC(0));
+
+ set_irq_type(musb->nIrq, IRQ_TYPE_LEVEL_LOW);
+
+ /* maybe force into the Default-A OTG state machine */
+ if (!(musb_readl(tbase, TUSB_DEV_OTG_STAT)
+ & TUSB_DEV_OTG_STAT_ID_STATUS))
+ musb_writel(tbase, TUSB_INT_SRC_SET,
+ TUSB_INT_SRC_ID_STATUS_CHNG);
+
+ if (is_dma_capable() && dma_off)
+ printk(KERN_WARNING "%s %s: dma not reactivated\n",
+ __FILE__, __func__);
+ else
+ dma_off = 1;
+}
+
+/*
+ * Disables TUSB6010. Caller must take care of locking.
+ */
+void musb_platform_disable(struct musb *musb)
+{
+ void __iomem *tbase = musb->ctrl_base;
+
+ /* FIXME stop DMA, IRQs, timers, ... */
+
+ /* disable all IRQs */
+ musb_writel(tbase, TUSB_INT_MASK, ~TUSB_INT_MASK_RESERVED_BITS);
+ musb_writel(tbase, TUSB_USBIP_INT_MASK, 0x7fffffff);
+ musb_writel(tbase, TUSB_DMA_INT_MASK, 0x7fffffff);
+ musb_writel(tbase, TUSB_GPIO_INT_MASK, 0x1ff);
+
+ del_timer(&musb_idle_timer);
+
+ if (is_dma_capable() && !dma_off) {
+ printk(KERN_WARNING "%s %s: dma still active\n",
+ __FILE__, __func__);
+ dma_off = 1;
+ }
+}
+
+/*
+ * Sets up TUSB6010 CPU interface specific signals and registers
+ * Note: Settings optimized for OMAP24xx
+ */
+static void __init tusb_setup_cpu_interface(struct musb *musb)
+{
+ void __iomem *tbase = musb->ctrl_base;
+
+ /*
+ * Disable GPIO[5:0] pullups (used as output DMA requests)
+ * Don't disable GPIO[7:6] as they are needed for wake-up.
+ */
+ musb_writel(tbase, TUSB_PULLUP_1_CTRL, 0x0000003F);
+
+ /* Disable all pullups on NOR IF, DMAREQ0 and DMAREQ1 */
+ musb_writel(tbase, TUSB_PULLUP_2_CTRL, 0x01FFFFFF);
+
+ /* Turn GPIO[5:0] to DMAREQ[5:0] signals */
+ musb_writel(tbase, TUSB_GPIO_CONF, TUSB_GPIO_CONF_DMAREQ(0x3f));
+
+ /* Burst size 16x16 bits, all six DMA requests enabled, DMA request
+ * de-assertion time 2 system clocks p 62 */
+ musb_writel(tbase, TUSB_DMA_REQ_CONF,
+ TUSB_DMA_REQ_CONF_BURST_SIZE(2) |
+ TUSB_DMA_REQ_CONF_DMA_REQ_EN(0x3f) |
+ TUSB_DMA_REQ_CONF_DMA_REQ_ASSER(2));
+
+ /* Set 0 wait count for synchronous burst access */
+ musb_writel(tbase, TUSB_WAIT_COUNT, 1);
+}
+
+static int __init tusb_start(struct musb *musb)
+{
+ void __iomem *tbase = musb->ctrl_base;
+ int ret = 0;
+ unsigned long flags;
+ u32 reg;
+
+ if (musb->board_set_power)
+ ret = musb->board_set_power(1);
+ if (ret != 0) {
+ printk(KERN_ERR "tusb: Cannot enable TUSB6010\n");
+ return ret;
+ }
+
+ spin_lock_irqsave(&musb->lock, flags);
+
+ if (musb_readl(tbase, TUSB_PROD_TEST_RESET) !=
+ TUSB_PROD_TEST_RESET_VAL) {
+ printk(KERN_ERR "tusb: Unable to detect TUSB6010\n");
+ goto err;
+ }
+
+ ret = tusb_print_revision(musb);
+ if (ret < 2) {
+ printk(KERN_ERR "tusb: Unsupported TUSB6010 revision %i\n",
+ ret);
+ goto err;
+ }
+
+ /* The uint bit for "USB non-PDR interrupt enable" has to be 1 when
+ * NOR FLASH interface is used */
+ musb_writel(tbase, TUSB_VLYNQ_CTRL, 8);
+
+ /* Select PHY free running 60MHz as a system clock */
+ tusb_set_clock_source(musb, 1);
+
+ /* VBus valid timer 1us, disable DFT/Debug and VLYNQ clocks for
+ * power saving, enable VBus detect and session end comparators,
+ * enable IDpullup, enable VBus charging */
+ musb_writel(tbase, TUSB_PRCM_MNGMT,
+ TUSB_PRCM_MNGMT_VBUS_VALID_TIMER(0xa) |
+ TUSB_PRCM_MNGMT_VBUS_VALID_FLT_EN |
+ TUSB_PRCM_MNGMT_OTG_SESS_END_EN |
+ TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN |
+ TUSB_PRCM_MNGMT_OTG_ID_PULLUP);
+ tusb_setup_cpu_interface(musb);
+
+ /* simplify: always sense/pullup ID pins, as if in OTG mode */
+ reg = musb_readl(tbase, TUSB_PHY_OTG_CTRL_ENABLE);
+ reg |= TUSB_PHY_OTG_CTRL_WRPROTECT | TUSB_PHY_OTG_CTRL_OTG_ID_PULLUP;
+ musb_writel(tbase, TUSB_PHY_OTG_CTRL_ENABLE, reg);
+
+ reg = musb_readl(tbase, TUSB_PHY_OTG_CTRL);
+ reg |= TUSB_PHY_OTG_CTRL_WRPROTECT | TUSB_PHY_OTG_CTRL_OTG_ID_PULLUP;
+ musb_writel(tbase, TUSB_PHY_OTG_CTRL, reg);
+
+ spin_unlock_irqrestore(&musb->lock, flags);
+
+ return 0;
+
+err:
+ spin_unlock_irqrestore(&musb->lock, flags);
+
+ if (musb->board_set_power)
+ musb->board_set_power(0);
+
+ return -ENODEV;
+}
+
+int __init musb_platform_init(struct musb *musb)
+{
+ struct platform_device *pdev;
+ struct resource *mem;
+ void __iomem *sync;
+ int ret;
+
+ pdev = to_platform_device(musb->controller);
+
+ /* dma address for async dma */
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ musb->async = mem->start;
+
+ /* dma address for sync dma */
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!mem) {
+ pr_debug("no sync dma resource?\n");
+ return -ENODEV;
+ }
+ musb->sync = mem->start;
+
+ sync = ioremap(mem->start, mem->end - mem->start + 1);
+ if (!sync) {
+ pr_debug("ioremap for sync failed\n");
+ return -ENOMEM;
+ }
+ musb->sync_va = sync;
+
+ /* Offsets from base: VLYNQ at 0x000, MUSB regs at 0x400,
+ * FIFOs at 0x600, TUSB at 0x800
+ */
+ musb->mregs += TUSB_BASE_OFFSET;
+
+ ret = tusb_start(musb);
+ if (ret) {
+ printk(KERN_ERR "Could not start tusb6010 (%d)\n",
+ ret);
+ return -ENODEV;
+ }
+ musb->isr = tusb_interrupt;
+
+ if (is_host_enabled(musb))
+ musb->board_set_vbus = tusb_source_power;
+ if (is_peripheral_enabled(musb))
+ musb->xceiv.set_power = tusb_draw_power;
+
+ setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
+
+ return ret;
+}
+
+int musb_platform_exit(struct musb *musb)
+{
+ del_timer_sync(&musb_idle_timer);
+
+ if (musb->board_set_power)
+ musb->board_set_power(0);
+
+ iounmap(musb->sync_va);
+
+ return 0;
+}
--- /dev/null
+/*
+ * Definitions for TUSB6010 USB 2.0 OTG Dual Role controller
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Jarkko Nikula <jarkko.nikula@nokia.com>
+ * Tony Lindgren <tony@atomide.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __TUSB6010_H__
+#define __TUSB6010_H__
+
+extern u8 tusb_get_revision(struct musb *musb);
+
+#ifdef CONFIG_USB_TUSB6010
+#define musb_in_tusb() 1
+#else
+#define musb_in_tusb() 0
+#endif
+
+#ifdef CONFIG_USB_TUSB_OMAP_DMA
+#define tusb_dma_omap() 1
+#else
+#define tusb_dma_omap() 0
+#endif
+
+/* VLYNQ control register. 32-bit at offset 0x000 */
+#define TUSB_VLYNQ_CTRL 0x004
+
+/* Mentor Graphics OTG core registers. 8,- 16- and 32-bit at offset 0x400 */
+#define TUSB_BASE_OFFSET 0x400
+
+/* FIFO registers 32-bit at offset 0x600 */
+#define TUSB_FIFO_BASE 0x600
+
+/* Device System & Control registers. 32-bit at offset 0x800 */
+#define TUSB_SYS_REG_BASE 0x800
+
+#define TUSB_DEV_CONF (TUSB_SYS_REG_BASE + 0x000)
+#define TUSB_DEV_CONF_USB_HOST_MODE (1 << 16)
+#define TUSB_DEV_CONF_PROD_TEST_MODE (1 << 15)
+#define TUSB_DEV_CONF_SOFT_ID (1 << 1)
+#define TUSB_DEV_CONF_ID_SEL (1 << 0)
+
+#define TUSB_PHY_OTG_CTRL_ENABLE (TUSB_SYS_REG_BASE + 0x004)
+#define TUSB_PHY_OTG_CTRL (TUSB_SYS_REG_BASE + 0x008)
+#define TUSB_PHY_OTG_CTRL_WRPROTECT (0xa5 << 24)
+#define TUSB_PHY_OTG_CTRL_OTG_ID_PULLUP (1 << 23)
+#define TUSB_PHY_OTG_CTRL_OTG_VBUS_DET_EN (1 << 19)
+#define TUSB_PHY_OTG_CTRL_OTG_SESS_END_EN (1 << 18)
+#define TUSB_PHY_OTG_CTRL_TESTM2 (1 << 17)
+#define TUSB_PHY_OTG_CTRL_TESTM1 (1 << 16)
+#define TUSB_PHY_OTG_CTRL_TESTM0 (1 << 15)
+#define TUSB_PHY_OTG_CTRL_TX_DATA2 (1 << 14)
+#define TUSB_PHY_OTG_CTRL_TX_GZ2 (1 << 13)
+#define TUSB_PHY_OTG_CTRL_TX_ENABLE2 (1 << 12)
+#define TUSB_PHY_OTG_CTRL_DM_PULLDOWN (1 << 11)
+#define TUSB_PHY_OTG_CTRL_DP_PULLDOWN (1 << 10)
+#define TUSB_PHY_OTG_CTRL_OSC_EN (1 << 9)
+#define TUSB_PHY_OTG_CTRL_PHYREF_CLKSEL(v) (((v) & 3) << 7)
+#define TUSB_PHY_OTG_CTRL_PD (1 << 6)
+#define TUSB_PHY_OTG_CTRL_PLL_ON (1 << 5)
+#define TUSB_PHY_OTG_CTRL_EXT_RPU (1 << 4)
+#define TUSB_PHY_OTG_CTRL_PWR_GOOD (1 << 3)
+#define TUSB_PHY_OTG_CTRL_RESET (1 << 2)
+#define TUSB_PHY_OTG_CTRL_SUSPENDM (1 << 1)
+#define TUSB_PHY_OTG_CTRL_CLK_MODE (1 << 0)
+
+/*OTG status register */
+#define TUSB_DEV_OTG_STAT (TUSB_SYS_REG_BASE + 0x00c)
+#define TUSB_DEV_OTG_STAT_PWR_CLK_GOOD (1 << 8)
+#define TUSB_DEV_OTG_STAT_SESS_END (1 << 7)
+#define TUSB_DEV_OTG_STAT_SESS_VALID (1 << 6)
+#define TUSB_DEV_OTG_STAT_VBUS_VALID (1 << 5)
+#define TUSB_DEV_OTG_STAT_VBUS_SENSE (1 << 4)
+#define TUSB_DEV_OTG_STAT_ID_STATUS (1 << 3)
+#define TUSB_DEV_OTG_STAT_HOST_DISCON (1 << 2)
+#define TUSB_DEV_OTG_STAT_LINE_STATE (3 << 0)
+#define TUSB_DEV_OTG_STAT_DP_ENABLE (1 << 1)
+#define TUSB_DEV_OTG_STAT_DM_ENABLE (1 << 0)
+
+#define TUSB_DEV_OTG_TIMER (TUSB_SYS_REG_BASE + 0x010)
+# define TUSB_DEV_OTG_TIMER_ENABLE (1 << 31)
+# define TUSB_DEV_OTG_TIMER_VAL(v) ((v) & 0x07ffffff)
+#define TUSB_PRCM_REV (TUSB_SYS_REG_BASE + 0x014)
+
+/* PRCM configuration register */
+#define TUSB_PRCM_CONF (TUSB_SYS_REG_BASE + 0x018)
+#define TUSB_PRCM_CONF_SFW_CPEN (1 << 24)
+#define TUSB_PRCM_CONF_SYS_CLKSEL(v) (((v) & 3) << 16)
+
+/* PRCM management register */
+#define TUSB_PRCM_MNGMT (TUSB_SYS_REG_BASE + 0x01c)
+#define TUSB_PRCM_MNGMT_SRP_FIX_TIMER(v) (((v) & 0xf) << 25)
+#define TUSB_PRCM_MNGMT_SRP_FIX_EN (1 << 24)
+#define TUSB_PRCM_MNGMT_VBUS_VALID_TIMER(v) (((v) & 0xf) << 20)
+#define TUSB_PRCM_MNGMT_VBUS_VALID_FLT_EN (1 << 19)
+#define TUSB_PRCM_MNGMT_DFT_CLK_DIS (1 << 18)
+#define TUSB_PRCM_MNGMT_VLYNQ_CLK_DIS (1 << 17)
+#define TUSB_PRCM_MNGMT_OTG_SESS_END_EN (1 << 10)
+#define TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN (1 << 9)
+#define TUSB_PRCM_MNGMT_OTG_ID_PULLUP (1 << 8)
+#define TUSB_PRCM_MNGMT_15_SW_EN (1 << 4)
+#define TUSB_PRCM_MNGMT_33_SW_EN (1 << 3)
+#define TUSB_PRCM_MNGMT_5V_CPEN (1 << 2)
+#define TUSB_PRCM_MNGMT_PM_IDLE (1 << 1)
+#define TUSB_PRCM_MNGMT_DEV_IDLE (1 << 0)
+
+/* Wake-up source clear and mask registers */
+#define TUSB_PRCM_WAKEUP_SOURCE (TUSB_SYS_REG_BASE + 0x020)
+#define TUSB_PRCM_WAKEUP_CLEAR (TUSB_SYS_REG_BASE + 0x028)
+#define TUSB_PRCM_WAKEUP_MASK (TUSB_SYS_REG_BASE + 0x02c)
+#define TUSB_PRCM_WAKEUP_RESERVED_BITS (0xffffe << 13)
+#define TUSB_PRCM_WGPIO_7 (1 << 12)
+#define TUSB_PRCM_WGPIO_6 (1 << 11)
+#define TUSB_PRCM_WGPIO_5 (1 << 10)
+#define TUSB_PRCM_WGPIO_4 (1 << 9)
+#define TUSB_PRCM_WGPIO_3 (1 << 8)
+#define TUSB_PRCM_WGPIO_2 (1 << 7)
+#define TUSB_PRCM_WGPIO_1 (1 << 6)
+#define TUSB_PRCM_WGPIO_0 (1 << 5)
+#define TUSB_PRCM_WHOSTDISCON (1 << 4) /* Host disconnect */
+#define TUSB_PRCM_WBUS (1 << 3) /* USB bus resume */
+#define TUSB_PRCM_WNORCS (1 << 2) /* NOR chip select */
+#define TUSB_PRCM_WVBUS (1 << 1) /* OTG PHY VBUS */
+#define TUSB_PRCM_WID (1 << 0) /* OTG PHY ID detect */
+
+#define TUSB_PULLUP_1_CTRL (TUSB_SYS_REG_BASE + 0x030)
+#define TUSB_PULLUP_2_CTRL (TUSB_SYS_REG_BASE + 0x034)
+#define TUSB_INT_CTRL_REV (TUSB_SYS_REG_BASE + 0x038)
+#define TUSB_INT_CTRL_CONF (TUSB_SYS_REG_BASE + 0x03c)
+#define TUSB_USBIP_INT_SRC (TUSB_SYS_REG_BASE + 0x040)
+#define TUSB_USBIP_INT_SET (TUSB_SYS_REG_BASE + 0x044)
+#define TUSB_USBIP_INT_CLEAR (TUSB_SYS_REG_BASE + 0x048)
+#define TUSB_USBIP_INT_MASK (TUSB_SYS_REG_BASE + 0x04c)
+#define TUSB_DMA_INT_SRC (TUSB_SYS_REG_BASE + 0x050)
+#define TUSB_DMA_INT_SET (TUSB_SYS_REG_BASE + 0x054)
+#define TUSB_DMA_INT_CLEAR (TUSB_SYS_REG_BASE + 0x058)
+#define TUSB_DMA_INT_MASK (TUSB_SYS_REG_BASE + 0x05c)
+#define TUSB_GPIO_INT_SRC (TUSB_SYS_REG_BASE + 0x060)
+#define TUSB_GPIO_INT_SET (TUSB_SYS_REG_BASE + 0x064)
+#define TUSB_GPIO_INT_CLEAR (TUSB_SYS_REG_BASE + 0x068)
+#define TUSB_GPIO_INT_MASK (TUSB_SYS_REG_BASE + 0x06c)
+
+/* NOR flash interrupt source registers */
+#define TUSB_INT_SRC (TUSB_SYS_REG_BASE + 0x070)
+#define TUSB_INT_SRC_SET (TUSB_SYS_REG_BASE + 0x074)
+#define TUSB_INT_SRC_CLEAR (TUSB_SYS_REG_BASE + 0x078)
+#define TUSB_INT_MASK (TUSB_SYS_REG_BASE + 0x07c)
+#define TUSB_INT_SRC_TXRX_DMA_DONE (1 << 24)
+#define TUSB_INT_SRC_USB_IP_CORE (1 << 17)
+#define TUSB_INT_SRC_OTG_TIMEOUT (1 << 16)
+#define TUSB_INT_SRC_VBUS_SENSE_CHNG (1 << 15)
+#define TUSB_INT_SRC_ID_STATUS_CHNG (1 << 14)
+#define TUSB_INT_SRC_DEV_WAKEUP (1 << 13)
+#define TUSB_INT_SRC_DEV_READY (1 << 12)
+#define TUSB_INT_SRC_USB_IP_TX (1 << 9)
+#define TUSB_INT_SRC_USB_IP_RX (1 << 8)
+#define TUSB_INT_SRC_USB_IP_VBUS_ERR (1 << 7)
+#define TUSB_INT_SRC_USB_IP_VBUS_REQ (1 << 6)
+#define TUSB_INT_SRC_USB_IP_DISCON (1 << 5)
+#define TUSB_INT_SRC_USB_IP_CONN (1 << 4)
+#define TUSB_INT_SRC_USB_IP_SOF (1 << 3)
+#define TUSB_INT_SRC_USB_IP_RST_BABBLE (1 << 2)
+#define TUSB_INT_SRC_USB_IP_RESUME (1 << 1)
+#define TUSB_INT_SRC_USB_IP_SUSPEND (1 << 0)
+
+/* NOR flash interrupt registers reserved bits. Must be written as 0 */
+#define TUSB_INT_MASK_RESERVED_17 (0x3fff << 17)
+#define TUSB_INT_MASK_RESERVED_13 (1 << 13)
+#define TUSB_INT_MASK_RESERVED_8 (0xf << 8)
+#define TUSB_INT_SRC_RESERVED_26 (0x1f << 26)
+#define TUSB_INT_SRC_RESERVED_18 (0x3f << 18)
+#define TUSB_INT_SRC_RESERVED_10 (0x03 << 10)
+
+/* Reserved bits for NOR flash interrupt mask and clear register */
+#define TUSB_INT_MASK_RESERVED_BITS (TUSB_INT_MASK_RESERVED_17 | \
+ TUSB_INT_MASK_RESERVED_13 | \
+ TUSB_INT_MASK_RESERVED_8)
+
+/* Reserved bits for NOR flash interrupt status register */
+#define TUSB_INT_SRC_RESERVED_BITS (TUSB_INT_SRC_RESERVED_26 | \
+ TUSB_INT_SRC_RESERVED_18 | \
+ TUSB_INT_SRC_RESERVED_10)
+
+#define TUSB_GPIO_REV (TUSB_SYS_REG_BASE + 0x080)
+#define TUSB_GPIO_CONF (TUSB_SYS_REG_BASE + 0x084)
+#define TUSB_DMA_CTRL_REV (TUSB_SYS_REG_BASE + 0x100)
+#define TUSB_DMA_REQ_CONF (TUSB_SYS_REG_BASE + 0x104)
+#define TUSB_EP0_CONF (TUSB_SYS_REG_BASE + 0x108)
+#define TUSB_DMA_EP_MAP (TUSB_SYS_REG_BASE + 0x148)
+
+/* Offsets from each ep base register */
+#define TUSB_EP_TX_OFFSET 0x10c /* EP_IN in docs */
+#define TUSB_EP_RX_OFFSET 0x14c /* EP_OUT in docs */
+#define TUSB_EP_MAX_PACKET_SIZE_OFFSET 0x188
+
+#define TUSB_WAIT_COUNT (TUSB_SYS_REG_BASE + 0x1c8)
+#define TUSB_SCRATCH_PAD (TUSB_SYS_REG_BASE + 0x1c4)
+#define TUSB_PROD_TEST_RESET (TUSB_SYS_REG_BASE + 0x1d8)
+
+/* Device System & Control register bitfields */
+#define TUSB_INT_CTRL_CONF_INT_RELCYC(v) (((v) & 0x7) << 18)
+#define TUSB_INT_CTRL_CONF_INT_POLARITY (1 << 17)
+#define TUSB_INT_CTRL_CONF_INT_MODE (1 << 16)
+#define TUSB_GPIO_CONF_DMAREQ(v) (((v) & 0x3f) << 24)
+#define TUSB_DMA_REQ_CONF_BURST_SIZE(v) (((v) & 3) << 26)
+#define TUSB_DMA_REQ_CONF_DMA_REQ_EN(v) (((v) & 0x3f) << 20)
+#define TUSB_DMA_REQ_CONF_DMA_REQ_ASSER(v) (((v) & 0xf) << 16)
+#define TUSB_EP0_CONFIG_SW_EN (1 << 8)
+#define TUSB_EP0_CONFIG_DIR_TX (1 << 7)
+#define TUSB_EP0_CONFIG_XFR_SIZE(v) ((v) & 0x7f)
+#define TUSB_EP_CONFIG_SW_EN (1 << 31)
+#define TUSB_EP_CONFIG_XFR_SIZE(v) ((v) & 0x7fffffff)
+#define TUSB_PROD_TEST_RESET_VAL 0xa596
+#define TUSB_EP_FIFO(ep) (TUSB_FIFO_BASE + (ep) * 0x20)
+
+#define TUSB_DIDR1_LO (TUSB_SYS_REG_BASE + 0x1f8)
+#define TUSB_DIDR1_HI (TUSB_SYS_REG_BASE + 0x1fc)
+#define TUSB_DIDR1_HI_CHIP_REV(v) (((v) >> 17) & 0xf)
+#define TUSB_DIDR1_HI_REV_20 0
+#define TUSB_DIDR1_HI_REV_30 1
+#define TUSB_DIDR1_HI_REV_31 2
+
+#define TUSB_REV_10 0x10
+#define TUSB_REV_20 0x20
+#define TUSB_REV_30 0x30
+#define TUSB_REV_31 0x31
+
+/*----------------------------------------------------------------------------*/
+
+#ifdef CONFIG_USB_TUSB6010
+
+/* configuration parameters specific to this silicon */
+
+/* Number of Tx endpoints. Legal values are 1 - 16 (this value includes EP0) */
+#define MUSB_C_NUM_EPT 16
+
+/* Number of Rx endpoints. Legal values are 1 - 16 (this value includes EP0) */
+#define MUSB_C_NUM_EPR 16
+
+/* Endpoint 1 to 15 direction types. C_EP1_DEF is defined if either Tx endpoint
+ * 1 or Rx endpoint 1 are used.
+ */
+#define MUSB_C_EP1_DEF
+
+/* C_EP1_TX_DEF is defined if Tx endpoint 1 is used */
+#define MUSB_C_EP1_TX_DEF
+
+/* C_EP1_RX_DEF is defined if Rx endpoint 1 is used */
+#define MUSB_C_EP1_RX_DEF
+
+/* C_EP1_TOR_DEF is defined if Tx endpoint 1 and Rx endpoint 1 share a FIFO */
+/* #define C_EP1_TOR_DEF */
+
+/* C_EP1_TAR_DEF is defined if both Tx endpoint 1 and Rx endpoint 1 are used
+ * and do not share a FIFO.
+ */
+#define MUSB_C_EP1_TAR_DEF
+
+/* Similarly for all other used endpoints */
+#define MUSB_C_EP2_DEF
+#define MUSB_C_EP2_TX_DEF
+#define MUSB_C_EP2_RX_DEF
+#define MUSB_C_EP2_TAR_DEF
+#define MUSB_C_EP3_DEF
+#define MUSB_C_EP3_TX_DEF
+#define MUSB_C_EP3_RX_DEF
+#define MUSB_C_EP3_TAR_DEF
+#define MUSB_C_EP4_DEF
+#define MUSB_C_EP4_TX_DEF
+#define MUSB_C_EP4_RX_DEF
+#define MUSB_C_EP4_TAR_DEF
+
+/* Endpoint 1 to 15 FIFO address bits. Legal values are 3 to 13 - corresponding
+ * to FIFO sizes of 8 to 8192 bytes. If an Tx endpoint shares a FIFO with an Rx
+ * endpoint then the Rx FIFO size must be the same as the Tx FIFO size. All
+ * endpoints 1 to 15 must be defined, unused endpoints should be set to 2.
+ */
+#define MUSB_C_EP1T_BITS 5
+#define MUSB_C_EP1R_BITS 5
+#define MUSB_C_EP2T_BITS 5
+#define MUSB_C_EP2R_BITS 5
+#define MUSB_C_EP3T_BITS 3
+#define MUSB_C_EP3R_BITS 3
+#define MUSB_C_EP4T_BITS 3
+#define MUSB_C_EP4R_BITS 3
+
+#define MUSB_C_EP5T_BITS 2
+#define MUSB_C_EP5R_BITS 2
+#define MUSB_C_EP6T_BITS 2
+#define MUSB_C_EP6R_BITS 2
+#define MUSB_C_EP7T_BITS 2
+#define MUSB_C_EP7R_BITS 2
+#define MUSB_C_EP8T_BITS 2
+#define MUSB_C_EP8R_BITS 2
+#define MUSB_C_EP9T_BITS 2
+#define MUSB_C_EP9R_BITS 2
+#define MUSB_C_EP10T_BITS 2
+#define MUSB_C_EP10R_BITS 2
+#define MUSB_C_EP11T_BITS 2
+#define MUSB_C_EP11R_BITS 2
+#define MUSB_C_EP12T_BITS 2
+#define MUSB_C_EP12R_BITS 2
+#define MUSB_C_EP13T_BITS 2
+#define MUSB_C_EP13R_BITS 2
+#define MUSB_C_EP14T_BITS 2
+#define MUSB_C_EP14R_BITS 2
+#define MUSB_C_EP15T_BITS 2
+#define MUSB_C_EP15R_BITS 2
+
+/* Define the following constant if the USB2.0 Transceiver Macrocell data width
+ * is 16-bits.
+ */
+/* #define C_UTM_16 */
+
+/* Define this constant if the CPU uses big-endian byte ordering. */
+/* #define C_BIGEND */
+
+/* Define the following constant if any Tx endpoint is required to support
+ * multiple bulk packets.
+ */
+/* #define C_MP_TX */
+
+/* Define the following constant if any Rx endpoint is required to support
+ * multiple bulk packets.
+ */
+/* #define C_MP_RX */
+
+/* Define the following constant if any Tx endpoint is required to support high
+ * bandwidth ISO.
+ */
+/* #define C_HB_TX */
+
+/* Define the following constant if any Rx endpoint is required to support high
+ * bandwidth ISO.
+ */
+/* #define C_HB_RX */
+
+/* Define the following constant if software connect/disconnect control is
+ * required.
+ */
+#define MUSB_C_SOFT_CON
+
+/* Define the following constant if Vendor Control Registers are required. */
+/* #define C_VEND_REG */
+
+/* Vendor control register widths. */
+#define MUSB_C_VCTL_BITS 4
+#define MUSB_C_VSTAT_BITS 8
+
+/* Define the following constant to include a DMA controller. */
+/* #define C_DMA */
+
+/* Define the following constant if 2 or more DMA channels are required. */
+/* #define C_DMA2 */
+
+/* Define the following constant if 3 or more DMA channels are required. */
+/* #define C_DMA3 */
+
+/* Define the following constant if 4 or more DMA channels are required. */
+/* #define C_DMA4 */
+
+/* Define the following constant if 5 or more DMA channels are required. */
+/* #define C_DMA5 */
+
+/* Define the following constant if 6 or more DMA channels are required. */
+/* #define C_DMA6 */
+
+/* Define the following constant if 7 or more DMA channels are required. */
+/* #define C_DMA7 */
+
+/* Define the following constant if 8 or more DMA channels are required. */
+/* #define C_DMA8 */
+
+/* Enable Dynamic FIFO Sizing */
+#define MUSB_C_DYNFIFO_DEF
+
+/* Derived constants. The following constants are derived from the previous
+ * configuration constants
+ */
+
+/* Total number of endpoints. Legal values are 2 - 16. This must be equal to
+ * the larger of C_NUM_EPT, C_NUM_EPR
+ */
+/* #define MUSB_C_NUM_EPS 5 */
+
+/* C_EPMAX_BITS is equal to the largest endpoint FIFO word address bits */
+#define MUSB_C_EPMAX_BITS 11
+
+/* C_RAM_BITS is the number of address bits required to address the RAM (32-bit
+ * addresses). It is defined as log2 of the sum of 2** of all the endpoint FIFO
+ * dword address bits (rounded up).
+ */
+#define MUSB_C_RAM_BITS 12
+
+#endif /* CONFIG_USB_TUSB6010 */
+
+#endif /* __TUSB6010_H__ */
--- /dev/null
+/*
+ * TUSB6010 USB 2.0 OTG Dual Role controller OMAP DMA interface
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Tony Lindgren <tony@atomide.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/usb.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <asm/arch/dma.h>
+#include <asm/arch/mux.h>
+
+#include "musb_core.h"
+
+#define to_chdat(c) (struct tusb_omap_dma_ch *)(c)->private_data
+
+#define MAX_DMAREQ 5 /* REVISIT: Really 6, but req5 not OK */
+
+struct tusb_omap_dma_ch {
+ struct musb *musb;
+ void __iomem *tbase;
+ unsigned long phys_offset;
+ int epnum;
+ u8 tx;
+ struct musb_hw_ep *hw_ep;
+
+ int ch;
+ s8 dmareq;
+ s8 sync_dev;
+
+ struct tusb_omap_dma *tusb_dma;
+
+ void __iomem *dma_addr;
+
+ u32 len;
+ u16 packet_sz;
+ u16 transfer_packet_sz;
+ u32 transfer_len;
+ u32 completed_len;
+};
+
+struct tusb_omap_dma {
+ struct dma_controller controller;
+ struct musb *musb;
+ void __iomem *tbase;
+
+ int ch;
+ s8 dmareq;
+ s8 sync_dev;
+ unsigned multichannel:1;
+};
+
+static int tusb_omap_dma_start(struct dma_controller *c)
+{
+ struct tusb_omap_dma *tusb_dma;
+
+ tusb_dma = container_of(c, struct tusb_omap_dma, controller);
+
+ /* DBG(3, "ep%i ch: %i\n", chdat->epnum, chdat->ch); */
+
+ return 0;
+}
+
+static int tusb_omap_dma_stop(struct dma_controller *c)
+{
+ struct tusb_omap_dma *tusb_dma;
+
+ tusb_dma = container_of(c, struct tusb_omap_dma, controller);
+
+ /* DBG(3, "ep%i ch: %i\n", chdat->epnum, chdat->ch); */
+
+ return 0;
+}
+
+/*
+ * Allocate dmareq0 to the current channel unless it's already taken
+ */
+static inline int tusb_omap_use_shared_dmareq(struct tusb_omap_dma_ch *chdat)
+{
+ u32 reg = musb_readl(chdat->tbase, TUSB_DMA_EP_MAP);
+
+ if (reg != 0) {
+ DBG(3, "ep%i dmareq0 is busy for ep%i\n",
+ chdat->epnum, reg & 0xf);
+ return -EAGAIN;
+ }
+
+ if (chdat->tx)
+ reg = (1 << 4) | chdat->epnum;
+ else
+ reg = chdat->epnum;
+
+ musb_writel(chdat->tbase, TUSB_DMA_EP_MAP, reg);
+
+ return 0;
+}
+
+static inline void tusb_omap_free_shared_dmareq(struct tusb_omap_dma_ch *chdat)
+{
+ u32 reg = musb_readl(chdat->tbase, TUSB_DMA_EP_MAP);
+
+ if ((reg & 0xf) != chdat->epnum) {
+ printk(KERN_ERR "ep%i trying to release dmareq0 for ep%i\n",
+ chdat->epnum, reg & 0xf);
+ return;
+ }
+ musb_writel(chdat->tbase, TUSB_DMA_EP_MAP, 0);
+}
+
+/*
+ * See also musb_dma_completion in plat_uds.c and musb_g_[tx|rx]() in
+ * musb_gadget.c.
+ */
+static void tusb_omap_dma_cb(int lch, u16 ch_status, void *data)
+{
+ struct dma_channel *channel = (struct dma_channel *)data;
+ struct tusb_omap_dma_ch *chdat = to_chdat(channel);
+ struct tusb_omap_dma *tusb_dma = chdat->tusb_dma;
+ struct musb *musb = chdat->musb;
+ struct musb_hw_ep *hw_ep = chdat->hw_ep;
+ void __iomem *ep_conf = hw_ep->conf;
+ void __iomem *mbase = musb->mregs;
+ unsigned long remaining, flags, pio;
+ int ch;
+
+ spin_lock_irqsave(&musb->lock, flags);
+
+ if (tusb_dma->multichannel)
+ ch = chdat->ch;
+ else
+ ch = tusb_dma->ch;
+
+ if (ch_status != OMAP_DMA_BLOCK_IRQ)
+ printk(KERN_ERR "TUSB DMA error status: %i\n", ch_status);
+
+ DBG(3, "ep%i %s dma callback ch: %i status: %x\n",
+ chdat->epnum, chdat->tx ? "tx" : "rx",
+ ch, ch_status);
+
+ if (chdat->tx)
+ remaining = musb_readl(ep_conf, TUSB_EP_TX_OFFSET);
+ else
+ remaining = musb_readl(ep_conf, TUSB_EP_RX_OFFSET);
+
+ remaining = TUSB_EP_CONFIG_XFR_SIZE(remaining);
+
+ /* HW issue #10: XFR_SIZE may get corrupt on DMA (both async & sync) */
+ if (unlikely(remaining > chdat->transfer_len)) {
+ DBG(2, "Corrupt %s dma ch%i XFR_SIZE: 0x%08lx\n",
+ chdat->tx ? "tx" : "rx", chdat->ch,
+ remaining);
+ remaining = 0;
+ }
+
+ channel->actual_len = chdat->transfer_len - remaining;
+ pio = chdat->len - channel->actual_len;
+
+ DBG(3, "DMA remaining %lu/%u\n", remaining, chdat->transfer_len);
+
+ /* Transfer remaining 1 - 31 bytes */
+ if (pio > 0 && pio < 32) {
+ u8 *buf;
+
+ DBG(3, "Using PIO for remaining %lu bytes\n", pio);
+ buf = phys_to_virt((u32)chdat->dma_addr) + chdat->transfer_len;
+ if (chdat->tx) {
+ dma_cache_maint(phys_to_virt((u32)chdat->dma_addr),
+ chdat->transfer_len, DMA_TO_DEVICE);
+ musb_write_fifo(hw_ep, pio, buf);
+ } else {
+ musb_read_fifo(hw_ep, pio, buf);
+ dma_cache_maint(phys_to_virt((u32)chdat->dma_addr),
+ chdat->transfer_len, DMA_FROM_DEVICE);
+ }
+ channel->actual_len += pio;
+ }
+
+ if (!tusb_dma->multichannel)
+ tusb_omap_free_shared_dmareq(chdat);
+
+ channel->status = MUSB_DMA_STATUS_FREE;
+
+ /* Handle only RX callbacks here. TX callbacks must be handled based
+ * on the TUSB DMA status interrupt.
+ * REVISIT: Use both TUSB DMA status interrupt and OMAP DMA callback
+ * interrupt for RX and TX.
+ */
+ if (!chdat->tx)
+ musb_dma_completion(musb, chdat->epnum, chdat->tx);
+
+ /* We must terminate short tx transfers manually by setting TXPKTRDY.
+ * REVISIT: This same problem may occur with other MUSB dma as well.
+ * Easy to test with g_ether by pinging the MUSB board with ping -s54.
+ */
+ if ((chdat->transfer_len < chdat->packet_sz)
+ || (chdat->transfer_len % chdat->packet_sz != 0)) {
+ u16 csr;
+
+ if (chdat->tx) {
+ DBG(3, "terminating short tx packet\n");
+ musb_ep_select(mbase, chdat->epnum);
+ csr = musb_readw(hw_ep->regs, MUSB_TXCSR);
+ csr |= MUSB_TXCSR_MODE | MUSB_TXCSR_TXPKTRDY
+ | MUSB_TXCSR_P_WZC_BITS;
+ musb_writew(hw_ep->regs, MUSB_TXCSR, csr);
+ }
+ }
+
+ spin_unlock_irqrestore(&musb->lock, flags);
+}
+
+static int tusb_omap_dma_program(struct dma_channel *channel, u16 packet_sz,
+ u8 rndis_mode, dma_addr_t dma_addr, u32 len)
+{
+ struct tusb_omap_dma_ch *chdat = to_chdat(channel);
+ struct tusb_omap_dma *tusb_dma = chdat->tusb_dma;
+ struct musb *musb = chdat->musb;
+ struct musb_hw_ep *hw_ep = chdat->hw_ep;
+ void __iomem *mbase = musb->mregs;
+ void __iomem *ep_conf = hw_ep->conf;
+ dma_addr_t fifo = hw_ep->fifo_sync;
+ struct omap_dma_channel_params dma_params;
+ u32 dma_remaining;
+ int src_burst, dst_burst;
+ u16 csr;
+ int ch;
+ s8 dmareq;
+ s8 sync_dev;
+
+ if (unlikely(dma_addr & 0x1) || (len < 32) || (len > packet_sz))
+ return false;
+
+ /*
+ * HW issue #10: Async dma will eventually corrupt the XFR_SIZE
+ * register which will cause missed DMA interrupt. We could try to
+ * use a timer for the callback, but it is unsafe as the XFR_SIZE
+ * register is corrupt, and we won't know if the DMA worked.
+ */
+ if (dma_addr & 0x2)
+ return false;
+
+ /*
+ * Because of HW issue #10, it seems like mixing sync DMA and async
+ * PIO access can confuse the DMA. Make sure XFR_SIZE is reset before
+ * using the channel for DMA.
+ */
+ if (chdat->tx)
+ dma_remaining = musb_readl(ep_conf, TUSB_EP_TX_OFFSET);
+ else
+ dma_remaining = musb_readl(ep_conf, TUSB_EP_RX_OFFSET);
+
+ dma_remaining = TUSB_EP_CONFIG_XFR_SIZE(dma_remaining);
+ if (dma_remaining) {
+ DBG(2, "Busy %s dma ch%i, not using: %08x\n",
+ chdat->tx ? "tx" : "rx", chdat->ch,
+ dma_remaining);
+ return false;
+ }
+
+ chdat->transfer_len = len & ~0x1f;
+
+ if (len < packet_sz)
+ chdat->transfer_packet_sz = chdat->transfer_len;
+ else
+ chdat->transfer_packet_sz = packet_sz;
+
+ if (tusb_dma->multichannel) {
+ ch = chdat->ch;
+ dmareq = chdat->dmareq;
+ sync_dev = chdat->sync_dev;
+ } else {
+ if (tusb_omap_use_shared_dmareq(chdat) != 0) {
+ DBG(3, "could not get dma for ep%i\n", chdat->epnum);
+ return false;
+ }
+ if (tusb_dma->ch < 0) {
+ /* REVISIT: This should get blocked earlier, happens
+ * with MSC ErrorRecoveryTest
+ */
+ WARN_ON(1);
+ return false;
+ }
+
+ ch = tusb_dma->ch;
+ dmareq = tusb_dma->dmareq;
+ sync_dev = tusb_dma->sync_dev;
+ omap_set_dma_callback(ch, tusb_omap_dma_cb, channel);
+ }
+
+ chdat->packet_sz = packet_sz;
+ chdat->len = len;
+ channel->actual_len = 0;
+ chdat->dma_addr = (void __iomem *)dma_addr;
+ channel->status = MUSB_DMA_STATUS_BUSY;
+
+ /* Since we're recycling dma areas, we need to clean or invalidate */
+ if (chdat->tx)
+ dma_cache_maint(phys_to_virt(dma_addr), len, DMA_TO_DEVICE);
+ else
+ dma_cache_maint(phys_to_virt(dma_addr), len, DMA_FROM_DEVICE);
+
+ /* Use 16-bit transfer if dma_addr is not 32-bit aligned */
+ if ((dma_addr & 0x3) == 0) {
+ dma_params.data_type = OMAP_DMA_DATA_TYPE_S32;
+ dma_params.elem_count = 8; /* Elements in frame */
+ } else {
+ dma_params.data_type = OMAP_DMA_DATA_TYPE_S16;
+ dma_params.elem_count = 16; /* Elements in frame */
+ fifo = hw_ep->fifo_async;
+ }
+
+ dma_params.frame_count = chdat->transfer_len / 32; /* Burst sz frame */
+
+ DBG(3, "ep%i %s dma ch%i dma: %08x len: %u(%u) packet_sz: %i(%i)\n",
+ chdat->epnum, chdat->tx ? "tx" : "rx",
+ ch, dma_addr, chdat->transfer_len, len,
+ chdat->transfer_packet_sz, packet_sz);
+
+ /*
+ * Prepare omap DMA for transfer
+ */
+ if (chdat->tx) {
+ dma_params.src_amode = OMAP_DMA_AMODE_POST_INC;
+ dma_params.src_start = (unsigned long)dma_addr;
+ dma_params.src_ei = 0;
+ dma_params.src_fi = 0;
+
+ dma_params.dst_amode = OMAP_DMA_AMODE_DOUBLE_IDX;
+ dma_params.dst_start = (unsigned long)fifo;
+ dma_params.dst_ei = 1;
+ dma_params.dst_fi = -31; /* Loop 32 byte window */
+
+ dma_params.trigger = sync_dev;
+ dma_params.sync_mode = OMAP_DMA_SYNC_FRAME;
+ dma_params.src_or_dst_synch = 0; /* Dest sync */
+
+ src_burst = OMAP_DMA_DATA_BURST_16; /* 16x32 read */
+ dst_burst = OMAP_DMA_DATA_BURST_8; /* 8x32 write */
+ } else {
+ dma_params.src_amode = OMAP_DMA_AMODE_DOUBLE_IDX;
+ dma_params.src_start = (unsigned long)fifo;
+ dma_params.src_ei = 1;
+ dma_params.src_fi = -31; /* Loop 32 byte window */
+
+ dma_params.dst_amode = OMAP_DMA_AMODE_POST_INC;
+ dma_params.dst_start = (unsigned long)dma_addr;
+ dma_params.dst_ei = 0;
+ dma_params.dst_fi = 0;
+
+ dma_params.trigger = sync_dev;
+ dma_params.sync_mode = OMAP_DMA_SYNC_FRAME;
+ dma_params.src_or_dst_synch = 1; /* Source sync */
+
+ src_burst = OMAP_DMA_DATA_BURST_8; /* 8x32 read */
+ dst_burst = OMAP_DMA_DATA_BURST_16; /* 16x32 write */
+ }
+
+ DBG(3, "ep%i %s using %i-bit %s dma from 0x%08lx to 0x%08lx\n",
+ chdat->epnum, chdat->tx ? "tx" : "rx",
+ (dma_params.data_type == OMAP_DMA_DATA_TYPE_S32) ? 32 : 16,
+ ((dma_addr & 0x3) == 0) ? "sync" : "async",
+ dma_params.src_start, dma_params.dst_start);
+
+ omap_set_dma_params(ch, &dma_params);
+ omap_set_dma_src_burst_mode(ch, src_burst);
+ omap_set_dma_dest_burst_mode(ch, dst_burst);
+ omap_set_dma_write_mode(ch, OMAP_DMA_WRITE_LAST_NON_POSTED);
+
+ /*
+ * Prepare MUSB for DMA transfer
+ */
+ if (chdat->tx) {
+ musb_ep_select(mbase, chdat->epnum);
+ csr = musb_readw(hw_ep->regs, MUSB_TXCSR);
+ csr |= (MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAENAB
+ | MUSB_TXCSR_DMAMODE | MUSB_TXCSR_MODE);
+ csr &= ~MUSB_TXCSR_P_UNDERRUN;
+ musb_writew(hw_ep->regs, MUSB_TXCSR, csr);
+ } else {
+ musb_ep_select(mbase, chdat->epnum);
+ csr = musb_readw(hw_ep->regs, MUSB_RXCSR);
+ csr |= MUSB_RXCSR_DMAENAB;
+ csr &= ~(MUSB_RXCSR_AUTOCLEAR | MUSB_RXCSR_DMAMODE);
+ musb_writew(hw_ep->regs, MUSB_RXCSR,
+ csr | MUSB_RXCSR_P_WZC_BITS);
+ }
+
+ /*
+ * Start DMA transfer
+ */
+ omap_start_dma(ch);
+
+ if (chdat->tx) {
+ /* Send transfer_packet_sz packets at a time */
+ musb_writel(ep_conf, TUSB_EP_MAX_PACKET_SIZE_OFFSET,
+ chdat->transfer_packet_sz);
+
+ musb_writel(ep_conf, TUSB_EP_TX_OFFSET,
+ TUSB_EP_CONFIG_XFR_SIZE(chdat->transfer_len));
+ } else {
+ /* Receive transfer_packet_sz packets at a time */
+ musb_writel(ep_conf, TUSB_EP_MAX_PACKET_SIZE_OFFSET,
+ chdat->transfer_packet_sz << 16);
+
+ musb_writel(ep_conf, TUSB_EP_RX_OFFSET,
+ TUSB_EP_CONFIG_XFR_SIZE(chdat->transfer_len));
+ }
+
+ return true;
+}
+
+static int tusb_omap_dma_abort(struct dma_channel *channel)
+{
+ struct tusb_omap_dma_ch *chdat = to_chdat(channel);
+ struct tusb_omap_dma *tusb_dma = chdat->tusb_dma;
+
+ if (!tusb_dma->multichannel) {
+ if (tusb_dma->ch >= 0) {
+ omap_stop_dma(tusb_dma->ch);
+ omap_free_dma(tusb_dma->ch);
+ tusb_dma->ch = -1;
+ }
+
+ tusb_dma->dmareq = -1;
+ tusb_dma->sync_dev = -1;
+ }
+
+ channel->status = MUSB_DMA_STATUS_FREE;
+
+ return 0;
+}
+
+static inline int tusb_omap_dma_allocate_dmareq(struct tusb_omap_dma_ch *chdat)
+{
+ u32 reg = musb_readl(chdat->tbase, TUSB_DMA_EP_MAP);
+ int i, dmareq_nr = -1;
+
+ const int sync_dev[6] = {
+ OMAP24XX_DMA_EXT_DMAREQ0,
+ OMAP24XX_DMA_EXT_DMAREQ1,
+ OMAP242X_DMA_EXT_DMAREQ2,
+ OMAP242X_DMA_EXT_DMAREQ3,
+ OMAP242X_DMA_EXT_DMAREQ4,
+ OMAP242X_DMA_EXT_DMAREQ5,
+ };
+
+ for (i = 0; i < MAX_DMAREQ; i++) {
+ int cur = (reg & (0xf << (i * 5))) >> (i * 5);
+ if (cur == 0) {
+ dmareq_nr = i;
+ break;
+ }
+ }
+
+ if (dmareq_nr == -1)
+ return -EAGAIN;
+
+ reg |= (chdat->epnum << (dmareq_nr * 5));
+ if (chdat->tx)
+ reg |= ((1 << 4) << (dmareq_nr * 5));
+ musb_writel(chdat->tbase, TUSB_DMA_EP_MAP, reg);
+
+ chdat->dmareq = dmareq_nr;
+ chdat->sync_dev = sync_dev[chdat->dmareq];
+
+ return 0;
+}
+
+static inline void tusb_omap_dma_free_dmareq(struct tusb_omap_dma_ch *chdat)
+{
+ u32 reg;
+
+ if (!chdat || chdat->dmareq < 0)
+ return;
+
+ reg = musb_readl(chdat->tbase, TUSB_DMA_EP_MAP);
+ reg &= ~(0x1f << (chdat->dmareq * 5));
+ musb_writel(chdat->tbase, TUSB_DMA_EP_MAP, reg);
+
+ chdat->dmareq = -1;
+ chdat->sync_dev = -1;
+}
+
+static struct dma_channel *dma_channel_pool[MAX_DMAREQ];
+
+static struct dma_channel *
+tusb_omap_dma_allocate(struct dma_controller *c,
+ struct musb_hw_ep *hw_ep,
+ u8 tx)
+{
+ int ret, i;
+ const char *dev_name;
+ struct tusb_omap_dma *tusb_dma;
+ struct musb *musb;
+ void __iomem *tbase;
+ struct dma_channel *channel = NULL;
+ struct tusb_omap_dma_ch *chdat = NULL;
+ u32 reg;
+
+ tusb_dma = container_of(c, struct tusb_omap_dma, controller);
+ musb = tusb_dma->musb;
+ tbase = musb->ctrl_base;
+
+ reg = musb_readl(tbase, TUSB_DMA_INT_MASK);
+ if (tx)
+ reg &= ~(1 << hw_ep->epnum);
+ else
+ reg &= ~(1 << (hw_ep->epnum + 15));
+ musb_writel(tbase, TUSB_DMA_INT_MASK, reg);
+
+ /* REVISIT: Why does dmareq5 not work? */
+ if (hw_ep->epnum == 0) {
+ DBG(3, "Not allowing DMA for ep0 %s\n", tx ? "tx" : "rx");
+ return NULL;
+ }
+
+ for (i = 0; i < MAX_DMAREQ; i++) {
+ struct dma_channel *ch = dma_channel_pool[i];
+ if (ch->status == MUSB_DMA_STATUS_UNKNOWN) {
+ ch->status = MUSB_DMA_STATUS_FREE;
+ channel = ch;
+ chdat = ch->private_data;
+ break;
+ }
+ }
+
+ if (!channel)
+ return NULL;
+
+ if (tx) {
+ chdat->tx = 1;
+ dev_name = "TUSB transmit";
+ } else {
+ chdat->tx = 0;
+ dev_name = "TUSB receive";
+ }
+
+ chdat->musb = tusb_dma->musb;
+ chdat->tbase = tusb_dma->tbase;
+ chdat->hw_ep = hw_ep;
+ chdat->epnum = hw_ep->epnum;
+ chdat->dmareq = -1;
+ chdat->completed_len = 0;
+ chdat->tusb_dma = tusb_dma;
+
+ channel->max_len = 0x7fffffff;
+ channel->desired_mode = 0;
+ channel->actual_len = 0;
+
+ if (tusb_dma->multichannel) {
+ ret = tusb_omap_dma_allocate_dmareq(chdat);
+ if (ret != 0)
+ goto free_dmareq;
+
+ ret = omap_request_dma(chdat->sync_dev, dev_name,
+ tusb_omap_dma_cb, channel, &chdat->ch);
+ if (ret != 0)
+ goto free_dmareq;
+ } else if (tusb_dma->ch == -1) {
+ tusb_dma->dmareq = 0;
+ tusb_dma->sync_dev = OMAP24XX_DMA_EXT_DMAREQ0;
+
+ /* Callback data gets set later in the shared dmareq case */
+ ret = omap_request_dma(tusb_dma->sync_dev, "TUSB shared",
+ tusb_omap_dma_cb, NULL, &tusb_dma->ch);
+ if (ret != 0)
+ goto free_dmareq;
+
+ chdat->dmareq = -1;
+ chdat->ch = -1;
+ }
+
+ DBG(3, "ep%i %s dma: %s dma%i dmareq%i sync%i\n",
+ chdat->epnum,
+ chdat->tx ? "tx" : "rx",
+ chdat->ch >= 0 ? "dedicated" : "shared",
+ chdat->ch >= 0 ? chdat->ch : tusb_dma->ch,
+ chdat->dmareq >= 0 ? chdat->dmareq : tusb_dma->dmareq,
+ chdat->sync_dev >= 0 ? chdat->sync_dev : tusb_dma->sync_dev);
+
+ return channel;
+
+free_dmareq:
+ tusb_omap_dma_free_dmareq(chdat);
+
+ DBG(3, "ep%i: Could not get a DMA channel\n", chdat->epnum);
+ channel->status = MUSB_DMA_STATUS_UNKNOWN;
+
+ return NULL;
+}
+
+static void tusb_omap_dma_release(struct dma_channel *channel)
+{
+ struct tusb_omap_dma_ch *chdat = to_chdat(channel);
+ struct musb *musb = chdat->musb;
+ void __iomem *tbase = musb->ctrl_base;
+ u32 reg;
+
+ DBG(3, "ep%i ch%i\n", chdat->epnum, chdat->ch);
+
+ reg = musb_readl(tbase, TUSB_DMA_INT_MASK);
+ if (chdat->tx)
+ reg |= (1 << chdat->epnum);
+ else
+ reg |= (1 << (chdat->epnum + 15));
+ musb_writel(tbase, TUSB_DMA_INT_MASK, reg);
+
+ reg = musb_readl(tbase, TUSB_DMA_INT_CLEAR);
+ if (chdat->tx)
+ reg |= (1 << chdat->epnum);
+ else
+ reg |= (1 << (chdat->epnum + 15));
+ musb_writel(tbase, TUSB_DMA_INT_CLEAR, reg);
+
+ channel->status = MUSB_DMA_STATUS_UNKNOWN;
+
+ if (chdat->ch >= 0) {
+ omap_stop_dma(chdat->ch);
+ omap_free_dma(chdat->ch);
+ chdat->ch = -1;
+ }
+
+ if (chdat->dmareq >= 0)
+ tusb_omap_dma_free_dmareq(chdat);
+
+ channel = NULL;
+}
+
+void dma_controller_destroy(struct dma_controller *c)
+{
+ struct tusb_omap_dma *tusb_dma;
+ int i;
+
+ tusb_dma = container_of(c, struct tusb_omap_dma, controller);
+ for (i = 0; i < MAX_DMAREQ; i++) {
+ struct dma_channel *ch = dma_channel_pool[i];
+ if (ch) {
+ kfree(ch->private_data);
+ kfree(ch);
+ }
+ }
+
+ if (!tusb_dma->multichannel && tusb_dma && tusb_dma->ch >= 0)
+ omap_free_dma(tusb_dma->ch);
+
+ kfree(tusb_dma);
+}
+
+struct dma_controller *__init
+dma_controller_create(struct musb *musb, void __iomem *base)
+{
+ void __iomem *tbase = musb->ctrl_base;
+ struct tusb_omap_dma *tusb_dma;
+ int i;
+
+ /* REVISIT: Get dmareq lines used from board-*.c */
+
+ musb_writel(musb->ctrl_base, TUSB_DMA_INT_MASK, 0x7fffffff);
+ musb_writel(musb->ctrl_base, TUSB_DMA_EP_MAP, 0);
+
+ musb_writel(tbase, TUSB_DMA_REQ_CONF,
+ TUSB_DMA_REQ_CONF_BURST_SIZE(2)
+ | TUSB_DMA_REQ_CONF_DMA_REQ_EN(0x3f)
+ | TUSB_DMA_REQ_CONF_DMA_REQ_ASSER(2));
+
+ tusb_dma = kzalloc(sizeof(struct tusb_omap_dma), GFP_KERNEL);
+ if (!tusb_dma)
+ goto cleanup;
+
+ tusb_dma->musb = musb;
+ tusb_dma->tbase = musb->ctrl_base;
+
+ tusb_dma->ch = -1;
+ tusb_dma->dmareq = -1;
+ tusb_dma->sync_dev = -1;
+
+ tusb_dma->controller.start = tusb_omap_dma_start;
+ tusb_dma->controller.stop = tusb_omap_dma_stop;
+ tusb_dma->controller.channel_alloc = tusb_omap_dma_allocate;
+ tusb_dma->controller.channel_release = tusb_omap_dma_release;
+ tusb_dma->controller.channel_program = tusb_omap_dma_program;
+ tusb_dma->controller.channel_abort = tusb_omap_dma_abort;
+
+ if (tusb_get_revision(musb) >= TUSB_REV_30)
+ tusb_dma->multichannel = 1;
+
+ for (i = 0; i < MAX_DMAREQ; i++) {
+ struct dma_channel *ch;
+ struct tusb_omap_dma_ch *chdat;
+
+ ch = kzalloc(sizeof(struct dma_channel), GFP_KERNEL);
+ if (!ch)
+ goto cleanup;
+
+ dma_channel_pool[i] = ch;
+
+ chdat = kzalloc(sizeof(struct tusb_omap_dma_ch), GFP_KERNEL);
+ if (!chdat)
+ goto cleanup;
+
+ ch->status = MUSB_DMA_STATUS_UNKNOWN;
+ ch->private_data = chdat;
+ }
+
+ return &tusb_dma->controller;
+
+cleanup:
+ dma_controller_destroy(&tusb_dma->controller);
+
+ return NULL;
+}
If you have a HP Jornada 680, say y to enable the
backlight driver.
+config BACKLIGHT_OMAP
+ tristate "OMAP LCD Backlight"
+ depends on BACKLIGHT_CLASS_DEVICE && (ARCH_OMAP1 || ARCH_OMAP2)
+ default y
+ help
+ This driver controls the LCD backlight level and power
+ for the PWL module of OMAP processors. Say Y if you plan
+ to use power saving.
+
config BACKLIGHT_PROGEAR
tristate "Frontpath ProGear Backlight Driver"
depends on BACKLIGHT_CLASS_DEVICE && PCI && X86
--- /dev/null
+/*
+ * drivers/video/backlight/omap_bl.c
+ *
+ * Backlight driver for OMAP based boards.
+ *
+ * Copyright (c) 2006 Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this package; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/fb.h>
+#include <linux/backlight.h>
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/board.h>
+#include <asm/arch/mux.h>
+
+#define OMAPBL_MAX_INTENSITY 0xff
+
+struct omap_backlight {
+ int powermode;
+ int current_intensity;
+
+ struct device *dev;
+ struct omap_backlight_config *pdata;
+};
+
+static void inline omapbl_send_intensity(int intensity)
+{
+ omap_writeb(intensity, OMAP_PWL_ENABLE);
+}
+
+static void inline omapbl_send_enable(int enable)
+{
+ omap_writeb(enable, OMAP_PWL_CLK_ENABLE);
+}
+
+static void omapbl_blank(struct omap_backlight *bl, int mode)
+{
+ if (bl->pdata->set_power)
+ bl->pdata->set_power(bl->dev, mode);
+
+ switch (mode) {
+ case FB_BLANK_NORMAL:
+ case FB_BLANK_VSYNC_SUSPEND:
+ case FB_BLANK_HSYNC_SUSPEND:
+ case FB_BLANK_POWERDOWN:
+ omapbl_send_intensity(0);
+ omapbl_send_enable(0);
+ break;
+
+ case FB_BLANK_UNBLANK:
+ omapbl_send_intensity(bl->current_intensity);
+ omapbl_send_enable(1);
+ break;
+ }
+}
+
+#ifdef CONFIG_PM
+static int omapbl_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct backlight_device *dev = platform_get_drvdata(pdev);
+ struct omap_backlight *bl = dev_get_drvdata(&dev->dev);
+
+ omapbl_blank(bl, FB_BLANK_POWERDOWN);
+ return 0;
+}
+
+static int omapbl_resume(struct platform_device *pdev)
+{
+ struct backlight_device *dev = platform_get_drvdata(pdev);
+ struct omap_backlight *bl = dev_get_drvdata(&dev->dev);
+
+ omapbl_blank(bl, bl->powermode);
+ return 0;
+}
+#else
+#define omapbl_suspend NULL
+#define omapbl_resume NULL
+#endif
+
+static int omapbl_set_power(struct backlight_device *dev, int state)
+{
+ struct omap_backlight *bl = dev_get_drvdata(&dev->dev);
+
+ omapbl_blank(bl, state);
+ bl->powermode = state;
+
+ return 0;
+}
+
+static int omapbl_update_status(struct backlight_device *dev)
+{
+ struct omap_backlight *bl = dev_get_drvdata(&dev->dev);
+
+ if (bl->current_intensity != dev->props.brightness) {
+ if (dev->props.brightness < 0)
+ return -EPERM; /* Leave current_intensity untouched */
+
+ if (bl->powermode == FB_BLANK_UNBLANK)
+ omapbl_send_intensity(dev->props.brightness);
+ bl->current_intensity = dev->props.brightness;
+ }
+
+ if (dev->props.fb_blank != bl->powermode)
+ omapbl_set_power(dev, dev->props.fb_blank);
+
+ return 0;
+}
+
+
+static int omapbl_get_intensity(struct backlight_device *dev)
+{
+ struct omap_backlight *bl = dev_get_drvdata(&dev->dev);
+ return bl->current_intensity;
+}
+
+static struct backlight_ops omapbl_ops = {
+ .get_brightness = omapbl_get_intensity,
+ .update_status = omapbl_update_status,
+};
+
+
+static int omapbl_probe(struct platform_device *pdev)
+{
+ struct backlight_device *dev;
+ struct omap_backlight *bl;
+ struct omap_backlight_config *pdata = pdev->dev.platform_data;
+
+ if (!pdata)
+ return -ENXIO;
+
+ omapbl_ops.check_fb = pdata->check_fb;
+
+ bl = kzalloc(sizeof(struct omap_backlight), GFP_KERNEL);
+ if (unlikely(!bl))
+ return -ENOMEM;
+
+ dev = backlight_device_register("omap-bl", &pdev->dev,
+ bl, &omapbl_ops);
+ if (IS_ERR(dev)) {
+ kfree(bl);
+ return PTR_ERR(dev);
+ }
+
+ bl->powermode = FB_BLANK_POWERDOWN;
+ bl->current_intensity = 0;
+
+ bl->pdata = pdata;
+ bl->dev = &pdev->dev;
+
+ platform_set_drvdata(pdev, dev);
+
+ omap_cfg_reg(PWL); /* Conflicts with UART3 */
+
+ dev->props.fb_blank = FB_BLANK_UNBLANK;
+ dev->props.max_brightness = OMAPBL_MAX_INTENSITY;
+ dev->props.brightness = pdata->default_intensity;
+ omapbl_update_status(dev);
+
+ printk(KERN_INFO "OMAP LCD backlight initialised\n");
+
+ return 0;
+}
+
+static int omapbl_remove(struct platform_device *pdev)
+{
+ struct backlight_device *dev = platform_get_drvdata(pdev);
+ struct omap_backlight *bl = dev_get_drvdata(&dev->dev);
+
+ backlight_device_unregister(dev);
+ kfree(bl);
+
+ return 0;
+}
+
+static struct platform_driver omapbl_driver = {
+ .probe = omapbl_probe,
+ .remove = omapbl_remove,
+ .suspend = omapbl_suspend,
+ .resume = omapbl_resume,
+ .driver = {
+ .name = "omap-bl",
+ },
+};
+
+static int __init omapbl_init(void)
+{
+ return platform_driver_register(&omapbl_driver);
+}
+
+static void __exit omapbl_exit(void)
+{
+ platform_driver_unregister(&omapbl_driver);
+}
+
+module_init(omapbl_init);
+module_exit(omapbl_exit);
+
+MODULE_AUTHOR("Andrzej Zaborowski <balrog@zabor.org>");
+MODULE_DESCRIPTION("OMAP LCD Backlight driver");
+MODULE_LICENSE("GPL");
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_LCDC_BLIZZARD
+ bool "Epson Blizzard 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 Blizzard 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_MIPID
+ bool "MIPI DBI-C/DCS compatible LCD support"
+ depends on FB_OMAP && SPI_MASTER && CBUS_TAHVO
+ help
+ Say Y here if you want to have support for LCDs compatible with
+ the Mobile Industry Processor Interface DBI-C/DCS
+ specification. (Supported LCDs: Philips LPH8923, Sharp LS041Y3)
+
config FB_OMAP_BOOTLOADER_INIT
bool "Check bootloader initialization"
depends on FB_OMAP
answer yes. Answer no if you have a dedicated video
memory, or don't use any of the accelerated features.
-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_LCDC_BLIZZARD
- bool "Epson Blizzard 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 Blizzard LCD controller.
objs-y$(CONFIG_ARCH_OMAP1) += lcdc.o
objs-y$(CONFIG_ARCH_OMAP2) += dispc.o
+objs-y$(CONFIG_ARCH_OMAP3) += 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_FB_OMAP_LCDC_BLIZZARD) += blizzard.o
+objs-y$(CONFIG_MACH_AMS_DELTA) += lcd_ams_delta.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-y$(CONFIG_MACH_OMAP_PALMTT) += lcd_palmtt.o
objs-y$(CONFIG_MACH_OMAP_PALMZ71) += lcd_palmz71.o
objs-y$(CONFIG_MACH_OMAP_OSK) += lcd_osk.o
objs-y$(CONFIG_MACH_SX1) += lcd_sx1.o
+objs-y$(CONFIG_MACH_OMAP_APOLLON) += lcd_apollon.o
+objs-y$(CONFIG_MACH_OMAP_2430SDP) += lcd_2430sdp.o
+objs-y$(CONFIG_MACH_OMAP_3430SDP) += lcd_2430sdp.o
+objs-y$(CONFIG_MACH_OMAP3EVM) += lcd_omap3evm.o
+objs-y$(CONFIG_FB_OMAP_LCD_MIPID) += lcd_mipid.o
+
omapfb-objs := $(objs-yy)
#define BLIZZARD_CLK_SRC 0x0e
#define BLIZZARD_MEM_BANK0_ACTIVATE 0x10
#define BLIZZARD_MEM_BANK0_STATUS 0x14
+#define BLIZZARD_PANEL_CONFIGURATION 0x28
#define BLIZZARD_HDISP 0x2a
#define BLIZZARD_HNDP 0x2c
#define BLIZZARD_VDISP0 0x2e
return 0;
}
+static int blizzard_set_rotate(int angle)
+{
+ u32 l;
+
+ l = blizzard_read_reg(BLIZZARD_PANEL_CONFIGURATION);
+ l &= ~0x03;
+
+ switch (angle) {
+ case 0:
+ l = l | 0x00;
+ break;
+ case 90:
+ l = l | 0x03;
+ break;
+ case 180:
+ l = l | 0x02;
+ break;
+ case 270:
+ l = l | 0x01;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ blizzard_write_reg(BLIZZARD_PANEL_CONFIGURATION, l);
+
+ return 0;
+}
+
static int blizzard_enable_plane(int plane, int enable)
{
if (enable)
caps->ctrl |= OMAPFB_CAPS_MANUAL_UPDATE |
OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE |
OMAPFB_CAPS_WINDOW_SCALE |
- OMAPFB_CAPS_WINDOW_OVERLAY;
+ OMAPFB_CAPS_WINDOW_OVERLAY |
+ OMAPFB_CAPS_WINDOW_ROTATE;
if (blizzard.te_connected)
caps->ctrl |= OMAPFB_CAPS_TEARSYNC;
caps->wnd_color |= (1 << OMAPFB_COLOR_RGB565) |
.setup_plane = blizzard_setup_plane,
.set_scale = blizzard_set_scale,
.enable_plane = blizzard_enable_plane,
+ .set_rotate = blizzard_set_rotate,
.update_window = blizzard_update_window_async,
.sync = blizzard_sync,
.suspend = blizzard_suspend,
static int get_dss_clocks(void)
{
- if (IS_ERR((dispc.dss_ick = clk_get(dispc.fbdev->dev, "dss_ick")))) {
- dev_err(dispc.fbdev->dev, "can't get dss_ick\n");
+ char *dss_ick = "dss_ick";
+ char *dss1_fck = cpu_is_omap34xx() ? "dss1_alwon_fck" : "dss1_fck";
+ char *tv_fck = cpu_is_omap34xx() ? "dss_tv_fck" : "dss_54m_fck";
+
+ if (IS_ERR((dispc.dss_ick = clk_get(dispc.fbdev->dev, dss_ick)))) {
+ dev_err(dispc.fbdev->dev, "can't get %s", dss_ick);
return PTR_ERR(dispc.dss_ick);
}
- if (IS_ERR((dispc.dss1_fck = clk_get(dispc.fbdev->dev, "dss1_fck")))) {
- dev_err(dispc.fbdev->dev, "can't get dss1_fck\n");
+ if (IS_ERR((dispc.dss1_fck = clk_get(dispc.fbdev->dev, dss1_fck)))) {
+ dev_err(dispc.fbdev->dev, "can't get %s", 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")))) {
- dev_err(dispc.fbdev->dev, "can't get dss_54m_fck\n");
+ clk_get(dispc.fbdev->dev, tv_fck)))) {
+ dev_err(dispc.fbdev->dev, "can't get %s", tv_fck);
clk_put(dispc.dss_ick);
clk_put(dispc.dss1_fck);
return PTR_ERR(dispc.dss_54m_fck);
}
/* Enable smart idle and autoidle */
- l = dispc_read_reg(DISPC_CONTROL);
+ l = dispc_read_reg(DISPC_SYSCONFIG);
l &= ~((3 << 12) | (3 << 3));
l |= (2 << 12) | (2 << 3) | (1 << 0);
dispc_write_reg(DISPC_SYSCONFIG, l);
dispc_write_reg(DISPC_CONFIG, l);
l = dispc_read_reg(DISPC_IRQSTATUS);
- dispc_write_reg(l, DISPC_IRQSTATUS);
+ dispc_write_reg(DISPC_IRQSTATUS, l);
/* Enable those that we handle always */
omap_dispc_enable_irqs(DISPC_IRQ_FRAMEMASK);
--- /dev/null
+/*
+ * LCD panel support for the TI 2430SDP board
+ *
+ * Copyright (C) 2007 MontaVista
+ * Author: Hunyue Yau <hyau@mvista.com>
+ *
+ * Derived from drivers/video/omap/lcd-apollon.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 <linux/i2c/twl4030.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/omapfb.h>
+#include <asm/mach-types.h>
+
+#define SDP2430_LCD_PANEL_BACKLIGHT_GPIO 91
+#define SDP2430_LCD_PANEL_ENABLE_GPIO 154
+#define SDP3430_LCD_PANEL_BACKLIGHT_GPIO 24
+#define SDP3430_LCD_PANEL_ENABLE_GPIO 28
+
+static unsigned backlight_gpio;
+static unsigned enable_gpio;
+
+#define LCD_PIXCLOCK_MAX 5400 /* freq 5.4 MHz */
+#define PM_RECEIVER TWL4030_MODULE_PM_RECEIVER
+#define ENABLE_VAUX2_DEDICATED 0x09
+#define ENABLE_VAUX2_DEV_GRP 0x20
+#define ENABLE_VAUX3_DEDICATED 0x03
+#define ENABLE_VAUX3_DEV_GRP 0x20
+
+
+#define t2_out(c, r, v) twl4030_i2c_write_u8(c, r, v)
+
+
+static int sdp2430_panel_init(struct lcd_panel *panel,
+ struct omapfb_device *fbdev)
+{
+ if (machine_is_omap_3430sdp()) {
+ enable_gpio = SDP3430_LCD_PANEL_ENABLE_GPIO;
+ backlight_gpio = SDP3430_LCD_PANEL_BACKLIGHT_GPIO;
+ } else {
+ enable_gpio = SDP2430_LCD_PANEL_ENABLE_GPIO;
+ backlight_gpio = SDP2430_LCD_PANEL_BACKLIGHT_GPIO;
+ }
+
+ omap_request_gpio(enable_gpio); /* LCD panel */
+ omap_request_gpio(backlight_gpio); /* LCD backlight */
+ omap_set_gpio_direction(enable_gpio, 0); /* output */
+ omap_set_gpio_direction(backlight_gpio, 0); /* output */
+
+ return 0;
+}
+
+static void sdp2430_panel_cleanup(struct lcd_panel *panel)
+{
+}
+
+static int sdp2430_panel_enable(struct lcd_panel *panel)
+{
+ u8 ded_val, ded_reg;
+ u8 grp_val, grp_reg;
+
+ if (machine_is_omap_3430sdp()) {
+ ded_reg = TWL4030_VAUX3_DEDICATED;
+ ded_val = ENABLE_VAUX3_DEDICATED;
+ grp_reg = TWL4030_VAUX3_DEV_GRP;
+ grp_val = ENABLE_VAUX3_DEV_GRP;
+ } else {
+ ded_reg = TWL4030_VAUX2_DEDICATED;
+ ded_val = ENABLE_VAUX2_DEDICATED;
+ grp_reg = TWL4030_VAUX2_DEV_GRP;
+ grp_val = ENABLE_VAUX2_DEV_GRP;
+ }
+
+ omap_set_gpio_dataout(enable_gpio, 1);
+ omap_set_gpio_dataout(backlight_gpio, 1);
+
+ if (0 != t2_out(PM_RECEIVER, ded_val, ded_reg))
+ return -EIO;
+ if (0 != t2_out(PM_RECEIVER, grp_val, grp_reg))
+ return -EIO;
+
+ return 0;
+}
+
+static void sdp2430_panel_disable(struct lcd_panel *panel)
+{
+ omap_set_gpio_dataout(enable_gpio, 0);
+ omap_set_gpio_dataout(backlight_gpio, 0);
+}
+
+static unsigned long sdp2430_panel_get_caps(struct lcd_panel *panel)
+{
+ return 0;
+}
+
+struct lcd_panel sdp2430_panel = {
+ .name = "sdp2430",
+ .config = OMAP_LCDC_PANEL_TFT | OMAP_LCDC_INV_VSYNC |
+ OMAP_LCDC_INV_HSYNC,
+
+ .bpp = 16,
+ .data_lines = 16,
+ .x_res = 240,
+ .y_res = 320,
+ .hsw = 3, /* hsync_len (4) - 1 */
+ .hfp = 3, /* right_margin (4) - 1 */
+ .hbp = 39, /* left_margin (40) - 1 */
+ .vsw = 1, /* vsync_len (2) - 1 */
+ .vfp = 2, /* lower_margin */
+ .vbp = 7, /* upper_margin (8) - 1 */
+
+ .pixel_clock = LCD_PIXCLOCK_MAX,
+
+ .init = sdp2430_panel_init,
+ .cleanup = sdp2430_panel_cleanup,
+ .enable = sdp2430_panel_enable,
+ .disable = sdp2430_panel_disable,
+ .get_caps = sdp2430_panel_get_caps,
+};
+
+static int sdp2430_panel_probe(struct platform_device *pdev)
+{
+ omapfb_register_panel(&sdp2430_panel);
+ return 0;
+}
+
+static int sdp2430_panel_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static int sdp2430_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+ return 0;
+}
+
+static int sdp2430_panel_resume(struct platform_device *pdev)
+{
+ return 0;
+}
+
+struct platform_driver sdp2430_panel_driver = {
+ .probe = sdp2430_panel_probe,
+ .remove = sdp2430_panel_remove,
+ .suspend = sdp2430_panel_suspend,
+ .resume = sdp2430_panel_resume,
+ .driver = {
+ .name = "sdp2430_lcd",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init sdp2430_panel_drv_init(void)
+{
+ return platform_driver_register(&sdp2430_panel_driver);
+}
+
+static void __exit sdp2430_panel_drv_exit(void)
+{
+ platform_driver_unregister(&sdp2430_panel_driver);
+}
+
+module_init(sdp2430_panel_drv_init);
+module_exit(sdp2430_panel_drv_exit);
--- /dev/null
+/*
+ * File: drivers/video/omap/lcd_ams_delta.c
+ *
+ * Based on drivers/video/omap/lcd_inn1510.c
+ *
+ * LCD panel support for the Amstrad E3 (Delta) videophone.
+ *
+ * Copyright (C) 2006 Jonathan McDowell <noodles@earth.li>
+ *
+ * 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/delay.h>
+#include <asm/io.h>
+
+#include <asm/arch/board-ams-delta.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/omapfb.h>
+
+#define AMS_DELTA_DEFAULT_CONTRAST 112
+
+static int ams_delta_panel_init(struct lcd_panel *panel,
+ struct omapfb_device *fbdev)
+{
+ return 0;
+}
+
+static void ams_delta_panel_cleanup(struct lcd_panel *panel)
+{
+}
+
+static int ams_delta_panel_enable(struct lcd_panel *panel)
+{
+ ams_delta_latch2_write(AMS_DELTA_LATCH2_LCD_NDISP,
+ AMS_DELTA_LATCH2_LCD_NDISP);
+ ams_delta_latch2_write(AMS_DELTA_LATCH2_LCD_VBLEN,
+ AMS_DELTA_LATCH2_LCD_VBLEN);
+
+ omap_writeb(1, OMAP_PWL_CLK_ENABLE);
+ omap_writeb(AMS_DELTA_DEFAULT_CONTRAST, OMAP_PWL_ENABLE);
+
+ return 0;
+}
+
+static void ams_delta_panel_disable(struct lcd_panel *panel)
+{
+ ams_delta_latch2_write(AMS_DELTA_LATCH2_LCD_VBLEN, 0);
+ ams_delta_latch2_write(AMS_DELTA_LATCH2_LCD_NDISP, 0);
+}
+
+static unsigned long ams_delta_panel_get_caps(struct lcd_panel *panel)
+{
+ return 0;
+}
+
+static struct lcd_panel ams_delta_panel = {
+ .name = "ams-delta",
+ .config = 0,
+
+ .bpp = 12,
+ .data_lines = 16,
+ .x_res = 480,
+ .y_res = 320,
+ .pixel_clock = 4687,
+ .hsw = 3,
+ .hfp = 1,
+ .hbp = 1,
+ .vsw = 1,
+ .vfp = 0,
+ .vbp = 0,
+ .pcd = 0,
+ .acb = 37,
+
+ .init = ams_delta_panel_init,
+ .cleanup = ams_delta_panel_cleanup,
+ .enable = ams_delta_panel_enable,
+ .disable = ams_delta_panel_disable,
+ .get_caps = ams_delta_panel_get_caps,
+};
+
+static int ams_delta_panel_probe(struct platform_device *pdev)
+{
+ omapfb_register_panel(&ams_delta_panel);
+ return 0;
+}
+
+static int ams_delta_panel_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static int ams_delta_panel_suspend(struct platform_device *pdev,
+ pm_message_t mesg)
+{
+ return 0;
+}
+
+static int ams_delta_panel_resume(struct platform_device *pdev)
+{
+ return 0;
+}
+
+struct platform_driver ams_delta_panel_driver = {
+ .probe = ams_delta_panel_probe,
+ .remove = ams_delta_panel_remove,
+ .suspend = ams_delta_panel_suspend,
+ .resume = ams_delta_panel_resume,
+ .driver = {
+ .name = "lcd_ams_delta",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int ams_delta_panel_drv_init(void)
+{
+ return platform_driver_register(&ams_delta_panel_driver);
+}
+
+static void ams_delta_panel_drv_cleanup(void)
+{
+ platform_driver_unregister(&ams_delta_panel_driver);
+}
+
+module_init(ams_delta_panel_drv_init);
+module_exit(ams_delta_panel_drv_cleanup);
--- /dev/null
+/*
+ * 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 USE_35INCH_LCD 1 */
+
+static int apollon_panel_init(struct lcd_panel *panel,
+ struct omapfb_device *fbdev)
+{
+ /* configure LCD PWR_EN */
+ omap_cfg_reg(M21_242X_GPIO11);
+ return 0;
+}
+
+static void apollon_panel_cleanup(struct lcd_panel *panel)
+{
+}
+
+static int apollon_panel_enable(struct lcd_panel *panel)
+{
+ return 0;
+}
+
+static void apollon_panel_disable(struct lcd_panel *panel)
+{
+}
+
+static unsigned long apollon_panel_get_caps(struct lcd_panel *panel)
+{
+ 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)
+{
+ omapfb_register_panel(&apollon_panel);
+ return 0;
+}
+
+static int apollon_panel_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static int apollon_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+ return 0;
+}
+
+static int apollon_panel_resume(struct platform_device *pdev)
+{
+ 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
+/*
+ * 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 <linux/spi/tsc2101.h>
+
+#include <asm/arch/mux.h>
+#include <asm/arch/omapfb.h>
+
+static struct {
+ struct platform_device *lcd_dev;
+ struct spi_device *tsc2101_dev;
+} h2_panel_dev;
+
+static int h2_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
+{
+ return 0;
+}
+
+static void h2_panel_cleanup(struct lcd_panel *panel)
+{
+}
+
+static int h2_panel_enable(struct lcd_panel *panel)
+{
+ int r;
+
+ /*
+ * Assert LCD_EN, BKLIGHT_EN pins on LCD panel
+ * page2, GPIO config reg, GPIO(0,1) to out and asserted
+ */
+ r = tsc2101_write_sync(h2_panel_dev.tsc2101_dev, 2, 0x23, 0xcc00);
+ if (r < 0)
+ dev_err(&h2_panel_dev.lcd_dev->dev,
+ "failed to enable LCD panel\n");
+
+ return r;
+}
+
+static void h2_panel_disable(struct lcd_panel *panel)
+{
+ /*
+ * Deassert LCD_EN and BKLIGHT_EN pins on LCD panel
+ * page2, GPIO config reg, GPIO(0,1) to out and deasserted
+ */
+ if (tsc2101_write_sync(h2_panel_dev.tsc2101_dev, 2, 0x23, 0x8800))
+ dev_err(&h2_panel_dev.lcd_dev->dev,
+ "failed to disable LCD panel\n");
+}
+
+static unsigned long h2_panel_get_caps(struct lcd_panel *panel)
+{
+ 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)
+{
+ struct spi_device *tsc2101;
+
+ tsc2101 = pdev->dev.platform_data;
+ if (tsc2101 == NULL) {
+ dev_err(&pdev->dev, "no platform data\n");
+ return -ENODEV;
+ }
+ if (strncmp(tsc2101->modalias, "tsc2101", 8) != 0) {
+ dev_err(&pdev->dev, "tsc2101 not found\n");
+ return -EINVAL;
+ }
+ h2_panel_dev.lcd_dev = pdev;
+ h2_panel_dev.tsc2101_dev = tsc2101;
+ omapfb_register_panel(&h2_panel);
+ return 0;
+}
+
+static int h2_panel_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static int h2_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+ return 0;
+}
+
+static int h2_panel_resume(struct platform_device *pdev)
+{
+ 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
+/*
+ * LCD driver for MIPI DBI-C / DCS compatible LCDs
+ *
+ * Copyright (C) 2006 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/device.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <linux/spi/spi.h>
+
+#include <asm/arch/omapfb.h>
+#include <asm/arch/lcd_mipid.h>
+
+#include "../../cbus/tahvo.h"
+
+#define MIPID_MODULE_NAME "lcd_mipid"
+
+#define MIPID_CMD_READ_DISP_ID 0x04
+#define MIPID_CMD_READ_RED 0x06
+#define MIPID_CMD_READ_GREEN 0x07
+#define MIPID_CMD_READ_BLUE 0x08
+#define MIPID_CMD_READ_DISP_STATUS 0x09
+#define MIPID_CMD_RDDSDR 0x0F
+#define MIPID_CMD_SLEEP_IN 0x10
+#define MIPID_CMD_SLEEP_OUT 0x11
+#define MIPID_CMD_DISP_OFF 0x28
+#define MIPID_CMD_DISP_ON 0x29
+
+#define MIPID_VER_LPH8923 3
+#define MIPID_VER_LS041Y3 4
+
+#define MIPID_ESD_CHECK_PERIOD msecs_to_jiffies(5000)
+
+#define to_mipid_device(p) container_of(p, struct mipid_device, \
+ panel)
+struct mipid_device {
+ int enabled;
+ int model;
+ int revision;
+ 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;
+ struct mutex mutex;
+ struct lcd_panel panel;
+
+ struct workqueue_struct *esd_wq;
+ struct delayed_work esd_work;
+ void (*esd_check)(struct mipid_device *m);
+};
+
+static void mipid_transfer(struct mipid_device *md, int cmd, const u8 *wbuf,
+ int wlen, u8 *rbuf, int rlen)
+{
+ struct spi_message m;
+ struct spi_transfer *x, xfer[4];
+ u16 w;
+ int r;
+
+ BUG_ON(md->spi == NULL);
+
+ spi_message_init(&m);
+
+ memset(xfer, 0, sizeof(xfer));
+ x = &xfer[0];
+
+ cmd &= 0xff;
+ x->tx_buf = &cmd;
+ x->bits_per_word= 9;
+ x->len = 2;
+ spi_message_add_tail(x, &m);
+
+ if (wlen) {
+ x++;
+ x->tx_buf = wbuf;
+ x->len = wlen;
+ x->bits_per_word= 9;
+ spi_message_add_tail(x, &m);
+ }
+
+ if (rlen) {
+ x++;
+ x->rx_buf = &w;
+ x->len = 1;
+ spi_message_add_tail(x, &m);
+
+ if (rlen > 1) {
+ /* Arrange for the extra clock before the first
+ * data bit.
+ */
+ x->bits_per_word = 9;
+ x->len = 2;
+
+ x++;
+ x->rx_buf = &rbuf[1];
+ x->len = rlen - 1;
+ spi_message_add_tail(x, &m);
+ }
+ }
+
+ r = spi_sync(md->spi, &m);
+ if (r < 0)
+ dev_dbg(&md->spi->dev, "spi_sync %d\n", r);
+
+ if (rlen)
+ rbuf[0] = w & 0xff;
+}
+
+static inline void mipid_cmd(struct mipid_device *md, int cmd)
+{
+ mipid_transfer(md, cmd, NULL, 0, NULL, 0);
+}
+
+static inline void mipid_write(struct mipid_device *md,
+ int reg, const u8 *buf, int len)
+{
+ mipid_transfer(md, reg, buf, len, NULL, 0);
+}
+
+static inline void mipid_read(struct mipid_device *md,
+ int reg, u8 *buf, int len)
+{
+ mipid_transfer(md, reg, NULL, 0, buf, len);
+}
+
+static void set_data_lines(struct mipid_device *md, int data_lines)
+{
+ u16 par;
+
+ switch (data_lines) {
+ case 16:
+ par = 0x150;
+ break;
+ case 18:
+ par = 0x160;
+ break;
+ case 24:
+ par = 0x170;
+ break;
+ }
+ mipid_write(md, 0x3a, (u8 *)&par, 2);
+}
+
+static void send_init_string(struct mipid_device *md)
+{
+ u16 initpar[] = { 0x0102, 0x0100, 0x0100 };
+
+ mipid_write(md, 0xc2, (u8 *)initpar, sizeof(initpar));
+ set_data_lines(md, md->panel.data_lines);
+}
+
+static void hw_guard_start(struct mipid_device *md, int guard_msec)
+{
+ md->hw_guard_wait = msecs_to_jiffies(guard_msec);
+ md->hw_guard_end = jiffies + md->hw_guard_wait;
+}
+
+static void hw_guard_wait(struct mipid_device *md)
+{
+ unsigned long wait = md->hw_guard_end - jiffies;
+
+ if ((long)wait > 0 && wait <= md->hw_guard_wait) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(wait);
+ }
+}
+
+static void set_sleep_mode(struct mipid_device *md, int on)
+{
+ int cmd, sleep_time = 50;
+
+ if (on)
+ cmd = MIPID_CMD_SLEEP_IN;
+ else
+ cmd = MIPID_CMD_SLEEP_OUT;
+ hw_guard_wait(md);
+ mipid_cmd(md, cmd);
+ hw_guard_start(md, 120);
+ /*
+ * When we enable the panel, it seems we _have_ to sleep
+ * 120 ms before sending the init string. When disabling the
+ * panel we'll sleep for the duration of 2 frames, so that the
+ * controller can still provide the PCLK,HS,VS signals. */
+ if (!on)
+ sleep_time = 120;
+ msleep(sleep_time);
+}
+
+static void set_display_state(struct mipid_device *md, int enabled)
+{
+ int cmd = enabled ? MIPID_CMD_DISP_ON : MIPID_CMD_DISP_OFF;
+
+ mipid_cmd(md, cmd);
+}
+
+static int mipid_set_bklight_level(struct lcd_panel *panel, unsigned int level)
+{
+ struct mipid_device *md = to_mipid_device(panel);
+
+ if (level > tahvo_get_max_backlight_level())
+ return -EINVAL;
+ if (!md->enabled) {
+ md->saved_bklight_level = level;
+ return 0;
+ }
+ tahvo_set_backlight_level(level);
+
+ return 0;
+}
+
+static unsigned int mipid_get_bklight_level(struct lcd_panel *panel)
+{
+ return tahvo_get_backlight_level();
+}
+
+static unsigned int mipid_get_bklight_max(struct lcd_panel *panel)
+{
+ return tahvo_get_max_backlight_level();
+}
+
+
+static unsigned long mipid_get_caps(struct lcd_panel *panel)
+{
+ return OMAPFB_CAPS_SET_BACKLIGHT;
+}
+
+static u16 read_first_pixel(struct mipid_device *md)
+{
+ u16 pixel;
+ u8 red, green, blue;
+
+ mutex_lock(&md->mutex);
+ mipid_read(md, MIPID_CMD_READ_RED, &red, 1);
+ mipid_read(md, MIPID_CMD_READ_GREEN, &green, 1);
+ mipid_read(md, MIPID_CMD_READ_BLUE, &blue, 1);
+ mutex_unlock(&md->mutex);
+
+ switch (md->panel.data_lines) {
+ case 16:
+ pixel = ((red >> 1) << 11) | (green << 5) | (blue >> 1);
+ break;
+ case 24:
+ /* 24 bit -> 16 bit */
+ pixel = ((red >> 3) << 11) | ((green >> 2) << 5) |
+ (blue >> 3);
+ break;
+ default:
+ BUG();
+ }
+
+ return pixel;
+}
+
+static int mipid_run_test(struct lcd_panel *panel, int test_num)
+{
+ struct mipid_device *md = to_mipid_device(panel);
+ static const u16 test_values[4] = {
+ 0x0000, 0xffff, 0xaaaa, 0x5555,
+ };
+ int i;
+
+ if (test_num != MIPID_TEST_RGB_LINES)
+ return MIPID_TEST_INVALID;
+
+ for (i = 0; i < ARRAY_SIZE(test_values); i++) {
+ int delay;
+ unsigned long tmo;
+
+ omapfb_write_first_pixel(md->fbdev, test_values[i]);
+ tmo = jiffies + msecs_to_jiffies(100);
+ delay = 25;
+ while (1) {
+ u16 pixel;
+
+ msleep(delay);
+ pixel = read_first_pixel(md);
+ if (pixel == test_values[i])
+ break;
+ if (time_after(jiffies, tmo)) {
+ dev_err(&md->spi->dev,
+ "MIPI LCD RGB I/F test failed: "
+ "expecting %04x, got %04x\n",
+ test_values[i], pixel);
+ return MIPID_TEST_FAILED;
+ }
+ delay = 10;
+ }
+ }
+
+ return 0;
+}
+
+static void ls041y3_esd_recover(struct mipid_device *md)
+{
+ dev_err(&md->spi->dev, "performing LCD ESD recovery\n");
+ set_sleep_mode(md, 1);
+ set_sleep_mode(md, 0);
+}
+
+static void ls041y3_esd_check_mode1(struct mipid_device *md)
+{
+ u8 state1, state2;
+
+ mipid_read(md, MIPID_CMD_RDDSDR, &state1, 1);
+ set_sleep_mode(md, 0);
+ mipid_read(md, MIPID_CMD_RDDSDR, &state2, 1);
+ dev_dbg(&md->spi->dev, "ESD mode 1 state1 %02x state2 %02x\n",
+ state1, state2);
+ /* Each sleep out command will trigger a self diagnostic and flip
+ * Bit6 if the test passes.
+ */
+ if (!((state1 ^ state2) & (1 << 6)))
+ ls041y3_esd_recover(md);
+}
+
+static void ls041y3_esd_check_mode2(struct mipid_device *md)
+{
+ int i;
+ u8 rbuf[2];
+ static const struct {
+ int cmd;
+ int wlen;
+ u16 wbuf[3];
+ } *rd, rd_ctrl[7] = {
+ { 0xb0, 4, { 0x0101, 0x01fe, } },
+ { 0xb1, 4, { 0x01de, 0x0121, } },
+ { 0xc2, 4, { 0x0100, 0x0100, } },
+ { 0xbd, 2, { 0x0100, } },
+ { 0xc2, 4, { 0x01fc, 0x0103, } },
+ { 0xb4, 0, },
+ { 0x00, 0, },
+ };
+
+ rd = rd_ctrl;
+ for (i = 0; i < 3; i++, rd++)
+ mipid_write(md, rd->cmd, (u8 *)rd->wbuf, rd->wlen);
+
+ udelay(10);
+ mipid_read(md, rd->cmd, rbuf, 2);
+ rd++;
+
+ for (i = 0; i < 3; i++, rd++) {
+ udelay(10);
+ mipid_write(md, rd->cmd, (u8 *)rd->wbuf, rd->wlen);
+ }
+
+ dev_dbg(&md->spi->dev, "ESD mode 2 state %02x\n", rbuf[1]);
+ if (rbuf[1] == 0x00)
+ ls041y3_esd_recover(md);
+}
+
+static void ls041y3_esd_check(struct mipid_device *md)
+{
+ ls041y3_esd_check_mode1(md);
+ if (md->revision >= 0x88)
+ ls041y3_esd_check_mode2(md);
+}
+
+static void mipid_esd_start_check(struct mipid_device *md)
+{
+ if (md->esd_check != NULL)
+ queue_delayed_work(md->esd_wq, &md->esd_work,
+ MIPID_ESD_CHECK_PERIOD);
+}
+
+static void mipid_esd_stop_check(struct mipid_device *md)
+{
+ if (md->esd_check != NULL)
+ cancel_rearming_delayed_workqueue(md->esd_wq, &md->esd_work);
+}
+
+static void mipid_esd_work(struct work_struct *work)
+{
+ struct mipid_device *md = container_of(work, struct mipid_device, esd_work.work);
+
+ mutex_lock(&md->mutex);
+ md->esd_check(md);
+ mutex_unlock(&md->mutex);
+ mipid_esd_start_check(md);
+}
+
+static int mipid_enable(struct lcd_panel *panel)
+{
+ struct mipid_device *md = to_mipid_device(panel);
+
+ mutex_lock(&md->mutex);
+
+ if (md->enabled) {
+ mutex_unlock(&md->mutex);
+ return 0;
+ }
+ set_sleep_mode(md, 0);
+ md->enabled = 1;
+ send_init_string(md);
+ set_display_state(md, 1);
+ mipid_set_bklight_level(panel, md->saved_bklight_level);
+ mipid_esd_start_check(md);
+
+ mutex_unlock(&md->mutex);
+ return 0;
+}
+
+static void mipid_disable(struct lcd_panel *panel)
+{
+ struct mipid_device *md = to_mipid_device(panel);
+
+ /*
+ * A final ESD work might be called before returning,
+ * so do this without holding the lock.
+ */
+ mipid_esd_stop_check(md);
+ mutex_lock(&md->mutex);
+
+ if (!md->enabled) {
+ mutex_unlock(&md->mutex);
+ return;
+ }
+ md->saved_bklight_level = mipid_get_bklight_level(panel);
+ mipid_set_bklight_level(panel, 0);
+ set_display_state(md, 0);
+ set_sleep_mode(md, 1);
+ md->enabled = 0;
+
+ mutex_unlock(&md->mutex);
+}
+
+static int panel_enabled(struct mipid_device *md)
+{
+ u32 disp_status;
+ int enabled;
+
+ mipid_read(md, MIPID_CMD_READ_DISP_STATUS, (u8 *)&disp_status, 4);
+ disp_status = __be32_to_cpu(disp_status);
+ enabled = (disp_status & (1 << 17)) && (disp_status & (1 << 10));
+ dev_dbg(&md->spi->dev,
+ "LCD panel %senabled by bootloader (status 0x%04x)\n",
+ enabled ? "" : "not ", disp_status);
+ return enabled;
+}
+
+static int mipid_init(struct lcd_panel *panel,
+ struct omapfb_device *fbdev)
+{
+ struct mipid_device *md = to_mipid_device(panel);
+
+ md->fbdev = fbdev;
+ md->esd_wq = create_singlethread_workqueue("mipid_esd");
+ if (md->esd_wq == NULL) {
+ dev_err(&md->spi->dev, "can't create ESD workqueue\n");
+ return -ENOMEM;
+ }
+ INIT_DELAYED_WORK(&md->esd_work, mipid_esd_work);
+ mutex_init(&md->mutex);
+
+ md->enabled = panel_enabled(md);
+
+ if (md->enabled)
+ mipid_esd_start_check(md);
+ else
+ md->saved_bklight_level = mipid_get_bklight_level(panel);
+
+ return 0;
+}
+
+static void mipid_cleanup(struct lcd_panel *panel)
+{
+ struct mipid_device *md = to_mipid_device(panel);
+
+ if (md->enabled)
+ mipid_esd_stop_check(md);
+ destroy_workqueue(md->esd_wq);
+}
+
+static struct lcd_panel mipid_panel = {
+ .config = OMAP_LCDC_PANEL_TFT,
+
+ .bpp = 16,
+ .x_res = 800,
+ .y_res = 480,
+ .pixel_clock = 21940,
+ .hsw = 50,
+ .hfp = 20,
+ .hbp = 15,
+ .vsw = 2,
+ .vfp = 1,
+ .vbp = 3,
+
+ .init = mipid_init,
+ .cleanup = mipid_cleanup,
+ .enable = mipid_enable,
+ .disable = mipid_disable,
+ .get_caps = mipid_get_caps,
+ .set_bklight_level= mipid_set_bklight_level,
+ .get_bklight_level= mipid_get_bklight_level,
+ .get_bklight_max= mipid_get_bklight_max,
+ .run_test = mipid_run_test,
+};
+
+static int mipid_detect(struct mipid_device *md)
+{
+ struct mipid_platform_data *pdata;
+
+ pdata = md->spi->dev.platform_data;
+ if (pdata == NULL) {
+ dev_err(&md->spi->dev, "missing platform data\n");
+ return -ENOENT;
+ }
+
+ mipid_read(md, MIPID_CMD_READ_DISP_ID, md->display_id, 3);
+ dev_dbg(&md->spi->dev, "MIPI display ID: %02x%02x%02x\n",
+ md->display_id[0], md->display_id[1], md->display_id[2]);
+
+ switch (md->display_id[0]) {
+ case 0x45:
+ md->model = MIPID_VER_LPH8923;
+ md->panel.name = "lph8923";
+ break;
+ case 0x83:
+ md->model = MIPID_VER_LS041Y3;
+ md->panel.name = "ls041y3";
+ md->esd_check = ls041y3_esd_check;
+ break;
+ default:
+ md->panel.name = "unknown";
+ dev_err(&md->spi->dev, "invalid display ID\n");
+ return -ENODEV;
+ }
+
+ md->revision = md->display_id[1];
+ md->panel.data_lines = pdata->data_lines;
+ pr_info("omapfb: %s rev %02x LCD detected\n",
+ md->panel.name, md->revision);
+
+ return 0;
+}
+
+static int mipid_spi_probe(struct spi_device *spi)
+{
+ struct mipid_device *md;
+ int r;
+
+ md = kzalloc(sizeof(*md), GFP_KERNEL);
+ if (md == NULL) {
+ dev_err(&spi->dev, "out of memory\n");
+ return -ENOMEM;
+ }
+
+ spi->mode = SPI_MODE_0;
+ md->spi = spi;
+ dev_set_drvdata(&spi->dev, md);
+ md->panel = mipid_panel;
+
+ r = mipid_detect(md);
+ if (r < 0)
+ return r;
+
+ omapfb_register_panel(&md->panel);
+
+ return 0;
+}
+
+static int mipid_spi_remove(struct spi_device *spi)
+{
+ struct mipid_device *md = dev_get_drvdata(&spi->dev);
+
+ mipid_disable(&md->panel);
+ kfree(md);
+
+ return 0;
+}
+
+static struct spi_driver mipid_spi_driver = {
+ .driver = {
+ .name = MIPID_MODULE_NAME,
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = mipid_spi_probe,
+ .remove = __devexit_p(mipid_spi_remove),
+};
+
+static int mipid_drv_init(void)
+{
+ spi_register_driver(&mipid_spi_driver);
+
+ return 0;
+}
+module_init(mipid_drv_init);
+
+static void mipid_drv_cleanup(void)
+{
+ spi_unregister_driver(&mipid_spi_driver);
+}
+module_exit(mipid_drv_cleanup);
+
+MODULE_DESCRIPTION("MIPI display driver");
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * LCD panel support for the TI OMAP3 EVM board
+ *
+ * Author: Steve Sakoman <steve@sakoman.com>
+ *
+ * Derived from drivers/video/omap/lcd-apollon.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 <linux/i2c/twl4030.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/omapfb.h>
+#include <asm/mach-types.h>
+
+#define LCD_PANEL_ENABLE_GPIO 153
+#define LCD_PANEL_LR 2
+#define LCD_PANEL_UD 3
+#define LCD_PANEL_INI 152
+#define LCD_PANEL_QVGA 154
+#define LCD_PANEL_RESB 155
+
+#define LCD_XRES 480
+#define LCD_YRES 640
+#define LCD_PIXCLOCK_MAX 41700 /* in pico seconds */
+#define LCD_PIXCLOCK_MIN 38000 /* in pico seconds */
+
+#define ENABLE_VDAC_DEDICATED 0x03
+#define ENABLE_VDAC_DEV_GRP 0x20
+#define ENABLE_VPLL2_DEDICATED 0x05
+#define ENABLE_VPLL2_DEV_GRP 0xE0
+
+static int omap3evm_panel_init(struct lcd_panel *panel,
+ struct omapfb_device *fbdev)
+{
+ omap_request_gpio(LCD_PANEL_LR);
+ omap_request_gpio(LCD_PANEL_UD);
+ omap_request_gpio(LCD_PANEL_INI);
+ omap_request_gpio(LCD_PANEL_RESB);
+ omap_request_gpio(LCD_PANEL_QVGA);
+
+ omap_set_gpio_direction(LCD_PANEL_LR, 0);
+ omap_set_gpio_direction(LCD_PANEL_UD, 0);
+ omap_set_gpio_direction(LCD_PANEL_INI, 0);
+ omap_set_gpio_direction(LCD_PANEL_RESB, 0);
+ omap_set_gpio_direction(LCD_PANEL_QVGA, 0);
+
+ twl4030_i2c_write_u8(TWL4030_MODULE_PWMA, 0x7F, 0);
+ twl4030_i2c_write_u8(TWL4030_MODULE_PWMA, 0x7F, 1);
+ twl4030_i2c_write_u8(TWL4030_MODULE_PWMB, 0x7F, 0);
+ twl4030_i2c_write_u8(TWL4030_MODULE_PWMB, 0x7F, 1);
+
+ omap_set_gpio_dataout(LCD_PANEL_RESB, 1);
+ omap_set_gpio_dataout(LCD_PANEL_INI, 1);
+ omap_set_gpio_dataout(LCD_PANEL_QVGA, 0);
+ omap_set_gpio_dataout(LCD_PANEL_LR, 1);
+ omap_set_gpio_dataout(LCD_PANEL_UD, 1);
+
+ return 0;
+}
+
+static void omap3evm_panel_cleanup(struct lcd_panel *panel)
+{
+}
+
+static int omap3evm_panel_enable(struct lcd_panel *panel)
+{
+ omap_set_gpio_dataout(LCD_PANEL_ENABLE_GPIO, 0);
+ return 0;
+}
+
+static void omap3evm_panel_disable(struct lcd_panel *panel)
+{
+ omap_set_gpio_dataout(LCD_PANEL_ENABLE_GPIO, 1);
+}
+
+static unsigned long omap3evm_panel_get_caps(struct lcd_panel *panel)
+{
+ return 0;
+}
+
+struct lcd_panel omap3evm_panel = {
+ .name = "omap3evm",
+ .config = OMAP_LCDC_PANEL_TFT | OMAP_LCDC_INV_VSYNC |
+ OMAP_LCDC_INV_HSYNC,
+
+ .bpp = 16,
+ .data_lines = 18,
+ .x_res = LCD_XRES,
+ .y_res = LCD_YRES,
+ .hsw = 3, /* hsync_len (4) - 1 */
+ .hfp = 3, /* right_margin (4) - 1 */
+ .hbp = 39, /* left_margin (40) - 1 */
+ .vsw = 1, /* vsync_len (2) - 1 */
+ .vfp = 2, /* lower_margin */
+ .vbp = 7, /* upper_margin (8) - 1 */
+
+ .pixel_clock = LCD_PIXCLOCK_MAX,
+
+ .init = omap3evm_panel_init,
+ .cleanup = omap3evm_panel_cleanup,
+ .enable = omap3evm_panel_enable,
+ .disable = omap3evm_panel_disable,
+ .get_caps = omap3evm_panel_get_caps,
+};
+
+static int omap3evm_panel_probe(struct platform_device *pdev)
+{
+ omapfb_register_panel(&omap3evm_panel);
+ return 0;
+}
+
+static int omap3evm_panel_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static int omap3evm_panel_suspend(struct platform_device *pdev,
+ pm_message_t mesg)
+{
+ return 0;
+}
+
+static int omap3evm_panel_resume(struct platform_device *pdev)
+{
+ return 0;
+}
+
+struct platform_driver omap3evm_panel_driver = {
+ .probe = omap3evm_panel_probe,
+ .remove = omap3evm_panel_remove,
+ .suspend = omap3evm_panel_suspend,
+ .resume = omap3evm_panel_resume,
+ .driver = {
+ .name = "omap3evm_lcd",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init omap3evm_panel_drv_init(void)
+{
+ return platform_driver_register(&omap3evm_panel_driver);
+}
+
+static void __exit omap3evm_panel_drv_exit(void)
+{
+ platform_driver_unregister(&omap3evm_panel_driver);
+}
+
+module_init(omap3evm_panel_drv_init);
+module_exit(omap3evm_panel_drv_exit);
--- /dev/null
+/*
+ * 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 "../drivers/ssi/omap-uwire.h"
+
+#define LCD_UWIRE_CS 0
+
+static int p2_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
+{
+ return 0;
+}
+
+static void p2_panel_cleanup(struct lcd_panel *panel)
+{
+}
+
+static int p2_panel_enable(struct lcd_panel *panel)
+{
+ int i;
+ unsigned long value;
+
+ /* 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);
+
+ return 0;
+}
+
+static void p2_panel_disable(struct lcd_panel *panel)
+{
+}
+
+static unsigned long p2_panel_get_caps(struct lcd_panel *panel)
+{
+ 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)
+{
+ omapfb_register_panel(&p2_panel);
+ return 0;
+}
+
+static int p2_panel_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static int p2_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+ return 0;
+}
+
+static int p2_panel_resume(struct platform_device *pdev)
+{
+ 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);
+
{ OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE, "pixel double window" },
{ OMAPFB_CAPS_WINDOW_SCALE, "scale window" },
{ OMAPFB_CAPS_WINDOW_OVERLAY, "overlay window" },
+ { OMAPFB_CAPS_WINDOW_ROTATE, "rotate window" },
{ OMAPFB_CAPS_SET_BACKLIGHT, "backlight setting" },
};
offset, var->xres_virtual,
plane->info.pos_x, plane->info.pos_y,
var->xres, var->yres, plane->color_mode);
+ if (r < 0)
+ return r;
+
+ if (fbdev->ctrl->set_rotate != NULL)
+ if((r = fbdev->ctrl->set_rotate(var->rotate)) < 0)
+ return r;
+
if (fbdev->ctrl->set_scale != NULL)
r = fbdev->ctrl->set_scale(plane->idx,
var->xres, var->yres,
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;
if (plane->color_mode == OMAPFB_COLOR_RGB444) {
var->red.offset = 8; var->red.length = 4;
struct omapfb_device *fbdev = plane->fbdev;
omapfb_rqueue_lock(fbdev);
- if (cpu_is_omap15xx() && rotate != fbi->var.rotate) {
+ if (rotate != fbi->var.rotate) {
struct fb_var_screeninfo *new_var = &fbdev->new_var;
memcpy(new_var, &fbi->var, sizeof(*new_var));
void (*callback)(void *),
void *callback_data)
{
+ int xres, yres;
struct omapfb_plane_struct *plane = fbi->par;
struct omapfb_device *fbdev = plane->fbdev;
- struct fb_var_screeninfo *var;
+ struct fb_var_screeninfo *var = &fbi->var;
- var = &fbi->var;
- if (win->x >= var->xres || win->y >= var->yres ||
- win->out_x > var->xres || win->out_y >= var->yres)
+ switch (var->rotate) {
+ case 0:
+ case 180:
+ xres = fbdev->panel->x_res;
+ yres = fbdev->panel->y_res;
+ break;
+ case 90:
+ case 270:
+ xres = fbdev->panel->y_res;
+ yres = fbdev->panel->x_res;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (win->x >= xres || win->y >= yres ||
+ win->out_x > xres || win->out_y > yres)
return -EINVAL;
if (!fbdev->ctrl->update_window ||
fbdev->ctrl->get_update_mode() != OMAPFB_MANUAL_UPDATE)
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;
- /* The out sizes should be cropped to the LCD size */
- if (win->out_x + win->out_width > fbdev->panel->x_res)
- win->out_width = fbdev->panel->x_res - win->out_x;
- if (win->out_y + win->out_height > fbdev->panel->y_res)
- win->out_height = fbdev->panel->y_res - win->out_y;
+ if (win->x + win->width > xres)
+ win->width = xres - win->x;
+ if (win->y + win->height > yres)
+ win->height = yres - win->y;
+ if (win->out_x + win->out_width > xres)
+ win->out_width = xres - win->out_x;
+ if (win->out_y + win->out_height > yres)
+ win->out_height = yres - win->out_y;
if (!win->width || !win->height || !win->out_width || !win->out_height)
return 0;
{
struct omapfb_device *fbdev = platform_get_drvdata(pdev);
- omapfb_blank(VESA_POWERDOWN, fbdev->fb_info[0]);
-
+ if (fbdev != NULL)
+ omapfb_blank(VESA_POWERDOWN, fbdev->fb_info[0]);
return 0;
}
{
struct omapfb_device *fbdev = platform_get_drvdata(pdev);
- omapfb_blank(VESA_NO_BLANKING, fbdev->fb_info[0]);
+ if (fbdev != NULL)
+ omapfb_blank(VESA_NO_BLANKING, fbdev->fb_info[0]);
return 0;
}
* OMAP2 Remote Frame Buffer Interface support
*
* Copyright (C) 2005 Nokia Corporation
- * Author: Juha Yrjölä <juha.yrjola@nokia.com>
+ * 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
* OMAP1 Special OptimiSed Screen Interface support
*
* Copyright (C) 2004-2005 Nokia Corporation
- * Author: Juha Yrjölä <juha.yrjola@nokia.com>
+ * 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
in HP iPAQ devices like h5xxx, h2200, and ASIC3-based like
hx4700.
+config HDQ_MASTER_OMAP
+ tristate "OMAP HDQ driver"
+ depends on ARCH_OMAP2430 || ARCH_OMAP34XX
+ help
+ Say Y here if you want support for the 1-wire or HDQ Interface
+ on an OMAP processor.
+
config W1_MASTER_GPIO
tristate "GPIO 1-wire busmaster"
depends on GENERIC_GPIO
obj-$(CONFIG_W1_MASTER_DS2490) += ds2490.o
obj-$(CONFIG_W1_MASTER_DS2482) += ds2482.o
obj-$(CONFIG_W1_MASTER_DS1WM) += ds1wm.o
+obj-$(CONFIG_HDQ_MASTER_OMAP) += omap_hdq.o
obj-$(CONFIG_W1_MASTER_GPIO) += w1-gpio.o
--- /dev/null
+/*
+ * drivers/w1/masters/omap_hdq.c
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <asm/irq.h>
+#include <asm/hardware.h>
+
+#include "../w1.h"
+#include "../w1_int.h"
+
+#define MOD_NAME "OMAP_HDQ:"
+
+#define OMAP_HDQ_REVISION 0x00
+#define OMAP_HDQ_TX_DATA 0x04
+#define OMAP_HDQ_RX_DATA 0x08
+#define OMAP_HDQ_CTRL_STATUS 0x0c
+#define OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK (1<<6)
+#define OMAP_HDQ_CTRL_STATUS_CLOCKENABLE (1<<5)
+#define OMAP_HDQ_CTRL_STATUS_GO (1<<4)
+#define OMAP_HDQ_CTRL_STATUS_INITIALIZATION (1<<2)
+#define OMAP_HDQ_CTRL_STATUS_DIR (1<<1)
+#define OMAP_HDQ_CTRL_STATUS_MODE (1<<0)
+#define OMAP_HDQ_INT_STATUS 0x10
+#define OMAP_HDQ_INT_STATUS_TXCOMPLETE (1<<2)
+#define OMAP_HDQ_INT_STATUS_RXCOMPLETE (1<<1)
+#define OMAP_HDQ_INT_STATUS_TIMEOUT (1<<0)
+#define OMAP_HDQ_SYSCONFIG 0x14
+#define OMAP_HDQ_SYSCONFIG_SOFTRESET (1<<1)
+#define OMAP_HDQ_SYSCONFIG_AUTOIDLE (1<<0)
+#define OMAP_HDQ_SYSSTATUS 0x18
+#define OMAP_HDQ_SYSSTATUS_RESETDONE (1<<0)
+
+#define OMAP_HDQ_FLAG_CLEAR 0
+#define OMAP_HDQ_FLAG_SET 1
+#define OMAP_HDQ_TIMEOUT (HZ/5)
+
+#define OMAP_HDQ_MAX_USER 4
+
+DECLARE_WAIT_QUEUE_HEAD(hdq_wait_queue);
+int W1_ID;
+
+struct hdq_data {
+ resource_size_t hdq_base;
+ struct semaphore hdq_semlock;
+ int hdq_usecount;
+ struct clk *hdq_ick;
+ struct clk *hdq_fck;
+ u8 hdq_irqstatus;
+ spinlock_t hdq_spinlock;
+};
+
+static struct hdq_data *hdq_data;
+
+static int omap_hdq_get(void);
+static int omap_hdq_put(void);
+static int omap_hdq_break(void);
+
+static int __init omap_hdq_probe(struct platform_device *pdev);
+static int omap_hdq_remove(struct platform_device *pdev);
+
+static struct platform_driver omap_hdq_driver = {
+ .probe = omap_hdq_probe,
+ .remove = omap_hdq_remove,
+ .suspend = NULL,
+ .resume = NULL,
+ .driver = {
+ .name = "omap_hdq",
+ },
+};
+
+static u8 omap_w1_read_byte(void *data);
+static void omap_w1_write_byte(void *data, u8 byte);
+static u8 omap_w1_reset_bus(void *data);
+static void omap_w1_search_bus(void *data, u8 search_type,
+ w1_slave_found_callback slave_found);
+
+static struct w1_bus_master omap_w1_master = {
+ .read_byte = omap_w1_read_byte,
+ .write_byte = omap_w1_write_byte,
+ .reset_bus = omap_w1_reset_bus,
+ .search = omap_w1_search_bus,
+};
+
+/*
+ * HDQ register I/O routines
+ */
+static inline u8
+hdq_reg_in(u32 offset)
+{
+ return omap_readb(hdq_data->hdq_base + offset);
+}
+
+static inline u8
+hdq_reg_out(u32 offset, u8 val)
+{
+ omap_writeb(val, hdq_data->hdq_base + offset);
+ return val;
+}
+
+static inline u8
+hdq_reg_merge(u32 offset, u8 val, u8 mask)
+{
+ u8 new_val = (omap_readb(hdq_data->hdq_base + offset) & ~mask)
+ | (val & mask);
+ omap_writeb(new_val, hdq_data->hdq_base + offset);
+ return new_val;
+}
+
+/*
+ * Wait for one or more bits in flag change.
+ * HDQ_FLAG_SET: wait until any bit in the flag is set.
+ * HDQ_FLAG_CLEAR: wait until all bits in the flag are cleared.
+ * return 0 on success and -ETIMEDOUT in the case of timeout.
+ */
+static int
+hdq_wait_for_flag(u32 offset, u8 flag, u8 flag_set, u8 *status)
+{
+ int ret = 0;
+ unsigned long timeout = jiffies + OMAP_HDQ_TIMEOUT;
+
+ if (flag_set == OMAP_HDQ_FLAG_CLEAR) {
+ /* wait for the flag clear */
+ while (((*status = hdq_reg_in(offset)) & flag)
+ && time_before(jiffies, timeout)) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(1);
+ }
+ if (unlikely(*status & flag))
+ ret = -ETIMEDOUT;
+ } else if (flag_set == OMAP_HDQ_FLAG_SET) {
+ /* wait for the flag set */
+ while (!((*status = hdq_reg_in(offset)) & flag)
+ && time_before(jiffies, timeout)) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(1);
+ }
+ if (unlikely(!(*status & flag)))
+ ret = -ETIMEDOUT;
+ } else
+ return -EINVAL;
+
+ return ret;
+}
+
+/*
+ * write out a byte and fill *status with HDQ_INT_STATUS
+ */
+static int
+hdq_write_byte(u8 val, u8 *status)
+{
+ int ret;
+ u8 tmp_status;
+ unsigned long irqflags;
+
+ *status = 0;
+
+ spin_lock_irqsave(&hdq_data->hdq_spinlock, irqflags);
+ /* clear interrupt flags via a dummy read */
+ hdq_reg_in(OMAP_HDQ_INT_STATUS);
+ /* ISR loads it with new INT_STATUS */
+ hdq_data->hdq_irqstatus = 0;
+ spin_unlock_irqrestore(&hdq_data->hdq_spinlock, irqflags);
+
+ hdq_reg_out(OMAP_HDQ_TX_DATA, val);
+
+ /* set the GO bit */
+ hdq_reg_merge(OMAP_HDQ_CTRL_STATUS, OMAP_HDQ_CTRL_STATUS_GO,
+ OMAP_HDQ_CTRL_STATUS_DIR | OMAP_HDQ_CTRL_STATUS_GO);
+ /* wait for the TXCOMPLETE bit */
+ ret = wait_event_interruptible_timeout(hdq_wait_queue,
+ hdq_data->hdq_irqstatus, OMAP_HDQ_TIMEOUT);
+ if (unlikely(ret < 0)) {
+ pr_debug("wait interrupted");
+ return -EINTR;
+ }
+
+ spin_lock_irqsave(&hdq_data->hdq_spinlock, irqflags);
+ *status = hdq_data->hdq_irqstatus;
+ spin_unlock_irqrestore(&hdq_data->hdq_spinlock, irqflags);
+ /* check irqstatus */
+ if (!(*status & OMAP_HDQ_INT_STATUS_TXCOMPLETE)) {
+ pr_debug("timeout waiting for TXCOMPLETE/RXCOMPLETE, %x",
+ *status);
+ return -ETIMEDOUT;
+ }
+
+ /* wait for the GO bit return to zero */
+ ret = hdq_wait_for_flag(OMAP_HDQ_CTRL_STATUS, OMAP_HDQ_CTRL_STATUS_GO,
+ OMAP_HDQ_FLAG_CLEAR, &tmp_status);
+ if (ret) {
+ pr_debug("timeout waiting GO bit return to zero, %x",
+ tmp_status);
+ return ret;
+ }
+
+ return ret;
+}
+
+/*
+ * HDQ Interrupt service routine.
+ */
+static irqreturn_t
+hdq_isr(int irq, void *arg)
+{
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&hdq_data->hdq_spinlock, irqflags);
+ hdq_data->hdq_irqstatus = hdq_reg_in(OMAP_HDQ_INT_STATUS);
+ spin_unlock_irqrestore(&hdq_data->hdq_spinlock, irqflags);
+ pr_debug("hdq_isr: %x", hdq_data->hdq_irqstatus);
+
+ if (hdq_data->hdq_irqstatus &
+ (OMAP_HDQ_INT_STATUS_TXCOMPLETE | OMAP_HDQ_INT_STATUS_RXCOMPLETE
+ | OMAP_HDQ_INT_STATUS_TIMEOUT)) {
+ /* wake up sleeping process */
+ wake_up_interruptible(&hdq_wait_queue);
+ }
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * HDQ Mode: always return success.
+ */
+static u8 omap_w1_reset_bus(void *data)
+{
+ return 0;
+}
+
+/*
+ * W1 search callback function.
+ */
+static void omap_w1_search_bus(void *data, u8 search_type,
+ w1_slave_found_callback slave_found)
+{
+ u64 module_id, rn_le, cs, id;
+
+ if (W1_ID)
+ module_id = W1_ID;
+ else
+ module_id = 0x1;
+
+ rn_le = cpu_to_le64(module_id);
+ /*
+ * HDQ might not obey truly the 1-wire spec.
+ * So calculate CRC based on module parameter.
+ */
+ cs = w1_calc_crc8((u8 *)&rn_le, 7);
+ id = (cs << 56) | module_id;
+
+ slave_found(data, id);
+}
+
+static int
+_omap_hdq_reset(void)
+{
+ int ret;
+ u8 tmp_status;
+
+ hdq_reg_out(OMAP_HDQ_SYSCONFIG, OMAP_HDQ_SYSCONFIG_SOFTRESET);
+ /*
+ * Select HDQ mode & enable clocks.
+ * It is observed that INT flags can't be cleared via a read and GO/INIT
+ * won't return to zero if interrupt is disabled. So we always enable
+ * interrupt.
+ */
+ hdq_reg_out(OMAP_HDQ_CTRL_STATUS,
+ OMAP_HDQ_CTRL_STATUS_CLOCKENABLE |
+ OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK);
+
+ /* wait for reset to complete */
+ ret = hdq_wait_for_flag(OMAP_HDQ_SYSSTATUS,
+ OMAP_HDQ_SYSSTATUS_RESETDONE, OMAP_HDQ_FLAG_SET, &tmp_status);
+ if (ret)
+ pr_debug("timeout waiting HDQ reset, %x", tmp_status);
+ else {
+ hdq_reg_out(OMAP_HDQ_CTRL_STATUS,
+ OMAP_HDQ_CTRL_STATUS_CLOCKENABLE |
+ OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK);
+ hdq_reg_out(OMAP_HDQ_SYSCONFIG, OMAP_HDQ_SYSCONFIG_AUTOIDLE);
+ }
+
+ return ret;
+}
+
+/*
+ * Issue break pulse to the device.
+ */
+static int
+omap_hdq_break()
+{
+ int ret;
+ u8 tmp_status;
+ unsigned long irqflags;
+
+ ret = down_interruptible(&hdq_data->hdq_semlock);
+ if (ret < 0)
+ return -EINTR;
+
+ if (!hdq_data->hdq_usecount) {
+ up(&hdq_data->hdq_semlock);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&hdq_data->hdq_spinlock, irqflags);
+ /* clear interrupt flags via a dummy read */
+ hdq_reg_in(OMAP_HDQ_INT_STATUS);
+ /* ISR loads it with new INT_STATUS */
+ hdq_data->hdq_irqstatus = 0;
+ spin_unlock_irqrestore(&hdq_data->hdq_spinlock, irqflags);
+
+ /* set the INIT and GO bit */
+ hdq_reg_merge(OMAP_HDQ_CTRL_STATUS,
+ OMAP_HDQ_CTRL_STATUS_INITIALIZATION | OMAP_HDQ_CTRL_STATUS_GO,
+ OMAP_HDQ_CTRL_STATUS_DIR | OMAP_HDQ_CTRL_STATUS_INITIALIZATION |
+ OMAP_HDQ_CTRL_STATUS_GO);
+
+ /* wait for the TIMEOUT bit */
+ ret = wait_event_interruptible_timeout(hdq_wait_queue,
+ hdq_data->hdq_irqstatus, OMAP_HDQ_TIMEOUT);
+ if (unlikely(ret < 0)) {
+ pr_debug("wait interrupted");
+ up(&hdq_data->hdq_semlock);
+ return -EINTR;
+ }
+
+ spin_lock_irqsave(&hdq_data->hdq_spinlock, irqflags);
+ tmp_status = hdq_data->hdq_irqstatus;
+ spin_unlock_irqrestore(&hdq_data->hdq_spinlock, irqflags);
+ /* check irqstatus */
+ if (!(tmp_status & OMAP_HDQ_INT_STATUS_TIMEOUT)) {
+ pr_debug("timeout waiting for TIMEOUT, %x", tmp_status);
+ up(&hdq_data->hdq_semlock);
+ return -ETIMEDOUT;
+ }
+ /*
+ * wait for both INIT and GO bits rerurn to zero.
+ * zero wait time expected for interrupt mode.
+ */
+ ret = hdq_wait_for_flag(OMAP_HDQ_CTRL_STATUS,
+ OMAP_HDQ_CTRL_STATUS_INITIALIZATION |
+ OMAP_HDQ_CTRL_STATUS_GO, OMAP_HDQ_FLAG_CLEAR,
+ &tmp_status);
+ if (ret)
+ pr_debug("timeout waiting INIT&GO bits return to zero, %x",
+ tmp_status);
+
+ up(&hdq_data->hdq_semlock);
+ return ret;
+}
+
+static int hdq_read_byte(u8 *val)
+{
+ int ret;
+ u8 status;
+ unsigned long irqflags;
+
+ ret = down_interruptible(&hdq_data->hdq_semlock);
+ if (ret < 0)
+ return -EINTR;
+
+ if (!hdq_data->hdq_usecount) {
+ up(&hdq_data->hdq_semlock);
+ return -EINVAL;
+ }
+
+ if (!(hdq_data->hdq_irqstatus & OMAP_HDQ_INT_STATUS_RXCOMPLETE)) {
+ hdq_reg_merge(OMAP_HDQ_CTRL_STATUS,
+ OMAP_HDQ_CTRL_STATUS_DIR | OMAP_HDQ_CTRL_STATUS_GO,
+ OMAP_HDQ_CTRL_STATUS_DIR | OMAP_HDQ_CTRL_STATUS_GO);
+ /*
+ * The RX comes immediately after TX. It
+ * triggers another interrupt before we
+ * sleep. So we have to wait for RXCOMPLETE bit.
+ */
+ {
+ unsigned long timeout = jiffies + OMAP_HDQ_TIMEOUT;
+ while (!(hdq_data->hdq_irqstatus
+ & OMAP_HDQ_INT_STATUS_RXCOMPLETE)
+ && time_before(jiffies, timeout)) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(1);
+ }
+ }
+ hdq_reg_merge(OMAP_HDQ_CTRL_STATUS, 0,
+ OMAP_HDQ_CTRL_STATUS_DIR);
+ spin_lock_irqsave(&hdq_data->hdq_spinlock, irqflags);
+ status = hdq_data->hdq_irqstatus;
+ spin_unlock_irqrestore(&hdq_data->hdq_spinlock, irqflags);
+ /* check irqstatus */
+ if (!(status & OMAP_HDQ_INT_STATUS_RXCOMPLETE)) {
+ pr_debug("timeout waiting for RXCOMPLETE, %x", status);
+ up(&hdq_data->hdq_semlock);
+ return -ETIMEDOUT;
+ }
+ }
+ /* the data is ready. Read it in! */
+ *val = hdq_reg_in(OMAP_HDQ_RX_DATA);
+ up(&hdq_data->hdq_semlock);
+
+ return 0;
+
+}
+
+/*
+ * Enable clocks and set the controller to HDQ mode.
+ */
+static int
+omap_hdq_get()
+{
+ int ret = 0;
+
+ ret = down_interruptible(&hdq_data->hdq_semlock);
+ if (ret < 0)
+ return -EINTR;
+
+ if (OMAP_HDQ_MAX_USER == hdq_data->hdq_usecount) {
+ pr_debug("attempt to exceed the max use count");
+ up(&hdq_data->hdq_semlock);
+ ret = -EINVAL;
+ } else {
+ hdq_data->hdq_usecount++;
+ try_module_get(THIS_MODULE);
+ if (1 == hdq_data->hdq_usecount) {
+ if (clk_enable(hdq_data->hdq_ick)) {
+ pr_debug("Can not enable ick\n");
+ clk_put(hdq_data->hdq_ick);
+ clk_put(hdq_data->hdq_fck);
+ up(&hdq_data->hdq_semlock);
+ return -ENODEV;
+ }
+ if (clk_enable(hdq_data->hdq_fck)) {
+ pr_debug("Can not enable fck\n");
+ clk_put(hdq_data->hdq_ick);
+ clk_put(hdq_data->hdq_fck);
+ up(&hdq_data->hdq_semlock);
+ return -ENODEV;
+ }
+
+ /* make sure HDQ is out of reset */
+ if (!(hdq_reg_in(OMAP_HDQ_SYSSTATUS) &
+ OMAP_HDQ_SYSSTATUS_RESETDONE)) {
+ ret = _omap_hdq_reset();
+ if (ret)
+ /* back up the count */
+ hdq_data->hdq_usecount--;
+ } else {
+ /* select HDQ mode & enable clocks */
+ hdq_reg_out(OMAP_HDQ_CTRL_STATUS,
+ OMAP_HDQ_CTRL_STATUS_CLOCKENABLE |
+ OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK);
+ hdq_reg_out(OMAP_HDQ_SYSCONFIG,
+ OMAP_HDQ_SYSCONFIG_AUTOIDLE);
+ hdq_reg_in(OMAP_HDQ_INT_STATUS);
+ }
+ }
+ }
+ up(&hdq_data->hdq_semlock);
+ return ret;
+}
+
+/*
+ * Disable clocks to the module.
+ */
+static int
+omap_hdq_put()
+{
+ int ret = 0;
+
+ ret = down_interruptible(&hdq_data->hdq_semlock);
+ if (ret < 0)
+ return -EINTR;
+
+ if (0 == hdq_data->hdq_usecount) {
+ pr_debug("attempt to decrement use count when it is zero");
+ ret = -EINVAL;
+ } else {
+ hdq_data->hdq_usecount--;
+ module_put(THIS_MODULE);
+ if (0 == hdq_data->hdq_usecount) {
+ clk_disable(hdq_data->hdq_ick);
+ clk_disable(hdq_data->hdq_fck);
+ }
+ }
+ up(&hdq_data->hdq_semlock);
+ return ret;
+}
+
+/*
+ * Used to control the call to omap_hdq_get and omap_hdq_put.
+ * HDQ Protocol: Write the CMD|REG_address first, followed by
+ * the data wrire or read.
+ */
+static int init_trans;
+
+/*
+ * Read a byte of data from the device.
+ */
+static u8 omap_w1_read_byte(void *data)
+{
+ u8 val;
+ int ret;
+
+ ret = hdq_read_byte(&val);
+ if (ret)
+ return -1;
+
+ /* Write followed by a read, release the module */
+ if (init_trans) {
+ init_trans = 0;
+ omap_hdq_put();
+ }
+
+ return val;
+}
+
+/*
+ * Write a byte of data to the device.
+ */
+static void omap_w1_write_byte(void *data, u8 byte)
+{
+ u8 status;
+
+ /* First write to initialize the transfer */
+ if (init_trans == 0)
+ omap_hdq_get();
+
+ init_trans++;
+
+ hdq_write_byte(byte, &status);
+ pr_debug("Ctrl status %x\n", status);
+
+ /* Second write, data transfered. Release the module */
+ if (init_trans > 1) {
+ omap_hdq_put();
+ init_trans = 0;
+ }
+
+ return;
+}
+
+static int __init omap_hdq_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ int ret, irq;
+ u8 rev;
+
+ if (!pdev)
+ return -ENODEV;
+
+ hdq_data = kmalloc(sizeof(*hdq_data), GFP_KERNEL);
+ if (!hdq_data)
+ return -ENODEV;
+
+ platform_set_drvdata(pdev, hdq_data);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ platform_set_drvdata(pdev, NULL);
+ kfree(hdq_data);
+ return -ENXIO;
+ }
+
+ hdq_data->hdq_base = res->start;
+
+ /* get interface & functional clock objects */
+ hdq_data->hdq_ick = clk_get(&pdev->dev, "hdq_ick");
+ hdq_data->hdq_fck = clk_get(&pdev->dev, "hdq_fck");
+
+ if (IS_ERR(hdq_data->hdq_ick) || IS_ERR(hdq_data->hdq_fck)) {
+ pr_debug("Can't get HDQ clock objects\n");
+ if (IS_ERR(hdq_data->hdq_ick)) {
+ ret = PTR_ERR(hdq_data->hdq_ick);
+ platform_set_drvdata(pdev, NULL);
+ kfree(hdq_data);
+ return ret;
+ }
+ if (IS_ERR(hdq_data->hdq_fck)) {
+ ret = PTR_ERR(hdq_data->hdq_fck);
+ platform_set_drvdata(pdev, NULL);
+ kfree(hdq_data);
+ return ret;
+ }
+ }
+
+ hdq_data->hdq_usecount = 0;
+ sema_init(&hdq_data->hdq_semlock, 1);
+
+ if (clk_enable(hdq_data->hdq_ick)) {
+ pr_debug("Can not enable ick\n");
+ clk_put(hdq_data->hdq_ick);
+ clk_put(hdq_data->hdq_fck);
+ platform_set_drvdata(pdev, NULL);
+ kfree(hdq_data);
+ return -ENODEV;
+ }
+
+ if (clk_enable(hdq_data->hdq_fck)) {
+ pr_debug("Can not enable fck\n");
+ clk_disable(hdq_data->hdq_ick);
+ clk_put(hdq_data->hdq_ick);
+ clk_put(hdq_data->hdq_fck);
+ platform_set_drvdata(pdev, NULL);
+ kfree(hdq_data);
+ return -ENODEV;
+ }
+
+ rev = hdq_reg_in(OMAP_HDQ_REVISION);
+ pr_info("OMAP HDQ Hardware Revision %c.%c. Driver in %s mode.\n",
+ (rev >> 4) + '0', (rev & 0x0f) + '0', "Interrupt");
+
+ spin_lock_init(&hdq_data->hdq_spinlock);
+ omap_hdq_break();
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ platform_set_drvdata(pdev, NULL);
+ kfree(hdq_data);
+ return -ENXIO;
+ }
+
+ if (request_irq(irq, hdq_isr, IRQF_DISABLED, "OMAP HDQ",
+ &hdq_data->hdq_semlock)) {
+ pr_debug("request_irq failed\n");
+ clk_disable(hdq_data->hdq_ick);
+ clk_put(hdq_data->hdq_ick);
+ clk_put(hdq_data->hdq_fck);
+ platform_set_drvdata(pdev, NULL);
+ kfree(hdq_data);
+ return -ENODEV;
+ }
+
+ /* don't clock the HDQ until it is needed */
+ clk_disable(hdq_data->hdq_ick);
+ clk_disable(hdq_data->hdq_fck);
+
+ ret = w1_add_master_device(&omap_w1_master);
+ if (ret) {
+ pr_debug("Failure in registering w1 master\n");
+ clk_put(hdq_data->hdq_ick);
+ clk_put(hdq_data->hdq_fck);
+ platform_set_drvdata(pdev, NULL);
+ kfree(hdq_data);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int omap_hdq_remove(struct platform_device *pdev)
+{
+ down_interruptible(&hdq_data->hdq_semlock);
+ if (0 != hdq_data->hdq_usecount) {
+ pr_debug("removed when use count is not zero\n");
+ return -EBUSY;
+ }
+ up(&hdq_data->hdq_semlock);
+
+ /* remove module dependency */
+ clk_put(hdq_data->hdq_ick);
+ clk_put(hdq_data->hdq_fck);
+ free_irq(INT_24XX_HDQ_IRQ, &hdq_data->hdq_semlock);
+ platform_set_drvdata(pdev, NULL);
+ kfree(hdq_data);
+
+ return 0;
+}
+
+static int __init
+omap_hdq_init(void)
+{
+ return platform_driver_register(&omap_hdq_driver);
+}
+
+static void __exit
+omap_hdq_exit(void)
+{
+ platform_driver_unregister(&omap_hdq_driver);
+}
+
+module_init(omap_hdq_init);
+module_exit(omap_hdq_exit);
+
+module_param(W1_ID, int, S_IRUSR);
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("HDQ driver Library");
+MODULE_LICENSE("GPL");
If you are unsure, say N.
+config W1_SLAVE_BQ27000
+ tristate "BQ27000 slave support"
+ depends on W1
+ help
+ Say Y here if you want to use a hdq
+ bq27000 slave support.
+
+
endmenu
obj-$(CONFIG_W1_SLAVE_SMEM) += w1_smem.o
obj-$(CONFIG_W1_SLAVE_DS2433) += w1_ds2433.o
obj-$(CONFIG_W1_SLAVE_DS2760) += w1_ds2760.o
-
+obj-$(CONFIG_W1_SLAVE_BQ27000) += w1_bq27000.o
--- /dev/null
+/*
+ * drivers/w1/slaves/w1_bq27000.c
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+
+#include "../w1.h"
+#include "../w1_int.h"
+#include "../w1_family.h"
+
+#define HDQ_CMD_READ (0)
+#define HDQ_CMD_WRITE (1<<7)
+
+int F_ID;
+int family_id;
+
+void w1_bq27000_write(struct device *dev, u8 buf, u8 reg)
+{
+ struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
+ if (!dev) {
+ pr_info("Could not obtain slave dev ptr\n");
+ return;
+ }
+
+ w1_write_8(sl->master, HDQ_CMD_WRITE | reg);
+ w1_write_8(sl->master, buf);
+}
+EXPORT_SYMBOL(w1_bq27000_write);
+
+int w1_bq27000_read(struct device *dev, u8 reg)
+{
+ u8 val;
+ struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
+ if (!dev)
+ return 0;
+
+ w1_write_8(sl->master, HDQ_CMD_READ | reg);
+ val = w1_read_8(sl->master);
+
+ return val;
+}
+EXPORT_SYMBOL(w1_bq27000_read);
+
+static int w1_bq27000_add_slave(struct w1_slave *sl)
+{
+ int ret;
+ int id = 1;
+ struct platform_device *pdev;
+
+ pdev = platform_device_alloc("bq27000-battery", id);
+ if (!pdev) {
+ ret = -ENOMEM;
+ return ret;
+ }
+ pdev->dev.parent = &sl->dev;
+
+ ret = platform_device_add(pdev);
+ if (ret)
+ goto pdev_add_failed;
+
+ dev_set_drvdata(&sl->dev, pdev);
+
+ goto success;
+
+pdev_add_failed:
+ platform_device_unregister(pdev);
+success:
+ return ret;
+}
+
+static void w1_bq27000_remove_slave(struct w1_slave *sl)
+{
+ struct platform_device *pdev = dev_get_drvdata(&sl->dev);
+ platform_device_unregister(pdev);
+}
+
+static struct w1_family_ops w1_bq27000_fops = {
+ .add_slave = w1_bq27000_add_slave,
+ .remove_slave = w1_bq27000_remove_slave,
+};
+
+static struct w1_family w1_bq27000_family = {
+ .fid = 1,
+ .fops = &w1_bq27000_fops,
+};
+
+static int __init w1_bq27000_init(void)
+{
+ if (F_ID)
+ w1_bq27000_family.fid = F_ID;
+
+ return w1_register_family(&w1_bq27000_family);
+}
+
+static void __exit w1_bq27000_exit(void)
+{
+ w1_unregister_family(&w1_bq27000_family);
+}
+
+
+module_init(w1_bq27000_init);
+module_exit(w1_bq27000_exit);
+
+module_param(F_ID, int, S_IRUSR);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Texas Instruments Ltd");
+MODULE_DESCRIPTION("HDQ/1-wire slave driver bq27000 battery monitor chip");
u8 w1_triplet(struct w1_master *dev, int bdir);
void w1_write_8(struct w1_master *, u8);
+u8 w1_read_8(struct w1_master *);
int w1_reset_bus(struct w1_master *);
u8 w1_calc_crc8(u8 *, int);
void w1_write_block(struct w1_master *, const u8 *, int);
* @param dev the master device
* @return the byte read
*/
-static u8 w1_read_8(struct w1_master * dev)
+u8 w1_read_8(struct w1_master *dev)
{
int i;
u8 res = 0;
return res;
}
+EXPORT_SYMBOL_GPL(w1_read_8);
/**
* Writes a series of bytes.
config OMAP_WATCHDOG
tristate "OMAP Watchdog"
- depends on ARCH_OMAP16XX || ARCH_OMAP24XX
+ depends on ARCH_OMAP16XX || ARCH_OMAP24XX || ARCH_OMAP34XX
help
- Support for TI OMAP1610/OMAP1710/OMAP2420 watchdog. Say 'Y' here to
- enable the OMAP1610/OMAP1710 watchdog timer.
+ Support for TI OMAP1610/OMAP1710/OMAP2420/OMAP3430 watchdog. Say 'Y'
+ here to enable the OMAP1610/OMAP1710/OMAP2420/OMAP3430 watchdog timer.
config PNX4008_WATCHDOG
tristate "PNX4008 Watchdog"
/*
- * linux/drivers/char/watchdog/omap_wdt.c
+ * linux/drivers/watchdog/omap_wdt.c
*
- * Watchdog driver for the TI OMAP 16xx & 24xx 32KHz (non-secure) watchdog
+ * Watchdog driver for the TI OMAP 16xx & 24xx/34xx 32KHz (non-secure) watchdog
*
* Author: MontaVista Software, Inc.
* <gdavis@mvista.com> or <source@mvista.com>
#include <linux/platform_device.h>
#include <linux/moduleparam.h>
#include <linux/clk.h>
-#include <linux/bitops.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 struct platform_device *omap_wdt_dev;
+
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;
+struct omap_wdt_dev {
+ void __iomem *base; /* physical */
+ struct device *dev;
+ int omap_wdt_users;
+ struct clk *armwdt_ck;
+ struct clk *mpu_wdt_ick;
+ struct clk *mpu_wdt_fck;
+ struct resource *mem;
+ struct miscdevice omap_wdt_miscdev;
+};
-static void omap_wdt_ping(void)
+static void omap_wdt_ping(struct omap_wdt_dev *wdev)
{
+ void __iomem *base = wdev->base;
/* wait for posted write to complete */
- while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x08)
+ while ((omap_readl(base + OMAP_WATCHDOG_WPS)) & 0x08)
cpu_relax();
wdt_trgr_pattern = ~wdt_trgr_pattern;
- omap_writel(wdt_trgr_pattern, (OMAP_WATCHDOG_TGR));
+ omap_writel(wdt_trgr_pattern, (base + OMAP_WATCHDOG_TGR));
/* wait for posted write to complete */
- while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x08)
+ while ((omap_readl(base + OMAP_WATCHDOG_WPS)) & 0x08)
cpu_relax();
/* reloaded WCRR from WLDR */
}
-static void omap_wdt_enable(void)
+static void omap_wdt_enable(struct omap_wdt_dev *wdev)
{
+ void __iomem *base;
+ base = wdev->base;
/* Sequence to enable the watchdog */
- omap_writel(0xBBBB, OMAP_WATCHDOG_SPR);
- while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x10)
+ omap_writel(0xBBBB, base + OMAP_WATCHDOG_SPR);
+ while ((omap_readl(base + OMAP_WATCHDOG_WPS)) & 0x10)
cpu_relax();
- omap_writel(0x4444, OMAP_WATCHDOG_SPR);
- while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x10)
+ omap_writel(0x4444, base + OMAP_WATCHDOG_SPR);
+ while ((omap_readl(base + OMAP_WATCHDOG_WPS)) & 0x10)
cpu_relax();
}
-static void omap_wdt_disable(void)
+static void omap_wdt_disable(struct omap_wdt_dev *wdev)
{
+ void __iomem *base;
+ base = wdev->base;
/* sequence required to disable watchdog */
- omap_writel(0xAAAA, OMAP_WATCHDOG_SPR); /* TIMER_MODE */
- while (omap_readl(OMAP_WATCHDOG_WPS) & 0x10)
+ omap_writel(0xAAAA, base + OMAP_WATCHDOG_SPR); /* TIMER_MODE */
+ while (omap_readl(base + OMAP_WATCHDOG_WPS) & 0x10)
cpu_relax();
- omap_writel(0x5555, OMAP_WATCHDOG_SPR); /* TIMER_MODE */
- while (omap_readl(OMAP_WATCHDOG_WPS) & 0x10)
+ omap_writel(0x5555, base + OMAP_WATCHDOG_SPR); /* TIMER_MODE */
+ while (omap_readl(base + OMAP_WATCHDOG_WPS) & 0x10)
cpu_relax();
}
timer_margin = new_timeout;
}
-static void omap_wdt_set_timeout(void)
+static void omap_wdt_set_timeout(struct omap_wdt_dev *wdev)
{
u32 pre_margin = GET_WLDR_VAL(timer_margin);
+ void __iomem *base;
+ base = wdev->base;
/* just count up at 32 KHz */
- while (omap_readl(OMAP_WATCHDOG_WPS) & 0x04)
+ while (omap_readl(base + OMAP_WATCHDOG_WPS) & 0x04)
cpu_relax();
- omap_writel(pre_margin, OMAP_WATCHDOG_LDR);
- while (omap_readl(OMAP_WATCHDOG_WPS) & 0x04)
+ omap_writel(pre_margin, base + OMAP_WATCHDOG_LDR);
+ while (omap_readl(base + OMAP_WATCHDOG_WPS) & 0x04)
cpu_relax();
}
static int omap_wdt_open(struct inode *inode, struct file *file)
{
- if (test_and_set_bit(1, (unsigned long *)&omap_wdt_users))
+ struct omap_wdt_dev *wdev;
+ void __iomem *base;
+ wdev = platform_get_drvdata(omap_wdt_dev);
+ base = wdev->base;
+ if (test_and_set_bit(1, (unsigned long *)&(wdev->omap_wdt_users)))
return -EBUSY;
if (cpu_is_omap16xx())
- clk_enable(armwdt_ck); /* Enable the clock */
+ clk_enable(wdev->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 */
+ if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
+ clk_enable(wdev->mpu_wdt_ick); /* Enable the interface clock */
+ clk_enable(wdev->mpu_wdt_fck); /* Enable the functional clock */
}
/* initialize prescaler */
- while (omap_readl(OMAP_WATCHDOG_WPS) & 0x01)
+ while (omap_readl(base + OMAP_WATCHDOG_WPS) & 0x01)
cpu_relax();
- omap_writel((1 << 5) | (PTV << 2), OMAP_WATCHDOG_CNTRL);
- while (omap_readl(OMAP_WATCHDOG_WPS) & 0x01)
+ omap_writel((1 << 5) | (PTV << 2), base + OMAP_WATCHDOG_CNTRL);
+ while (omap_readl(base + OMAP_WATCHDOG_WPS) & 0x01)
cpu_relax();
- omap_wdt_set_timeout();
- omap_wdt_enable();
+ file->private_data = (void *) wdev;
+
+ omap_wdt_set_timeout(wdev);
+ omap_wdt_enable(wdev);
return nonseekable_open(inode, file);
}
static int omap_wdt_release(struct inode *inode, struct file *file)
{
+ struct omap_wdt_dev *wdev;
+ wdev = file->private_data;
/*
* 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;
- }
+ omap_wdt_disable(wdev);
- 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;
+ if (cpu_is_omap16xx())
+ clk_disable(wdev->armwdt_ck); /* Disable the clock */
+
+ if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
+ clk_disable(wdev->mpu_wdt_ick); /* Disable the clock */
+ clk_disable(wdev->mpu_wdt_fck); /* Disable the clock */
}
#else
printk(KERN_CRIT "omap_wdt: Unexpected close, not stopping!\n");
#endif
- omap_wdt_users = 0;
+ wdev->omap_wdt_users = 0;
return 0;
}
omap_wdt_write(struct file *file, const char __user *data,
size_t len, loff_t *ppos)
{
+ struct omap_wdt_dev *wdev;
+ wdev = file->private_data;
/* Refresh LOAD_TIME. */
if (len)
- omap_wdt_ping();
+ omap_wdt_ping(wdev);
return len;
}
omap_wdt_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
+ struct omap_wdt_dev *wdev;
int new_margin;
static struct watchdog_info ident = {
.identity = "OMAP Watchdog",
.options = WDIOF_SETTIMEOUT,
.firmware_version = 0,
};
+ wdev = file->private_data;
switch (cmd) {
default:
return put_user(omap_prcm_get_reset_sources(),
(int __user *)arg);
case WDIOC_KEEPALIVE:
- omap_wdt_ping();
+ omap_wdt_ping(wdev);
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_disable(wdev);
+ omap_wdt_set_timeout(wdev);
+ omap_wdt_enable(wdev);
- omap_wdt_ping();
+ omap_wdt_ping(wdev);
/* Fall */
case WDIOC_GETTIMEOUT:
return put_user(timer_margin, (int __user *)arg);
}
+ return 0;
}
static const struct file_operations omap_wdt_fops = {
.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;
+ struct omap_wdt_dev *wdev;
/* reserve static register mappings */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENOENT;
+ if (omap_wdt_dev)
+ return -EBUSY;
+
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;
+ wdev = kzalloc(sizeof(struct omap_wdt_dev), GFP_KERNEL);
+ if (!wdev) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+ wdev->omap_wdt_users = 0;
+ wdev->mem = mem;
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;
+ wdev->armwdt_ck = clk_get(&pdev->dev, "armwdt_ck");
+ if (IS_ERR(wdev->armwdt_ck)) {
+ ret = PTR_ERR(wdev->armwdt_ck);
+ wdev->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;
+ wdev->mpu_wdt_ick = clk_get(&pdev->dev, "mpu_wdt_ick");
+ if (IS_ERR(wdev->mpu_wdt_ick)) {
+ ret = PTR_ERR(wdev->mpu_wdt_ick);
+ wdev->mpu_wdt_ick = NULL;
+ goto fail;
+ }
+ wdev->mpu_wdt_fck = clk_get(&pdev->dev, "mpu_wdt_fck");
+ if (IS_ERR(wdev->mpu_wdt_fck)) {
+ ret = PTR_ERR(wdev->mpu_wdt_fck);
+ wdev->mpu_wdt_fck = NULL;
+ goto fail;
+ }
+ }
+
+ if (cpu_is_omap34xx()) {
+ wdev->mpu_wdt_ick = clk_get(&pdev->dev, "wdt2_ick");
+ if (IS_ERR(wdev->mpu_wdt_ick)) {
+ ret = PTR_ERR(wdev->mpu_wdt_ick);
+ wdev->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;
+ wdev->mpu_wdt_fck = clk_get(&pdev->dev, "wdt2_fck");
+ if (IS_ERR(wdev->mpu_wdt_fck)) {
+ ret = PTR_ERR(wdev->mpu_wdt_fck);
+ wdev->mpu_wdt_fck = NULL;
goto fail;
}
}
+ wdev->base = (void __iomem *) (mem->start);
+ platform_set_drvdata(pdev, wdev);
- omap_wdt_disable();
+ omap_wdt_disable(wdev);
omap_wdt_adjust_timeout(timer_margin);
- omap_wdt_miscdev.parent = &pdev->dev;
- ret = misc_register(&omap_wdt_miscdev);
+ wdev->omap_wdt_miscdev.parent = &pdev->dev;
+ wdev->omap_wdt_miscdev.minor = WATCHDOG_MINOR;
+ wdev->omap_wdt_miscdev.name = "watchdog";
+ wdev->omap_wdt_miscdev.fops = &omap_wdt_fops;
+
+ ret = misc_register(&(wdev->omap_wdt_miscdev));
if (ret)
goto fail;
- pr_info("OMAP Watchdog Timer: initial timeout %d sec\n", timer_margin);
+ pr_info("OMAP Watchdog Timer Rev 0x%02x: initial timeout %d sec\n",
+ omap_readl(wdev->base + OMAP_WATCHDOG_REV) & 0xFF,
+ timer_margin);
/* autogate OCP interface clock */
- omap_writel(0x01, OMAP_WATCHDOG_SYS_CONFIG);
+ omap_writel(0x01, wdev->base + OMAP_WATCHDOG_SYS_CONFIG);
+
+ omap_wdt_dev = pdev;
+
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);
+ if (wdev) {
+ platform_set_drvdata(pdev, NULL);
+ if (wdev->armwdt_ck)
+ clk_put(wdev->armwdt_ck);
+ if (wdev->mpu_wdt_ick)
+ clk_put(wdev->mpu_wdt_ick);
+ if (wdev->mpu_wdt_fck)
+ clk_put(wdev->mpu_wdt_fck);
+ kfree(wdev);
+ }
+ if (mem) {
+ release_resource(mem);
+ }
return ret;
}
static void omap_wdt_shutdown(struct platform_device *pdev)
{
- omap_wdt_disable();
+ struct omap_wdt_dev *wdev;
+ wdev = platform_get_drvdata(pdev);
+
+ if (wdev->omap_wdt_users)
+ omap_wdt_disable(wdev);
}
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);
+ struct omap_wdt_dev *wdev;
+ wdev = platform_get_drvdata(pdev);
+
+ misc_deregister(&(wdev->omap_wdt_miscdev));
+ release_resource(wdev->mem);
+ platform_set_drvdata(pdev, NULL);
+ if (wdev->armwdt_ck) {
+ clk_put(wdev->armwdt_ck);
+ wdev->armwdt_ck = NULL;
+ }
+ if (wdev->mpu_wdt_ick) {
+ clk_put(wdev->mpu_wdt_ick);
+ wdev->mpu_wdt_ick = NULL;
+ }
+ if (wdev->mpu_wdt_fck) {
+ clk_put(wdev->mpu_wdt_fck);
+ wdev->mpu_wdt_fck = NULL;
+ }
+ kfree(wdev);
+ omap_wdt_dev = NULL;
return 0;
}
static int omap_wdt_suspend(struct platform_device *pdev, pm_message_t state)
{
- if (omap_wdt_users)
- omap_wdt_disable();
+ struct omap_wdt_dev *wdev;
+ wdev = platform_get_drvdata(pdev);
+ if (wdev->omap_wdt_users)
+ omap_wdt_disable(wdev);
return 0;
}
static int omap_wdt_resume(struct platform_device *pdev)
{
- if (omap_wdt_users) {
- omap_wdt_enable();
- omap_wdt_ping();
+ struct omap_wdt_dev *wdev;
+ wdev = platform_get_drvdata(pdev);
+ if (wdev->omap_wdt_users) {
+ omap_wdt_enable(wdev);
+ omap_wdt_ping(wdev);
}
return 0;
}
#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)
+#define OMAP_WATCHDOG_REV (0x00)
+#define OMAP_WATCHDOG_SYS_CONFIG (0x10)
+#define OMAP_WATCHDOG_STATUS (0x14)
+#define OMAP_WATCHDOG_CNTRL (0x24)
+#define OMAP_WATCHDOG_CRR (0x28)
+#define OMAP_WATCHDOG_LDR (0x2c)
+#define OMAP_WATCHDOG_TGR (0x30)
+#define OMAP_WATCHDOG_WPS (0x34)
+#define OMAP_WATCHDOG_SPR (0x48)
/* Using the prescaler, the OMAP watchdog could go for many
* months before firing. These limits work without scaling,
arch
+asm-offsets.h
mach-types.h
--- /dev/null
+/*
+ * linux/include/asm-arm/arch-omap/board-2430osk.h
+ *
+ * Hardware definitions for TI OMAP2430 OSK board.
+ *
+ * Based on board-2330sdp.h
+ *
+ * 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_2430OSK_H
+#define __ASM_ARCH_OMAP_2430OSK_H
+
+/* Placeholder for 2430OSK specific defines */
+#define OMAP24XX_ETHR_START 0x08000300
+#define OMAP24XX_ETHR_GPIO_IRQ 149
+
+#endif /* __ASM_ARCH_OMAP_2430OSK_H */
#define __ASM_ARCH_OMAP_2430SDP_H
/* Placeholder for 2430SDP specific defines */
-#define OMAP24XX_ETHR_START 0x08000300
+#define OMAP24XX_ETHR_START 0x08000300
#define OMAP24XX_ETHR_GPIO_IRQ 149
#define SDP2430_CS0_BASE 0x04000000
-#define TWL4030_IRQNUM INT_24XX_SYS_NIRQ
-
-/* TWL4030 Primary Interrupt Handler (PIH) interrupts */
-#define IH_TWL4030_BASE IH_BOARD_BASE
-#define IH_TWL4030_END (IH_TWL4030_BASE+8)
-#define NR_IRQS (IH_TWL4030_END)
+/* Function prototypes */
+extern void sdp2430_flash_init(void);
+extern void sdp2430_usb_init(void);
#endif /* __ASM_ARCH_OMAP_2430SDP_H */
--- /dev/null
+/*
+ * linux/include/asm-arm/arch-omap/board-3430sdp.h
+ *
+ * Hardware definitions for TI OMAP3430 SDP board.
+ *
+ * Initial creation by Syed Mohammed Khasim
+ *
+ * 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_3430SDP_H
+#define __ASM_ARCH_OMAP_3430SDP_H
+
+extern void sdp3430_usb_init(void);
+
+#define DEBUG_BASE 0x08000000 /* debug board */
+
+/* Placeholder for 3430SDP specific defines */
+
+#define OMAP34XX_ETHR_START DEBUG_BASE
+#define OMAP34XX_ETHR_GPIO_IRQ_SDPV1 29
+#define OMAP34XX_ETHR_GPIO_IRQ_SDPV2 6
+
+/*
+ * GPIO used for TSC2046, TI's Touchscreen controller
+ */
+#define OMAP34XX_TS_GPIO_IRQ_SDPV1 3
+#define OMAP34XX_TS_GPIO_IRQ_SDPV2 2
+
+/* NAND */
+/* IMPORTANT NOTE ON MAPPING
+ * 3430SDP - 34XX
+ * ----------
+ * NOR always on 0x04000000 for SDPV1
+ * NOR always on 0x10000000 for SDPV2
+ * MPDB always on 0x08000000
+ * NAND always on 0x0C000000
+ * OneNand Mapped to 0x20000000
+ * Boot Mode(NAND/NOR). The other on CS1
+ */
+#define FLASH_BASE_SDPV1 0x04000000 /* NOR flash (64 Meg aligned) */
+#define FLASH_BASE_SDPV2 0x10000000 /* NOR flash (256 Meg aligned) */
+#define DEBUG_BASE 0x08000000 /* debug board */
+#define NAND_BASE 0x0C000000 /* NAND flash */
+#define ONENAND_MAP 0x20000000 /* OneNand flash */
+
+/* various memory sizes */
+#define FLASH_SIZE_SDPV1 SZ_64M
+#define FLASH_SIZE_SDPV2 SZ_128M
+
+#endif /* __ASM_ARCH_OMAP_3430SDP_H */
+
extern void apollon_mmc_init(void);
+static inline int apollon_plus(void)
+{
+ /* The apollon plus has IDCODE revision 5 */
+ return system_rev & 0xc0;
+}
+
/* Placeholder for APOLLON specific defines */
#define APOLLON_ETHR_GPIO_IRQ 74
/* In OMAP1710 H3 the Ethernet is directly connected to CS1 */
#define OMAP1710_ETHR_START 0x04000300
-#define MAXIRQNUM (IH_BOARD_BASE)
-#define MAXFIQNUM MAXIRQNUM
-#define MAXSWINUM MAXIRQNUM
-
-#define NR_IRQS (MAXIRQNUM + 1)
-
extern void h3_mmc_init(void);
extern void h3_mmc_slot_cover_handler(void *arg, int state);
/*
* linux/include/asm-arm/arch-omap/board-h4.h
*
- * Hardware definitions for TI OMAP1610 H4 board.
+ * Hardware definitions for TI OMAP2420 H4 board.
*
* Initial creation by Dirk Behme <dirk.behme@de.bosch.com>
*
#ifndef __ASM_ARCH_OMAP_H4_H
#define __ASM_ARCH_OMAP_H4_H
+/* MMC Prototypes */
+extern void h4_mmc_init(void);
+
/* Placeholder for H4 specific defines */
#define OMAP24XX_ETHR_GPIO_IRQ 92
#endif /* __ASM_ARCH_OMAP_H4_H */
#define OMAP1510P1_EMIFS_PRI_VALUE 0x00
#define OMAP1510P1_EMIFF_PRI_VALUE 0x00
-#define NR_FPGA_IRQS 24
-#define NR_IRQS (IH_BOARD_BASE + NR_FPGA_IRQS)
-
#ifndef __ASSEMBLY__
void fpga_write(unsigned char val, int reg);
unsigned char fpga_read(int reg);
* Copyright (C) 2005 Nokia Corporation
*/
-#ifndef _OMAP_BOARD_NOKIA_H
-#define _OMAP_BOARD_NOKIA_H
+#ifndef __ASM_ARCH_OMAP_NOKIA_H
+#define __ASM_ARCH_OMAP_NOKIA_H
#include <linux/types.h>
+struct tsc2301_platform_data;
+struct dsp_kfunc_device;
+extern void n800_bt_init(void);
+extern void n800_dsp_init(void);
+extern void n800_flash_init(void);
+extern void n800_mmc_init(void);
+extern void n800_pm_init(void);
+extern void n800_usb_init(void);
+extern void n800_cam_init(void);
+extern void n800_audio_init(struct tsc2301_platform_data *);
+extern int n800_audio_enable(struct dsp_kfunc_device *kdev, int stage);
+extern int n800_audio_disable(struct dsp_kfunc_device *kdev, int stage);
+extern void n800_mmc_slot1_cover_handler(void *arg, int state);
+
#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
--- /dev/null
+/*
+ * linux/include/asm-arm/arch-omap/board-omap3beagle.h
+ *
+ * Hardware definitions for TI OMAP3 BEAGLE.
+ *
+ * Initial creation by Syed Mohammed Khasim <khasim@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 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_OMAP3_BEAGLE_H
+#define __ASM_ARCH_OMAP3_BEAGLE_H
+
+#endif /* __ASM_ARCH_OMAP3_BEAGLE_H */
+
--- /dev/null
+/*
+ * linux/include/asm-arm/arch-omap/board-omap3evm.h
+ *
+ * Hardware definitions for TI OMAP3 EVM.
+ *
+ * Initial creation by Syed Mohammed Khasim <khasim@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 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_OMAP3_EVM_H
+#define __ASM_ARCH_OMAP3_EVM_H
+
+extern void omap3evm_flash_init(void);
+
+#define OMAP3_EVM_TS_GPIO 175
+#define ONENAND_MAP 0x20000000
+
+#endif /* __ASM_ARCH_OMAP3_EVM_H */
+
#define OMAP_SDRAM_DEVICE D256M_1X16_4B
#endif
-#define MAXIRQNUM IH_BOARD_BASE
-#define MAXFIQNUM MAXIRQNUM
-#define MAXSWINUM MAXIRQNUM
-
-#define NR_IRQS (MAXIRQNUM + 1)
-
#endif
#define OMAP_TAG_FBMEM 0x4f08
#define OMAP_TAG_STI_CONSOLE 0x4f09
#define OMAP_TAG_CAMERA_SENSOR 0x4f0a
+#define OMAP_TAG_PARTITION 0x4f0b
+#define OMAP_TAG_TEA5761 0x4f10
+#define OMAP_TAG_TMP105 0x4f11
#define OMAP_TAG_BOOT_REASON 0x4f80
-#define OMAP_TAG_FLASH_PART 0x4f81
+#define OMAP_TAG_FLASH_PART_STR 0x4f81
#define OMAP_TAG_VERSION_STR 0x4f82
struct omap_clock_config {
unsigned cover:1;
/* 4 wire signaling is optional, and is only used for SD/SDIO */
unsigned wire4:1;
+ /* use the internal clock */
+ unsigned internal_clock:1;
s16 power_pin;
s16 switch_pin;
s16 wp_pin;
u8 channel;
};
-struct omap_camera_sensor_config {
- u16 reset_gpio;
- int (*power_on)(void * data);
- int (*power_off)(void * data);
-};
-
struct omap_usb_config {
/* Configure drivers according to the connectors on your board:
* - "A" connector (rectagular)
unsigned int enabled_uarts;
};
+struct omap_tea5761_config {
+ u16 enable_gpio;
+};
+
+/* This cannot be passed from the bootloader */
+struct omap_tmp105_config {
+ u16 tmp105_irq_pin;
+ int (* set_power)(int enable);
+};
-struct omap_flash_part_config {
+struct omap_partition_config {
+ char name[16];
+ unsigned int size;
+ unsigned int offset;
+ /* same as in include/linux/mtd/partitions.h */
+ unsigned int mask_flags;
+};
+
+struct omap_flash_part_str_config {
char part_table[0];
};
char version[12];
};
-
-#include <asm-arm/arch-omap/board-nokia.h>
-
struct omap_board_config_entry {
u16 tag;
u16 len;
* published by the Free Software Foundation.
*/
+#include <linux/cpufreq.h>
+
#ifndef __ARCH_ARM_OMAP_CLOCK_H
#define __ARCH_ARM_OMAP_CLOCK_H
+#include <asm/arch/clockdomain.h>
+
struct module;
struct clk;
void __iomem *mult_div1_reg;
u32 mult_mask;
u32 div1_mask;
+ u16 last_rounded_m;
+ u8 last_rounded_n;
+ unsigned long last_rounded_rate;
+ unsigned int rate_tolerance;
+ u16 max_multiplier;
+ u8 max_divider;
+ u32 max_tolerance;
# if defined(CONFIG_ARCH_OMAP3)
+ u32 freqsel_mask;
+ u8 modes;
void __iomem *control_reg;
u32 enable_mask;
u8 auto_recal_bit;
u8 recal_en_bit;
u8 recal_st_bit;
+ void __iomem *autoidle_reg;
+ u32 autoidle_mask;
+ void __iomem *idlest_reg;
+ u8 idlest_bit;
# endif
};
void __iomem *clksel_reg;
u32 clksel_mask;
const struct clksel *clksel;
- const struct dpll_data *dpll_data;
+ struct dpll_data *dpll_data;
+ const char *clkdm_name;
+ struct clockdomain *clkdm;
#else
__u8 rate_offset;
__u8 src_offset;
#endif
+#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS)
+ struct dentry *dent; /* For visible tree hierarchy */
+#endif
};
struct clk_functions {
void (*clk_allow_idle)(struct clk *clk);
void (*clk_deny_idle)(struct clk *clk);
void (*clk_disable_unused)(struct clk *clk);
+#ifdef CONFIG_CPU_FREQ
+ void (*clk_init_cpufreq_table)(struct cpufreq_frequency_table **table);
+#endif
};
extern unsigned int mpurate;
extern void clk_deny_idle(struct clk *clk);
extern int clk_get_usecount(struct clk *clk);
extern void clk_enable_init_clocks(void);
+#ifdef CONFIG_CPU_FREQ
+extern void clk_init_cpufreq_table(struct cpufreq_frequency_table **table);
+#endif
/* Clock flags */
#define RATE_CKCTL (1 << 0) /* Main fixed ratio clocks */
--- /dev/null
+/*
+ * linux/include/asm-arm/arch-omap/clockdomain.h
+ *
+ * OMAP2/3 clockdomain framework functions
+ *
+ * Copyright (C) 2008 Texas Instruments, Inc.
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Written by Paul Walmsley
+ *
+ * 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_ARM_ARCH_OMAP_CLOCKDOMAIN_H
+#define __ASM_ARM_ARCH_OMAP_CLOCKDOMAIN_H
+
+#include <asm/arch/powerdomain.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/cpu.h>
+
+/* Clockdomain capability flags */
+#define CLKDM_CAN_FORCE_SLEEP (1 << 0)
+#define CLKDM_CAN_FORCE_WAKEUP (1 << 1)
+#define CLKDM_CAN_ENABLE_AUTO (1 << 2)
+#define CLKDM_CAN_DISABLE_AUTO (1 << 3)
+
+#define CLKDM_CAN_HWSUP (CLKDM_CAN_ENABLE_AUTO | CLKDM_CAN_DISABLE_AUTO)
+#define CLKDM_CAN_SWSUP (CLKDM_CAN_FORCE_SLEEP | CLKDM_CAN_FORCE_WAKEUP)
+#define CLKDM_CAN_HWSUP_SWSUP (CLKDM_CAN_SWSUP | CLKDM_CAN_HWSUP)
+
+/* OMAP24XX CM_CLKSTCTRL_*.AUTOSTATE_* register bit values */
+#define OMAP24XX_CLKSTCTRL_DISABLE_AUTO 0x0
+#define OMAP24XX_CLKSTCTRL_ENABLE_AUTO 0x1
+
+/* OMAP3XXX CM_CLKSTCTRL_*.CLKTRCTRL_* register bit values */
+#define OMAP34XX_CLKSTCTRL_DISABLE_AUTO 0x0
+#define OMAP34XX_CLKSTCTRL_FORCE_SLEEP 0x1
+#define OMAP34XX_CLKSTCTRL_FORCE_WAKEUP 0x2
+#define OMAP34XX_CLKSTCTRL_ENABLE_AUTO 0x3
+
+/*
+ * struct clkdm_pwrdm_autodep - a powerdomain that should have wkdeps
+ * and sleepdeps added when a powerdomain should stay active in hwsup mode;
+ * and conversely, removed when the powerdomain should be allowed to go
+ * inactive in hwsup mode.
+ */
+struct clkdm_pwrdm_autodep {
+
+ /* Name of the powerdomain to add a wkdep/sleepdep on */
+ const char *pwrdm_name;
+
+ /* Powerdomain pointer (looked up at clkdm_init() time) */
+ struct powerdomain *pwrdm;
+
+ /* OMAP chip types that this clockdomain dep is valid on */
+ const struct omap_chip_id omap_chip;
+
+};
+
+struct clockdomain {
+
+ /* Clockdomain name */
+ const char *name;
+
+ /* Powerdomain enclosing this clockdomain */
+ const char *pwrdm_name;
+
+ /* CLKTRCTRL/AUTOSTATE field mask in CM_CLKSTCTRL reg */
+ const u16 clktrctrl_mask;
+
+ /* Clockdomain capability flags */
+ const u8 flags;
+
+ /* OMAP chip types that this clockdomain is valid on */
+ const struct omap_chip_id omap_chip;
+
+ /* Usecount tracking */
+ atomic_t usecount;
+
+ /* Powerdomain pointer assigned at clkdm_register() */
+ struct powerdomain *pwrdm;
+
+ struct list_head node;
+
+};
+
+void clkdm_init(struct clockdomain **clkdms, struct clkdm_pwrdm_autodep *autodeps);
+int clkdm_register(struct clockdomain *clkdm);
+int clkdm_unregister(struct clockdomain *clkdm);
+struct clockdomain *clkdm_lookup(const char *name);
+
+void omap2_clkdm_allow_idle(struct clockdomain *clkdm);
+void omap2_clkdm_deny_idle(struct clockdomain *clkdm);
+
+int omap2_clkdm_wakeup(struct clockdomain *clkdm);
+int omap2_clkdm_sleep(struct clockdomain *clkdm);
+
+int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk);
+int omap2_clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk);
+
+int clkdm_for_each(int (*fn)(struct clockdomain *clkdm));
+
+#endif
extern void omap_map_common_io(void);
extern struct sys_timer omap_timer;
extern void omap_serial_init(void);
+extern void omap_serial_enable_clocks(int enable);
#ifdef CONFIG_I2C_OMAP
extern int omap_register_i2c_bus(int bus_id, u32 clkrate,
struct i2c_board_info const *info,
}
#endif
+void omap2_set_globals_242x(void);
+void omap2_set_globals_243x(void);
+void omap2_set_globals_343x(void);
+
#endif /* __ARCH_ARM_MACH_OMAP_COMMON_H */
*
* OMAP cpu type detection
*
- * Copyright (C) 2004 Nokia Corporation
+ * Copyright (C) 2004, 2008 Nokia Corporation
*
* Written by Tony Lindgren <tony.lindgren@nokia.com>
*
#ifndef __ASM_ARCH_OMAP_CPU_H
#define __ASM_ARCH_OMAP_CPU_H
+struct omap_chip_id {
+ u8 oc;
+};
+
+#define OMAP_CHIP_INIT(x) { .oc = x }
+
extern unsigned int system_rev;
#define omap2_cpu_rev() ((system_rev >> 12) & 0x0f)
#define OMAP2430_REV_ES1_0 0x24300000
#define OMAP3430_REV_ES1_0 0x34300000
#define OMAP3430_REV_ES2_0 0x34301000
+#define OMAP3430_REV_ES2_1 0x34302000
+#define OMAP3430_REV_ES2_2 0x34303000
+
+/*
+ * omap_chip bits
+ *
+ * CHIP_IS_OMAP{2420,2430,3430} indicate that a particular structure is
+ * valid on all chips of that type. CHIP_IS_OMAP3430ES{1,2} indicates
+ * something that is only valid on that particular ES revision.
+ *
+ * These bits may be ORed together to indicate structures that are
+ * available on multiple chip types.
+ *
+ * To test whether a particular structure matches the current OMAP chip type,
+ * use omap_chip_is().
+ *
+ */
+#define CHIP_IS_OMAP2420 (1 << 0)
+#define CHIP_IS_OMAP2430 (1 << 1)
+#define CHIP_IS_OMAP3430 (1 << 2)
+#define CHIP_IS_OMAP3430ES1 (1 << 3)
+#define CHIP_IS_OMAP3430ES2 (1 << 4)
+
+#define CHIP_IS_OMAP24XX (CHIP_IS_OMAP2420 | CHIP_IS_OMAP2430)
+
+int omap_chip_is(struct omap_chip_id oci);
+
/*
* Macro to detect device type i.e. EMU/HS/TST/GP/BAD
#ifdef CONFIG_OMAP_LL_DEBUG_UART3
add \rx, \rx, #0x00004000 @ UART 3
#endif
+
+#elif CONFIG_ARCH_OMAP3
+ moveq \rx, #0x48000000 @ physical base address
+ movne \rx, #0xd8000000 @ virtual base
+ orr \rx, \rx, #0x0006a000
+#ifdef CONFIG_OMAP_LL_DEBUG_UART2
+ add \rx, \rx, #0x00002000 @ UART 2
+#endif
+#ifdef CONFIG_OMAP_LL_DEBUG_UART3
+ add \rx, \rx, #0x00fb0000 @ UART 3
+ add \rx, \rx, #0x00006000
+#endif
#endif
.endm
/* DMA channels for 24xx */
#define OMAP24XX_DMA_NO_DEVICE 0
+
#define OMAP24XX_DMA_XTI_DMA 1 /* S_DMA_0 */
#define OMAP24XX_DMA_EXT_DMAREQ0 2 /* S_DMA_1 */
#define OMAP24XX_DMA_EXT_DMAREQ1 3 /* S_DMA_2 */
#define OMAP24XX_DMA_GPMC 4 /* S_DMA_3 */
#define OMAP24XX_DMA_GFX 5 /* S_DMA_4 */
#define OMAP24XX_DMA_DSS 6 /* S_DMA_5 */
-#define OMAP24XX_DMA_VLYNQ_TX 7 /* S_DMA_6 */
+#define OMAP242X_DMA_VLYNQ_TX 7 /* S_DMA_6 */
+#define OMAP24XX_DMA_EXT_DMAREQ2 7 /* S_DMA_6 */
#define OMAP24XX_DMA_CWT 8 /* S_DMA_7 */
#define OMAP24XX_DMA_AES_TX 9 /* S_DMA_8 */
#define OMAP24XX_DMA_AES_RX 10 /* S_DMA_9 */
#define OMAP24XX_DMA_DES_TX 11 /* S_DMA_10 */
#define OMAP24XX_DMA_DES_RX 12 /* S_DMA_11 */
#define OMAP24XX_DMA_SHA1MD5_RX 13 /* S_DMA_12 */
-#define OMAP24XX_DMA_EXT_DMAREQ2 14 /* S_DMA_13 */
-#define OMAP24XX_DMA_EXT_DMAREQ3 15 /* S_DMA_14 */
-#define OMAP24XX_DMA_EXT_DMAREQ4 16 /* S_DMA_15 */
-#define OMAP24XX_DMA_EAC_AC_RD 17 /* S_DMA_16 */
-#define OMAP24XX_DMA_EAC_AC_WR 18 /* S_DMA_17 */
-#define OMAP24XX_DMA_EAC_MD_UL_RD 19 /* S_DMA_18 */
-#define OMAP24XX_DMA_EAC_MD_UL_WR 20 /* S_DMA_19 */
-#define OMAP24XX_DMA_EAC_MD_DL_RD 21 /* S_DMA_20 */
-#define OMAP24XX_DMA_EAC_MD_DL_WR 22 /* S_DMA_21 */
-#define OMAP24XX_DMA_EAC_BT_UL_RD 23 /* S_DMA_22 */
-#define OMAP24XX_DMA_EAC_BT_UL_WR 24 /* S_DMA_23 */
-#define OMAP24XX_DMA_EAC_BT_DL_RD 25 /* S_DMA_24 */
-#define OMAP24XX_DMA_EAC_BT_DL_WR 26 /* S_DMA_25 */
+#define OMAP34XX_DMA_SHA2MD5_RX 13 /* S_DMA_12 */
+#define OMAP242X_DMA_EXT_DMAREQ2 14 /* S_DMA_13 */
+#define OMAP242X_DMA_EXT_DMAREQ3 15 /* S_DMA_14 */
+#define OMAP242X_DMA_EXT_DMAREQ4 16 /* S_DMA_15 */
+#define OMAP242X_DMA_EAC_AC_RD 17 /* S_DMA_16 */
+#define OMAP242X_DMA_EAC_AC_WR 18 /* S_DMA_17 */
+#define OMAP242X_DMA_EAC_MD_UL_RD 19 /* S_DMA_18 */
+#define OMAP242X_DMA_EAC_MD_UL_WR 20 /* S_DMA_19 */
+#define OMAP242X_DMA_EAC_MD_DL_RD 21 /* S_DMA_20 */
+#define OMAP242X_DMA_EAC_MD_DL_WR 22 /* S_DMA_21 */
+#define OMAP242X_DMA_EAC_BT_UL_RD 23 /* S_DMA_22 */
+#define OMAP242X_DMA_EAC_BT_UL_WR 24 /* S_DMA_23 */
+#define OMAP242X_DMA_EAC_BT_DL_RD 25 /* S_DMA_24 */
+#define OMAP242X_DMA_EAC_BT_DL_WR 26 /* S_DMA_25 */
+#define OMAP243X_DMA_EXT_DMAREQ3 14 /* S_DMA_13 */
+#define OMAP24XX_DMA_SPI3_TX0 15 /* S_DMA_14 */
+#define OMAP24XX_DMA_SPI3_RX0 16 /* S_DMA_15 */
+#define OMAP24XX_DMA_MCBSP3_TX 17 /* S_DMA_16 */
+#define OMAP24XX_DMA_MCBSP3_RX 18 /* S_DMA_17 */
+#define OMAP24XX_DMA_MCBSP4_TX 19 /* S_DMA_18 */
+#define OMAP24XX_DMA_MCBSP4_RX 20 /* S_DMA_19 */
+#define OMAP24XX_DMA_MCBSP5_TX 21 /* S_DMA_20 */
+#define OMAP24XX_DMA_MCBSP5_RX 22 /* S_DMA_21 */
+#define OMAP24XX_DMA_SPI3_TX1 23 /* S_DMA_22 */
+#define OMAP24XX_DMA_SPI3_RX1 24 /* S_DMA_23 */
+#define OMAP243X_DMA_EXT_DMAREQ4 25 /* S_DMA_24 */
+#define OMAP243X_DMA_EXT_DMAREQ5 26 /* S_DMA_25 */
+#define OMAP34XX_DMA_I2C3_TX 25 /* S_DMA_24 */
+#define OMAP34XX_DMA_I2C3_RX 26 /* S_DMA_25 */
#define OMAP24XX_DMA_I2C1_TX 27 /* S_DMA_26 */
#define OMAP24XX_DMA_I2C1_RX 28 /* S_DMA_27 */
#define OMAP24XX_DMA_I2C2_TX 29 /* S_DMA_28 */
#define OMAP24XX_DMA_I2C2_RX 30 /* S_DMA_29 */
-#define OMAP24XX_DMA_MCBSP1_TX 31 /* SDMA_30 */
-#define OMAP24XX_DMA_MCBSP1_RX 32 /* SDMA_31 */
-#define OMAP24XX_DMA_MCBSP2_TX 33 /* SDMA_32 */
-#define OMAP24XX_DMA_MCBSP2_RX 34 /* SDMA_33 */
-#define OMAP24XX_DMA_SPI1_TX0 35 /* SDMA_34 */
-#define OMAP24XX_DMA_SPI1_RX0 36 /* SDMA_35 */
-#define OMAP24XX_DMA_SPI1_TX1 37 /* SDMA_36 */
-#define OMAP24XX_DMA_SPI1_RX1 38 /* SDMA_37 */
-#define OMAP24XX_DMA_SPI1_TX2 39 /* SDMA_38 */
-#define OMAP24XX_DMA_SPI1_RX2 40 /* SDMA_39 */
-#define OMAP24XX_DMA_SPI1_TX3 41 /* SDMA_40 */
-#define OMAP24XX_DMA_SPI1_RX3 42 /* SDMA_41 */
-#define OMAP24XX_DMA_SPI2_TX0 43 /* SDMA_42 */
-#define OMAP24XX_DMA_SPI2_RX0 44 /* SDMA_43 */
-#define OMAP24XX_DMA_SPI2_TX1 45 /* SDMA_44 */
-#define OMAP24XX_DMA_SPI2_RX1 46 /* SDMA_45 */
-
-#define OMAP24XX_DMA_UART1_TX 49 /* SDMA_48 */
-#define OMAP24XX_DMA_UART1_RX 50 /* SDMA_49 */
-#define OMAP24XX_DMA_UART2_TX 51 /* SDMA_50 */
-#define OMAP24XX_DMA_UART2_RX 52 /* SDMA_51 */
-#define OMAP24XX_DMA_UART3_TX 53 /* SDMA_52 */
-#define OMAP24XX_DMA_UART3_RX 54 /* SDMA_53 */
-#define OMAP24XX_DMA_USB_W2FC_TX0 55 /* SDMA_54 */
-#define OMAP24XX_DMA_USB_W2FC_RX0 56 /* SDMA_55 */
-#define OMAP24XX_DMA_USB_W2FC_TX1 57 /* SDMA_56 */
-#define OMAP24XX_DMA_USB_W2FC_RX1 58 /* SDMA_57 */
-#define OMAP24XX_DMA_USB_W2FC_TX2 59 /* SDMA_58 */
-#define OMAP24XX_DMA_USB_W2FC_RX2 60 /* SDMA_59 */
-#define OMAP24XX_DMA_MMC1_TX 61 /* SDMA_60 */
-#define OMAP24XX_DMA_MMC1_RX 62 /* SDMA_61 */
-#define OMAP24XX_DMA_MS 63 /* SDMA_62 */
-#define OMAP24XX_DMA_EXT_DMAREQ5 64 /* S_DMA_63 */
+#define OMAP24XX_DMA_MCBSP1_TX 31 /* S_DMA_30 */
+#define OMAP24XX_DMA_MCBSP1_RX 32 /* S_DMA_31 */
+#define OMAP24XX_DMA_MCBSP2_TX 33 /* S_DMA_32 */
+#define OMAP24XX_DMA_MCBSP2_RX 34 /* S_DMA_33 */
+#define OMAP24XX_DMA_SPI1_TX0 35 /* S_DMA_34 */
+#define OMAP24XX_DMA_SPI1_RX0 36 /* S_DMA_35 */
+#define OMAP24XX_DMA_SPI1_TX1 37 /* S_DMA_36 */
+#define OMAP24XX_DMA_SPI1_RX1 38 /* S_DMA_37 */
+#define OMAP24XX_DMA_SPI1_TX2 39 /* S_DMA_38 */
+#define OMAP24XX_DMA_SPI1_RX2 40 /* S_DMA_39 */
+#define OMAP24XX_DMA_SPI1_TX3 41 /* S_DMA_40 */
+#define OMAP24XX_DMA_SPI1_RX3 42 /* S_DMA_41 */
+#define OMAP24XX_DMA_SPI2_TX0 43 /* S_DMA_42 */
+#define OMAP24XX_DMA_SPI2_RX0 44 /* S_DMA_43 */
+#define OMAP24XX_DMA_SPI2_TX1 45 /* S_DMA_44 */
+#define OMAP24XX_DMA_SPI2_RX1 46 /* S_DMA_45 */
+#define OMAP24XX_DMA_MMC2_TX 47 /* S_DMA_46 */
+#define OMAP24XX_DMA_MMC2_RX 48 /* S_DMA_47 */
+#define OMAP24XX_DMA_UART1_TX 49 /* S_DMA_48 */
+#define OMAP24XX_DMA_UART1_RX 50 /* S_DMA_49 */
+#define OMAP24XX_DMA_UART2_TX 51 /* S_DMA_50 */
+#define OMAP24XX_DMA_UART2_RX 52 /* S_DMA_51 */
+#define OMAP24XX_DMA_UART3_TX 53 /* S_DMA_52 */
+#define OMAP24XX_DMA_UART3_RX 54 /* S_DMA_53 */
+#define OMAP24XX_DMA_USB_W2FC_TX0 55 /* S_DMA_54 */
+#define OMAP24XX_DMA_USB_W2FC_RX0 56 /* S_DMA_55 */
+#define OMAP24XX_DMA_USB_W2FC_TX1 57 /* S_DMA_56 */
+#define OMAP24XX_DMA_USB_W2FC_RX1 58 /* S_DMA_57 */
+#define OMAP24XX_DMA_USB_W2FC_TX2 59 /* S_DMA_58 */
+#define OMAP24XX_DMA_USB_W2FC_RX2 60 /* S_DMA_59 */
+#define OMAP24XX_DMA_MMC1_TX 61 /* S_DMA_60 */
+#define OMAP24XX_DMA_MMC1_RX 62 /* S_DMA_61 */
+#define OMAP24XX_DMA_MS 63 /* S_DMA_62 */
+#define OMAP242X_DMA_EXT_DMAREQ5 64 /* S_DMA_63 */
+#define OMAP243X_DMA_EXT_DMAREQ6 64 /* S_DMA_63 */
+#define OMAP34XX_DMA_EXT_DMAREQ3 64 /* S_DMA_63 */
+#define OMAP34XX_DMA_AES2_TX 65 /* S_DMA_64 */
+#define OMAP34XX_DMA_AES2_RX 66 /* S_DMA_65 */
+#define OMAP34XX_DMA_DES2_TX 67 /* S_DMA_66 */
+#define OMAP34XX_DMA_DES2_RX 68 /* S_DMA_67 */
+#define OMAP34XX_DMA_SHA1MD5_RX 69 /* S_DMA_68 */
+#define OMAP34XX_DMA_SPI4_TX0 70 /* S_DMA_69 */
+#define OMAP34XX_DMA_SPI4_RX0 71 /* S_DMA_70 */
+#define OMAP34XX_DSS_DMA0 72 /* S_DMA_71 */
+#define OMAP34XX_DSS_DMA1 73 /* S_DMA_72 */
+#define OMAP34XX_DSS_DMA2 74 /* S_DMA_73 */
+#define OMAP34XX_DSS_DMA3 75 /* S_DMA_74 */
+#define OMAP34XX_DMA_MMC3_TX 77 /* S_DMA_76 */
+#define OMAP34XX_DMA_MMC3_RX 78 /* S_DMA_77 */
+#define OMAP34XX_DMA_USIM_TX 79 /* S_DMA_78 */
+#define OMAP34XX_DMA_USIM_RX 80 /* S_DMA_79 */
/*----------------------------------------------------------------------------*/
OMAP_DMA_DATA_BURST_16,
};
+enum end_type {
+ LITTLE_ENDIAN = 0,
+ BIG_ENDIAN
+};
+
enum omap_dma_color_mode {
OMAP_DMA_COLOR_DIS = 0,
OMAP_DMA_CONSTANT_FILL,
int tparams);
extern int omap_dma_set_prio_lch(int lch, unsigned char read_prio,
unsigned char write_prio);
+extern void omap_set_dma_dst_endian_type(int lch, enum end_type etype);
+extern void omap_set_dma_src_endian_type(int lch, enum end_type etype);
+extern int omap_get_dma_index(int lch, int *ei, int *fi);
/* Chaining APIs */
#ifndef CONFIG_ARCH_OMAP1
void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source);
void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload, unsigned int value);
+void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload, unsigned int value);
void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable, unsigned int match);
void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on, int toggle, int trigger);
void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler);
--- /dev/null
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __ARCH_OMAP_DSP_H
+#define __ARCH_OMAP_DSP_H
+
+/*
+ * for /dev/dspctl/ctl
+ */
+#define DSPCTL_IOCTL_RESET 1
+#define DSPCTL_IOCTL_RUN 2
+#define DSPCTL_IOCTL_SETRSTVECT 3
+#ifdef CONFIG_ARCH_OMAP1
+#define DSPCTL_IOCTL_CPU_IDLE 4
+#define DSPCTL_IOCTL_MPUI_WORDSWAP_ON 5
+#define DSPCTL_IOCTL_MPUI_WORDSWAP_OFF 6
+#define DSPCTL_IOCTL_MPUI_BYTESWAP_ON 7
+#define DSPCTL_IOCTL_MPUI_BYTESWAP_OFF 8
+#define DSPCTL_IOCTL_GBL_IDLE 9
+#endif /* CONFIG_ARCH_OMAP1 */
+#define DSPCTL_IOCTL_DSPCFG 10
+#define DSPCTL_IOCTL_DSPUNCFG 11
+#define DSPCTL_IOCTL_TASKCNT 12
+#define DSPCTL_IOCTL_POLL 13
+#define DSPCTL_IOCTL_REGMEMR 40
+#define DSPCTL_IOCTL_REGMEMW 41
+#define DSPCTL_IOCTL_REGIOR 42
+#define DSPCTL_IOCTL_REGIOW 43
+#define DSPCTL_IOCTL_GETVAR 44
+#define DSPCTL_IOCTL_SETVAR 45
+#define DSPCTL_IOCTL_RUNLEVEL 50
+#define DSPCTL_IOCTL_SUSPEND 51
+#define DSPCTL_IOCTL_RESUME 52
+#ifdef CONFIG_OMAP_DSP_FBEXPORT
+#define DSPCTL_IOCTL_FBEN 53
+#define DSPCTL_IOCTL_FBDIS 54
+#endif /* CONFIG_OMAP_DSP_FBEXPORT */
+#define DSPCTL_IOCTL_MBSEND 99
+
+struct omap_dsp_mailbox_cmd {
+ __u16 cmd;
+ __u16 data;
+};
+
+struct omap_dsp_reginfo {
+ __u16 adr;
+ __u16 val;
+};
+
+struct omap_dsp_varinfo {
+ __u8 varid;
+ __u16 val[0];
+};
+
+/*
+ * for taskdev
+ * (ioctls below should be >= 0x10000)
+ */
+#define TASK_IOCTL_BFLSH 0x10000
+#define TASK_IOCTL_SETBSZ 0x10001
+#define TASK_IOCTL_LOCK 0x10002
+#define TASK_IOCTL_UNLOCK 0x10003
+#define TASK_IOCTL_GETNAME 0x10004
+
+/*
+ * for /dev/dspctl/mem
+ */
+#define MEM_IOCTL_EXMAP 1
+#define MEM_IOCTL_EXUNMAP 2
+#define MEM_IOCTL_EXMAP_FLUSH 3
+#define MEM_IOCTL_FBEXPORT 5
+#define MEM_IOCTL_MMUITACK 7
+#define MEM_IOCTL_MMUINIT 9
+#define MEM_IOCTL_KMEM_RESERVE 11
+#define MEM_IOCTL_KMEM_RELEASE 12
+
+struct omap_dsp_mapinfo {
+ __u32 dspadr;
+ __u32 size;
+};
+
+/*
+ * for /dev/dspctl/twch
+ */
+#define TWCH_IOCTL_MKDEV 1
+#define TWCH_IOCTL_RMDEV 2
+#define TWCH_IOCTL_TADD 11
+#define TWCH_IOCTL_TDEL 12
+#define TWCH_IOCTL_TKILL 13
+
+struct omap_dsp_taddinfo {
+ __u8 minor;
+ __u32 taskadr;
+};
+
+#define TADD_ABORTADR 0xffffffff
+
+#endif /* __ARCH_OMAP_DSP_H */
*
* Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
+ * 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_DSP_COMMON_H
#define ASM_ARCH_DSP_COMMON_H
+#include <linux/clk.h>
+
+struct dsp_kfunc_device {
+ char *name;
+ struct clk *fck;
+ struct clk *ick;;
+ spinlock_t lock;
+ int enabled;
+ int type;
+#define DSP_KFUNC_DEV_TYPE_COMMON 1
+#define DSP_KFUNC_DEV_TYPE_AUDIO 2
+
+ struct list_head entry;
+
+ int (*probe)(struct dsp_kfunc_device *, int);
+ int (*remove)(struct dsp_kfunc_device *, int);
+ int (*enable)(struct dsp_kfunc_device *, int);
+ int (*disable)(struct dsp_kfunc_device *, int);
+};
+
+extern int dsp_kfunc_device_register(struct dsp_kfunc_device *);
+
+struct dsp_platform_data {
+ struct list_head kdev_list;
+};
+
+struct omap_dsp {
+ struct mutex lock;
+ int enabled; /* stored peripheral status */
+ struct omap_mmu *mmu;
+ struct omap_mbox *mbox;
+ struct device *dev;
+ struct list_head *kdev_list;
+ int initialized;
+};
+
#if defined(CONFIG_ARCH_OMAP1) && defined(CONFIG_OMAP_MMU_FWK)
extern void omap_dsp_request_mpui(void);
extern void omap_dsp_release_mpui(void);
1510:
.endm
-#elif defined(CONFIG_ARCH_OMAP24XX)
+#endif
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP24XX)
#include <asm/arch/omap24xx.h>
+#endif
+#if defined(CONFIG_ARCH_OMAP34XX)
+#include <asm/arch/omap34xx.h>
+#endif
.macro disable_fiq
.endm
#define OMAP1510_INT_FPGA (IH_GPIO_BASE + 13)
/* IRQ Numbers for interrupts muxed through the FPGA */
-#define OMAP1510_IH_FPGA_BASE IH_BOARD_BASE
-#define OMAP1510_INT_FPGA_ATN (OMAP1510_IH_FPGA_BASE + 0)
-#define OMAP1510_INT_FPGA_ACK (OMAP1510_IH_FPGA_BASE + 1)
-#define OMAP1510_INT_FPGA2 (OMAP1510_IH_FPGA_BASE + 2)
-#define OMAP1510_INT_FPGA3 (OMAP1510_IH_FPGA_BASE + 3)
-#define OMAP1510_INT_FPGA4 (OMAP1510_IH_FPGA_BASE + 4)
-#define OMAP1510_INT_FPGA5 (OMAP1510_IH_FPGA_BASE + 5)
-#define OMAP1510_INT_FPGA6 (OMAP1510_IH_FPGA_BASE + 6)
-#define OMAP1510_INT_FPGA7 (OMAP1510_IH_FPGA_BASE + 7)
-#define OMAP1510_INT_FPGA8 (OMAP1510_IH_FPGA_BASE + 8)
-#define OMAP1510_INT_FPGA9 (OMAP1510_IH_FPGA_BASE + 9)
-#define OMAP1510_INT_FPGA10 (OMAP1510_IH_FPGA_BASE + 10)
-#define OMAP1510_INT_FPGA11 (OMAP1510_IH_FPGA_BASE + 11)
-#define OMAP1510_INT_FPGA12 (OMAP1510_IH_FPGA_BASE + 12)
-#define OMAP1510_INT_ETHER (OMAP1510_IH_FPGA_BASE + 13)
-#define OMAP1510_INT_FPGAUART1 (OMAP1510_IH_FPGA_BASE + 14)
-#define OMAP1510_INT_FPGAUART2 (OMAP1510_IH_FPGA_BASE + 15)
-#define OMAP1510_INT_FPGA_TS (OMAP1510_IH_FPGA_BASE + 16)
-#define OMAP1510_INT_FPGA17 (OMAP1510_IH_FPGA_BASE + 17)
-#define OMAP1510_INT_FPGA_CAM (OMAP1510_IH_FPGA_BASE + 18)
-#define OMAP1510_INT_FPGA_RTC_A (OMAP1510_IH_FPGA_BASE + 19)
-#define OMAP1510_INT_FPGA_RTC_B (OMAP1510_IH_FPGA_BASE + 20)
-#define OMAP1510_INT_FPGA_CD (OMAP1510_IH_FPGA_BASE + 21)
-#define OMAP1510_INT_FPGA22 (OMAP1510_IH_FPGA_BASE + 22)
-#define OMAP1510_INT_FPGA23 (OMAP1510_IH_FPGA_BASE + 23)
+#define OMAP1510_INT_FPGA_ATN (OMAP_FPGA_IRQ_BASE + 0)
+#define OMAP1510_INT_FPGA_ACK (OMAP_FPGA_IRQ_BASE + 1)
+#define OMAP1510_INT_FPGA2 (OMAP_FPGA_IRQ_BASE + 2)
+#define OMAP1510_INT_FPGA3 (OMAP_FPGA_IRQ_BASE + 3)
+#define OMAP1510_INT_FPGA4 (OMAP_FPGA_IRQ_BASE + 4)
+#define OMAP1510_INT_FPGA5 (OMAP_FPGA_IRQ_BASE + 5)
+#define OMAP1510_INT_FPGA6 (OMAP_FPGA_IRQ_BASE + 6)
+#define OMAP1510_INT_FPGA7 (OMAP_FPGA_IRQ_BASE + 7)
+#define OMAP1510_INT_FPGA8 (OMAP_FPGA_IRQ_BASE + 8)
+#define OMAP1510_INT_FPGA9 (OMAP_FPGA_IRQ_BASE + 9)
+#define OMAP1510_INT_FPGA10 (OMAP_FPGA_IRQ_BASE + 10)
+#define OMAP1510_INT_FPGA11 (OMAP_FPGA_IRQ_BASE + 11)
+#define OMAP1510_INT_FPGA12 (OMAP_FPGA_IRQ_BASE + 12)
+#define OMAP1510_INT_ETHER (OMAP_FPGA_IRQ_BASE + 13)
+#define OMAP1510_INT_FPGAUART1 (OMAP_FPGA_IRQ_BASE + 14)
+#define OMAP1510_INT_FPGAUART2 (OMAP_FPGA_IRQ_BASE + 15)
+#define OMAP1510_INT_FPGA_TS (OMAP_FPGA_IRQ_BASE + 16)
+#define OMAP1510_INT_FPGA17 (OMAP_FPGA_IRQ_BASE + 17)
+#define OMAP1510_INT_FPGA_CAM (OMAP_FPGA_IRQ_BASE + 18)
+#define OMAP1510_INT_FPGA_RTC_A (OMAP_FPGA_IRQ_BASE + 19)
+#define OMAP1510_INT_FPGA_RTC_B (OMAP_FPGA_IRQ_BASE + 20)
+#define OMAP1510_INT_FPGA_CD (OMAP_FPGA_IRQ_BASE + 21)
+#define OMAP1510_INT_FPGA22 (OMAP_FPGA_IRQ_BASE + 22)
+#define OMAP1510_INT_FPGA23 (OMAP_FPGA_IRQ_BASE + 23)
#endif
};
/* Call at init time only */
+#ifdef CONFIG_OMAP_GPIO_SWITCH
extern void omap_register_gpio_switches(const struct omap_gpio_switch *tbl,
int count);
+#else
+#define omap_register_gpio_switches(tbl, count) do { } while (0)
+#endif
#endif
extern void omap_set_gpio_direction(int gpio, int is_input);
extern void omap_set_gpio_dataout(int gpio, int enable);
extern int omap_get_gpio_datain(int gpio);
+extern void omap2_gpio_prepare_for_retention(void);
+extern void omap2_gpio_resume_after_retention(void);
extern void omap_set_gpio_debounce(int gpio, int enable);
extern void omap_set_gpio_debounce_time(int gpio, int enable);
#ifndef __OMAP2_GPMC_H
#define __OMAP2_GPMC_H
+/* Maximum Number of Chip Selects */
+#define GPMC_CS_NUM 8
+
#define GPMC_CS_CONFIG1 0x00
#define GPMC_CS_CONFIG2 0x04
#define GPMC_CS_CONFIG3 0x08
#define GPMC_CS_NAND_ADDRESS 0x20
#define GPMC_CS_NAND_DATA 0x24
+#define GPMC_CONFIG 0x50
+#define GPMC_STATUS 0x54
+
#define GPMC_CONFIG1_WRAPBURST_SUPP (1 << 31)
#define GPMC_CONFIG1_READMULTIPLE_SUPP (1 << 30)
#define GPMC_CONFIG1_READTYPE_ASYNC (0 << 29)
};
extern unsigned int gpmc_ns_to_ticks(unsigned int time_ns);
+extern unsigned int gpmc_ticks_to_ns(unsigned int ticks);
extern unsigned int gpmc_round_ns_to_ticks(unsigned int time_ns);
extern unsigned long gpmc_get_fclk_period(void);
#include "omap730.h"
#include "omap1510.h"
-#include "omap24xx.h"
#include "omap16xx.h"
+#include "omap24xx.h"
+#include "omap34xx.h"
#ifndef __ASSEMBLER__
#include "board-h4.h"
#endif
+#if defined(CONFIG_MACH_NOKIA_N800) || defined(CONFIG_MACH_NOKIA770)
+#include "board-nokia.h"
+#endif
+
#ifdef CONFIG_MACH_OMAP_2430SDP
#include "board-2430sdp.h"
#endif
+#ifdef CONFIG_MACH_OMAP_2430OSK
+#include "board-2430osk.h"
+#endif
+
+#ifdef CONFIG_MACH_OMAP_3430SDP
+#include "board-3430sdp.h"
+#endif
+
+#ifdef CONFIG_MACH_OMAP3EVM
+#include "board-omap3evm.h"
+#endif
+
+#ifdef CONFIG_MACH_OMAP3_BEAGLE
+#include "board-omap3beagle.h"
+#endif
+
#ifdef CONFIG_MACH_OMAP_APOLLON
#include "board-apollon.h"
#endif
--- /dev/null
+/*
+ * Copyright 2005 Mentor Graphics Corporation
+ * USB High-Speed Multi-Point Dual-Role Controller Configuration
+ *
+ * Copyright Mentor Graphics Corporation and Licensors 2004
+ * Copyright (C) 2005 by Texas Instruments
+ *
+ * This file contains configuration constants for the (m)hdrc
+ * silicon as integrated into DaVinci CPUs.
+ */
+
+#ifndef __ARCH_MUSB_HDRC_CNF
+#define __ARCH_MUSB_HDRC_CNF
+
+/* ** Number of Tx endpoints ** */
+/* Legal values are 1 - 16 (this value includes EP0) */
+#define MUSB_C_NUM_EPT 8
+
+/* ** Number of Rx endpoints ** */
+/* Legal values are 1 - 16 (this value includes EP0) */
+#define MUSB_C_NUM_EPR 8
+
+/* ** Endpoint 1 to 15 direction types ** */
+/* C_EP1_DEF is defined if either Tx endpoint 1 or Rx endpoint 1 are used */
+#define MUSB_C_EP1_DEF
+
+/* C_EP1_TX_DEF is defined if Tx endpoint 1 is used */
+#define MUSB_C_EP1_TX_DEF
+
+/* C_EP1_RX_DEF is defined if Rx endpoint 1 is used */
+#define MUSB_C_EP1_RX_DEF
+
+/* C_EP1_TOR_DEF is defined if Tx endpoint 1 and Rx endpoint 1 share a FIFO */
+/*`define C_EP1_TOR_DEF */
+
+/* C_EP1_TAR_DEF is defined if both Tx endpoint 1 and Rx endpoint 1 are used */
+/* and do not share a FIFO */
+#define MUSB_C_EP1_TAR_DEF
+
+/* Similarly for all other used endpoints */
+#define MUSB_C_EP2_DEF
+#define MUSB_C_EP2_TX_DEF
+#define MUSB_C_EP2_RX_DEF
+#define MUSB_C_EP2_TAR_DEF
+#define MUSB_C_EP3_DEF
+#define MUSB_C_EP3_TX_DEF
+#define MUSB_C_EP3_RX_DEF
+#define MUSB_C_EP3_TAR_DEF
+#define MUSB_C_EP4_DEF
+#define MUSB_C_EP4_TX_DEF
+#define MUSB_C_EP4_RX_DEF
+#define MUSB_C_EP4_TAR_DEF
+#define MUSB_C_EP5_DEF
+#define MUSB_C_EP5_TX_DEF
+#define MUSB_C_EP5_RX_DEF
+#define MUSB_C_EP5_TAR_DEF
+#define MUSB_C_EP6_DEF
+#define MUSB_C_EP6_TX_DEF
+#define MUSB_C_EP6_RX_DEF
+#define MUSB_C_EP6_TAR_DEF
+#define MUSB_C_EP7_DEF
+#define MUSB_C_EP7_TX_DEF
+#define MUSB_C_EP7_RX_DEF
+#define MUSB_C_EP7_TAR_DEF
+
+/* ** Endpoint 1 to 15 FIFO address bits ** */
+/* Legal values are 3 to 13 - corresponding to FIFO sizes of 8 to 8192 bytes. */
+/* If an Tx endpoint shares a FIFO with an Rx endpoint then the Rx FIFO size */
+/* must be the same as the Tx FIFO size. */
+/* All endpoints 1 to 15 must be defined, unused endpoints should be set to 2. */
+#define MUSB_C_EP1T_BITS 10
+#define MUSB_C_EP1R_BITS 10
+#define MUSB_C_EP2T_BITS 9
+#define MUSB_C_EP2R_BITS 9
+#define MUSB_C_EP3T_BITS 3
+#define MUSB_C_EP3R_BITS 3
+#define MUSB_C_EP4T_BITS 3
+#define MUSB_C_EP4R_BITS 3
+#define MUSB_C_EP5T_BITS 3
+#define MUSB_C_EP5R_BITS 3
+#define MUSB_C_EP6T_BITS 3
+#define MUSB_C_EP6R_BITS 3
+#define MUSB_C_EP7T_BITS 3
+#define MUSB_C_EP7R_BITS 3
+#define MUSB_C_EP8T_BITS 2
+#define MUSB_C_EP8R_BITS 2
+#define MUSB_C_EP9T_BITS 2
+#define MUSB_C_EP9R_BITS 2
+#define MUSB_C_EP10T_BITS 2
+#define MUSB_C_EP10R_BITS 2
+#define MUSB_C_EP11T_BITS 2
+#define MUSB_C_EP11R_BITS 2
+#define MUSB_C_EP12T_BITS 2
+#define MUSB_C_EP12R_BITS 2
+#define MUSB_C_EP13T_BITS 2
+#define MUSB_C_EP13R_BITS 2
+#define MUSB_C_EP14T_BITS 2
+#define MUSB_C_EP14R_BITS 2
+#define MUSB_C_EP15T_BITS 2
+#define MUSB_C_EP15R_BITS 2
+
+/* Define the following constant if the USB2.0 Transceiver Macrocell data width is 16-bits. */
+/* `define C_UTM_16 */
+
+/* Define this constant if the CPU uses big-endian byte ordering. */
+/*`define C_BIGEND */
+
+/* Define the following constant if any Tx endpoint is required to support multiple bulk packets. */
+/* `define C_MP_TX */
+
+/* Define the following constant if any Rx endpoint is required to support multiple bulk packets. */
+/* `define C_MP_RX */
+
+/* Define the following constant if any Tx endpoint is required to support high bandwidth ISO. */
+/* `define C_HB_TX */
+
+/* Define the following constant if any Rx endpoint is required to support high bandwidth ISO. */
+/* `define C_HB_RX */
+
+/* Define the following constant if software connect/disconnect control is required. */
+#define MUSB_C_SOFT_CON
+
+/* Define the following constant if Vendor Control Registers are required. */
+/* `define C_VEND_REG */
+
+/* Vendor control register widths. */
+#define MUSB_C_VCTL_BITS 4
+#define MUSB_C_VSTAT_BITS 8
+
+
+/* Define the following constant to include a DMA controller. */
+#define MUSB_C_DMA
+
+/* Define the following constant if 2 or more DMA channels are required. */
+#define MUSB_C_DMA2
+
+/* Define the following constant if 3 or more DMA channels are required. */
+#define MUSB_C_DMA3
+
+/* Define the following constant if 4 or more DMA channels are required. */
+#define MUSB_C_DMA4
+
+/* Define the following constant if 5 or more DMA channels are required. */
+/*`define C_DMA5 */
+
+/* Define the following constant if 6 or more DMA channels are required. */
+/*`define C_DMA6 */
+
+/* Define the following constant if 7 or more DMA channels are required. */
+/*`define C_DMA7 */
+
+/* Define the following constant if 8 or more DMA channels are required. */
+/*`define C_DMA8 */
+
+
+/* ** Enable Dynamic FIFO Sizing ** */
+#define MUSB_C_DYNFIFO_DEF
+
+/* ** Derived constants ** */
+/* The following constants are derived from the previous configuration constants */
+
+/* Total number of endpoints
+ * Legal values are 2 - 16
+ * This must be equal to the larger of C_NUM_EPT, C_NUM_EPR
+ */
+#define MUSB_C_NUM_EPS 8
+
+/* C_EPMAX_BITS is equal to the largest endpoint FIFO word address bits */
+#define MUSB_C_EPMAX_BITS 12
+
+/* C_RAM_BITS is the number of address bits required to address the RAM (32-bit
+ * addresses). It is defined as log2 of the sum of 2** of all the endpoint FIFO
+ * dword address bits (rounded up).
+ */
+#define MUSB_C_RAM_BITS 12
+
+#endif /* __ARCH_MUSB_HDRC_CNF */
--- /dev/null
+/*
+ * include/asm-arm/arch-omap/hsmmc.h
+ *
+ * Hardware definitions for SD/MMC Controller on OMAP243x and OMAP34xx
+ *
+ * Initial creation by Felipe Balbi.
+ *
+ * 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_HSMMC_H
+#define __ASM_ARCH_OMAP_HSMMC_H
+
+extern void hsmmc_init(void);
+
+#endif /* __ASM_ARCH_OMAP_HSMMC_H */
+
#define INT_UART2 (15 + IH2_BASE)
#define INT_BT_MCSI1TX (16 + IH2_BASE)
#define INT_BT_MCSI1RX (17 + IH2_BASE)
+#define INT_SOSSI_MATCH (19 + IH2_BASE)
#define INT_USB_W2FC (20 + IH2_BASE)
#define INT_1WIRE (21 + IH2_BASE)
#define INT_OS_TIMER (22 + IH2_BASE)
#define INT_1610_DMA_CH14 (61 + IH2_BASE)
#define INT_1610_DMA_CH15 (62 + IH2_BASE)
#define INT_1610_NAND (63 + IH2_BASE)
+#define INT_1610_SHA1MD5 (91 + IH2_BASE)
/*
* OMAP-730 specific IRQ numbers for interrupt handler 2
#define INT_24XX_GPTIMER10 46
#define INT_24XX_GPTIMER11 47
#define INT_24XX_GPTIMER12 48
+#define INT_24XX_SHA1MD5 51
#define INT_24XX_I2C1_IRQ 56
#define INT_24XX_I2C2_IRQ 57
+#define INT_24XX_HDQ_IRQ 58
#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_SPI1_IRQ 65
+#define INT_24XX_SPI2_IRQ 66
#define INT_24XX_UART1_IRQ 72
#define INT_24XX_UART2_IRQ 73
#define INT_24XX_UART3_IRQ 74
#define INT_24XX_USB_IRQ_HSOF 79
#define INT_24XX_USB_IRQ_OTG 80
#define INT_24XX_MMC_IRQ 83
+#define INT_24XX_MMC2_IRQ 86
+#define INT_24XX_SPI3_IRQ 91
+
+#define INT_243X_MCBSP2_IRQ 16
+#define INT_243X_MCBSP3_IRQ 17
+#define INT_243X_MCBSP4_IRQ 18
+#define INT_243X_MCBSP5_IRQ 19
+#define INT_243X_MCBSP1_IRQ 64
+#define INT_243X_HS_USB_MC 92
+#define INT_243X_HS_USB_DMA 93
+#define INT_243X_CARKIT_IRQ 94
+
+#define INT_34XX_ST_MCBSP2_IRQ 4
+#define INT_34XX_ST_MCBSP3_IRQ 5
+#define INT_34XX_SYS_NIRQ 7
+#define INT_34XX_MCBSP1_IRQ 16
+#define INT_34XX_MCBSP2_IRQ 17
+#define INT_34XX_MCBSP3_IRQ 22
+#define INT_34XX_MCBSP4_IRQ 23
+#define INT_34XX_CAM_IRQ 24
+#define INT_34XX_MCBSP5_IRQ 27
+#define INT_34XX_GPIO_BANK1 29
+#define INT_34XX_GPIO_BANK2 30
+#define INT_34XX_GPIO_BANK3 31
+#define INT_34XX_GPIO_BANK4 32
+#define INT_34XX_GPIO_BANK5 33
+#define INT_34XX_GPIO_BANK6 34
+#define INT_34XX_USIM_IRQ 35
+#define INT_34XX_WDT3_IRQ 36
+#define INT_34XX_SPI4_IRQ 48
+#define INT_34XX_I2C3_IRQ 61
+#define INT_34XX_PBIAS_IRQ 75
+#define INT_34XX_OHCI_IRQ 76
+#define INT_34XX_EHCI_IRQ 77
+#define INT_34XX_TLL_IRQ 78
+#define INT_34XX_MMC3_IRQ 94
+#define INT_34XX_GPT12_IRQ 95
/* Max. 128 level 2 IRQs (OMAP1610), 192 GPIOs (OMAP730) and
* 16 MPUIO lines */
#define OMAP_MAX_GPIO_LINES 192
#define IH_GPIO_BASE (128 + IH2_BASE)
#define IH_MPUIO_BASE (OMAP_MAX_GPIO_LINES + IH_GPIO_BASE)
-#define IH_BOARD_BASE (16 + IH_MPUIO_BASE)
+#define OMAP_IRQ_END (IH_MPUIO_BASE + 16)
+
+/* External FPGA handles interrupts on Innovator boards */
+#define OMAP_FPGA_IRQ_BASE (OMAP_IRQ_END)
+#ifdef CONFIG_MACH_OMAP_INNOVATOR
+#define OMAP_FPGA_NR_IRQS 24
+#else
+#define OMAP_FPGA_NR_IRQS 0
+#endif
+#define OMAP_FPGA_IRQ_END (OMAP_FPGA_IRQ_BASE + OMAP_FPGA_NR_IRQS)
+
+/* External TWL4030 can handle interrupts on 2430 and 34xx boards */
+#define TWL4030_IRQ_BASE (OMAP_FPGA_IRQ_END)
+#ifdef CONFIG_TWL4030_CORE
+#define TWL4030_BASE_NR_IRQS 8
+#define TWL4030_PWR_NR_IRQS 8
+#else
+#define TWL4030_BASE_NR_IRQS 0
+#define TWL4030_PWR_NR_IRQS 0
+#endif
+#define TWL4030_IRQ_END (TWL4030_IRQ_BASE + TWL4030_BASE_NR_IRQS)
+#define TWL4030_PWR_IRQ_BASE TWL4030_IRQ_END
+#define TWL4030_PWR_IRQ_END (TWL4030_PWR_IRQ_BASE + TWL4030_PWR_NR_IRQS)
+
+/* External TWL4030 gpio interrupts are optional */
+#define TWL4030_GPIO_IRQ_BASE TWL4030_PWR_IRQ_END
+#ifdef CONFIG_TWL4030_GPIO
+#define TWL4030_GPIO_NR_IRQS 18
+#else
+#define TWL4030_GPIO_NR_IRQS 0
+#endif
+#define TWL4030_GPIO_IRQ_END (TWL4030_GPIO_IRQ_BASE + TWL4030_GPIO_NR_IRQS)
+
+/* Total number of interrupts depends on the enabled blocks above */
+#define NR_IRQS TWL4030_GPIO_IRQ_END
#define OMAP_IRQ_BIT(irq) (1 << ((irq) % 32))
extern void omap_init_irq(void);
#endif
-/*
- * The definition of NR_IRQS is in board-specific header file, which is
- * included via hardware.h
- */
#include <asm/hardware.h>
-#ifndef NR_IRQS
-#define NR_IRQS IH_BOARD_BASE
-#endif
-
#endif
#define AUDIO_DMA_TX OMAP_DMA_MCBSP1_TX
#define AUDIO_DMA_RX OMAP_DMA_MCBSP1_RX
-#elif defined(CONFIG_ARCH_OMAP24XX)
+#elif defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
#define OMAP_MCBSP_REG_DRR2 0x00
#define OMAP_MCBSP_REG_DRR1 0x04
/* Polled read/write functions */
int omap_mcbsp_pollread(unsigned int id, u16 * buf);
int omap_mcbsp_pollwrite(unsigned int id, u16 buf);
+int omap_mcbsp_set_io_type(unsigned int id, omap_mcbsp_io_type_t io_type);
#endif
*/
#if defined(CONFIG_ARCH_OMAP1)
#define PHYS_OFFSET UL(0x10000000)
-#elif defined(CONFIG_ARCH_OMAP2)
+#elif defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
#define PHYS_OFFSET UL(0x80000000)
#endif
extern void menelaus_unregister_mmc_callback(void);
extern int menelaus_set_mmc_opendrain(int slot, int enable);
extern int menelaus_set_mmc_slot(int slot, int enable, int power, int cd_on);
+extern int menelaus_enable_slot(int slot, int enable);
extern int menelaus_set_vmem(unsigned int mV);
extern int menelaus_set_vio(unsigned int mV);
#include <linux/device.h>
#include <linux/mmc/host.h>
+#include <asm/arch/board.h>
+
#define OMAP_MMC_MAX_SLOTS 2
struct omap_mmc_platform_data {
- struct omap_mmc_conf conf;
+ struct omap_mmc_conf conf;
- unsigned enabled:1;
/* number of slots on board */
unsigned nr_slots:2;
- /* nomux means "standard" muxing is wrong on this board, and that
- * board-specific code handled it before common init logic.
- */
- unsigned nomux:1;
- /* 4 wire signaling is optional, and is only used for SD/SDIO and
- * MMCv4 */
- unsigned wire4:1;
+
/* set if your board has components or wiring that limits the
* maximum frequency on the MMC bus */
unsigned int max_freq;
* not supported */
int (* init)(struct device *dev);
void (* cleanup)(struct device *dev);
+ void (* shutdown)(struct device *dev);
+
+ /* To handle board related suspend/resume functionality for MMC */
+ int (*suspend)(struct device *dev, int slot);
+ int (*resume)(struct device *dev, int slot);
struct omap_mmc_slot_data {
int (* set_bus_mode)(struct device *dev, int slot, int bus_mode);
const char *name;
u32 ocr_mask;
+
+ /* Card detection IRQs */
+ int card_detect_irq;
+ int (* card_detect)(int irq);
+
+ unsigned int ban_openended:1;
+
} slots[OMAP_MMC_MAX_SLOTS];
};
extern void omap_set_mmc_info(int host, const struct omap_mmc_platform_data *info);
/* called from board-specific card detection service routine */
-extern void omap_mmc_notify_card_detect(struct device *dev, int slot, int detected);
extern void omap_mmc_notify_cover_event(struct device *dev, int slot, int is_closed);
#endif
--- /dev/null
+#ifndef __ARCH_OMAP_MMU_H
+#define __ARCH_OMAP_MMU_H
+
+#include <linux/device.h>
+#include <linux/workqueue.h>
+
+enum exmap_type {
+ EXMAP_TYPE_MEM,
+ EXMAP_TYPE_FB
+};
+
+enum omap_mmu_type {
+ OMAP_MMU_DSP,
+ OMAP_MMU_IVA1,
+ OMAP_MMU_CAMERA,
+};
+
+struct exmap_tbl {
+ unsigned int valid:1;
+ unsigned int prsvd:1;
+ int usecount; /* reference count by mmap */
+ enum exmap_type type;
+ void *buf; /* virtual address of the buffer,
+ * i.e. 0xc0000000 - */
+ void *vadr; /* DSP shadow space,
+ * i.e. 0xe0000000 - 0xe0ffffff */
+ unsigned int order;
+ struct {
+ int prev;
+ int next;
+ } link; /* grouping */
+};
+
+struct cam_ram_regset {
+ union {
+ struct {
+ u16 cam_l;
+ u16 cam_h;
+ };
+
+ u32 cam;
+ };
+
+ union {
+ struct {
+ u16 ram_l;
+ u16 ram_h;
+ };
+
+ u32 ram;
+ };
+};
+
+struct omap_mmu_tlb_lock {
+ int base;
+ int victim;
+};
+
+struct omap_mmu;
+struct omap_mmu_tlb_entry;
+
+#ifdef CONFIG_ARCH_OMAP1
+extern struct omap_mmu_ops omap1_mmu_ops;
+extern void omap_mmu_itack(struct omap_mmu *mmu);
+#elif defined(CONFIG_ARCH_OMAP2)
+extern struct omap_mmu_ops omap2_mmu_ops;
+static inline void omap_mmu_itack(struct omap_mmu *mmu)
+{
+}
+#endif
+
+struct omap_mmu_ops {
+ int (*startup)(struct omap_mmu *mmu);
+ void (*shutdown)(struct omap_mmu *mmu);
+
+ /* TLB operations */
+ void (*read_tlb)(struct omap_mmu *, struct cam_ram_regset *);
+ void (*load_tlb)(struct omap_mmu *, struct cam_ram_regset *);
+ ssize_t (*show)(struct omap_mmu *, char *, struct omap_mmu_tlb_lock *);
+
+ /* CAM / RAM operations */
+ struct cam_ram_regset *(*cam_ram_alloc)(struct omap_mmu *,
+ struct omap_mmu_tlb_entry *);
+ int (*cam_ram_valid)(struct cam_ram_regset *);
+ unsigned long (*cam_va)(struct cam_ram_regset *);
+
+ /* Memory operations */
+ int (*mem_enable)(struct omap_mmu *, void *);
+ int (*mem_disable)(struct omap_mmu *, void *);
+
+ void (*interrupt)(struct omap_mmu *);
+
+ /* PTE attribute operations */
+ pgprot_t (*pte_get_attr)(struct omap_mmu_tlb_entry *);
+};
+
+struct omap_mmu {
+ const char *name;
+ unsigned long base;
+ struct clk *clk;
+
+ unsigned long membase, memsize;
+ struct clk *memclk;
+
+ enum omap_mmu_type type;
+
+ struct device *dev;
+
+ struct rw_semaphore exmap_sem;
+ struct exmap_tbl *exmap_tbl;
+
+ unsigned int nr_tlb_entries;
+ unsigned int nr_exmap_preserved;
+
+ struct mm_struct *twl_mm;
+
+ /* Size of virtual address space, in bits */
+ unsigned int addrspace;
+
+ /* Interrupt */
+ unsigned int irq;
+ unsigned long fault_address;
+ struct work_struct irq_work;
+
+ struct omap_mmu_ops *ops;
+};
+
+#define omap_mmu_internal_memory(mmu, addr) \
+ (likely(mmu->membase) && (((unsigned long)(addr) >= mmu->membase) && \
+ ((unsigned long)(addr) < mmu->membase + mmu->memsize)))
+
+#define INIT_EXMAP_TBL_ENTRY(ent,b,v,typ,od) \
+do { \
+ (ent)->buf = (b); \
+ (ent)->vadr = (v); \
+ (ent)->valid = 1; \
+ (ent)->prsvd = 0; \
+ (ent)->usecount = 0; \
+ (ent)->type = (typ); \
+ (ent)->order = (od); \
+ (ent)->link.next = -1; \
+ (ent)->link.prev = -1; \
+} while (0)
+
+#define INIT_EXMAP_TBL_ENTRY_4KB_PRESERVED(ent,b,v) \
+do { \
+ (ent)->buf = (b); \
+ (ent)->vadr = (v); \
+ (ent)->valid = 1; \
+ (ent)->prsvd = 1; \
+ (ent)->usecount = 0; \
+ (ent)->type = EXMAP_TYPE_MEM; \
+ (ent)->order = 0; \
+ (ent)->link.next = -1; \
+ (ent)->link.prev = -1; \
+} while (0)
+
+#define omap_mmu_to_virt(mmu, db) ((void *)((mmu)->membase + (db)))
+#define virt_to_omap_mmu(mmu, va) \
+ (((unsigned long)(va) - (mmu)->membase))
+
+/* arch/arm/plat-omap/mmu.c */
+int omap_mmu_register(struct omap_mmu *mmu);
+void omap_mmu_unregister(struct omap_mmu *mmu);
+
+void omap_mmu_enable(struct omap_mmu *mmu, int reset);
+void omap_mmu_disable(struct omap_mmu *mmu);
+
+int omap_mmu_mem_enable(struct omap_mmu *mmu, void *addr);
+void omap_mmu_mem_disable(struct omap_mmu *mmu, void *addr);
+
+void omap_mmu_read_tlb(struct omap_mmu *mmu, struct omap_mmu_tlb_lock *lock,
+ struct cam_ram_regset *cr);
+
+int omap_mmu_load_tlb_entry(struct omap_mmu *, struct omap_mmu_tlb_entry *);
+int omap_mmu_clear_tlb_entry(struct omap_mmu *, unsigned long vadr);
+
+int omap_mmu_load_pte_entry(struct omap_mmu *mmu,
+ struct omap_mmu_tlb_entry *entry);
+int omap_mmu_clear_pte_entry(struct omap_mmu *mmu, unsigned long vadr);
+
+int omap_mmu_kmem_reserve(struct omap_mmu *mmu, unsigned long size);
+void omap_mmu_kmem_release(void);
+
+unsigned long omap_mmu_virt_to_phys(struct omap_mmu *mmu, void *vadr,
+ size_t *len);
+
+int omap_mmu_exmap(struct omap_mmu *mmu, unsigned long dspadr,
+ unsigned long padr, unsigned long size,
+ enum exmap_type type);
+int omap_mmu_exunmap(struct omap_mmu *mmu, unsigned long dspadr);
+void omap_mmu_exmap_flush(struct omap_mmu *mmu);
+void omap_mmu_exmap_use(struct omap_mmu *mmu, void *vadr, size_t len);
+void omap_mmu_exmap_unuse(struct omap_mmu *mmu, void *vadr, size_t len);
+
+int exmap_set_armmmu(struct omap_mmu *mmu, unsigned long virt,
+ unsigned long phys, unsigned long size);
+void exmap_clear_armmmu(struct omap_mmu *mmu, unsigned long virt,
+ unsigned long size);
+void exmap_setup_preserved_mem_page(struct omap_mmu *mmu, void *buf,
+ unsigned long dspadr, int index);
+void exmap_clear_mem_page(struct omap_mmu *mmu, unsigned long dspadr);
+int exmap_valid(struct omap_mmu *mmu, void *vadr, size_t len);
+
+/* To be obsolete for backward compatibility */
+ssize_t __omap_mmu_mem_read(struct omap_mmu *mmu, struct bin_attribute *,
+ char *buf, loff_t offset, size_t count);
+ssize_t __omap_mmu_mem_write(struct omap_mmu *mmu, struct bin_attribute *,
+ char *buf, loff_t offset, size_t count);
+
+#endif /* __ARCH_OMAP_MMU_H */
.pu_pd_val = pull_mode, \
},
-
-#define PULL_DISABLED 0
-#define PULL_ENABLED 1
-
-#define PULL_DOWN 0
-#define PULL_UP 1
+/* 24xx/34xx mux bit defines */
+#define OMAP2_PULL_ENA (1 << 3)
+#define OMAP2_PULL_UP (1 << 4)
+#define OMAP2_ALTELECTRICALSEL (1 << 5)
+
+/* 34xx specific mux bit defines */
+#define OMAP3_INPUT_EN (1 << 8)
+#define OMAP3_OFF_EN (1 << 9)
+#define OMAP3_OFFOUT_EN (1 << 10)
+#define OMAP3_OFFOUT_VAL (1 << 11)
+#define OMAP3_OFF_PULL_EN (1 << 12)
+#define OMAP3_OFF_PULL_UP (1 << 13)
+#define OMAP3_WAKEUP_EN (1 << 14)
+
+/* 34xx mux mode options for each pin. See TRM for options */
+#define OMAP34XX_MUX_MODE0 0
+#define OMAP34XX_MUX_MODE1 1
+#define OMAP34XX_MUX_MODE2 2
+#define OMAP34XX_MUX_MODE3 3
+#define OMAP34XX_MUX_MODE4 4
+#define OMAP34XX_MUX_MODE5 5
+#define OMAP34XX_MUX_MODE6 6
+#define OMAP34XX_MUX_MODE7 7
+
+/* 34xx active pin states */
+#define OMAP34XX_PIN_OUTPUT 0
+#define OMAP34XX_PIN_INPUT OMAP3_INPUT_EN
+#define OMAP34XX_PIN_INPUT_PULLUP (OMAP2_PULL_ENA | OMAP3_INPUT_EN \
+ | OMAP2_PULL_UP)
+#define OMAP34XX_PIN_INPUT_PULLDOWN (OMAP2_PULL_ENA | OMAP3_INPUT_EN)
+
+/* 34xx off mode states */
+#define OMAP34XX_PIN_OFF_NONE 0
+#define OMAP34XX_PIN_OFF_OUTPUT_HIGH (OMAP3_OFF_EN | OMAP3_OFFOUT_EN \
+ | OMAP3_OFFOUT_VAL)
+#define OMAP34XX_PIN_OFF_OUTPUT_LOW (OMAP3_OFF_EN | OMAP3_OFFOUT_EN)
+#define OMAP34XX_PIN_OFF_INPUT_PULLUP (OMAP3_OFF_EN | OMAP3_OFF_PULL_EN \
+ | OMAP3_OFF_PULL_UP)
+#define OMAP34XX_PIN_OFF_INPUT_PULLDOWN (OMAP3_OFF_EN | OMAP3_OFF_PULL_EN)
+#define OMAP34XX_PIN_OFF_WAKEUPENABLE OMAP3_WAKEUP_EN
+
+#define MUX_CFG_34XX(desc, reg_offset, mux_value){ \
+ .name = desc, \
+ .debug = 0, \
+ .mux_reg = reg_offset, \
+ .mux_val = mux_value \
+},
struct pin_config {
- char *name;
- unsigned char busy;
- unsigned char debug;
+ char *name;
+ const unsigned int mux_reg;
+ unsigned char debug;
- const char *mux_reg_name;
- const unsigned int mux_reg;
+#if defined(CONFIG_ARCH_OMAP34XX)
+ u16 mux_val; /* Wake-up, off mode, pull, mux mode */
+#endif
+
+#if defined(CONFIG_ARCH_OMAP1) || defined(CONFIG_ARCH_OMAP24XX)
const unsigned char mask_offset;
const unsigned char mask;
const char *pu_pd_name;
const unsigned int pu_pd_reg;
const unsigned char pu_pd_val;
+#endif
+
+#if defined(CONFIG_OMAP_MUX_DEBUG) || defined(CONFIG_OMAP_MUX_WARNINGS)
+ const char *mux_reg_name;
+#endif
+
};
enum omap730_index {
};
+enum omap34xx_index {
+
+ /* PHY - HSUSB: 12-pin ULPI PHY: Port 1*/
+ Y8_3430_USB1HS_PHY_CLK,
+ Y9_3430_USB1HS_PHY_STP,
+ AA14_3430_USB1HS_PHY_DIR,
+ AA11_3430_USB1HS_PHY_NXT,
+ W13_3430_USB1HS_PHY_DATA0,
+ W12_3430_USB1HS_PHY_DATA1,
+ W11_3430_USB1HS_PHY_DATA2,
+ Y11_3430_USB1HS_PHY_DATA3,
+ W9_3430_USB1HS_PHY_DATA4,
+ Y12_3430_USB1HS_PHY_DATA5,
+ W8_3430_USB1HS_PHY_DATA6,
+ Y13_3430_USB1HS_PHY_DATA7,
+
+ /* PHY - HSUSB: 12-pin ULPI PHY: Port 2*/
+ AA8_3430_USB2HS_PHY_CLK,
+ AA10_3430_USB2HS_PHY_STP,
+ AA9_3430_USB2HS_PHY_DIR,
+ AB11_3430_USB2HS_PHY_NXT,
+ AB10_3430_USB2HS_PHY_DATA0,
+ AB9_3430_USB2HS_PHY_DATA1,
+ W3_3430_USB2HS_PHY_DATA2,
+ T4_3430_USB2HS_PHY_DATA3,
+ T3_3430_USB2HS_PHY_DATA4,
+ R3_3430_USB2HS_PHY_DATA5,
+ R4_3430_USB2HS_PHY_DATA6,
+ T2_3430_USB2HS_PHY_DATA7,
+
+
+ /* TLL - HSUSB: 12-pin TLL Port 1*/
+ Y8_3430_USB1HS_TLL_CLK,
+ Y9_3430_USB1HS_TLL_STP,
+ AA14_3430_USB1HS_TLL_DIR,
+ AA11_3430_USB1HS_TLL_NXT,
+ W13_3430_USB1HS_TLL_DATA0,
+ W12_3430_USB1HS_TLL_DATA1,
+ W11_3430_USB1HS_TLL_DATA2,
+ Y11_3430_USB1HS_TLL_DATA3,
+ W9_3430_USB1HS_TLL_DATA4,
+ Y12_3430_USB1HS_TLL_DATA5,
+ W8_3430_USB1HS_TLL_DATA6,
+ Y13_3430_USB1HS_TLL_DATA7,
+
+ /* TLL - HSUSB: 12-pin TLL Port 2*/
+ AA8_3430_USB2HS_TLL_CLK,
+ AA10_3430_USB2HS_TLL_STP,
+ AA9_3430_USB2HS_TLL_DIR,
+ AB11_3430_USB2HS_TLL_NXT,
+ AB10_3430_USB2HS_TLL_DATA0,
+ AB9_3430_USB2HS_TLL_DATA1,
+ W3_3430_USB2HS_TLL_DATA2,
+ T4_3430_USB2HS_TLL_DATA3,
+ T3_3430_USB2HS_TLL_DATA4,
+ R3_3430_USB2HS_TLL_DATA5,
+ R4_3430_USB2HS_TLL_DATA6,
+ T2_3430_USB2HS_TLL_DATA7,
+
+ /* TLL - HSUSB: 12-pin TLL Port 3*/
+ AA6_3430_USB3HS_TLL_CLK,
+ AB3_3430_USB3HS_TLL_STP,
+ AA3_3430_USB3HS_TLL_DIR,
+ Y3_3430_USB3HS_TLL_NXT,
+ AA5_3430_USB3HS_TLL_DATA0,
+ Y4_3430_USB3HS_TLL_DATA1,
+ Y5_3430_USB3HS_TLL_DATA2,
+ W5_3430_USB3HS_TLL_DATA3,
+ AB12_3430_USB3HS_TLL_DATA4,
+ AB13_3430_USB3HS_TLL_DATA5,
+ AA13_3430_USB3HS_TLL_DATA6,
+ AA12_3430_USB3HS_TLL_DATA7
+
+};
+
struct omap_mux_cfg {
struct pin_config *pins;
unsigned long size;
#include <sound/pcm.h>
#include <asm/arch/mcbsp.h>
#include <linux/platform_device.h>
+/*
+ * Debug functions
+ */
+#undef DEBUG
+/* #define DEBUG */
+
+#define ERR(ARGS...) \
+ do { \
+ printk(KERN_ERR "{%s}-ERROR: ", __func__); \
+ printk(ARGS); \
+ } while (0)
+
+#ifdef DEBUG
+#define DPRINTK(ARGS...) \
+ do { \
+ printk(KERN_INFO "<%s>: ", __func__); \
+ printk(ARGS); \
+ } while (0)
+#define ADEBUG() printk("XXX Alsa debug f:%s, l:%d\n", __func__, __LINE__)
+#define FN_IN printk(KERN_INFO "[%s]: start\n", __func__)
+#define FN_OUT(n) printk(KERN_INFO "[%s]: end(%u)\n", __func__, n)
+#else
+#define DPRINTK(ARGS...) /* nop */
+#define ADEBUG() /* nop */
+#define FN_IN /* nop */
+#define FN_OUT(n) /* nop */
+#endif
#define DMA_BUF_SIZE (1024 * 8)
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 */
+ int periods; /* current registered periods in DMA engine */
spinlock_t dma_lock; /* for locking in DMA operations */
struct snd_pcm_substream *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 offset; /* start position of last period in alsa buf */
+ int (*hw_start)(void); /* interface to start HW interface, (McBSP) */
int (*hw_stop)(void); /* interface to stop HW interface, e.g. McBSP */
};
void snd_omap_resume_mixer(void);
#endif
-int snd_omap_alsa_post_probe(struct platform_device *pdev, struct omap_alsa_codec_config *config);
+int snd_omap_alsa_post_probe(struct platform_device *pdev,
+ struct omap_alsa_codec_config *config);
int snd_omap_alsa_remove(struct platform_device *pdev);
#ifdef CONFIG_PM
int snd_omap_alsa_suspend(struct platform_device *pdev, pm_message_t state);
#define OMAP1510_DSPREG_SIZE SZ_128K
#define OMAP1510_DSPREG_START 0xE1000000
+#define OMAP1510_DSP_MMU_BASE (0xfffed200)
+
#endif /* __ASM_ARCH_OMAP15XX_H */
#define OMAP16XX_DSPREG_SIZE SZ_128K
#define OMAP16XX_DSPREG_START 0xE1000000
+#define OMAP16XX_SEC_BASE 0xFFFE4000
+#define OMAP16XX_SEC_DES (OMAP16XX_SEC_BASE + 0x0000)
+#define OMAP16XX_SEC_SHA1MD5 (OMAP16XX_SEC_BASE + 0x0800)
+#define OMAP16XX_SEC_RNG (OMAP16XX_SEC_BASE + 0x1000)
+
/*
* ---------------------------------------------------------------------------
* Interrupts
#define WSPR_DISABLE_0 (0x0000aaaa)
#define WSPR_DISABLE_1 (0x00005555)
-/* Mailbox */
+#define OMAP16XX_DSP_MMU_BASE (0xfffed200)
#define OMAP16XX_MAILBOX_BASE (0xfffcf000)
#endif /* __ASM_ARCH_OMAP16XX_H */
--- /dev/null
+/*
+ * include/asm-arm/arch-omap/omap34xx.h
+ *
+ * This file contains the processor specific definitions of the TI OMAP34XX.
+ *
+ * Copyright (C) 2007 Texas Instruments.
+ * Copyright (C) 2007 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
+ */
+
+#ifndef __ASM_ARCH_OMAP34XX_H
+#define __ASM_ARCH_OMAP34XX_H
+
+/*
+ * Please place only base defines here and put the rest in device
+ * specific headers.
+ */
+
+#define L4_34XX_BASE 0x48000000
+#define L4_WK_34XX_BASE 0x48300000
+#define L4_WK_OMAP_BASE L4_WK_34XX_BASE
+#define L4_PER_34XX_BASE 0x49000000
+#define L4_PER_OMAP_BASE L4_PER_34XX_BASE
+#define L4_EMU_34XX_BASE 0x54000000
+#define L4_EMU_BASE L4_EMU_34XX_BASE
+#define L3_34XX_BASE 0x68000000
+#define L3_OMAP_BASE L3_34XX_BASE
+
+#define OMAP3430_32KSYNCT_BASE 0x48320000
+#define OMAP3430_CM_BASE 0x48004800
+#define OMAP3430_PRM_BASE 0x48306800
+#define OMAP343X_SMS_BASE 0x6C000000
+#define OMAP343X_SDRC_BASE 0x6D000000
+#define OMAP34XX_GPMC_BASE 0x6E000000
+#define OMAP343X_SCM_BASE 0x48002000
+#define OMAP343X_CTRL_BASE OMAP343X_SCM_BASE
+
+#define OMAP34XX_IC_BASE 0x48200000
+#define OMAP34XX_IVA_INTC_BASE 0x40000000
+#define OMAP34XX_HSUSB_OTG_BASE (L4_34XX_BASE + 0xAB000)
+#define OMAP34XX_HSUSB_HOST_BASE (L4_34XX_BASE + 0x64000)
+#define OMAP34XX_USBTLL_BASE (L4_34XX_BASE + 0x62000)
+#define IRQ_SIR_IRQ 0x0040
+
+
+#if defined(CONFIG_ARCH_OMAP3430)
+
+#define OMAP2_32KSYNCT_BASE OMAP3430_32KSYNCT_BASE
+#define OMAP2_CM_BASE OMAP3430_CM_BASE
+#define OMAP2_PRM_BASE OMAP3430_PRM_BASE
+#define OMAP2_VA_IC_BASE IO_ADDRESS(OMAP34XX_IC_BASE)
+
+#endif
+
+#define OMAP34XX_DSP_BASE 0x58000000
+#define OMAP34XX_DSP_MEM_BASE (OMAP34XX_DSP_BASE + 0x0)
+#define OMAP34XX_DSP_IPI_BASE (OMAP34XX_DSP_BASE + 0x1000000)
+#define OMAP34XX_DSP_MMU_BASE (OMAP34XX_DSP_BASE + 0x2000000)
+#endif /* __ASM_ARCH_OMAP34XX_H */
+
#define OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE 0x00010000
#define OMAPFB_CAPS_WINDOW_SCALE 0x00020000
#define OMAPFB_CAPS_WINDOW_OVERLAY 0x00040000
+#define OMAPFB_CAPS_WINDOW_ROTATE 0x00080000
#define OMAPFB_CAPS_SET_BACKLIGHT 0x01000000
/* Values from DSP must map to lower 16-bits */
int screen_width,
int pos_x, int pos_y, int width,
int height, int color_mode);
+ int (*set_rotate) (int angle);
int (*setup_mem) (int plane, size_t size,
int mem_type, unsigned long *paddr);
int (*mmap) (struct fb_info *info,
int gpio_irq;
struct mtd_partition *parts;
int nr_parts;
- int (*onenand_setup)(void __iomem *);
+ int (*onenand_setup)(void __iomem *, int freq);
int dma_channel;
};
+
+int omap2_onenand_rephase(void);
/*
- * linux/include/asm-arm/arch-omap/pm.h
+ * linux/include/asm/arch-omap/pm.h
*
* Header file for OMAP Power Management Routines
*
#if !defined(CONFIG_ARCH_OMAP730) && \
!defined(CONFIG_ARCH_OMAP15XX) && \
!defined(CONFIG_ARCH_OMAP16XX) && \
- !defined(CONFIG_ARCH_OMAP24XX)
+ !defined(CONFIG_ARCH_OMAP24XX) && \
+ !defined(CONFIG_ARCH_OMAP34XX)
#error "Power management for this processor not implemented yet"
#endif
#include <linux/clk.h>
+extern struct kset power_subsys;
+
extern void prevent_idle_sleep(void);
extern void allow_idle_sleep(void);
extern void omap_pm_idle(void);
extern void omap_pm_suspend(void);
+#ifdef CONFIG_PM
+extern void omap2_block_sleep(void);
+extern void omap2_allow_sleep(void);
+#else
+static inline void omap2_block_sleep(void) { }
+static inline void omap2_allow_sleep(void) { }
+#endif
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);
#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
#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_CLKSTCTRL_MPU,
- OMAP24XX_SLEEP_SAVE_CM_CLKSTCTRL_CORE,
- OMAP24XX_SLEEP_SAVE_CM_CLKSTCTRL_GFX,
- OMAP24XX_SLEEP_SAVE_CM_CLKSTCTRL_DSP,
- OMAP24XX_SLEEP_SAVE_CM_CLKSTCTRL_MDM,
-
- OMAP24XX_SLEEP_SAVE_PM_PWSTCTRL_MPU,
- OMAP24XX_SLEEP_SAVE_PM_PWSTCTRL_CORE,
- OMAP24XX_SLEEP_SAVE_PM_PWSTCTRL_GFX,
- OMAP24XX_SLEEP_SAVE_PM_PWSTCTRL_DSP,
- OMAP24XX_SLEEP_SAVE_PM_PWSTCTRL_MDM,
-
- OMAP24XX_SLEEP_SAVE_CM_IDLEST1_CORE,
- OMAP24XX_SLEEP_SAVE_CM_IDLEST2_CORE,
- OMAP24XX_SLEEP_SAVE_CM_IDLEST3_CORE,
- OMAP24XX_SLEEP_SAVE_CM_IDLEST4_CORE,
- OMAP24XX_SLEEP_SAVE_CM_IDLEST_GFX,
- OMAP24XX_SLEEP_SAVE_CM_IDLEST_WKUP,
- OMAP24XX_SLEEP_SAVE_CM_IDLEST_CKGEN,
- OMAP24XX_SLEEP_SAVE_CM_IDLEST_DSP,
- OMAP24XX_SLEEP_SAVE_CM_IDLEST_MDM,
-
- OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE1_CORE,
- OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE2_CORE,
- OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE3_CORE,
- OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE4_CORE,
- OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE_WKUP,
- OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE_PLL,
- OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE_DSP,
- OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE_MDM,
-
- 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_ICLKEN3_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 */
--- /dev/null
+/*
+ * OMAP2/3 powerdomain control
+ *
+ * Copyright (C) 2007-8 Texas Instruments, Inc.
+ * Copyright (C) 2007-8 Nokia Corporation
+ *
+ * Written by Paul Walmsley
+ *
+ * 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_ARM_ARCH_OMAP_POWERDOMAIN
+#define ASM_ARM_ARCH_OMAP_POWERDOMAIN
+
+#include <linux/types.h>
+#include <linux/list.h>
+
+#include <asm/atomic.h>
+
+#include <asm/arch/cpu.h>
+
+
+/* Powerdomain basic power states */
+#define PWRDM_POWER_OFF 0x0
+#define PWRDM_POWER_RET 0x1
+#define PWRDM_POWER_INACTIVE 0x2
+#define PWRDM_POWER_ON 0x3
+
+/* Powerdomain allowable state bitfields */
+#define PWRSTS_OFF_ON ((1 << PWRDM_POWER_OFF) | \
+ (1 << PWRDM_POWER_ON))
+
+#define PWRSTS_OFF_RET ((1 << PWRDM_POWER_OFF) | \
+ (1 << PWRDM_POWER_RET))
+
+#define PWRSTS_OFF_RET_ON (PWRSTS_OFF_RET | (1 << PWRDM_POWER_ON))
+
+
+/*
+ * Number of memory banks that are power-controllable. On OMAP3430, the
+ * maximum is 4.
+ */
+#define PWRDM_MAX_MEM_BANKS 4
+
+/*
+ * Maximum number of clockdomains that can be associated with a powerdomain.
+ * CORE powerdomain is probably the worst case.
+ */
+#define PWRDM_MAX_CLKDMS 3
+
+/* XXX A completely arbitrary number. What is reasonable here? */
+#define PWRDM_TRANSITION_BAILOUT 100000
+
+struct clockdomain;
+struct powerdomain;
+
+/* Encodes dependencies between powerdomains - statically defined */
+struct pwrdm_dep {
+
+ /* Powerdomain name */
+ const char *pwrdm_name;
+
+ /* Powerdomain pointer - resolved by the powerdomain code */
+ struct powerdomain *pwrdm;
+
+ /* Flags to mark OMAP chip restrictions, etc. */
+ const struct omap_chip_id omap_chip;
+
+};
+
+struct powerdomain {
+
+ /* Powerdomain name */
+ const char *name;
+
+ /* the address offset from CM_BASE/PRM_BASE */
+ const s16 prcm_offs;
+
+ /* Used to represent the OMAP chip types containing this pwrdm */
+ const struct omap_chip_id omap_chip;
+
+ /* Bit shift of this powerdomain's PM_WKDEP/CM_SLEEPDEP bit */
+ const u8 dep_bit;
+
+ /* Powerdomains that can be told to wake this powerdomain up */
+ struct pwrdm_dep *wkdep_srcs;
+
+ /* Powerdomains that can be told to keep this pwrdm from inactivity */
+ struct pwrdm_dep *sleepdep_srcs;
+
+ /* Possible powerdomain power states */
+ const u8 pwrsts;
+
+ /* Possible logic power states when pwrdm in RETENTION */
+ const u8 pwrsts_logic_ret;
+
+ /* Number of software-controllable memory banks in this powerdomain */
+ const u8 banks;
+
+ /* Possible memory bank pwrstates when pwrdm in RETENTION */
+ const u8 pwrsts_mem_ret[PWRDM_MAX_MEM_BANKS];
+
+ /* Possible memory bank pwrstates when pwrdm is ON */
+ const u8 pwrsts_mem_on[PWRDM_MAX_MEM_BANKS];
+
+ /* Clockdomains in this powerdomain */
+ struct clockdomain *pwrdm_clkdms[PWRDM_MAX_CLKDMS];
+
+ struct list_head node;
+
+};
+
+
+void pwrdm_init(struct powerdomain **pwrdm_list);
+
+int pwrdm_register(struct powerdomain *pwrdm);
+int pwrdm_unregister(struct powerdomain *pwrdm);
+struct powerdomain *pwrdm_lookup(const char *name);
+
+int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm));
+
+int pwrdm_add_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm);
+int pwrdm_del_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm);
+int pwrdm_for_each_clkdm(struct powerdomain *pwrdm,
+ int (*fn)(struct powerdomain *pwrdm,
+ struct clockdomain *clkdm));
+
+int pwrdm_add_wkdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2);
+int pwrdm_del_wkdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2);
+int pwrdm_read_wkdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2);
+int pwrdm_add_sleepdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2);
+int pwrdm_del_sleepdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2);
+int pwrdm_read_sleepdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2);
+
+int pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst);
+int pwrdm_read_next_pwrst(struct powerdomain *pwrdm);
+int pwrdm_read_prev_pwrst(struct powerdomain *pwrdm);
+int pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm);
+
+int pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst);
+int pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst);
+int pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, u8 pwrst);
+
+int pwrdm_read_logic_pwrst(struct powerdomain *pwrdm);
+int pwrdm_read_prev_logic_pwrst(struct powerdomain *pwrdm);
+int pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank);
+int pwrdm_read_prev_mem_pwrst(struct powerdomain *pwrdm, u8 bank);
+
+int pwrdm_wait_transition(struct powerdomain *pwrdm);
+
+#endif
#define OMAP_UART1_BASE 0x4806a000
#define OMAP_UART2_BASE 0x4806c000
#define OMAP_UART3_BASE 0x4806e000
+#elif defined(CONFIG_ARCH_OMAP3)
+/* OMAP3 serial ports */
+#define OMAP_UART1_BASE 0x4806a000
+#define OMAP_UART2_BASE 0x4806c000
+#define OMAP_UART3_BASE 0x49020000
#endif
#define OMAP_MAX_NR_PORTS 3
#define OMAP1510_BASE_BAUD (12000000/16)
#define OMAP16XX_BASE_BAUD (48000000/16)
+#define OMAP24XX_BASE_BAUD (48000000/16)
#define is_omap_port(p) ({int __ret = 0; \
if (p == IO_ADDRESS(OMAP_UART1_BASE) || \
#ifndef __ARCH_ARM_OMAP_SRAM_H
#define __ARCH_ARM_OMAP_SRAM_H
+#include <linux/poison.h> /* for SRAM_VA_MAGIC */
+
extern void * omap_sram_push(void * start, unsigned long size);
+extern int omap_sram_patch_va(void *srcfn, void *srcd, void *sramfn, void __iomem *d);
extern void omap_sram_reprogram_clock(u32 dpllctl, u32 ckctl);
extern void omap2_sram_ddr_init(u32 *slow_dll_ctrl, u32 fast_dll_ctrl,
extern u32 omap2_set_prcm(u32 dpll_ctrl_val, u32 sdrc_rfr_val, int bypass);
/* Do not use these */
-extern void sram_reprogram_clock(u32 ckctl, u32 dpllctl);
-extern unsigned long sram_reprogram_clock_sz;
+extern void omap1_sram_reprogram_clock(u32 ckctl, u32 dpllctl);
+extern unsigned long omap1_sram_reprogram_clock_sz;
+
+extern void omap24xx_sram_reprogram_clock(u32 ckctl, u32 dpllctl);
+extern unsigned long omap24xx_sram_reprogram_clock_sz;
-extern void sram_ddr_init(u32 *slow_dll_ctrl, u32 fast_dll_ctrl,
- u32 base_cs, u32 force_unlock);
-extern unsigned long sram_ddr_init_sz;
+extern void omap24xx_sram_ddr_init(u32 *slow_dll_ctrl, u32 fast_dll_ctrl,
+ u32 base_cs, u32 force_unlock);
+extern unsigned long omap24xx_sram_ddr_init_sz;
-extern u32 sram_set_prcm(u32 dpll_ctrl_val, u32 sdrc_rfr_val, int bypass);
-extern unsigned long sram_set_prcm_sz;
+extern u32 omap24xx_sram_set_prcm(u32 dpll_ctrl_val, u32 sdrc_rfr_val,
+ int bypass);
+extern unsigned long omap24xx_sram_set_prcm_sz;
-extern void sram_reprogram_sdrc(u32 perf_level, u32 dll_val, u32 mem_type);
-extern unsigned long sram_reprogram_sdrc_sz;
+extern void omap24xx_sram_reprogram_sdrc(u32 perf_level, u32 dll_val,
+ u32 mem_type);
+extern unsigned long omap24xx_sram_reprogram_sdrc_sz;
#endif
--- /dev/null
+#ifndef __ASM_ARCH_OMAP_STI_H
+#define __ASM_ARCH_OMAP_STI_H
+
+#include <asm/io.h>
+
+/*
+ * STI/SDTI
+ */
+#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_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 */
+};
+
+#define STI_PERCHANNEL_SIZE 4
+
+#define to_channel_address(channel) \
+ (sti_channel_base + STI_PERCHANNEL_SIZE * (channel))
+
+#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)
+
+#define to_channel_address(channel) \
+ (sti_channel_base + STI_PERCHANNEL_SIZE * (channel))
+
+#elif defined(CONFIG_ARCH_OMAP3)
+
+#define STI_PERCHANNEL_SIZE 0x1000
+#define to_channel_address(channel) \
+ (sti_channel_base + STI_PERCHANNEL_SIZE * (channel) + 0x800)
+
+#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);
+}
+
+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 */
static inline void arch_reset(char mode)
{
- if (!cpu_is_omap24xx())
+ if (!cpu_class_is_omap2())
omap1_arch_reset(mode);
else
omap_prcm_arch_reset(mode);
--- /dev/null
+/*
+ * linux/include/asm-arm/arch-omap/usb-ehci.h
+ *
+ * Hardware definitions for Synopsys EHCI host controller.
+ *
+ * Initial creation by Felipe Balbi.
+ *
+ * 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_USB_EHCI_H
+#define __ASM_ARCH_OMAP_USB_EHCI_H
+
+extern void usb_ehci_init(void);
+
+#endif /* __ASM_ARCH_OMAP_USB_EHCI_H */
+
--- /dev/null
+/*
+ * linux/include/asm-arm/arch-omap/usb-musb.h
+ *
+ * Hardware definitions for Mentor Graphics MUSBMHDRC.
+ *
+ * Initial creation by Felipe Balbi.
+ *
+ * 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_USB_MUSB_H
+#define __ASM_ARCH_OMAP_USB_MUSB_H
+
+extern void usb_musb_init(void);
+
+#endif /* __ASM_ARCH_OMAP_USB_MUSB_H */
+
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#define VMALLOC_END (PAGE_OFFSET + 0x10000000)
+#define VMALLOC_END (PAGE_OFFSET + 0x17000000)
* ignore 'ext'.
*/
void (*set_pte_ext)(pte_t *ptep, pte_t pte, unsigned int ext);
+ /*
+ * Retrieve prefetch fault address.
+ */
+ unsigned long (*pabort_addr)(unsigned long lr);
} processor;
#define cpu_proc_init() processor._proc_init()
--- /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 */
#define pmd_none(pmd) (!pmd_val(pmd))
#define pmd_present(pmd) (pmd_val(pmd))
#define pmd_bad(pmd) (pmd_val(pmd) & 2)
+#define pmd_table(pmd) ((pmd_val(pmd) & PMD_TYPE_MASK) == PMD_TYPE_TABLE)
#define copy_pmd(pmdpd,pmdps) \
do { \
__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 CN_VAL_CIFS 0x1
#define CN_W1_IDX 0x3 /* w1 communication */
#define CN_W1_VAL 0x1
+#define CN_IDX_SX1SND 0x4
+#define CN_VAL_SX1SND 0x1
#define CN_IDX_V86D 0x4
#define CN_VAL_V86D_UVESAFB 0x1
#define I2C_DRIVERID_M52790 95 /* Mitsubishi M52790SP/FP AV switch */
#define I2C_DRIVERID_CS5345 96 /* cs5345 audio processor */
+#define I2C_DRIVERID_MISC 99 /* Whatever until sorted out */
+
#define I2C_DRIVERID_I2CDEV 900
#define I2C_DRIVERID_OV7670 1048 /* Omnivision 7670 camera */
--- /dev/null
+/*
+ * include/lm8323.h
+ *
+ * Configuration for LM8323 keypad driver.
+ */
+
+#ifndef __LINUX_LM8323_H
+#define __LINUX_LM8323_H
+
+#include <linux/types.h>
+
+/*
+ * Largest keycode that the chip can send, plus one,
+ * so keys can be mapped directly at the index of the
+ * LM8323 keycode instead of subtracting one.
+ */
+#define LM8323_KEYMAP_SIZE (0x7f + 1)
+
+struct lm8323_platform_data {
+ u16 irq_gpio;
+
+ int debounce_time; /* Time to watch for key bouncing, in ms. */
+ int active_time; /* Idle time until sleep, in ms. */
+
+ int size_x;
+ int size_y;
+ int repeat : 1;
+ const s16 *keymap;
+
+ char *pwm1_name; /* Device name for PWM1. */
+ char *pwm2_name; /* Device name for PWM2. */
+ char *pwm3_name; /* Device name for PWM3. */
+
+ char *name; /* Device name. */
+};
+
+void __init lm8323_set_platform_data(struct lm8323_platform_data *pdata);
+
+#endif /* __LINUX_LM8323_H */
--- /dev/null
+/*
+ * include/linux/i2c/twl4030-madc.h
+ *
+ * TWL4030 MADC module driver header
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Mikko Ylinen <mikko.k.ylinen@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef _TWL4030_MADC_H
+#define _TWL4030_MADC_H
+
+struct twl4030_madc_conversion_method {
+ u8 sel;
+ u8 avg;
+ u8 rbase;
+ u8 ctrl;
+};
+
+#define TWL4030_MADC_MAX_CHANNELS 16
+
+struct twl4030_madc_request {
+ u16 channels;
+ u16 do_avg;
+ u16 method;
+ u16 type;
+ int active;
+ int result_pending;
+ int rbuf[TWL4030_MADC_MAX_CHANNELS];
+ void (*func_cb)(int len, int channels, int *buf);
+};
+
+enum conversion_methods {
+ TWL4030_MADC_RT,
+ TWL4030_MADC_SW1,
+ TWL4030_MADC_SW2,
+ TWL4030_MADC_NUM_METHODS
+};
+
+enum sample_type {
+ TWL4030_MADC_WAIT,
+ TWL4030_MADC_IRQ_ONESHOT,
+ TWL4030_MADC_IRQ_REARM
+};
+
+#define TWL4030_MADC_CTRL1 0x00
+#define TWL4030_MADC_CTRL2 0x01
+
+#define TWL4030_MADC_RTSELECT_LSB 0x02
+#define TWL4030_MADC_SW1SELECT_LSB 0x06
+#define TWL4030_MADC_SW2SELECT_LSB 0x0A
+
+#define TWL4030_MADC_RTAVERAGE_LSB 0x04
+#define TWL4030_MADC_SW1AVERAGE_LSB 0x08
+#define TWL4030_MADC_SW2AVERAGE_LSB 0x0C
+
+#define TWL4030_MADC_CTRL_SW1 0x12
+#define TWL4030_MADC_CTRL_SW2 0x13
+
+#define TWL4030_MADC_RTCH0_LSB 0x17
+#define TWL4030_MADC_GPCH0_LSB 0x37
+
+#define TWL4030_MADC_ISR1 0x61
+#define TWL4030_MADC_IMR1 0x62
+#define TWL4030_MADC_ISR2 0x63
+#define TWL4030_MADC_IMR2 0x64
+#define TWL4030_MADC_SIR 0x65
+#define TWL4030_MADC_EDR 0x66
+#define TWL4030_MADC_SIH_CTRL 0x67
+
+#define TWL4030_MADC_MADCON (1<<0) /* MADC power on */
+#define TWL4030_MADC_BUSY (1<<0) /* MADC busy */
+#define TWL4030_MADC_EOC_SW (1<<1) /* MADC conversion completion */
+#define TWL4030_MADC_SW_START (1<<5) /* MADC SWx start conversion */
+
+#define TWL4030_MADC_ADCIN0 (1<<0)
+#define TWL4030_MADC_ADCIN1 (1<<1)
+#define TWL4030_MADC_ADCIN2 (1<<2)
+#define TWL4030_MADC_ADCIN3 (1<<3)
+#define TWL4030_MADC_ADCIN4 (1<<4)
+#define TWL4030_MADC_ADCIN5 (1<<5)
+#define TWL4030_MADC_ADCIN6 (1<<6)
+#define TWL4030_MADC_ADCIN7 (1<<7)
+#define TWL4030_MADC_ADCIN8 (1<<8)
+#define TWL4030_MADC_ADCIN9 (1<<9)
+#define TWL4030_MADC_ADCIN10 (1<<10)
+#define TWL4030_MADC_ADCIN11 (1<<11)
+#define TWL4030_MADC_ADCIN12 (1<<12)
+#define TWL4030_MADC_ADCIN13 (1<<13)
+#define TWL4030_MADC_ADCIN14 (1<<14)
+#define TWL4030_MADC_ADCIN15 (1<<15)
+
+/* Fixed channels */
+#define TWL4030_MADC_BTEMP TWL4030_MADC_ADCIN1
+#define TWL4030_MADC_VBUS TWL4030_MADC_ADCIN8
+#define TWL4030_MADC_VBKB TWL4030_MADC_ADCIN9
+#define TWL4030_MADC_ICHG TWL4030_MADC_ADCIN10
+#define TWL4030_MADC_VCHG TWL4030_MADC_ADCIN11
+#define TWL4030_MADC_VBAT TWL4030_MADC_ADCIN12
+
+/* BCI related - XXX To be moved elsewhere */
+#define TWL4030_BCI_BCICTL1 0x23
+#define TWL4030_BCI_MESBAT (1<<1)
+#define TWL4030_BCI_TYPEN (1<<4)
+#define TWL4030_BCI_ITHEN (1<<3)
+
+#define TWL4030_MADC_IOC_MAGIC '`'
+#define TWL4030_MADC_IOCX_ADC_RAW_READ _IO(TWL4030_MADC_IOC_MAGIC, 0)
+
+struct twl4030_madc_user_parms {
+ int channel;
+ int average;
+ int status;
+ u16 result;
+};
+
+int twl4030_madc_conversion(struct twl4030_madc_request *conv);
+
+#endif
--- /dev/null
+/*
+ * include/asm-arm/arch-omap/twl4030-rtc.h
+ *
+ * Copyright (C) 2006 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 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 __TWL4030_RTC_H__
+#define __TWL4030_RTC_H__
+
+#define REG_SECONDS_REG (0x0)
+#define REG_MINUTES_REG (0x1)
+#define REG_HOURS_REG (0x2)
+#define REG_DAYS_REG (0x3)
+#define REG_MONTHS_REG (0x4)
+#define REG_YEARS_REG (0x5)
+#define REG_WEEKS_REG (0x6)
+#define REG_ALARM_SECONDS_REG (0x7)
+#define REG_ALARM_MINUTES_REG (0x8)
+#define REG_ALARM_HOURS_REG (0x9)
+#define REG_ALARM_DAYS_REG (0xA)
+#define REG_ALARM_MONTHS_REG (0xB)
+#define REG_ALARM_YEARS_REG (0xC)
+#define REG_RTC_CTRL_REG (0xD)
+#define REG_RTC_STATUS_REG (0xE)
+#define REG_RTC_INTERRUPTS_REG (0xF)
+#define REG_RTC_COMP_LSB_REG (0x10)
+#define REG_RTC_COMP_MSB_REG (0x11)
+
+/* REVISIT: these TWL4030 power registers are only used
+ * by rtc-twl4030 driver, move to an appropriate header
+ * if other drivers need the registers
+ */
+/* Power registers */
+#define REG_PWR_ISR1 0x00
+#define REG_PWR_IMR1 0x01
+#define REG_PWR_EDR1 0x05
+
+#define PWR_RTC_IT_UNMASK ~(0x08)
+#define PWR_RTC_INT_CLR 0x08
+
+/**** BitField Definitions */
+/* SECONDS_REG Fields */
+#define BIT_SECONDS_REG_SEC0 (0x000)
+#define BIT_SECONDS_REG_SEC0_M (0x0000000F)
+#define BIT_SECONDS_REG_SEC1 (0x004)
+#define BIT_SECONDS_REG_SEC1_M (0x00000070)
+/* MINUTES_REG Fields */
+#define BIT_MINUTES_REG_MIN0 (0x000)
+#define BIT_MINUTES_REG_MIN0_M (0x0000000F)
+#define BIT_MINUTES_REG_MIN1 (0x004)
+#define BIT_MINUTES_REG_MIN1_M (0x00000070)
+/* HOURS_REG Fields */
+#define BIT_HOURS_REG_HOUR0 (0x000)
+#define BIT_HOURS_REG_HOUR0_M (0x0000000F)
+#define BIT_HOURS_REG_HOUR1 (0x004)
+#define BIT_HOURS_REG_HOUR1_M (0x00000030)
+#define BIT_HOURS_REG_PM_NAM (0x007)
+#define BIT_HOURS_REG_PM_NAM_M (0x00000080)
+/* DAYS_REG Fields */
+#define BIT_DAYS_REG_DAY0 (0x000)
+#define BIT_DAYS_REG_DAY0_M (0x0000000F)
+#define BIT_DAYS_REG_DAY1 (0x004)
+#define BIT_DAYS_REG_DAY1_M (0x00000030)
+/* MONTHS_REG Fields */
+#define BIT_MONTHS_REG_MONTH0 (0x000)
+#define BIT_MONTHS_REG_MONTH0_M (0x0000000F)
+#define BIT_MONTHS_REG_MONTH1 (0x004)
+#define BIT_MONTHS_REG_MONTH1_M (0x00000010)
+/* YEARS_REG Fields */
+#define BIT_YEARS_REG_YEAR0 (0x000)
+#define BIT_YEARS_REG_YEAR0_M (0x0000000F)
+#define BIT_YEARS_REG_YEAR1 (0x004)
+#define BIT_YEARS_REG_YEAR1_M (0x000000F0)
+/* WEEKS_REG Fields */
+#define BIT_WEEKS_REG_WEEK (0x000)
+#define BIT_WEEKS_REG_WEEK_M (0x00000007)
+/* ALARM_SECONDS_REG Fields */
+#define BIT_ALARM_SECONDS_REG_ALARM_SEC0 (0x000)
+#define BIT_ALARM_SECONDS_REG_ALARM_SEC0_M (0x0000000F)
+#define BIT_ALARM_SECONDS_REG_ALARM_SEC1 (0x004)
+#define BIT_ALARM_SECONDS_REG_ALARM_SEC1_M (0x00000070)
+/* ALARM_MINUTES_REG Fields */
+#define BIT_ALARM_MINUTES_REG_ALARM_MIN0 (0x000)
+#define BIT_ALARM_MINUTES_REG_ALARM_MIN0_M (0x0000000F)
+#define BIT_ALARM_MINUTES_REG_ALARM_MIN1 (0x004)
+#define BIT_ALARM_MINUTES_REG_ALARM_MIN1_M (0x00000070)
+/* ALARM_HOURS_REG Fields */
+#define BIT_ALARM_HOURS_REG_ALARM_HOUR0 (0x000)
+#define BIT_ALARM_HOURS_REG_ALARM_HOUR0_M (0x0000000F)
+#define BIT_ALARM_HOURS_REG_ALARM_HOUR1 (0x004)
+#define BIT_ALARM_HOURS_REG_ALARM_HOUR1_M (0x00000030)
+#define BIT_ALARM_HOURS_REG_ALARM_PM_NAM (0x007)
+#define BIT_ALARM_HOURS_REG_ALARM_PM_NAM_M (0x00000080)
+/* ALARM_DAYS_REG Fields */
+#define BIT_ALARM_DAYS_REG_ALARM_DAY0 (0x000)
+#define BIT_ALARM_DAYS_REG_ALARM_DAY0_M (0x0000000F)
+#define BIT_ALARM_DAYS_REG_ALARM_DAY1 (0x004)
+#define BIT_ALARM_DAYS_REG_ALARM_DAY1_M (0x00000030)
+/* ALARM_MONTHS_REG Fields */
+#define BIT_ALARM_MONTHS_REG_ALARM_MONTH0 (0x000)
+#define BIT_ALARM_MONTHS_REG_ALARM_MONTH0_M (0x0000000F)
+#define BIT_ALARM_MONTHS_REG_ALARM_MONTH1 (0x004)
+#define BIT_ALARM_MONTHS_REG_ALARM_MONTH1_M (0x00000010)
+/* ALARM_YEARS_REG Fields */
+#define BIT_ALARM_YEARS_REG_ALARM_YEAR0 (0x000)
+#define BIT_ALARM_YEARS_REG_ALARM_YEAR0_M (0x0000000F)
+#define BIT_ALARM_YEARS_REG_ALARM_YEAR1 (0x004)
+#define BIT_ALARM_YEARS_REG_ALARM_YEAR1_M (0x000000F0)
+/* RTC_CTRL_REG Fields */
+#define BIT_RTC_CTRL_REG_STOP_RTC (0x000)
+#define BIT_RTC_CTRL_REG_STOP_RTC_M (0x00000001)
+#define BIT_RTC_CTRL_REG_ROUND_30S (0x001)
+#define BIT_RTC_CTRL_REG_ROUND_30S_M (0x00000002)
+#define BIT_RTC_CTRL_REG_AUTO_COMP (0x002)
+#define BIT_RTC_CTRL_REG_AUTO_COMP_M (0x00000004)
+#define BIT_RTC_CTRL_REG_MODE_12_24 (0x003)
+#define BIT_RTC_CTRL_REG_MODE_12_24_M (0x00000008)
+#define BIT_RTC_CTRL_REG_TEST_MODE (0x004)
+#define BIT_RTC_CTRL_REG_TEST_MODE_M (0x00000010)
+#define BIT_RTC_CTRL_REG_SET_32_COUNTER (0x005)
+#define BIT_RTC_CTRL_REG_SET_32_COUNTER_M (0x00000020)
+#define BIT_RTC_CTRL_REG_GET_TIME (0x006)
+#define BIT_RTC_CTRL_REG_GET_TIME_M (0x00000040)
+/* RTC_STATUS_REG Fields */
+#define BIT_RTC_STATUS_REG_RUN (0x001)
+#define BIT_RTC_STATUS_REG_RUN_M (0x00000002)
+#define BIT_RTC_STATUS_REG_1S_EVENT (0x002)
+#define BIT_RTC_STATUS_REG_1S_EVENT_M (0x00000004)
+#define BIT_RTC_STATUS_REG_1M_EVENT (0x003)
+#define BIT_RTC_STATUS_REG_1M_EVENT_M (0x00000008)
+#define BIT_RTC_STATUS_REG_1H_EVENT (0x004)
+#define BIT_RTC_STATUS_REG_1H_EVENT_M (0x00000010)
+#define BIT_RTC_STATUS_REG_1D_EVENT (0x005)
+#define BIT_RTC_STATUS_REG_1D_EVENT_M (0x00000020)
+#define BIT_RTC_STATUS_REG_ALARM (0x006)
+#define BIT_RTC_STATUS_REG_ALARM_M (0x00000040)
+#define BIT_RTC_STATUS_REG_POWER_UP (0x007)
+#define BIT_RTC_STATUS_REG_POWER_UP_M (0x00000080)
+
+/* RTC_INTERRUPTS_REG Fields */
+#define BIT_RTC_INTERRUPTS_REG_EVERY (0x000)
+#define BIT_RTC_INTERRUPTS_REG_EVERY_M (0x00000003)
+#define BIT_RTC_INTERRUPTS_REG_IT_TIMER (0x002)
+#define BIT_RTC_INTERRUPTS_REG_IT_TIMER_M (0x00000004)
+#define BIT_RTC_INTERRUPTS_REG_IT_ALARM (0x003)
+#define BIT_RTC_INTERRUPTS_REG_IT_ALARM_M (0x00000008)
+/* RTC_COMP_LSB_REG Fields */
+#define BIT_RTC_COMP_LSB_REG_RTC_COMP_LSB (0x000)
+#define BIT_RTC_COMP_LSB_REG_RTC_COMP_LSB_M (0x000000FF)
+/* RTC_COMP_MSB_REG Fields */
+#define BIT_RTC_COMP_MSB_REG_RTC_COMP_MSB (0x000)
+#define BIT_RTC_COMP_MSB_REG_RTC_COMP_MSB_M (0x000000FF)
+
+/* ALARM_DAYS_REG Fields */
+#define BIT_ALARM_DAYS_REG_ALARM_DAY1 (0x004)
+#define BIT_ALARM_DAYS_REG_ALARM_DAY1_M (0x00000030)
+/* ALARM_MONTHS_REG Fields */
+#define BIT_ALARM_MONTHS_REG_ALARM_MONTH0 (0x000)
+#define BIT_ALARM_MONTHS_REG_ALARM_MONTH0_M (0x0000000F)
+#define BIT_ALARM_MONTHS_REG_ALARM_MONTH1 (0x004)
+#define BIT_ALARM_MONTHS_REG_ALARM_MONTH1_M (0x00000010)
+/* ALARM_YEARS_REG Fields */
+#define BIT_ALARM_YEARS_REG_ALARM_YEAR0 (0x000)
+#define BIT_ALARM_YEARS_REG_ALARM_YEAR0_M (0x0000000F)
+#define BIT_ALARM_YEARS_REG_ALARM_YEAR1 (0x004)
+#define BIT_ALARM_YEARS_REG_ALARM_YEAR1_M (0x000000F0)
+/* RTC_CTRL_REG Fields */
+#define BIT_RTC_CTRL_REG_STOP_RTC (0x000)
+#define BIT_RTC_CTRL_REG_STOP_RTC_M (0x00000001)
+#define BIT_RTC_CTRL_REG_ROUND_30S (0x001)
+#define BIT_RTC_CTRL_REG_ROUND_30S_M (0x00000002)
+#define BIT_RTC_CTRL_REG_AUTO_COMP (0x002)
+#define BIT_RTC_CTRL_REG_AUTO_COMP_M (0x00000004)
+#define BIT_RTC_CTRL_REG_MODE_12_24 (0x003)
+#define BIT_RTC_CTRL_REG_MODE_12_24_M (0x00000008)
+#define BIT_RTC_CTRL_REG_TEST_MODE (0x004)
+#define BIT_RTC_CTRL_REG_TEST_MODE_M (0x00000010)
+#define BIT_RTC_CTRL_REG_SET_32_COUNTER (0x005)
+#define BIT_RTC_CTRL_REG_SET_32_COUNTER_M (0x00000020)
+#define BIT_RTC_CTRL_REG_GET_TIME (0x006)
+#define BIT_RTC_CTRL_REG_GET_TIME_M (0x00000040)
+/* RTC_STATUS_REG Fields */
+#define BIT_RTC_STATUS_REG_RUN (0x001)
+#define BIT_RTC_STATUS_REG_RUN_M (0x00000002)
+#define BIT_RTC_STATUS_REG_1S_EVENT (0x002)
+#define BIT_RTC_STATUS_REG_1S_EVENT_M (0x00000004)
+#define BIT_RTC_STATUS_REG_1M_EVENT (0x003)
+#define BIT_RTC_STATUS_REG_1M_EVENT_M (0x00000008)
+#define BIT_RTC_STATUS_REG_1H_EVENT (0x004)
+#define BIT_RTC_STATUS_REG_1H_EVENT_M (0x00000010)
+#define BIT_RTC_STATUS_REG_1D_EVENT (0x005)
+#define BIT_RTC_STATUS_REG_1D_EVENT_M (0x00000020)
+#define BIT_RTC_STATUS_REG_ALARM (0x006)
+#define BIT_RTC_STATUS_REG_ALARM_M (0x00000040)
+#define BIT_RTC_STATUS_REG_POWER_UP (0x007)
+#define BIT_RTC_STATUS_REG_POWER_UP_M (0x00000080)
+/* RTC_INTERRUPTS_REG Fields */
+#define BIT_RTC_INTERRUPTS_REG_EVERY (0x000)
+#define BIT_RTC_INTERRUPTS_REG_EVERY_M (0x00000003)
+#define BIT_RTC_INTERRUPTS_REG_IT_TIMER (0x002)
+#define BIT_RTC_INTERRUPTS_REG_IT_TIMER_M (0x00000004)
+#define BIT_RTC_INTERRUPTS_REG_IT_ALARM (0x003)
+#define BIT_RTC_INTERRUPTS_REG_IT_ALARM_M (0x00000008)
+/* RTC_COMP_LSB_REG Fields */
+#define BIT_RTC_COMP_LSB_REG_RTC_COMP_LSB (0x000)
+#define BIT_RTC_COMP_LSB_REG_RTC_COMP_LSB_M (0x000000FF)
+/* RTC_COMP_MSB_REG Fields */
+#define BIT_RTC_COMP_MSB_REG_RTC_COMP_MSB (0x000)
+#define BIT_RTC_COMP_MSB_REG_RTC_COMP_MSB_M (0x000000FF)
+
+
+struct twl4030rtc_platform_data {
+ int (*init)(void);
+ void (*exit)(void);
+};
+
+#endif /* End of __TWL4030_RTC_H__ */
--- /dev/null
+/*
+ * twl4030.h - header for TWL4030 PM and audio CODEC device
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * Based on tlv320aic23.c:
+ * Copyright (c) by Kai Svahn <kai.svahn@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 __TWL4030_H_
+#define __TWL4030_H_
+
+/* USB ID */
+#define TWL4030_MODULE_USB 0x00
+/* AUD ID */
+#define TWL4030_MODULE_AUDIO_VOICE 0x01
+#define TWL4030_MODULE_GPIO 0x02
+#define TWL4030_MODULE_INTBR 0x03
+#define TWL4030_MODULE_PIH 0x04
+#define TWL4030_MODULE_TEST 0x05
+/* AUX ID */
+#define TWL4030_MODULE_KEYPAD 0x06
+#define TWL4030_MODULE_MADC 0x07
+#define TWL4030_MODULE_INTERRUPTS 0x08
+#define TWL4030_MODULE_LED 0x09
+#define TWL4030_MODULE_MAIN_CHARGE 0x0A
+#define TWL4030_MODULE_PRECHARGE 0x0B
+#define TWL4030_MODULE_PWM0 0x0C
+#define TWL4030_MODULE_PWM1 0x0D
+#define TWL4030_MODULE_PWMA 0x0E
+#define TWL4030_MODULE_PWMB 0x0F
+/* POWER ID */
+#define TWL4030_MODULE_BACKUP 0x10
+#define TWL4030_MODULE_INT 0x11
+#define TWL4030_MODULE_PM_MASTER 0x12
+#define TWL4030_MODULE_PM_RECEIVER 0x13
+#define TWL4030_MODULE_RTC 0x14
+#define TWL4030_MODULE_SECURED_REG 0x15
+
+/* IRQ information-need base */
+#include <asm/arch/irqs.h>
+/* TWL4030 interrupts */
+
+#define TWL4030_MODIRQ_GPIO (TWL4030_IRQ_BASE + 0)
+#define TWL4030_MODIRQ_KEYPAD (TWL4030_IRQ_BASE + 1)
+#define TWL4030_MODIRQ_BCI (TWL4030_IRQ_BASE + 2)
+#define TWL4030_MODIRQ_MADC (TWL4030_IRQ_BASE + 3)
+#define TWL4030_MODIRQ_USB (TWL4030_IRQ_BASE + 4)
+#define TWL4030_MODIRQ_PWR (TWL4030_IRQ_BASE + 5)
+
+#define TWL4030_PWRIRQ_PWRBTN (TWL4030_PWR_IRQ_BASE + 0)
+#define TWL4030_PWRIRQ_CHG_PRES (TWL4030_PWR_IRQ_BASE + 1)
+#define TWL4030_PWRIRQ_USB_PRES (TWL4030_PWR_IRQ_BASE + 2)
+#define TWL4030_PWRIRQ_RTC (TWL4030_PWR_IRQ_BASE + 3)
+#define TWL4030_PWRIRQ_HOT_DIE (TWL4030_PWR_IRQ_BASE + 4)
+#define TWL4030_PWRIRQ_PWROK_TIMEOUT (TWL4030_PWR_IRQ_BASE + 5)
+#define TWL4030_PWRIRQ_MBCHG (TWL4030_PWR_IRQ_BASE + 6)
+#define TWL4030_PWRIRQ_SC_DETECT (TWL4030_PWR_IRQ_BASE + 7)
+
+/* Rest are unsued currently*/
+
+/* Offsets to Power Registers */
+#define TWL4030_VDAC_DEV_GRP 0x3B
+#define TWL4030_VDAC_DEDICATED 0x3E
+#define TWL4030_VAUX2_DEV_GRP 0x1B
+#define TWL4030_VAUX2_DEDICATED 0x1E
+#define TWL4030_VAUX3_DEV_GRP 0x1F
+#define TWL4030_VAUX3_DEDICATED 0x22
+
+/* TWL4030 GPIO interrupt definitions */
+
+#define TWL4030_GPIO_MIN 0
+#define TWL4030_GPIO_MAX 18
+#define TWL4030_GPIO_MAX_CD 2
+#define TWL4030_GPIO_IRQ_NO(n) (TWL4030_GPIO_IRQ_BASE + (n))
+#define TWL4030_GPIO_IS_INPUT 1
+#define TWL4030_GPIO_IS_OUTPUT 0
+#define TWL4030_GPIO_IS_ENABLE 1
+#define TWL4030_GPIO_IS_DISABLE 0
+#define TWL4030_GPIO_PULL_UP 0
+#define TWL4030_GPIO_PULL_DOWN 1
+#define TWL4030_GPIO_PULL_NONE 2
+#define TWL4030_GPIO_EDGE_NONE 0
+#define TWL4030_GPIO_EDGE_RISING 1
+#define TWL4030_GPIO_EDGE_FALLING 2
+
+/* Functions to read and write from TWL4030 */
+
+/*
+ * IMP NOTE:
+ * The base address of the module will be added by the triton driver
+ * It is the caller's responsibility to ensure sane values
+ */
+int twl4030_i2c_write_u8(u8 mod_no, u8 val, u8 reg);
+int twl4030_i2c_read_u8(u8 mod_no, u8 *val, u8 reg);
+
+ /*
+ * i2c_write: IMPORTANT - Allocate value num_bytes+1 and valid data starts at
+ * Offset 1.
+ */
+int twl4030_i2c_write(u8 mod_no, u8 *value, u8 reg, u8 num_bytes);
+int twl4030_i2c_read(u8 mod_no, u8 *value, u8 reg, u8 num_bytes);
+
+/*
+ * Exported TWL4030 GPIO APIs
+ */
+int twl4030_get_gpio_datain(int gpio);
+int twl4030_request_gpio(int gpio);
+int twl4030_set_gpio_edge_ctrl(int gpio, int edge);
+int twl4030_set_gpio_debounce(int gpio, int enable);
+int twl4030_free_gpio(int gpio);
+
+#endif /* End of __TWL4030_H */
unsigned char *buffer, unsigned int len);
extern unsigned int __kfifo_get(struct kfifo *fifo,
unsigned char *buffer, unsigned int len);
+extern unsigned int __kfifo_get_to_user(struct kfifo *fifo,
+ unsigned char __user *buffer,
+ unsigned int len);
/**
* __kfifo_reset - removes the entire FIFO contents, no locking version
return ret;
}
+/**
+ * kfifo_get_to_user - gets some data from the FIFO
+ * @fifo: the fifo to be used.
+ * @buffer: where the data must be copied. user buffer
+ * @len: the size of the destination buffer.
+ *
+ * This function copies at most @len bytes from the FIFO into the
+ * user @buffer and returns the number of copied bytes.
+ */
+static inline unsigned int kfifo_get_to_user(struct kfifo *fifo,
+ unsigned char __user *buffer,
+ unsigned int len)
+{
+ unsigned long flags;
+ unsigned int ret;
+
+ spin_lock_irqsave(fifo->lock, flags);
+
+ ret = __kfifo_get_to_user(fifo, buffer, len);
+
+ /*
+ * optimization: if the FIFO is empty, set the indices to 0
+ * so we don't wrap the next time
+ */
+ if (fifo->in == fifo->out)
+ fifo->in = fifo->out = 0;
+
+ spin_unlock_irqrestore(fifo->lock, flags);
+
+ return ret;
+}
+
#endif
--- /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
/********** sound/oss/ **********/
#define OSS_POISON_FREE 0xAB
+/*
+ * Used in arch/arm/plat-omap/sram.h to mark SRAM addresses that
+ * will be patched at runtime
+ */
+#define SRAM_VA_MAGIC 0xbadfeed1
+
#endif
void **filter_data);
int (*filter) (void *filter_data, int data_idx, int *val);
void (*filter_cleanup)(void *filter_data);
+
+ /* controls enabling/disabling*/
+ int (*vaux_control)(int vaux_cntrl);
+#define VAUX_ENABLE 1
+#define VAUX_DISABLE 0
};
--- /dev/null
+#ifndef _LINUX_SPI_TSC2005_H
+#define _LINUX_SPI_TSC2005_H
+
+#include <linux/types.h>
+
+struct tsc2005_platform_data {
+ s16 reset_gpio;
+ s16 dav_gpio;
+ s16 pen_int_gpio;
+ u16 ts_x_plate_ohm;
+ u32 ts_stab_time; /* voltage settling time */
+ u8 ts_hw_avg; /* HW assiseted averaging. Can be
+ 0, 4, 8, 16 samples per reading */
+ u32 ts_touch_pressure; /* Pressure limit until we report a
+ touch event. After that we switch
+ to ts_max_pressure. */
+ u32 ts_pressure_max;/* Samples with bigger pressure value will
+ be ignored, since the corresponding X, Y
+ values are unreliable */
+ u32 ts_pressure_fudge;
+ u32 ts_x_max;
+ u32 ts_x_fudge;
+ u32 ts_y_max;
+ u32 ts_y_fudge;
+
+ unsigned ts_ignore_last : 1;
+};
+
+#endif
--- /dev/null
+/*
+ * include/linux/spi/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
+
+#include <linux/spi/spi.h>
+
+struct tsc2101_platform_data {
+ int (*init)(struct spi_device *spi);
+ void (*cleanup)(struct spi_device *spi);
+ void (*enable_mclk)(struct spi_device *spi);
+ void (*disable_mclk)(struct spi_device *spi);
+};
+
+extern int tsc2101_read_sync(struct spi_device *spi, int page, u8 address);
+extern int tsc2101_reads_sync(struct spi_device *spi, int page,
+ u8 startaddress, u16 * data, int numregs);
+extern int tsc2101_write_sync(struct spi_device *spi, int page, u8 address,
+ u16 data);
+
+extern int tsc2101_enable_mclk(struct spi_device *spi);
+extern void tsc2101_disable_mclk(struct spi_device *spi);
+
+#endif
+
--- /dev/null
+/*
+ * include/linux/spi/tsc2102.h
+ *
+ * TI TSC2102 Touchscreen, Audio and Battery control register definitions
+ *
+ * Copyright (c) 2005 Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this package; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __LINUX_SPI_TSC2102_H
+#define __LINUX_SPI_TSC2102_H
+
+struct apm_power_info;
+struct tsc2102_config {
+ int use_internal; /* Use internal reference voltage */
+ uint32_t monitor; /* What inputs are relevant */
+ int temp_at25c[2]; /* Thermometer calibration data */
+ void (*apm_report)(struct apm_power_info *info, int *battery);
+ /* Report status to APM based on battery[] */
+ void *alsa_config; /* .platform_data for the ALSA device */
+};
+
+#define TSC_BAT1 (1 << 0)
+#define TSC_BAT2 (1 << 1)
+#define TSC_AUX (1 << 2)
+#define TSC_TEMP (1 << 4)
+
+extern u16 tsc2102_read_sync(int page, u8 address);
+extern void tsc2102_reads_sync(int page, u8 startaddress, u16 *data,
+ int numregs);
+extern void tsc2102_write_sync(int page, u8 address, u16 data);
+
+typedef void (*tsc2102_touch_t)(int touching);
+typedef void (*tsc2102_coords_t)(int x, int y, int z1, int z2);
+typedef void (*tsc2102_ports_t)(int bat1, int bat2, int aux);
+typedef void (*tsc2102_temp_t)(int temp);
+extern int tsc2102_touch_cb(tsc2102_touch_t handler);
+extern int tsc2102_coords_cb(tsc2102_coords_t handler);
+extern int tsc2102_ports_cb(tsc2102_ports_t handler);
+extern int tsc2102_temp1_cb(tsc2102_temp_t handler);
+extern int tsc2102_temp2_cb(tsc2102_temp_t handler);
+
+#if defined(CONFIG_SND_OMAP_TSC2102) || defined(CONFIG_SND_OMAP_TSC2102_MODULE)
+extern void tsc2102_set_volume(uint8_t left_ch, uint8_t right_ch);
+extern void tsc2102_set_mute(int left_ch, int right_ch);
+extern void tsc2102_get_mute(int *left_ch, int *right_ch);
+extern void tsc2102_dac_power(int state);
+extern int tsc2102_set_rate(int rate);
+extern void tsc2102_set_i2s_master(int state);
+extern void tsc2102_set_deemphasis(int enable);
+extern void tsc2102_set_bassboost(int enable);
+#endif
+
+extern void tsc2102_keyclick(int amplitude, int freq, int length);
+
+#define TSC2102_REG(pg, addr) pg, addr
+
+/* Page 0, Touch Screen & Keypad Data registers */
+#define TSC2102_TS_X TSC2102_REG(0, 0x00)
+#define TSC2102_TS_Y TSC2102_REG(0, 0x01)
+#define TSC2102_TS_Z1 TSC2102_REG(0, 0x02)
+#define TSC2102_TS_Z2 TSC2102_REG(0, 0x03)
+#define TSC2102_TS_BAT1 TSC2102_REG(0, 0x05)
+#define TSC2102_TS_BAT2 TSC2102_REG(0, 0x06)
+#define TSC2102_TS_AUX TSC2102_REG(0, 0x07)
+#define TSC2102_TS_TEMP1 TSC2102_REG(0, 0x09)
+#define TSC2102_TS_TEMP2 TSC2102_REG(0, 0x0a)
+
+/* Page 1, Touch Screen & Keypad Control registers */
+#define TSC2102_TS_ADC_CTRL TSC2102_REG(1, 0x00)
+#define TSC2102_TS_STATUS_CTRL TSC2102_REG(1, 0x01)
+#define TSC2102_TS_REF_CTRL TSC2102_REG(1, 0x03)
+#define TSC2102_TS_RESET_CTRL TSC2102_REG(1, 0x04)
+#define TSC2102_TS_CONFIG_CTRL TSC2102_REG(1, 0x05)
+
+/* Page 2, Audio Control registers */
+#define TSC2102_AUDIO1_CTRL TSC2102_REG(2, 0x00)
+#define TSC2102_DAC_GAIN_CTRL TSC2102_REG(2, 0x02)
+#define TSC2102_AUDIO2_CTRL TSC2102_REG(2, 0x04)
+#define TSC2102_DAC_POWER_CTRL TSC2102_REG(2, 0x05)
+#define TSC2102_AUDIO3_CTRL TSC2102_REG(2, 0x06)
+#define TSC2102_LCH_BASS_BOOST_N0 TSC2102_REG(2, 0x07)
+#define TSC2102_LCH_BASS_BOOST_N1 TSC2102_REG(2, 0x08)
+#define TSC2102_LCH_BASS_BOOST_N2 TSC2102_REG(2, 0x09)
+#define TSC2102_LCH_BASS_BOOST_N3 TSC2102_REG(2, 0x0a)
+#define TSC2102_LCH_BASS_BOOST_N4 TSC2102_REG(2, 0x0b)
+#define TSC2102_LCH_BASS_BOOST_N5 TSC2102_REG(2, 0x0c)
+#define TSC2102_LCH_BASS_BOOST_D1 TSC2102_REG(2, 0x0d)
+#define TSC2102_LCH_BASS_BOOST_D2 TSC2102_REG(2, 0x0e)
+#define TSC2102_LCH_BASS_BOOST_D4 TSC2102_REG(2, 0x0f)
+#define TSC2102_LCH_BASS_BOOST_D5 TSC2102_REG(2, 0x10)
+#define TSC2102_RCH_BASS_BOOST_N0 TSC2102_REG(2, 0x11)
+#define TSC2102_RCH_BASS_BOOST_N1 TSC2102_REG(2, 0x12)
+#define TSC2102_RCH_BASS_BOOST_N2 TSC2102_REG(2, 0x13)
+#define TSC2102_RCH_BASS_BOOST_N3 TSC2102_REG(2, 0x14)
+#define TSC2102_RCH_BASS_BOOST_N4 TSC2102_REG(2, 0x15)
+#define TSC2102_RCH_BASS_BOOST_N5 TSC2102_REG(2, 0x16)
+#define TSC2102_RCH_BASS_BOOST_D1 TSC2102_REG(2, 0x17)
+#define TSC2102_RCH_BASS_BOOST_D2 TSC2102_REG(2, 0x18)
+#define TSC2102_RCH_BASS_BOOST_D4 TSC2102_REG(2, 0x19)
+#define TSC2102_RCH_BASS_BOOST_D5 TSC2102_REG(2, 0x1a)
+#define TSC2102_PLL1_CTRL TSC2102_REG(2, 0x1b)
+#define TSC2102_PLL2_CTRL TSC2102_REG(2, 0x1c)
+#define TSC2102_AUDIO4_CTRL TSC2102_REG(2, 0x1d)
+
+/* Field masks for Audio Control 1 */
+#define AC1_WLEN(ARG) (((ARG) & 0x03) << 10)
+#define AC1_DATFM(ARG) (((ARG) & 0x03) << 8)
+#define AC1_DACFS(ARG) ((ARG) & 0x3f)
+
+/* Field masks for TSC2102_DAC_GAIN_CTRL */
+#define DGC_DALMU (1 << 15)
+#define DGC_DALVL(ARG) (((ARG) & 0x7f) << 8)
+#define DGC_DARMU (1 << 7)
+#define DGC_DARVL(ARG) (((ARG) & 0x7f))
+
+/* Field formats for TSC2102_AUDIO2_CTRL */
+#define AC2_KCLEN (1 << 15)
+#define AC2_KCLAC(ARG) (((ARG) & 0x07) << 12)
+#define AC2_KCLFRQ(ARG) (((ARG) & 0x07) << 8)
+#define AC2_KCLLN(ARG) (((ARG) & 0x0f) << 4)
+#define AC2_DLGAF (1 << 3)
+#define AC2_DRGAF (1 << 2)
+#define AC2_DASTC (1 << 1)
+
+/* Field masks for TSC2102_DAC_POWER_CTRL */
+#define CPC_PWDNC (1 << 15)
+#define CPC_DAODRC (1 << 12)
+#define CPC_DAPWDN (1 << 10)
+#define CPC_VGPWDN (1 << 8)
+#define CPC_DAPWDF (1 << 6)
+#define CPC_BASSBC (1 << 1)
+#define CPC_DEEMPF (0x01)
+
+/* Field masks for TSC2101_AUDIO_CTRL_3 */
+#define AC3_DMSVOL(ARG) (((ARG) & 0x03) << 14)
+#define AC3_REFFS (1 << 13)
+#define AC3_DAXFM (1 << 12)
+#define AC3_SLVMS (1 << 11)
+#define AC3_DALOVF (1 << 7)
+#define AC3_DAROVF (1 << 6)
+#define AC3_REVID(ARG) (((ARG) & 0x07))
+
+/* Field masks for TSC2102_PLL1_CTRL */
+#define PLL1_PLLEN (1 << 15)
+#define PLL1_Q_VAL(ARG) (((ARG) & 0x0f) << 11)
+#define PLL1_P_VAL(ARG) (((ARG) & 0x07) << 8)
+#define PLL1_I_VAL(ARG) (((ARG) & 0x3f) << 2)
+
+/* Field masks for TSC2102_PLL2_CTRL */
+#define PLL2_D_VAL(ARG) (((ARG) & 0x3fff) << 2)
+
+/* Field masks for TSC2101_AUDIO_CTRL_4 */
+#define AC4_DASTPD (1 << 14)
+
+struct tsc2102_rate_info_s {
+ u16 sample_rate;
+ u8 divisor;
+ u8 fs_44k; /* 44.1 kHz Fsref if 1, 48 kHz if 0 */
+};
+
+#endif /* __LINUX_SPI_TSC2102_H */
--- /dev/null
+/*
+ * include/linux/spi/tsc2102.h
+ *
+ * TI TSC2101/2102 control register definitions.
+ *
+ * Copyright (c) 2005-2007 Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this package; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __LINUX_SPI_TSC210X_H
+#define __LINUX_SPI_TSC210X_H
+
+struct apm_power_info;
+
+struct tsc210x_config {
+ int use_internal; /* Use internal reference voltage */
+ u32 monitor; /* What inputs are wired on this board */
+ int temp_at25c[2]; /* Thermometer calibration data */
+ void (*apm_report)(struct apm_power_info *info, int battery[]);
+ /* Report status to APM based on battery[] */
+ void *alsa_config; /* .platform_data for the ALSA device */
+ const char *mclk; /* Optional: mclk name */
+ const char *bclk; /* Optional: bclk name */
+};
+
+#define TSC_BAT1 (1 << 0)
+#define TSC_BAT2 (1 << 1)
+#define TSC_AUX1 (1 << 2)
+#define TSC_AUX2 (1 << 3)
+#define TSC_TEMP (1 << 4)
+
+#define TSC_AUX TSC_AUX1
+#define TSC_VBAT TSC_BAT1
+
+struct tsc210x_dev;
+
+/* Drivers for tsc210x components like touchscreen, sensor, and audio
+ * are packaged as platform drivers which can issue synchronous register
+ * acceses, and may also register a callback to process their particular
+ * type of data when that data is automatically sampled. The platform
+ * device is a child of the TSC spi device.
+ */
+
+extern int tsc210x_read_sync(struct tsc210x_dev *dev, int page, u8 address);
+extern int tsc210x_reads_sync(struct tsc210x_dev *dev, int page,
+ u8 startaddress, u16 *data, int numregs);
+extern int tsc210x_write_sync(struct tsc210x_dev *dev, int page,
+ u8 address, u16 data);
+
+typedef void (*tsc210x_touch_t)(void *context, int touching);
+typedef void (*tsc210x_coords_t)(void *context, int x, int y, int z1, int z2);
+typedef void (*tsc210x_ports_t)(void *context, int bat[], int aux[]);
+typedef void (*tsc210x_temp_t)(void *context, int temp);
+
+extern int tsc210x_touch_cb(struct device *dev,
+ tsc210x_touch_t handler, void *context);
+extern int tsc210x_coords_cb(struct device *dev,
+ tsc210x_coords_t handler, void *context);
+extern int tsc210x_ports_cb(struct device *dev,
+ tsc210x_ports_t handler, void *context);
+extern int tsc210x_temp1_cb(struct device *dev,
+ tsc210x_temp_t handler, void *context);
+extern int tsc210x_temp2_cb(struct device *dev,
+ tsc210x_temp_t handler, void *context);
+
+#if defined(CONFIG_SOUND) || defined(CONFIG_SOUND_MODULE)
+extern void tsc210x_set_dac_volume(struct device *dev, u8 left, u8 right);
+extern void tsc210x_set_dac_mute(struct device *dev, int left, int right);
+extern void tsc210x_get_dac_mute(struct device *dev, int *left, int *right);
+extern void tsc210x_dac_power(struct device *dev, int on);
+extern int tsc210x_set_rate(struct device *dev, int rate);
+extern void tsc210x_set_i2s_master(struct device *dev, int state);
+extern void tsc210x_set_deemphasis(struct device *dev, int enable);
+extern void tsc2102_set_bassboost(struct device *dev, int enable);
+#endif
+
+/*
+ * Emit a short keyclick typically in order to give feedback to
+ * user on specific events.
+ *
+ * amplitude must be between 0 (lowest) and 2 (highest).
+ * freq must be between 0 (corresponds to 62.5 Hz) and 7 (8 kHz).
+ * length should be between 2 and 32 periods.
+ *
+ * This function sleeps but for a period unrelated to the length of
+ * the sound, i.e. returning doesn't indicate that the sound has
+ * finished.
+ */
+extern void tsc210x_keyclick(struct tsc210x_dev *dev,
+ int amplitude, int freq, int length);
+
+/* Page 0, Touch Screen & Keypad Data registers */
+#define TSC210X_TS_X 0, 0x00
+#define TSC210X_TS_Y 0, 0x01
+#define TSC210X_TS_Z1 0, 0x02
+#define TSC210X_TS_Z2 0, 0x03
+#define TSC210X_TS_BAT1 0, 0x05
+#define TSC2102_TS_BAT2 0, 0x06
+#define TSC210X_TS_AUX1 0, 0x07
+#define TSC2101_TS_AUX2 0, 0x08
+#define TSC210X_TS_TEMP1 0, 0x09
+#define TSC210X_TS_TEMP2 0, 0x0a
+
+/* Page 1, Touch Screen & Keypad Control registers */
+#define TSC210X_TS_ADC_CTRL 1, 0x00
+#define TSC210X_TS_STATUS_CTRL 1, 0x01
+#define TSC2101_TS_BUFFER_CTRL 1, 0x02
+#define TSC210X_TS_REF_CTRL 1, 0x03
+#define TSC210X_TS_RESET_CTRL 1, 0x04
+#define TSC210X_TS_CONFIG_CTRL 1, 0x05
+#define TSC2101_TS_TEMPMAX_CTRL 1, 0x06
+#define TSC2101_TS_TEMPMIN_CTRL 1, 0x07
+#define TSC2101_TS_AUX1MAX_CTRL 1, 0x08
+#define TSC2101_TS_AUX1MIN_CTRL 1, 0x09
+#define TSC2101_TS_AUX2MAX_CTRL 1, 0x0a
+#define TSC2101_TS_AUX2MIN_CTRL 1, 0x0b
+#define TSC2101_TS_MCONFIG_CTRL 1, 0x0c
+#define TSC2101_TS_DELAY_CTRL 1, 0x0d
+
+/* Page 2, Audio Control registers */
+#define TSC210X_AUDIO1_CTRL 2, 0x00
+#define TSC2101_HEADSET_GAIN_CTRL 2, 0x01
+#define TSC210X_DAC_GAIN_CTRL 2, 0x02
+#define TSC2101_MIXER_GAIN_CTRL 2, 0x03
+#define TSC210X_AUDIO2_CTRL 2, 0x04
+#define TSC210X_POWER_CTRL 2, 0x05
+#define TSC210X_AUDIO3_CTRL 2, 0x06
+#define TSC210X_LCH_BASS_BOOST_N0 2, 0x07
+#define TSC210X_LCH_BASS_BOOST_N1 2, 0x08
+#define TSC210X_LCH_BASS_BOOST_N2 2, 0x09
+#define TSC210X_LCH_BASS_BOOST_N3 2, 0x0a
+#define TSC210X_LCH_BASS_BOOST_N4 2, 0x0b
+#define TSC210X_LCH_BASS_BOOST_N5 2, 0x0c
+#define TSC210X_LCH_BASS_BOOST_D1 2, 0x0d
+#define TSC210X_LCH_BASS_BOOST_D2 2, 0x0e
+#define TSC210X_LCH_BASS_BOOST_D4 2, 0x0f
+#define TSC210X_LCH_BASS_BOOST_D5 2, 0x10
+#define TSC210X_RCH_BASS_BOOST_N0 2, 0x11
+#define TSC210X_RCH_BASS_BOOST_N1 2, 0x12
+#define TSC210X_RCH_BASS_BOOST_N2 2, 0x13
+#define TSC210X_RCH_BASS_BOOST_N3 2, 0x14
+#define TSC210X_RCH_BASS_BOOST_N4 2, 0x15
+#define TSC210X_RCH_BASS_BOOST_N5 2, 0x16
+#define TSC210X_RCH_BASS_BOOST_D1 2, 0x17
+#define TSC210X_RCH_BASS_BOOST_D2 2, 0x18
+#define TSC210X_RCH_BASS_BOOST_D4 2, 0x19
+#define TSC210X_RCH_BASS_BOOST_D5 2, 0x1a
+#define TSC210X_PLL1_CTRL 2, 0x1b
+#define TSC210X_PLL2_CTRL 2, 0x1c
+#define TSC210X_AUDIO4_CTRL 2, 0x1d
+#define TSC2101_HANDSET_GAIN_CTRL 2, 0x1e
+#define TSC2101_CELL_GAIN_CTRL 2, 0x1f
+#define TSC2101_AUIDO5_CTRL 2, 0x20
+#define TSC2101_AUDIO6_CTRL 2, 0x21
+#define TSC2101_AUDIO7_CTRL 2, 0x22
+#define TSC2101_GPIO_CTRL 2, 0x23
+#define TSC2101_IN_AGC_CTRL 2, 0x24
+#define TSC2101_POWER_STATUS 2, 0x25
+#define TSC2101_MIX_AGC_CTRL 2, 0x26
+#define TSC2101_CELL_AGC_CTRL 2, 0x27
+
+/* Field masks for Audio Control 1 */
+#define AC1_WLEN(ARG) (((ARG) & 0x03) << 10)
+#define AC1_DATFM(ARG) (((ARG) & 0x03) << 8)
+#define AC1_DACFS(ARG) ((ARG) & 0x3f)
+
+/* Field masks for TSC2102_DAC_GAIN_CTRL */
+#define DGC_DALMU (1 << 15)
+#define DGC_DALVL(ARG) (((ARG) & 0x7f) << 8)
+#define DGC_DARMU (1 << 7)
+#define DGC_DARVL(ARG) (((ARG) & 0x7f))
+
+/* Field formats for TSC210X_AUDIO2_CTRL */
+#define AC2_KCLEN (1 << 15)
+#define AC2_KCLAC(ARG) (((ARG) & 0x07) << 12)
+#define AC2_KCLFRQ(ARG) (((ARG) & 0x07) << 8)
+#define AC2_KCLLN(ARG) (((ARG) & 0x0f) << 4)
+#define AC2_DLGAF (1 << 3)
+#define AC2_DRGAF (1 << 2)
+#define AC2_DASTC (1 << 1)
+
+/* Field masks for TSC210X_DAC_POWER_CTRL */
+#define CPC_PWDNC (1 << 15)
+#define CPC_DAODRC (1 << 12)
+#define CPC_DAPWDN (1 << 10)
+#define CPC_VGPWDN (1 << 8)
+#define CPC_DAPWDF (1 << 6)
+#define CPC_BASSBC (1 << 1)
+#define CPC_DEEMPF (0x01)
+
+/* Field masks for TSC210X_AUDIO3_CTRL */
+#define AC3_DMSVOL(ARG) (((ARG) & 0x03) << 14)
+#define AC3_REFFS (1 << 13)
+#define AC3_DAXFM (1 << 12)
+#define AC3_SLVMS (1 << 11)
+#define AC3_DALOVF (1 << 7)
+#define AC3_DAROVF (1 << 6)
+#define AC3_REVID(ARG) (((ARG) & 0x07))
+
+/* Field masks for TSC210X_PLL1_CTRL */
+#define PLL1_PLLEN (1 << 15)
+#define PLL1_Q_VAL(ARG) (((ARG) & 0x0f) << 11)
+#define PLL1_P_VAL(ARG) (((ARG) & 0x07) << 8)
+#define PLL1_I_VAL(ARG) (((ARG) & 0x3f) << 2)
+
+/* Field masks for TSC210X_PLL2_CTRL */
+#define PLL2_D_VAL(ARG) (((ARG) & 0x3fff) << 2)
+
+/* Field masks for TSC210X_AUDIO4_CTRL */
+#define AC4_DASTPD (1 << 14)
+
+struct tsc210x_rate_info_s {
+ u16 sample_rate;
+ u8 divisor;
+ u8 fs_44k; /* 44.1 kHz Fsref if 1, 48 kHz if 0 */
+};
+
+#endif /* __LINUX_SPI_TSC210X_H */
--- /dev/null
+#ifndef _LINUX_SPI_TSC2301_H
+#define _LINUX_SPI_TSC2301_H
+
+#include <linux/types.h>
+#include <linux/timer.h>
+
+struct tsc2301_platform_data {
+ /*
+ * Keypad
+ */
+ s16 reset_gpio;
+ s16 keyb_int;
+ s16 keymap[16]; /* Set a key to a negative value if not used */
+ unsigned kp_rep:1; /* Enable keypad repeating */
+ char *keyb_name; /* Keyboard device name */
+
+ /*
+ * Touchscreen
+ */
+ s16 dav_int;
+ u16 ts_x_plate_ohm;
+ u32 ts_stab_time; /* voltage settling time */
+ u8 ts_hw_avg; /* HW assiseted averaging. Can be
+ 0, 4, 8, 16 samples per reading */
+ u32 ts_max_pressure;/* Samples with bigger pressure value will
+ be ignored, since the corresponding X, Y
+ values are unreliable */
+ u32 ts_touch_pressure; /* Pressure limit until we report a
+ touch event. After that we switch
+ to ts_max_pressure. */
+ u32 ts_pressure_fudge;
+ u32 ts_x_max;
+ u32 ts_x_fudge;
+ u32 ts_y_max;
+ u32 ts_y_fudge;
+
+ /*
+ * Audio
+ */
+ unsigned pll_pdc:4;
+ unsigned pll_a:4;
+ unsigned pll_n:4;
+ unsigned pll_output:1; /* Output PLL on GPIO_0 */
+
+ unsigned mclk_ratio:2;
+ unsigned i2s_sample_rate:4;
+ unsigned i2s_format:2;
+ /* Mask for audio blocks to be powered down */
+ u16 power_down_blocks;
+
+ /* Called after codec has been initialized, can be NULL */
+ int (* codec_init)(struct device *tsc2301_dev);
+ /* Called when codec is being removed, can be NULL */
+ void (* codec_cleanup)(struct device *tsc2301_dev);
+ int (*enable_clock)(struct device *dev);
+ void (*disable_clock)(struct device *dev);
+
+ const struct tsc2301_mixer_gpio {
+ const char *name;
+ unsigned gpio:4;
+ unsigned inverted:1;
+ unsigned def_enable:1; /* enable by default */
+ unsigned deactivate_on_pd:1; /* power-down flag */
+ } *mixer_gpios;
+ int n_mixer_gpios;
+};
+
+struct tsc2301_kp;
+struct tsc2301_ts;
+struct tsc2301_mixer;
+
+struct tsc2301 {
+ struct spi_device *spi;
+
+ s16 reset_gpio;
+ u16 config2_shadow;
+
+ struct tsc2301_kp *kp;
+ struct tsc2301_ts *ts;
+ struct tsc2301_mixer *mixer;
+
+ int (*enable_clock)(struct device *dev);
+ void (*disable_clock)(struct device *dev);
+};
+
+
+#define TSC2301_HZ 33000000
+
+#define TSC2301_REG(page, addr) (((page) << 11) | ((addr) << 5))
+#define TSC2301_REG_TO_PAGE(reg) (((reg) >> 11) & 0x03)
+#define TSC2301_REG_TO_ADDR(reg) (((reg) >> 5) & 0x1f)
+
+#define TSC2301_REG_X TSC2301_REG(0, 0)
+#define TSC2301_REG_Y TSC2301_REG(0, 1)
+#define TSC2301_REG_Z1 TSC2301_REG(0, 2)
+#define TSC2301_REG_Z2 TSC2301_REG(0, 3)
+#define TSC2301_REG_KPDATA TSC2301_REG(0, 4)
+#define TSC2301_REG_ADC TSC2301_REG(1, 0)
+#define TSC2301_REG_KEY TSC2301_REG(1, 1)
+#define TSC2301_REG_DAC TSC2301_REG(1, 2)
+#define TSC2301_REG_REF TSC2301_REG(1, 3)
+#define TSC2301_REG_RESET TSC2301_REG(1, 4)
+#define TSC2301_REG_CONFIG TSC2301_REG(1, 5)
+#define TSC2301_REG_CONFIG2 TSC2301_REG(1, 6)
+#define TSC2301_REG_KPMASK TSC2301_REG(1, 16)
+#define TSC2301_REG_AUDCNTL TSC2301_REG(2, 0)
+#define TSC2301_REG_ADCVOL TSC2301_REG(2, 1)
+#define TSC2301_REG_DACVOL TSC2301_REG(2, 2)
+#define TSC2301_REG_BPVOL TSC2301_REG(2, 3)
+#define TSC2301_REG_KEYCTL TSC2301_REG(2, 4)
+#define TSC2301_REG_PD_MISC TSC2301_REG(2, 5)
+#define TSC2301_REG_GPIO TSC2301_REG(2, 6)
+#define TSC2301_REG_ADCLKCFG TSC2301_REG(2, 27)
+
+#define TSC2301_REG_PD_MISC_APD (1 << 15)
+#define TSC2301_REG_PD_MISC_AVPD (1 << 14)
+#define TSC2301_REG_PD_MISC_ABPD (1 << 13)
+#define TSC2301_REG_PD_MISC_HAPD (1 << 12)
+#define TSC2301_REG_PD_MISC_MOPD (1 << 11)
+#define TSC2301_REG_PD_MISC_DAPD (1 << 10)
+#define TSC2301_REG_PD_MISC_ADPDL (1 << 9)
+#define TSC2301_REG_PD_MISC_ADPDR (1 << 8)
+#define TSC2301_REG_PD_MISC_PDSTS (1 << 7)
+#define TSC2301_REG_PD_MISC_MIBPD (1 << 6)
+#define TSC2301_REG_PD_MISC_OTSYN (1 << 2)
+
+/* I2S sample rate */
+#define TSC2301_I2S_SR_48000 0x00
+#define TSC2301_I2S_SR_44100 0x01
+#define TSC2301_I2S_SR_32000 0x02
+#define TSC2301_I2S_SR_24000 0x03
+#define TSC2301_I2S_SR_22050 0x04
+#define TSC2301_I2S_SR_16000 0x05
+#define TSC2301_I2S_SR_12000 0x06
+#define TSC2301_I2S_SR_11050 0x07
+#define TSC2301_I2S_SR_8000 0x08
+
+/* 16-bit, MSB-first. DAC Right-Justified, ADC Left-Justified */
+#define TSC2301_I2S_FORMAT0 0x00
+/* 20-bit, MSB-first. DAC Right-Justified, ADC Left-Justified */
+#define TSC2301_I2S_FORMAT1 0x01
+/* 20-bit, MSB-first. DAC Left-Justified, ADC Left-Justified */
+#define TSC2301_I2S_FORMAT2 0x02
+/* 20-bit, MSB-first */
+#define TSC2301_I2S_FORMAT3 0x03
+
+/* Master Clock Ratio */
+#define TSC2301_MCLK_256xFS 0x00 /* default */
+#define TSC2301_MCLK_384xFS 0x01
+#define TSC2301_MCLK_512xFS 0x02
+
+
+extern u16 tsc2301_read_reg(struct tsc2301 *tsc, int reg);
+extern void tsc2301_write_reg(struct tsc2301 *tsc, int reg, u16 val);
+extern void tsc2301_write_kbc(struct tsc2301 *tsc, int val);
+extern void tsc2301_write_pll(struct tsc2301 *tsc, int pll_n, int pll_a,
+ int pll_pdc, int pct_e, int pll_o);
+extern void tsc2301_read_buf(struct tsc2301 *tsc, int reg, u16 *buf, int len);
+
+#define TSC2301_DECL_MOD(module) \
+extern int tsc2301_##module##_init(struct tsc2301 *tsc, \
+ struct tsc2301_platform_data *pdata); \
+extern void tsc2301_##module##_exit(struct tsc2301 *tsc); \
+extern int tsc2301_##module##_suspend(struct tsc2301 *tsc); \
+extern void tsc2301_##module##_resume(struct tsc2301 *tsc);
+
+#define TSC2301_DECL_EMPTY_MOD(module) \
+static inline int tsc2301_##module##_init(struct tsc2301 *tsc, \
+ struct tsc2301_platform_data *pdata) \
+{ \
+ return 0; \
+} \
+static inline void tsc2301_##module##_exit(struct tsc2301 *tsc) {} \
+static inline int tsc2301_##module##_suspend(struct tsc2301 *tsc) \
+{ \
+ return 0; \
+} \
+static inline void tsc2301_##module##_resume(struct tsc2301 *tsc) {}
+
+#ifdef CONFIG_KEYBOARD_TSC2301
+TSC2301_DECL_MOD(kp)
+void tsc2301_kp_restart(struct tsc2301 *tsc);
+#else
+TSC2301_DECL_EMPTY_MOD(kp)
+static inline void tsc2301_kp_restart(struct tsc2301 *tsc) {}
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_TSC2301
+TSC2301_DECL_MOD(ts)
+#else
+TSC2301_DECL_EMPTY_MOD(ts)
+#endif
+
+#ifdef CONFIG_SPI_TSC2301_AUDIO
+TSC2301_DECL_MOD(mixer)
+extern void tsc2301_mixer_set_power(struct device *tsc_dev, int dac, int adc);
+
+struct snd_card;
+extern int tsc2301_mixer_register_controls(struct device *tsc_dev,
+ struct snd_card *card);
+#else
+TSC2301_DECL_EMPTY_MOD(mixer)
+#endif
+
+extern void tsc2301_mixer_enable_mclk(struct device *tsc_dev);
+extern void tsc2301_mixer_disable_mclk(struct device *tsc_dev);
+
+#endif
--- /dev/null
+/*
+ * This is used to for host and peripheral modes of the driver for
+ * Inventra (Multidrop) Highspeed Dual-Role Controllers: (M)HDRC.
+ *
+ * Board initialization should put one of these into dev->platform_data,
+ * probably on some platform_device named "musb_hdrc". It encapsulates
+ * key configuration differences between boards.
+ */
+
+/* The USB role is defined by the connector used on the board, so long as
+ * standards are being followed. (Developer boards sometimes won't.)
+ */
+enum musb_mode {
+ MUSB_UNDEFINED = 0,
+ MUSB_HOST, /* A or Mini-A connector */
+ MUSB_PERIPHERAL, /* B or Mini-B connector */
+ MUSB_OTG /* Mini-AB connector */
+};
+
+struct clk;
+
+struct musb_hdrc_platform_data {
+ /* MUSB_HOST, MUSB_PERIPHERAL, or MUSB_OTG */
+ u8 mode;
+
+ /* for clk_get() */
+ const char *clock;
+
+ /* (HOST or OTG) switch VBUS on/off */
+ int (*set_vbus)(struct device *dev, int is_on);
+
+ /* (HOST or OTG) mA/2 power supplied on (default = 8mA) */
+ u8 power;
+
+ /* (PERIPHERAL) mA/2 max power consumed (default = 100mA) */
+ u8 min_power;
+
+ /* (HOST or OTG) msec/2 after VBUS on till power good */
+ u8 potpgt;
+
+ /* TBD: chip defaults should probably go someplace else,
+ * e.g. number of tx/rx endpoints, etc
+ */
+ unsigned multipoint:1;
+
+ /* Power the device on or off */
+ int (*set_power)(int state);
+
+ /* Turn device clock on or off */
+ int (*set_clock)(struct clk *clock, int is_on);
+};
+
+
+/* TUSB 6010 support */
+
+#define TUSB6010_OSCCLK_60 16667 /* psec/clk @ 60.0 MHz */
+#define TUSB6010_REFCLK_24 41667 /* psec/clk @ 24.0 MHz XI */
+#define TUSB6010_REFCLK_19 52083 /* psec/clk @ 19.2 MHz CLKIN */
+
+#ifdef CONFIG_ARCH_OMAP2
+
+extern int __init tusb6010_setup_interface(
+ struct musb_hdrc_platform_data *data,
+ unsigned ps_refclk, unsigned waitpin,
+ unsigned async_cs, unsigned sync_cs,
+ unsigned irq, unsigned dmachan);
+
+extern int tusb6010_platform_retime(unsigned is_refclk);
+
+#endif /* OMAP2 */
#include <linux/err.h>
#include <linux/kfifo.h>
#include <linux/log2.h>
+#include <linux/uaccess.h>
/**
* kfifo_init - allocates a new FIFO using a preallocated buffer
return len;
}
EXPORT_SYMBOL(__kfifo_get);
+
+/**
+ * __kfifo_get_to_user - gets some data from the FIFO, no locking version
+ * @fifo: the fifo to be used.
+ * @buffer: where the data must be copied. user buffer.
+ * @len: the size of the destination buffer.
+ *
+ * This function copies at most @len bytes from the FIFO into the
+ * user @buffer and returns the number of copied bytes.
+ *
+ * Note that with only one concurrent reader and one concurrent
+ * writer, you don't need extra locking to use these functions.
+ */
+unsigned int __kfifo_get_to_user(struct kfifo *fifo,
+ unsigned char __user *buffer,
+ unsigned int len)
+{
+ unsigned int n1, n2;
+ int ret;
+
+ len = min(len, fifo->in - fifo->out);
+
+ /*
+ * Ensure that we sample the fifo->in index -before- we
+ * start removing bytes from the kfifo.
+ */
+
+ smp_rmb();
+
+ /* first get the data from fifo->out until the end of the buffer */
+ n1 = min(len, fifo->size - (fifo->out & (fifo->size - 1)));
+ n2 = len -n1;
+ ret = copy_to_user(buffer,
+ fifo->buffer + (fifo->out & (fifo->size - 1)), n1);
+ if (ret) {
+ len = n1 - ret;
+ goto out;
+ }
+
+ /* then get the rest (if any) from the beginning of the buffer */
+ ret = copy_to_user(buffer + n1, fifo->buffer, n2);
+ if (ret)
+ len = n1 + n2 - ret;
+
+ /*
+ * Ensure that we remove the bytes from the kfifo -before-
+ * we update the fifo->out index.
+ */
+out:
+ smp_mb();
+
+ fifo->out += len;
+
+ return len;
+}
+EXPORT_SYMBOL(__kfifo_get_to_user);
#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 */
printed_len += vscnprintf(printk_buf + printed_len,
sizeof(printk_buf) - printed_len, 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
address part intact. It is similar to Fast NAT, except that
Netfilter's connection tracking doesn't work well with Fast NAT.
+ 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.
+
+
To compile it as a module, choose M here. If unsure, say N.
config NF_NAT_SNMP_BASIC
obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o
obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o
+obj-$(CONFIG_IP_NF_TARGET_IDLETIMER) += ipt_IDLETIMER.o
obj-$(CONFIG_IP_NF_TARGET_TTL) += ipt_TTL.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. All rights reserved.
+ * Written by Timo Teras <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
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/module.h>
+#include <linux/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/x_tables.h>
+#include <linux/netfilter_ipv4/ipt_IDLETIMER.h>
+#include <linux/kobject.h>
+#include <linux/workqueue.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 device *, struct device_attribute *attr, char *buf);
+static ssize_t utimer_attr_store(struct device *, struct device_attribute *attr,
+ const char *buf, size_t count);
+
+struct utimer_t {
+ char name[IFNAMSIZ];
+ struct list_head entry;
+ struct timer_list timer;
+ struct work_struct work;
+};
+
+static LIST_HEAD(active_utimer_head);
+static DEFINE_SPINLOCK(list_lock);
+static 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_work(struct work_struct *work)
+{
+ struct utimer_t *timer = container_of(work, struct utimer_t, work);
+ struct net_device *netdev;
+
+ netdev = dev_get_by_name(&init_net, timer->name);
+
+ if (netdev != NULL) {
+ sysfs_notify(&netdev->dev.kobj, NULL,
+ "idletimer");
+ dev_put(netdev);
+ }
+}
+
+static void utimer_expired(unsigned long data)
+{
+ struct utimer_t *timer = (struct utimer_t *) data;
+
+ DEBUGP("Timer '%s' expired\n", timer->name);
+
+ spin_lock_bh(&list_lock);
+ utimer_delete(timer);
+ spin_unlock_bh(&list_lock);
+
+ schedule_work(&timer->work);
+}
+
+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;
+
+ INIT_WORK(&timer->work, utimer_work);
+
+ 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 device *dev, struct device_attribute *attr, char *buf)
+{
+ struct utimer_t *timer;
+ unsigned long expires = 0;
+ struct net_device *netdev = container_of(dev, struct net_device, dev);
+
+ spin_lock_bh(&list_lock);
+ timer = __utimer_find(netdev->name);
+ 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 device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int expires;
+ struct net_device *netdev = container_of(dev, struct net_device, dev);
+
+ if (sscanf(buf, "%d", &expires) == 1) {
+ if (expires > 0)
+ utimer_modify(netdev->name,
+ 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;
+ int ret = NOTIFY_DONE;
+
+ switch (event) {
+ case NETDEV_UP:
+ DEBUGP("NETDEV_UP: %s\n", dev->name);
+ ret = device_create_file(&dev->dev,
+ &dev_attr_idletimer);
+ break;
+ case NETDEV_DOWN:
+ DEBUGP("NETDEV_DOWN: %s\n", dev->name);
+ device_remove_file(&dev->dev,
+ &dev_attr_idletimer);
+ break;
+ }
+
+ return ret;
+}
+
+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_each_netdev(&init_net, dev)
+ 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 struct xt_target *xttarget,
+ const void *targinfo)
+{
+ 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 XT_CONTINUE;
+}
+
+static bool ipt_idletimer_checkentry(const char *tablename,
+ const void *e,
+ const struct xt_target *target,
+ void *targinfo,
+ unsigned int hookmask)
+{
+ struct ipt_idletimer_info *info =
+ (struct ipt_idletimer_info *) targinfo;
+
+ if (info->timeout == 0) {
+ DEBUGP("timeout value is zero\n");
+ return 0;
+ }
+
+ return true;
+}
+
+static struct xt_target ipt_idletimer = {
+ .name = "IDLETIMER",
+ .target = ipt_idletimer_target,
+ .checkentry = ipt_idletimer_checkentry,
+ .me = THIS_MODULE,
+ .targetsize = sizeof(struct ipt_idletimer_info),
+};
+
+static int __init init(void)
+{
+ int ret;
+
+ ret = utimer_init();
+ if (ret)
+ return ret;
+
+ if (xt_register_target(&ipt_idletimer)) {
+ utimer_fini();
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void __exit fini(void)
+{
+ xt_unregister_target(&ipt_idletimer);
+ utimer_fini();
+}
+
+module_init(init);
+module_exit(fini);
+
+MODULE_AUTHOR("Timo Teras <ext-timo.teras@nokia.com>");
+MODULE_DESCRIPTION("iptables idletimer target module");
+MODULE_LICENSE("GPL");
If you are unsure how to answer this question, answer N.
+config SECURITY_LOWMEM
+ tristate "Low memory watermark support"
+ depends on SECURITY
+ help
+ Implements low memory watermark support
+
+ If you are unsure how to answer this question, answer N.
+
config SECURITY_DEFAULT_MMAP_MIN_ADDR
int "Low address space to protect from user allocation"
depends on SECURITY
obj-$(CONFIG_SECURITY_SMACK) += commoncap.o smack/built-in.o
obj-$(CONFIG_SECURITY_CAPABILITIES) += commoncap.o capability.o
obj-$(CONFIG_SECURITY_ROOTPLUG) += commoncap.o root_plug.o
+obj-$(CONFIG_SECURITY_LOWMEM) += commoncap.o lowmem.o
obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o
--- /dev/null
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/mman.h>
+#include <linux/init.h>
+#include <linux/security.h>
+#include <linux/sysctl.h>
+#include <linux/swap.h>
+#include <linux/kobject.h>
+#include <linux/pagemap.h>
+#include <linux/hugetlb.h>
+#include <linux/sysfs.h>
+
+#define MY_NAME "lowmem"
+
+#define LOWMEM_MAX_UIDS 8
+
+enum {
+ VM_LOWMEM_DENY = 1,
+ VM_LOWMEM_LEVEL1_NOTIFY,
+ VM_LOWMEM_LEVEL2_NOTIFY,
+ VM_LOWMEM_NR_DECAY_PAGES,
+ VM_LOWMEM_ALLOWED_UIDS,
+ VM_LOWMEM_ALLOWED_PAGES,
+ VM_LOWMEM_USED_PAGES,
+};
+
+static unsigned int deny_percentage;
+static unsigned int l1_notify, l2_notify;
+static unsigned int nr_decay_pages;
+static unsigned long allowed_pages;
+static long used_pages;
+static unsigned int allowed_uids[LOWMEM_MAX_UIDS];
+static unsigned int minuid = 1;
+static unsigned int maxuid = 65535;
+
+static ctl_table lowmem_table[] = {
+ {
+ .ctl_name = VM_LOWMEM_DENY,
+ .procname = "lowmem_deny_watermark",
+ .data = &deny_percentage,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .child = NULL,
+ .proc_handler = &proc_dointvec,
+ .strategy = &sysctl_intvec,
+ }, {
+ .ctl_name = VM_LOWMEM_LEVEL1_NOTIFY,
+ .procname = "lowmem_notify_low",
+ .data = &l1_notify,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .child = NULL,
+ .proc_handler = &proc_dointvec,
+ .strategy = &sysctl_intvec,
+ }, {
+ .ctl_name = VM_LOWMEM_LEVEL2_NOTIFY,
+ .procname = "lowmem_notify_high",
+ .data = &l2_notify,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .child = NULL,
+ .proc_handler = &proc_dointvec,
+ .strategy = &sysctl_intvec,
+ }, {
+ .ctl_name = VM_LOWMEM_NR_DECAY_PAGES,
+ .procname = "lowmem_nr_decay_pages",
+ .data = &nr_decay_pages,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .child = NULL,
+ .proc_handler = &proc_dointvec_minmax,
+ .strategy = &sysctl_intvec,
+ }, {
+ .ctl_name = VM_LOWMEM_ALLOWED_UIDS,
+ .procname = "lowmem_allowed_uids",
+ .data = &allowed_uids,
+ .maxlen = LOWMEM_MAX_UIDS * sizeof(unsigned int),
+ .mode = 0644,
+ .child = NULL,
+ .proc_handler = &proc_dointvec_minmax,
+ .strategy = &sysctl_intvec,
+ .extra1 = &minuid,
+ .extra2 = &maxuid,
+ }, {
+ .ctl_name = VM_LOWMEM_ALLOWED_PAGES,
+ .procname = "lowmem_allowed_pages",
+ .data = &allowed_pages,
+ .maxlen = sizeof(unsigned long),
+ .mode = 0444,
+ .child = NULL,
+ .proc_handler = &proc_dointvec_minmax,
+ .strategy = &sysctl_intvec,
+ }, {
+ .ctl_name = VM_LOWMEM_USED_PAGES,
+ .procname = "lowmem_used_pages",
+ .data = &used_pages,
+ .maxlen = sizeof(long),
+ .mode = 0444,
+ .child = NULL,
+ .proc_handler = &proc_dointvec_minmax,
+ .strategy = &sysctl_intvec,
+ }, {
+ .ctl_name = 0
+ }
+};
+
+static ctl_table lowmem_root_table[] = {
+ {
+ .ctl_name = CTL_VM,
+ .procname = "vm",
+ .mode = 0555,
+ .child = lowmem_table,
+ }, {
+ .ctl_name = 0
+ }
+};
+
+#define KERNEL_ATTR_RO(_name) \
+static struct subsys_attribute _name##_attr = __ATTR_RO(_name)
+
+static int low_watermark_reached, high_watermark_reached;
+
+static ssize_t low_watermark_show(struct subsystem *subsys, char *page)
+{
+ return sprintf(page, "%u\n", low_watermark_reached);
+}
+
+static ssize_t high_watermark_show(struct subsystem *subsys, char *page)
+{
+ return sprintf(page, "%u\n", high_watermark_reached);
+}
+
+KERNEL_ATTR_RO(low_watermark);
+KERNEL_ATTR_RO(high_watermark);
+
+static void low_watermark_state(int new_state)
+{
+ int changed = 0;
+
+ if (low_watermark_reached != new_state) {
+ low_watermark_reached = new_state;
+ changed = 1;
+ }
+
+ if (changed)
+ sysfs_notify(&kernel_subsys.kset.kobj, NULL, "low_watermark");
+}
+
+static void high_watermark_state(int new_state)
+{
+ int changed = 0;
+
+ if (high_watermark_reached != new_state) {
+ high_watermark_reached = new_state;
+ changed = 1;
+ }
+
+ if (changed)
+ sysfs_notify(&kernel_subsys.kset.kobj, NULL, "high_watermark");
+}
+
+static int low_vm_enough_memory(long pages)
+{
+ unsigned long free, allowed;
+ long deny_threshold, level1, level2, used;
+ int cap_sys_admin = 0, notify;
+
+ if (cap_capable(current, CAP_SYS_ADMIN) == 0)
+ cap_sys_admin = 1;
+
+ /* We activate ourselves only after both parameters have been
+ * configured. */
+ if (deny_percentage == 0 || l1_notify == 0 || l2_notify == 0)
+ return __vm_enough_memory(pages, cap_sys_admin);
+
+ allowed = totalram_pages - hugetlb_total_pages();
+ deny_threshold = allowed * deny_percentage / 100;
+ level1 = allowed * l1_notify / 100;
+ level2 = allowed * l2_notify / 100;
+
+ vm_acct_memory(pages);
+
+ /* Easily freed pages when under VM pressure or direct reclaim */
+ free = global_page_state(NR_FILE_PAGES);
+ free += nr_swap_pages;
+ free += global_page_state(NR_SLAB_RECLAIMABLE);
+
+ used = allowed - free;
+ if (unlikely(used < 0))
+ used = 0;
+
+ /* The hot path, plenty of memory */
+ if (likely(used < level1))
+ goto enough_memory;
+
+ /* No luck, lets make it more expensive and try again.. */
+ used -= nr_free_pages();
+
+ if (used >= deny_threshold) {
+ int i;
+
+ allowed_pages = allowed;
+ used_pages = used;
+ low_watermark_state(1);
+ high_watermark_state(1);
+ /* Memory allocations by root are always allowed */
+ if (cap_sys_admin)
+ return 0;
+
+ /* uids from allowed_uids vector are also allowed no matter what */
+ for (i = 0; i < LOWMEM_MAX_UIDS && allowed_uids[i]; i++)
+ if (current->uid == allowed_uids[i])
+ return 0;
+
+ vm_unacct_memory(pages);
+ if (printk_ratelimit()) {
+ printk(MY_NAME ": denying memory allocation to process %d (%s)\n",
+ current->pid, current->comm);
+ }
+ return -ENOMEM;
+ }
+
+enough_memory:
+ /* See if we need to notify level 1 */
+ low_watermark_state(used >= level1);
+
+ /*
+ * In the level 2 notification case things are more complicated,
+ * as the level that we drop the state and send a notification
+ * should be lower than when it is first triggered. Having this
+ * on the same watermark level ends up bouncing back and forth
+ * when applications are being stupid.
+ */
+ notify = used >= level2;
+ if (notify || used + nr_decay_pages < level2)
+ high_watermark_state(notify);
+
+ /* We have plenty of memory */
+ allowed_pages = allowed;
+ used_pages = used;
+ return 0;
+}
+
+static struct security_operations lowmem_security_ops = {
+ /* Use the capability functions for some of the hooks */
+ .ptrace = cap_ptrace,
+ .capget = cap_capget,
+ .capset_check = cap_capset_check,
+ .capset_set = cap_capset_set,
+ .capable = cap_capable,
+
+ .bprm_apply_creds = cap_bprm_apply_creds,
+ .bprm_set_security = cap_bprm_set_security,
+
+ .task_post_setuid = cap_task_post_setuid,
+ .task_reparent_to_init = cap_task_reparent_to_init,
+ .vm_enough_memory = low_vm_enough_memory,
+};
+
+static struct ctl_table_header *lowmem_table_header;
+/* flag to keep track of how we were registered */
+static int secondary;
+
+static struct attribute *lowmem_attrs[] = {
+ &low_watermark_attr.attr,
+ &high_watermark_attr.attr,
+ NULL,
+};
+
+static struct attribute_group lowmem_attr_group = {
+ .attrs = lowmem_attrs,
+};
+
+static int __init lowmem_init(void)
+{
+ int r;
+
+ /* register ourselves with the security framework */
+ if (register_security(&lowmem_security_ops)) {
+ printk(KERN_ERR MY_NAME ": Failure registering with the kernel\n");
+ /* try registering with primary module */
+ if (mod_reg_security(MY_NAME, &lowmem_security_ops)) {
+ printk(KERN_ERR ": Failure registering with the primary"
+ "security module.\n");
+ return -EINVAL;
+ }
+ secondary = 1;
+ }
+
+ /* initialize the uids vector */
+ memset(allowed_uids, 0, sizeof(allowed_uids));
+
+ lowmem_table_header = register_sysctl_table(lowmem_root_table);
+ if (unlikely(!lowmem_table_header))
+ return -EPERM;
+
+ kernel_subsys.kset.kobj.kset = &kernel_subsys.kset;
+
+ r = sysfs_create_group(&kernel_subsys.kset.kobj,
+ &lowmem_attr_group);
+ if (unlikely(r))
+ return r;
+
+ printk(KERN_INFO MY_NAME ": Module initialized.\n");
+
+ return 0;
+}
+
+static void __exit lowmem_exit(void)
+{
+ /* remove ourselves from the security framework */
+ if (secondary) {
+ if (mod_unreg_security(MY_NAME, &lowmem_security_ops))
+ printk(KERN_ERR MY_NAME ": Failure unregistering "
+ "with the primary security module.\n");
+ } else {
+ if (unregister_security(&lowmem_security_ops)) {
+ printk(KERN_ERR MY_NAME ": Failure unregistering "
+ "with the kernel.\n");
+ }
+ }
+
+ unregister_sysctl_table(lowmem_table_header);
+
+ sysfs_remove_group(&kernel_subsys.kset.kobj, &lowmem_attr_group);
+
+ printk(KERN_INFO MY_NAME ": Module removed.\n");
+}
+
+module_init(lowmem_init);
+module_exit(lowmem_exit);
+
+MODULE_DESCRIPTION("Low watermark LSM module");
+MODULE_LICENSE("GPL");
Say Y or M if you want to support any AC97 codec attached to
the PXA2xx AC97 interface.
+config SND_OMAP_AIC23
+ tristate "OMAP AIC23 alsa driver (osk5912)"
+ depends on ARCH_OMAP && SND
+ select SND_PCM
+ select I2C
+ select I2C_OMAP if ARCH_OMAP
+ select SENSORS_TLV320AIC23
+ help
+ Say Y here if you have a OSK platform board
+ and want to use its AIC23 audio chip.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-omap-aic23.
+
+config SND_OMAP_TSC2101
+ tristate "OMAP TSC2101 alsa driver"
+ depends on ARCH_OMAP && SND
+ select SND_PCM
+ select SPI_TSC2101
+ help
+ Say Y here if you have a OMAP platform board
+ and want to use its TSC2101 audio chip. Driver has
+ been tested with H2 and iPAQ h6300.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-omap-tsc2101.
+
+config SND_SX1
+ tristate "Siemens SX1 Egold alsa driver"
+ depends on ARCH_OMAP && SND
+ select SND_PCM
+ help
+ Say Y here if you have a OMAP310 based Siemens SX1.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-omap-sx1.
+
+config SND_OMAP_TSC2102
+ tristate "OMAP TSC2102 alsa driver"
+ depends on ARCH_OMAP && SND
+ select SND_PCM
+ select SPI_TSC2102
+ help
+ Say Y here if you have an OMAP platform board
+ and want to use its TSC2102 audio chip.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-omap-tsc2102.
+
+config SND_OMAP24XX_EAC
+ tristate "Audio driver for OMAP24xx EAC"
+ depends on SND
+ help
+ Audio driver for Enhanced Audio Controller found in TI's OMAP24xx
+ processors.
+
+ Currently contains only low-level support functions for
+ initializing EAC HW, creating ALSA sound card instance for it
+ and registering mixer controls implemented by a codec driver.
+ PCM stream is expected to be under DSP co-processor control.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-omap24xx-eac.
+
endmenu
obj-$(CONFIG_SND_PXA2XX_AC97) += snd-pxa2xx-ac97.o
snd-pxa2xx-ac97-objs := pxa2xx-ac97.o
+
+obj-$(CONFIG_SND) += omap/
--- /dev/null
+#
+## Makefile for ALSA OMAP
+#
+#
+obj-$(CONFIG_SND_OMAP_AIC23) += snd-omap-alsa-aic23.o
+snd-omap-alsa-aic23-objs := omap-alsa.o omap-alsa-dma.o omap-alsa-aic23.o omap-alsa-aic23-mixer.o
+
+obj-$(CONFIG_SND_OMAP_TSC2101) += snd-omap-alsa-tsc2101.o
+snd-omap-alsa-tsc2101-objs := omap-alsa.o omap-alsa-dma.o omap-alsa-tsc2101.o omap-alsa-tsc2101-mixer.o
+
+obj-$(CONFIG_SND_OMAP_TSC2102) += snd-omap-alsa-tsc2102.o
+snd-omap-alsa-tsc2102-objs := omap-alsa.o omap-alsa-dma.o omap-alsa-tsc2102.o omap-alsa-tsc2102-mixer.o
+
+obj-$(CONFIG_SND_SX1) += snd-omap-alsa-sx1.o
+snd-omap-alsa-sx1-objs := omap-alsa.o omap-alsa-dma.o omap-alsa-sx1.o omap-alsa-sx1-mixer.o
+
+obj-$(CONFIG_SND_OMAP24XX_EAC) += snd-omap24xx-eac.o
+snd-omap24xx-eac-objs := eac.o
--- /dev/null
+/*
+ * linux/sound/arm/omap/omap-alsa-eac.c
+ *
+ * OMAP24xx Enhanced Audio Controller sound driver
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ *
+ * Contact: Jarkko Nikula <jarkko.nikula@nokia.com>
+ * Juha Yrjölä
+ *
+ * Definitions:
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#define DEBUG
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+#include <asm/arch/eac.h>
+
+#include <sound/core.h>
+#include <sound/initval.h>
+
+
+#define EAC_CPCFR1 0x0000
+#define EAC_CPCFR2 0x0004
+#define EAC_CPCFR3 0x0008
+#define EAC_CPCFR4 0x000C
+#define EAC_CPTCTL 0x0010
+#define EAC_CPTTADR 0x0014
+#define EAC_CPTDATL 0x0018
+#define EAC_CPTDATH 0x001C
+#define EAC_CPTVSLL 0x0020
+#define EAC_CPTVSLH 0x0024
+#define EAC_MPCTR 0x0040
+#define EAC_MPMCCFR 0x0044
+#define EAC_BPCTR 0x0060
+#define EAC_BPMCCFR 0x0064
+#define EAC_AMSCFR 0x0080
+#define EAC_AMVCTR 0x0084
+#define EAC_AM1VCTR 0x0088
+#define EAC_AM2VCTR 0x008C
+#define EAC_AM3VCTR 0x0090
+#define EAC_ASTCTR 0x0094
+#define EAC_APD1LCR 0x0098
+#define EAC_APD1RCR 0x009C
+#define EAC_APD2LCR 0x00A0
+#define EAC_APD2RCR 0x00A4
+#define EAC_APD3LCR 0x00A8
+#define EAC_APD3RCR 0x00AC
+#define EAC_APD4R 0x00B0
+#define EAC_ADWR 0x00B4
+#define EAC_ADRDR 0x00B8
+#define EAC_AGCFR 0x00BC
+#define EAC_AGCTR 0x00C0
+#define EAC_AGCFR2 0x00C4
+#define EAC_AGCFR3 0x00C8
+#define EAC_MBPDMACTR 0x00CC
+#define EAC_MPDDMARR 0x00D0
+#define EAC_MPDDMAWR 0x00D4
+#define EAC_MPUDMARR 0x00D8
+#define EAC_MPUDMAWR 0x00E0
+#define EAC_BPDDMARR 0x00E4
+#define EAC_BPDDMAWR 0x00E8
+#define EAC_BPUDMARR 0x00EC
+#define EAC_BPUDMAWR 0x00F0
+#define EAC_VERSION 0x0100
+#define EAC_SYSCONFIG 0x0104
+#define EAC_SYSSTATUS 0x0108
+
+/* CPTCTL */
+#define CPTCTL_RXF (1 << 7) /* receive data register full */
+#define CPTCTL_RXIE (1 << 6) /* receive interrupt enable */
+#define CPTCTL_TXE (1 << 5) /* transmit register empty */
+#define CPTCTL_TXIE (1 << 4) /* transmit interrupt enable */
+#define CPTCTL_CPEN (1 << 3) /* codec port enable */
+#define CPTCTL_CRST (1 << 0) /* external codec reset */
+
+/* CPCFR1 */
+#define CPCFR1_MTSL(val) ((val & 0x1f) << 3) /* number of time slots per frame */
+#define CPCFR1_MTSL_BITS (0x1f << 3)
+#define CPCFR1_MODE(val) ((val & 0x7) << 0) /* codec port interface mode */
+#define CPCFR1_MODE_BITS (0x7 << 0)
+
+/* CPCFR2 */
+#define CPCFR2_TSLOL(val) ((val & 0x3) << 6) /* time slot 0 length in number of serial clock (CLK_BIT) cycles */
+#define CPCFR2_TSLOL_BITS (0x3 << 6)
+#define CPCFR2_BPTSL(val) ((val & 0x7) << 3) /* number of data bits per audio time slot */
+#define CPCFR2_BPTSL_BITS (0x7 << 3)
+#define CPCFR2_TSLL(val) ((val & 0x7) << 0) /* time slot lenght (except slot 0) in number of serial clock cycles */
+#define CPCFR2_TSLL_BITS (0x7 << 0)
+
+/* CPCFR3 */
+#define CPCFR3_DDLY (1 << 7) /* data delay: data bits start according to SYNC signal leading edge */
+#define CPCFR3_TRSEN (1 << 6) /* 3-state enable: data serial output state during nonvalid audio frames */
+#define CPCFR3_CLKBP (1 << 5) /* clock polarity */
+#define CPCFR3_CSYNCP (1 << 4) /* cp_sync(synchro) polarity */
+#define CPCFR3_CSYNCL (1 << 3) /* csync length */
+/* bit 2 reserved */
+#define CPCFR3_CSCLKD (1 << 1) /* cp_sclk port (serial clock) direction */
+#define CPCFR3_CSYNCD (1 << 0) /* cp_sync (synchro) direction */
+
+/* CPCFR4 */
+#define CPCFR4_ATSL(val) ((val & 0xf) << 4) /* audio time slots for secondary communication address and data values */
+#define CPCFR4_ATSL_BITS (0xf << 4)
+#define CPCFR4_CLKS (1 << 3) /* clock source */
+#define CPCFR4_DIVB(val) ((val & 0x7) << 0) /* cp_sclk driver value */
+#define CPCFR4_DIVB_BITS (0x7 << 0)
+
+/* AGCFR */
+#define AGCFR_MN_ST (1 << 10) /* mono/stereo audio file */
+#define AGCFR_B8_16 (1 << 9) /* 8 bits/16 bits audio file */
+#define AGCFR_LI_BI (1 << 8) /* audio file endianism */
+#define AGCFR_FSINT(val) ((val & 0x3) << 6) /* intermediate sample frequency for DMA read and write operations */
+#define AGCFR_FINST_BITS (0x3 << 6)
+
+#define AGCFR_FSINT_8000 (0) /* 8000 Hz */
+#define AGCFR_FSINT_11025 (1) /* 11025 Hz */
+#define AGCFR_FSINT_22050 (2) /* 22050 Hz */
+#define AGCFR_FSINT_44100 (3) /* 44100 Hz */
+
+#define AGCFR_AUD_CKSRC(val)((val & 0x3) << 4) /* audio processing clock source */
+#define AGCFR_AUD_CKSRC_BITS (0x3 << 4)
+#define AGCFR_M_CKSRC (1 << 3) /* modem interface clock source */
+#define AGCFR_MCLK_OUT (1 << 1)
+#define AGCFR_MCLK (1 << 0)
+
+
+/* AGCTR */
+#define AGCTR_AUDRD (1 << 15) /* audio ready */
+#define AGCTR_AUDRDI (1 << 14) /* audio ready interrupt status */
+#define AGCTR_AUDRDIEN (1 << 13) /* audio ready interrupt enable */
+#define AGCTR_DMAREN (1 << 12) /* audio files play operation */
+#define AGCTR_DMAWEN (1 << 11) /* audio file record operation */
+/* bits 10:4 reserved */
+#define AGCTR_MCLK_EN (1 << 3) /* internal MCLK enable */
+#define AGCTR_OSCMCLK_EN (1 << 2) /* OSCMCLK_EN output for MCLK oscillator control */
+#define AGCTR_AUDEN (1 << 1) /* audio processing enable/disable */
+#define AGCTR_EACPWD (1 << 0) /* EAC operation */
+
+/* AGCFR2 */
+#define AGCFR2_BT_MD_WIDEBAND (1 << 5) /* the BT device and modem AuSPIs wide-band mode */
+#define AGCFR2_MCLK_I2S_N11M_12M (1 << 4) /* MCLK freq indicator for audio operations */
+#define AGCFR2_I2S_N44K_48K (1 << 3) /* Frame sample frecuency of I2S codec port, does not generate value */
+#define AGCFR2_FSINT2(val) ((val & 0x7) << 0) /* intermediate sample frequency for DMA channel read and write operations */
+#define AGCFR2_FSINT2_BITS (0x7 << 0)
+
+#define AGCFR2_FSINT2_8000 (0) /* 8000 Hz */
+#define AGCFR2_FSINT2_11025 (1) /* 11025 Hz */
+#define AGCFR2_FSINT2_22050 (2) /* 22050 Hz */
+#define AGCFR2_FSINT2_44100 (3) /* 44100 Hz */
+#define AGCFR2_FSINT2_48000 (4) /* 48000 Hz */
+#define AGCFR2_FSINT2_FSINT (7) /* based on AGCFR/FSINT */
+
+
+/* AGCFR3 */
+#define AGCFR3_CP_TR_DMA (1 << 15) /* codec port transparent DMA (to audio DMAs) */
+#define AGCFR3_BT_TR_DMA (1 << 14) /* BT transparent DMA (to BT UL write & DL read DMAs */
+#define AGCFR3_MD_TR_DMA (1 << 13) /* modem transparent DMA (to modem UL write and DL read DMAs) */
+#define AGCFR3_FSINT(val) ((val & 0xf) << 9) /* FSINT */
+#define AGCFR3_FSINT_BITS (0xf << 9)
+
+#define AGCFR3_FSINT_8000 (0) /* 8000 Hz */
+#define AGCFR3_FSINT_11025 (1) /* 11025 Hz */
+#define AGCFR3_FSINT_16000 (2) /* 16000 Hz */
+#define AGCFR3_FSINT_22050 (3) /* 22050 Hz */
+#define AGCFR3_FSINT_24000 (4) /* 24000 Hz */
+#define AGCFR3_FSINT_32000 (5) /* 32000 Hz */
+#define AGCFR3_FSINT_44100 (6) /* 44100 Hz */
+#define AGCFR3_FSINT_48000 (7) /* 48000 Hz */
+#define AGCFR3_FSINT_FSINT (15) /* based on AGCFR2/AGCFR */
+
+
+#define AGCFR3_BT_CKSRC(val) ((val & 0x3) << 7) /* BT port clock selection */
+#define AGCFR3_BT_CKSRC_BITS (0x3 << 7)
+#define AGCFR3_MD_CKSRC(val) ((val & 0x3) << 5) /* modem port clock source */
+#define AGCFR3_MD_CKSRC_BITS (0x3 << 5)
+#define AGCFR3_AUD_CKSRC(val) ((val & 0x7) << 2) /* audio and codec port clock source */
+#define AGCFR3_AUD_CKSRC_BITS (0x7 << 2)
+#define AGCFR3_CLK12MINT_SEL (1 << 1) /* internal 12MHz clock source */
+#define AGCFR3_MCLKINT_SEL (1 << 0) /* internal codec master clock source */
+
+/* AMSCFR */
+#define AMSCFR_K12 (1 << 11) /* K12 switch open/close */
+#define AMSCFR_K11 (1 << 10)
+#define AMSCFR_K10 (1 << 9)
+#define AMSCFR_K9 (1 << 8)
+#define AMSCFR_K8 (1 << 7)
+#define AMSCFR_K7 (1 << 6)
+#define AMSCFR_K6 (1 << 5)
+#define AMSCFR_K5 (1 << 4)
+#define AMSCFR_K4 (1 << 3)
+#define AMSCFR_K3 (1 << 2)
+#define AMSCFR_K2 (1 << 1)
+#define AMSCFR_K1 (1 << 0)
+
+/* AMVCTR */
+#define AMVCTR_GWO_BITS (0xff << 8)
+#define AMVCTR_GWO(val) ((val & 0xff) << 8) /* Gain on write DMA operation */
+#define AMVCTR_GRO_BITS (0xff << 0)
+#define AMVCTR_GRO(val) ((val & 0xff) << 0) /* Gain on read DMA operation */
+
+/* AM1VCTR */
+#define AM1VCTR_MUTE (1 << 15) /* mute/no mute on mixer output */
+#define AM1VCTR_GINB(val) ((val & 0x7f) << 8) /* gain on input B */
+#define AM1VCTR_GINB_BITS (0x7f << 8)
+#define AM1VCTR_GINA(val) ((val & 0x7f) << 0) /* gain on input A */
+#define AM1VCTR_GINA_BITS (0x7f << 0)
+
+/* AM2VCTR */
+#define AM2VCTR_MUTE (1 << 15) /* mute/no mute on mixer output */
+#define AM2VCTR_GINB(val) ((val & 0x7f) << 8) /* gain on input B */
+#define AM2VCTR_GINB_BITS (0x7f << 8)
+#define AM2VCTR_GINA(val) ((val & 0x7f) << 0) /* gain on input A */
+#define AM2VCTR_GINA_BITS (0x7f << 0)
+
+/* AM3VCTR */
+#define AM3VCTR_MUTE (1 << 15) /* mute/no mute */
+#define AM3VCTR_GINB(val) ((val & 0x7f) << 8) /* gain on input B */
+#define AM3VCTR_GINB_BITS (0x7f << 8)
+#define AM3VCTR_GINA(val) ((val & 0x7f) << 0) /* gain on input A */
+#define AM3VCTR_GINA_BITS (0x7f << 0)
+
+/* ASTCTR */
+#define ASTCTR_ATT(val) ((val & 0x7f) << 1) /* Attenuation of side tone */
+#define ASTCTR_ATT_BITS (0x7f << 1)
+#define ASTCTR_ATTEN (1 << 0) /* side tone enabled/disabled */
+
+
+/* internal structure of the EAC driver */
+struct omap_eac {
+ struct mutex mutex;
+ void __iomem * base;
+ struct platform_device * pdev;
+ struct eac_platform_data * pdata;
+ struct snd_card * card;
+ struct clk * fck;
+ struct clk * ick;
+ struct eac_codec * codec;
+
+ unsigned clocks_enabled:1;
+};
+
+static char *id = SNDRV_DEFAULT_STR1;
+module_param(id, charp, 0444);
+MODULE_PARM_DESC(id, "ID string for OMAP24xx EAC");
+
+
+#define MOD_REG_BIT(val, mask, set) do { \
+ if (set) \
+ val |= mask; \
+ else \
+ val &= ~mask; \
+} while(0)
+
+static inline void eac_write_reg(struct omap_eac *eac, int idx, u16 val)
+{
+ __raw_writew(val, eac->base + idx);
+}
+
+static inline u16 eac_read_reg(struct omap_eac *eac, int idx)
+{
+ return __raw_readw(eac->base + idx);
+}
+
+static int eac_get_clocks(struct omap_eac *eac)
+{
+ eac->ick = clk_get(NULL, "eac_ick");
+ if (IS_ERR(eac->ick)) {
+ dev_err(&eac->pdev->dev, "Could not get eac_ick");
+ return -ENODEV;
+ }
+
+ eac->fck = clk_get(NULL, "eac_fck");
+ if (IS_ERR(eac->fck)) {
+ dev_err(&eac->pdev->dev, "Could not get eac_fck");
+ clk_put(eac->ick);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static void eac_put_clocks(struct omap_eac *eac)
+{
+ clk_put(eac->fck);
+ clk_put(eac->ick);
+}
+
+static int eac_enable_clocks(struct omap_eac *eac)
+{
+ int err = 0;
+
+ if (eac->clocks_enabled)
+ return 0;
+
+ if (eac->pdata != NULL && eac->pdata->enable_ext_clocks != NULL) {
+ if ((err = eac->pdata->enable_ext_clocks(&eac->pdev->dev)) != 0)
+ return err;
+ }
+ clk_enable(eac->ick);
+ clk_enable(eac->fck);
+ eac->clocks_enabled = 1;
+
+ return 0;
+}
+
+static void eac_disable_clocks(struct omap_eac *eac)
+{
+ if (!eac->clocks_enabled)
+ return;
+ eac->clocks_enabled = 0;
+
+ clk_disable(eac->fck);
+ clk_disable(eac->ick);
+ if (eac->pdata != NULL && eac->pdata->disable_ext_clocks != NULL)
+ eac->pdata->disable_ext_clocks(&eac->pdev->dev);
+}
+
+static int eac_reset(struct omap_eac *eac)
+{
+ int i;
+
+ /* step 1 (see TRM) */
+ /* first, let's reset the EAC */
+ eac_write_reg(eac, EAC_SYSCONFIG, 0x2);
+ /* step 2 (see TRM) */
+ eac_write_reg(eac, EAC_AGCTR, AGCTR_MCLK_EN | AGCTR_AUDEN);
+ /* step 3 (see TRM) */
+ /* wait until reset done */
+ i = 10000;
+ while (!(eac_read_reg(eac, EAC_SYSSTATUS) & 1)) {
+ if (--i == 0)
+ return -ENODEV;
+ udelay(1);
+ }
+
+ return 0;
+}
+
+static int eac_calc_agcfr3_fsint(int rate)
+{
+ int fsint;
+
+ if (rate >= 48000)
+ fsint = AGCFR3_FSINT_48000;
+ else if (rate >= 44100)
+ fsint = AGCFR3_FSINT_44100;
+ else if (rate >= 32000)
+ fsint = AGCFR3_FSINT_32000;
+ else if (rate >= 24000)
+ fsint = AGCFR3_FSINT_24000;
+ else if (rate >= 22050)
+ fsint = AGCFR3_FSINT_22050;
+ else if (rate >= 16000)
+ fsint = AGCFR3_FSINT_16000;
+ else if (rate >= 11025)
+ fsint = AGCFR3_FSINT_11025;
+ else
+ fsint = AGCFR3_FSINT_8000;
+
+ return fsint;
+}
+
+static int eac_configure_pcm(struct omap_eac *eac, struct eac_codec *conf)
+{
+ dev_err(&eac->pdev->dev,
+ "EAC codec port configuration for PCM not implemented\n");
+
+ return -ENODEV;
+}
+
+static int eac_configure_ac97(struct omap_eac *eac, struct eac_codec *conf)
+{
+ dev_err(&eac->pdev->dev,
+ "EAC codec port configuration for AC97 not implemented\n");
+
+ return -ENODEV;
+}
+
+static int eac_configure_i2s(struct omap_eac *eac, struct eac_codec *conf)
+{
+ u16 cpcfr1, cpcfr2, cpcfr3, cpcfr4;
+
+ cpcfr1 = eac_read_reg(eac, EAC_CPCFR1);
+ cpcfr2 = eac_read_reg(eac, EAC_CPCFR2);
+ cpcfr3 = eac_read_reg(eac, EAC_CPCFR3);
+ cpcfr4 = eac_read_reg(eac, EAC_CPCFR4);
+
+ cpcfr1 &= ~(CPCFR1_MODE_BITS | CPCFR1_MTSL_BITS);
+ cpcfr1 |= CPCFR1_MTSL(1); /* 2 timeslots per frame (I2S default) */
+
+ /* audio time slot configuration for I2S mode */
+ cpcfr2 &= ~(CPCFR2_TSLL_BITS | CPCFR2_BPTSL_BITS | CPCFR2_TSLOL_BITS);
+ cpcfr2 |= CPCFR2_TSLOL(0); /* time slot 0 length same as TSLL */
+ cpcfr2 |= CPCFR2_BPTSL(1); /* 16 data bits per time slot */
+ cpcfr2 |= CPCFR2_TSLL(1); /* time slot length 16 serial clock cycles */
+
+ /* I2S link configuration */
+ MOD_REG_BIT(cpcfr3, CPCFR3_DDLY,
+ conf->codec_conf.i2s.sync_delay_enable); /* 0/1 clk delay */
+ /* data serial output enabled during nonvalid audio frames, clock
+ * polarity = falling edge, CSYNC lenght equal to time slot0 length */
+ MOD_REG_BIT(cpcfr3, CPCFR3_TRSEN, 1);
+ MOD_REG_BIT(cpcfr3, CPCFR3_CLKBP, 1);
+ MOD_REG_BIT(cpcfr3, CPCFR3_CSYNCL, 1);
+
+ cpcfr4 &= ~(CPCFR4_DIVB_BITS | CPCFR4_ATSL_BITS);
+ cpcfr4 |= CPCFR4_DIVB(7); /* CP_SCLK = MCLK / 8 */
+
+ /* configuration for normal I2S or polarity-changed I2S */
+ if (!conf->codec_conf.i2s.polarity_changed_mode) {
+ cpcfr1 |= CPCFR1_MODE(4); /* I2S mode */
+ MOD_REG_BIT(cpcfr3, CPCFR3_CSYNCP, 0); /* CP_SYNC active low */
+ /* audio time slots configuration for I2S */
+ cpcfr4 |= CPCFR4_ATSL(0);
+ } else {
+ cpcfr1 |= CPCFR1_MODE(1); /* PCM mode/polarity-changed I2S */
+ MOD_REG_BIT(cpcfr3, CPCFR3_CSYNCP, 1); /* CP_SYNC active
+ high */
+ /* audio time slots configuration for polarity-changed I2S */
+ cpcfr4 |= CPCFR4_ATSL(0xf);
+ };
+
+ /* master/slave configuration */
+ if (conf->codec_mode == EAC_CODEC_I2S_MASTER) {
+ /* EAC is master. Set CP_SCLK and CP_SYNC as outputs */
+ MOD_REG_BIT(cpcfr3, CPCFR3_CSCLKD, 0);
+ MOD_REG_BIT(cpcfr3, CPCFR3_CSYNCD, 0);
+ } else {
+ /* EAC is slave. Set CP_SCLK and CP_SYNC as inputs */
+ MOD_REG_BIT(cpcfr3, CPCFR3_CSCLKD, 1);
+ MOD_REG_BIT(cpcfr3, CPCFR3_CSYNCD, 1);
+ }
+
+ eac_write_reg(eac, EAC_CPCFR1, cpcfr1);
+ eac_write_reg(eac, EAC_CPCFR2, cpcfr2);
+ eac_write_reg(eac, EAC_CPCFR3, cpcfr3);
+ eac_write_reg(eac, EAC_CPCFR4, cpcfr4);
+
+ return 0;
+}
+
+static int eac_codec_port_init(struct omap_eac *eac, struct eac_codec *conf)
+{
+ u16 agcfr, agcfr2, agcfr3, agctr;
+ u16 cpctl, reg;
+ int err = 0, i;
+
+ /* use internal MCLK gating before doing full configuration for it.
+ * Partial or misconfigured MCLK will cause that access to some of the
+ * EAC registers causes "external abort on linefetch". Same happens
+ * also when using external clock as a MCLK source and if that clock is
+ * either missing or not having a right rate (e.g. half of it) */
+ agcfr3 = eac_read_reg(eac, EAC_AGCFR3);
+ MOD_REG_BIT(agcfr3, AGCFR3_MCLKINT_SEL, 1); /* 96 Mhz / 8.5 */
+ eac_write_reg(eac, EAC_AGCFR3, agcfr3);
+
+ /* disable codec port, enable access to config registers */
+ cpctl = eac_read_reg(eac, EAC_CPTCTL);
+ MOD_REG_BIT(cpctl, CPTCTL_CPEN, 0);
+ eac_write_reg(eac, EAC_CPTCTL, cpctl);
+
+ agcfr = eac_read_reg(eac, EAC_AGCFR);
+ agctr = eac_read_reg(eac, EAC_AGCTR);
+ agcfr2 = eac_read_reg(eac, EAC_AGCFR2);
+
+ /* MCLK source and frequency configuration */
+ MOD_REG_BIT(agcfr, AGCFR_MCLK, 0);
+ switch (conf->mclk_src) {
+ case EAC_MCLK_EXT_2x11289600:
+ MOD_REG_BIT(agcfr, AGCFR_MCLK, 1); /* div by 2 path */
+ MOD_REG_BIT(agcfr, AGCFR_MCLK_OUT, 1); /* div by 2 */
+ case EAC_MCLK_EXT_11289600:
+ MOD_REG_BIT(agcfr, AGCFR_MCLK, 1);
+ MOD_REG_BIT(agcfr2, AGCFR2_I2S_N44K_48K, 0); /* 44.1 kHz */
+ MOD_REG_BIT(agcfr2, AGCFR2_MCLK_I2S_N11M_12M, 0); /* 11.2896 */
+ MOD_REG_BIT(agcfr3, AGCFR3_MCLKINT_SEL, 0);
+ break;
+
+ case EAC_MCLK_EXT_2x12288000:
+ MOD_REG_BIT(agcfr, AGCFR_MCLK, 1); /* div by 2 path */
+ MOD_REG_BIT(agcfr, AGCFR_MCLK_OUT, 1); /* div by 2 */
+ case EAC_MCLK_EXT_12288000:
+ MOD_REG_BIT(agcfr2, AGCFR2_I2S_N44K_48K, 1); /* 48 kHz */
+ MOD_REG_BIT(agcfr2, AGCFR2_MCLK_I2S_N11M_12M, 1); /* 12.288 */
+ MOD_REG_BIT(agcfr3, AGCFR3_MCLKINT_SEL, 0);
+ break;
+
+ default:
+ /* internal MCLK gating */
+ break;
+ }
+ MOD_REG_BIT(agctr, AGCTR_MCLK_EN, 1);
+ MOD_REG_BIT(agctr, AGCTR_OSCMCLK_EN, 1); /* oscillator enabled? */
+ /* use MCLK just configured above as audio & codec port clock source */
+ agcfr3 &= ~AGCFR3_AUD_CKSRC_BITS;
+ agcfr3 |= AGCFR3_AUD_CKSRC(0);
+
+ /* audio data format */
+ MOD_REG_BIT(agcfr, AGCFR_MN_ST, 1); /* stereo file */
+ MOD_REG_BIT(agcfr, AGCFR_B8_16, 1); /* 16 bit audio file */
+ MOD_REG_BIT(agcfr, AGCFR_LI_BI, 0); /* little endian stream */
+
+ /* there are FSINT configuration bits in AGCFR, AGCFR2 and AGCFR3
+ * registers but it seems that it is just enough to set in AGCFR3
+ * only */
+ agcfr3 &= ~AGCFR3_FSINT_BITS;
+ agcfr3 |= AGCFR3_FSINT(eac_calc_agcfr3_fsint(conf->default_rate));
+
+ /* transparent DMA enable bits */
+ MOD_REG_BIT(agcfr3, AGCFR3_MD_TR_DMA, 1); /* modem */
+ MOD_REG_BIT(agcfr3, AGCFR3_BT_TR_DMA, 1); /* BT */
+ if (conf->codec_mode != EAC_CODEC_I2S_SLAVE)
+ MOD_REG_BIT(agcfr3, AGCFR3_CP_TR_DMA, 0);
+ else
+ MOD_REG_BIT(agcfr3, AGCFR3_CP_TR_DMA, 1);
+
+ /* step 4 (see TRM) */
+ eac_write_reg(eac, EAC_AGCFR3, agcfr3);
+ /* pre-write AGCTR now (finally in step 10) in order to get MCLK
+ * settings effective (especially when using external MCLK) */
+ eac_write_reg(eac, EAC_AGCTR, agctr);
+ eac_write_reg(eac, EAC_AGCFR2, agcfr2);
+
+ /* step 5 (see TRM) */
+ eac_write_reg(eac, EAC_AGCFR, agcfr);
+
+ /* step 6 (see TRM) */
+ /* wait until audio reset done */
+ i = 10000;
+ while (!(eac_read_reg(eac, EAC_SYSSTATUS) & (1 << 3))) {
+ if (--i == 0)
+ return -ETIMEDOUT;
+ udelay(1);
+ }
+
+ /* step 7 (see TRM) */
+ reg = eac_read_reg(eac, EAC_AMSCFR);
+ MOD_REG_BIT(reg, AMSCFR_K1, 1); /* K1 switch closed */
+ MOD_REG_BIT(reg, AMSCFR_K5, 1); /* K5 switch closed */
+ MOD_REG_BIT(reg, AMSCFR_K2, 0); /* K2 switch open */
+ MOD_REG_BIT(reg, AMSCFR_K6, 0); /* K6 switch open */
+ eac_write_reg(eac, EAC_AMSCFR, reg);
+
+ /* step 8 (see TRM) */
+ switch (conf->codec_mode) {
+ case EAC_CODEC_PCM:
+ err = eac_configure_pcm(eac, conf);
+ break;
+ case EAC_CODEC_AC97:
+ err = eac_configure_ac97(eac, conf);
+ break;
+ default:
+ err = eac_configure_i2s(eac, conf);
+ break;
+ }
+
+ /* step 9 (see TRM) */
+ MOD_REG_BIT(cpctl, CPTCTL_CPEN, 1); /* codec port enable */
+ MOD_REG_BIT(cpctl, CPTCTL_RXIE, 1); /* receive int enable */
+ MOD_REG_BIT(cpctl, CPTCTL_TXIE, 1); /* transmit int enable */
+ eac_write_reg(eac, EAC_CPTCTL, cpctl);
+
+ /* step 10 (see TRM) */
+ /* enable playing & recording */
+ MOD_REG_BIT(agctr, AGCTR_DMAREN, 1); /* playing enabled (DMA R) */
+ MOD_REG_BIT(agctr, AGCTR_DMAWEN, 1); /* recording enabled (DMA W) */
+ MOD_REG_BIT(agctr, AGCTR_AUDEN, 1); /* audio processing enabled */
+ eac_write_reg(eac, EAC_AGCTR, agctr);
+
+ /* audio mixer1, no mute on mixer output, gain = 0 dB */
+ reg = eac_read_reg(eac, EAC_AM1VCTR);
+ MOD_REG_BIT(reg, AM1VCTR_MUTE, 0);
+ reg = ((reg & ~AM1VCTR_GINB_BITS) | (AM1VCTR_GINB(0x67)));
+ eac_write_reg(eac, EAC_AM1VCTR, reg);
+
+ /* audio mixer3, no mute on mixer output, gain = 0 dB */
+ reg = eac_read_reg(eac, EAC_AM3VCTR);
+ MOD_REG_BIT(reg, AM3VCTR_MUTE, 0);
+ reg = ((reg & ~AM3VCTR_GINB_BITS) | (AM3VCTR_GINB(0x67)));
+ eac_write_reg(eac, EAC_AM3VCTR, reg);
+
+ /* audio side tone disabled */
+ eac_write_reg(eac, EAC_ASTCTR, 0x0);
+
+ return 0;
+}
+
+int eac_set_mode(struct device *dev, int play, int rec)
+{
+ struct omap_eac *eac = dev_get_drvdata(dev);
+
+#ifdef DEBUG
+ printk(KERN_DEBUG "EAC mode: play %s, rec %s\n",
+ play ? "enabled" : "disabled",
+ rec ? "enabled" : "disabled");
+#endif
+ BUG_ON(eac == NULL);
+ mutex_lock(&eac->mutex);
+ if (play || rec) {
+ /* activate clocks */
+ eac_enable_clocks(eac);
+
+ /* power-up codec */
+ if (eac->codec != NULL && eac->codec->set_power != NULL)
+ eac->codec->set_power(eac->codec->private_data,
+ play, rec);
+ } else {
+ /* shutdown codec */
+ if (eac->codec != NULL && eac->codec->set_power != NULL)
+ eac->codec->set_power(eac->codec->private_data, 0, 0);
+
+ /* de-activate clocks */
+ eac_disable_clocks(eac);
+ }
+ mutex_unlock(&eac->mutex);
+
+ return 0;
+}
+
+int eac_register_codec(struct device *dev, struct eac_codec *codec)
+{
+ struct omap_eac *eac = dev_get_drvdata(dev);
+ struct snd_card *card = eac->card;
+ int err;
+
+ BUG_ON(eac->codec != NULL);
+
+ mutex_lock(&eac->mutex);
+ eac->codec = codec;
+ eac_enable_clocks(eac);
+ err = eac_codec_port_init(eac, codec);
+ eac_disable_clocks(eac);
+ mutex_unlock(&eac->mutex);
+ if (err)
+ return err;
+
+ /* register mixer controls implemented by a codec driver */
+ if (codec->register_controls != NULL) {
+ err = codec->register_controls(codec->private_data, card);
+ if (err)
+ return err;
+ }
+
+ if (codec->short_name != NULL) {
+ sprintf(card->longname, "%s with codec %s", card->shortname,
+ codec->short_name);
+ strcpy(card->mixername, codec->short_name);
+ }
+
+ err = snd_card_register(card);
+ return err;
+}
+
+void eac_unregister_codec(struct device *dev)
+{
+ struct omap_eac *eac = dev_get_drvdata(dev);
+
+ BUG_ON(eac->codec == NULL);
+ eac_set_mode(dev, 0, 0);
+ snd_card_disconnect(eac->card);
+ eac->codec = NULL;
+}
+
+static int __devinit eac_probe(struct platform_device *pdev)
+{
+ struct eac_platform_data *pdata = pdev->dev.platform_data;
+ struct snd_card *card;
+ struct omap_eac *eac;
+ struct resource *res;
+ int err;
+
+ eac = kzalloc(sizeof(*eac), GFP_KERNEL);
+ if (!eac)
+ return -ENOMEM;
+
+ mutex_init(&eac->mutex);
+ eac->pdev = pdev;
+ platform_set_drvdata(pdev, eac);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ err = -ENODEV;
+ goto err1;
+ }
+ eac->base = (void __iomem *)io_p2v(res->start);
+ eac->pdata = pdata;
+
+ /* pre-initialize EAC hw */
+ err = eac_get_clocks(eac);
+ if (err)
+ goto err1;
+ err = eac_enable_clocks(eac);
+ if (err)
+ goto err2;
+
+ err = eac_reset(eac);
+ if (err)
+ goto err3;
+
+ dev_info(&pdev->dev, "EAC version: %d.%d\n",
+ eac_read_reg(eac, EAC_VERSION) >> 4,
+ eac_read_reg(eac, EAC_VERSION) & 0x0f);
+ eac_disable_clocks(eac);
+
+ /* create soundcard instance */
+ card = snd_card_new(-1, id, THIS_MODULE, 0);
+ if (card == NULL) {
+ err = -ENOMEM;
+ goto err3;
+ }
+ eac->card = card;
+ strcpy(card->driver, "EAC");
+ strcpy(card->shortname, "OMAP24xx EAC");
+
+ sprintf(card->longname, "%s", card->shortname);
+ strcpy(card->mixername, "EAC Mixer");
+
+ if (eac->pdata->init) {
+ err = eac->pdata->init(&pdev->dev);
+ if (err < 0) {
+ printk("init %d\n", err);
+ goto err4;
+ }
+ }
+
+ return 0;
+
+err4:
+ snd_card_free(card);
+err3:
+ eac_disable_clocks(eac);
+err2:
+ eac_put_clocks(eac);
+err1:
+ kfree(eac);
+ return err;
+}
+
+static int __devexit eac_remove(struct platform_device *pdev)
+{
+ struct omap_eac *eac = platform_get_drvdata(pdev);
+ struct snd_card *card = eac->card;
+
+ snd_card_free(card);
+
+ eac_disable_clocks(eac);
+ eac_put_clocks(eac);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver eac_driver = {
+ .driver = {
+ .name = "omap24xx-eac",
+ .bus = &platform_bus_type,
+ },
+ .probe = eac_probe,
+ .remove = eac_remove,
+};
+
+int __init eac_init(void)
+{
+ return platform_driver_register(&eac_driver);
+}
+
+void __exit eac_exit(void)
+{
+ platform_driver_unregister(&eac_driver);
+}
+
+module_init(eac_init);
+module_exit(eac_exit);
+MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@nokia.com>");
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * sound/arm/omap/omap-alsa-aic23-mixer.c
+ *
+ * Alsa Driver Mixer for generic codecs for omap boards
+ *
+ * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ * Written by David Cohen, Daniel Petrini
+ * {david.cohen, daniel.petrini}@indt.org.br
+ *
+ * Based on es1688_lib.c,
+ * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * History:
+ *
+ * 2005-08-02 INdT Kernel Team - Alsa mixer driver for omap osk.
+ * Creation of new file omap-alsa-mixer.c.
+ * Initial version with aic23 codec for osk5912
+ */
+
+#include <linux/kernel.h>
+
+#include <asm/arch/aic23.h>
+
+#include <asm/arch/omap-alsa.h>
+#include "omap-alsa-aic23.h"
+#include <sound/initval.h>
+#include <sound/control.h>
+
+MODULE_AUTHOR("David Cohen");
+MODULE_AUTHOR("Daniel Petrini");
+
+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)
+
+#define MIXER_NAME "Mixer AIC23"
+#define SND_OMAP_WRITE(reg, val) audio_aic23_write(reg, val)
+
+#endif
+
+/* Callback Functions */
+#define OMAP_BOOL(xname, xindex, reg, reg_index, mask, invert) \
+{ \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .index = xindex, \
+ .info = snd_omap_info_bool, \
+ .get = snd_omap_get_bool, \
+ .put = snd_omap_put_bool, \
+ .private_value = reg | (reg_index << 8) | (invert << 10) | \
+ (mask << 12) \
+}
+
+#define OMAP_MUX(xname, reg, reg_index, mask) \
+{ \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .info = snd_omap_info_mux, \
+ .get = snd_omap_get_mux, \
+ .put = snd_omap_put_mux, \
+ .private_value = reg | (reg_index << 8) | (mask << 10) \
+}
+
+#define OMAP_SINGLE(xname, xindex, reg, reg_index, reg_val, mask) \
+{\
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .index = xindex, \
+ .info = snd_omap_info_single, \
+ .get = snd_omap_get_single, \
+ .put = snd_omap_put_single, \
+ .private_value = reg | (reg_val << 8) | (reg_index << 16) |\
+ (mask << 18) \
+}
+
+#define OMAP_DOUBLE(xname, xindex, left_reg, right_reg, reg_index, mask) \
+{\
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .index = xindex, \
+ .info = snd_omap_info_double, \
+ .get = snd_omap_get_double, \
+ .put = snd_omap_put_double, \
+ .private_value = left_reg | (right_reg << 8) | (reg_index << 16) | \
+ (mask << 18) \
+}
+
+/* Local Registers */
+enum snd_device_index {
+ PCM_INDEX = 0,
+ LINE_INDEX,
+ AAC_INDEX, /* Analog Audio Control: reg = l_reg */
+};
+
+struct {
+ u16 l_reg;
+ u16 r_reg;
+ u8 sw;
+} omap_regs[3];
+
+#ifdef CONFIG_PM
+struct {
+ u16 l_reg;
+ u16 r_reg;
+ u8 sw;
+} omap_pm_regs[3];
+#endif
+
+u16 snd_sidetone[6] = {
+ SIDETONE_18,
+ SIDETONE_12,
+ SIDETONE_9,
+ SIDETONE_6,
+ SIDETONE_0,
+ 0
+};
+
+/* Begin Bool Functions */
+
+static int snd_omap_info_bool(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+
+ return 0;
+}
+
+static int snd_omap_get_bool(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int mic_index = (kcontrol->private_value >> 8) & 0x03;
+ u16 mask = (kcontrol->private_value >> 12) & 0xff;
+ int invert = (kcontrol->private_value >> 10) & 0x03;
+
+ if (invert)
+ ucontrol->value.integer.value[0] =
+ (omap_regs[mic_index].l_reg & mask) ? 0 : 1;
+ else
+ ucontrol->value.integer.value[0] =
+ (omap_regs[mic_index].l_reg & mask) ? 1 : 0;
+
+ return 0;
+}
+
+static int snd_omap_put_bool(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int mic_index = (kcontrol->private_value >> 8) & 0x03;
+ u16 mask = (kcontrol->private_value >> 12) & 0xff;
+ u16 reg = kcontrol->private_value & 0xff;
+ int invert = (kcontrol->private_value >> 10) & 0x03;
+
+ int changed = 1;
+
+ if (ucontrol->value.integer.value[0]) /* XOR */
+ if (invert)
+ omap_regs[mic_index].l_reg &= ~mask;
+ else
+ omap_regs[mic_index].l_reg |= mask;
+ else
+ if (invert)
+ omap_regs[mic_index].l_reg |= mask;
+ else
+ omap_regs[mic_index].l_reg &= ~mask;
+
+ SND_OMAP_WRITE(reg, omap_regs[mic_index].l_reg);
+
+ return changed;
+}
+
+/* End Bool Functions */
+
+/* Begin Mux Functions */
+
+static int snd_omap_info_mux(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ /* Mic = 0
+ * Line = 1 */
+ static char *texts[2] = { "Mic", "Line" };
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 2;
+
+ if (uinfo->value.enumerated.item > 1)
+ uinfo->value.enumerated.item = 1;
+
+ strcpy(uinfo->value.enumerated.name,
+ texts[uinfo->value.enumerated.item]);
+
+ return 0;
+}
+
+static int snd_omap_get_mux(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u16 mask = (kcontrol->private_value >> 10) & 0xff;
+ int mux_idx = (kcontrol->private_value >> 8) & 0x03;
+
+ ucontrol->value.enumerated.item[0] =
+ (omap_regs[mux_idx].l_reg & mask) ? 0 /* Mic */ : 1 /* Line */;
+
+ return 0;
+}
+
+static int snd_omap_put_mux(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u16 reg = kcontrol->private_value & 0xff;
+ u16 mask = (kcontrol->private_value >> 10) & 0xff;
+ int mux_index = (kcontrol->private_value >> 8) & 0x03;
+
+ int changed = 1;
+
+ if (!ucontrol->value.integer.value[0])
+ omap_regs[mux_index].l_reg |= mask; /* AIC23: Mic */
+ else
+ omap_regs[mux_index].l_reg &= ~mask; /* AIC23: Line */
+
+ SND_OMAP_WRITE(reg, omap_regs[mux_index].l_reg);
+
+ return changed;
+}
+
+/* End Mux Functions */
+
+/* Begin Single Functions */
+
+static int snd_omap_info_single(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ int mask = (kcontrol->private_value >> 18) & 0xff;
+ int reg_val = (kcontrol->private_value >> 8) & 0xff;
+
+ uinfo->type = mask ? SNDRV_CTL_ELEM_TYPE_INTEGER :
+ SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = reg_val-1;
+
+ return 0;
+}
+
+static int snd_omap_get_single(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u16 reg_val = (kcontrol->private_value >> 8) & 0xff;
+
+ ucontrol->value.integer.value[0] = snd_sidetone[reg_val];
+
+ return 0;
+}
+
+static int snd_omap_put_single(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u16 reg_index = (kcontrol->private_value >> 16) & 0x03;
+ u16 mask = (kcontrol->private_value >> 18) & 0x1ff;
+ u16 reg = kcontrol->private_value & 0xff;
+ u16 reg_val = (kcontrol->private_value >> 8) & 0xff;
+
+ int changed = 0;
+
+ /* Volume */
+ if ((omap_regs[reg_index].l_reg !=
+ (ucontrol->value.integer.value[0] & mask))) {
+ changed = 1;
+
+ omap_regs[reg_index].l_reg &= ~mask;
+ omap_regs[reg_index].l_reg |=
+ snd_sidetone[ucontrol->value.integer.value[0]];
+
+ snd_sidetone[reg_val] = ucontrol->value.integer.value[0];
+ SND_OMAP_WRITE(reg, omap_regs[reg_index].l_reg);
+ } else {
+ changed = 0;
+ }
+
+ return changed;
+}
+
+/* End Single Functions */
+
+/* Begin Double Functions */
+
+static int snd_omap_info_double(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ /*
+ * mask == 0 : Switch
+ * mask != 0 : Volume
+ */
+ int mask = (kcontrol->private_value >> 18) & 0xff;
+
+ uinfo->type = mask ? SNDRV_CTL_ELEM_TYPE_INTEGER :
+ SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = mask ? 2 : 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = mask ? mask : 1;
+
+ return 0;
+}
+
+static int snd_omap_get_double(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ /*
+ * mask == 0 : Switch
+ * mask != 0 : Volume
+ */
+ int mask = (kcontrol->private_value >> 18) & 0xff;
+ int vol_index = (kcontrol->private_value >> 16) & 0x03;
+
+ if (!mask) {
+ /* Switch */
+ ucontrol->value.integer.value[0] = omap_regs[vol_index].sw;
+ } else {
+ /* Volume */
+ ucontrol->value.integer.value[0] = omap_regs[vol_index].l_reg;
+ ucontrol->value.integer.value[1] = omap_regs[vol_index].r_reg;
+ }
+
+ return 0;
+}
+
+static int snd_omap_put_double(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ /* mask == 0 : Switch
+ * mask != 0 : Volume */
+ int vol_index = (kcontrol->private_value >> 16) & 0x03;
+ int mask = (kcontrol->private_value >> 18) & 0xff;
+ int left_reg = kcontrol->private_value & 0xff;
+ int right_reg = (kcontrol->private_value >> 8) & 0xff;
+
+ int changed = 0;
+
+ if (!mask) {
+ /* Switch */
+ if (!ucontrol->value.integer.value[0]) {
+ SND_OMAP_WRITE(left_reg, 0x00);
+ SND_OMAP_WRITE(right_reg, 0x00);
+ } else {
+ SND_OMAP_WRITE(left_reg, omap_regs[vol_index].l_reg);
+ SND_OMAP_WRITE(right_reg, omap_regs[vol_index].r_reg);
+ }
+ changed = 1;
+ omap_regs[vol_index].sw = ucontrol->value.integer.value[0];
+ } else {
+ /* Volume */
+ if ((omap_regs[vol_index].l_reg !=
+ (ucontrol->value.integer.value[0] & mask)) ||
+ (omap_regs[vol_index].r_reg !=
+ (ucontrol->value.integer.value[1] & mask))) {
+ changed = 1;
+
+ omap_regs[vol_index].l_reg &= ~mask;
+ omap_regs[vol_index].r_reg &= ~mask;
+ omap_regs[vol_index].l_reg |=
+ (ucontrol->value.integer.value[0] & mask);
+ omap_regs[vol_index].r_reg |=
+ (ucontrol->value.integer.value[1] & mask);
+ if (omap_regs[vol_index].sw) {
+ /* write to registers only if sw is actived */
+ SND_OMAP_WRITE(left_reg,
+ omap_regs[vol_index].l_reg);
+ SND_OMAP_WRITE(right_reg,
+ omap_regs[vol_index].r_reg);
+ }
+ } else {
+ changed = 0;
+ }
+ }
+
+ return changed;
+}
+
+/* End Double Functions */
+
+static struct snd_kcontrol_new snd_omap_controls[] = {
+ OMAP_DOUBLE("PCM Playback Switch", 0, LEFT_CHANNEL_VOLUME_ADDR,
+ RIGHT_CHANNEL_VOLUME_ADDR, PCM_INDEX, 0x00),
+ OMAP_DOUBLE("PCM Playback Volume", 0, LEFT_CHANNEL_VOLUME_ADDR,
+ RIGHT_CHANNEL_VOLUME_ADDR, PCM_INDEX,
+ OUTPUT_VOLUME_MASK),
+ OMAP_BOOL("Line Playback Switch", 0, ANALOG_AUDIO_CONTROL_ADDR,
+ AAC_INDEX, BYPASS_ON, 0),
+ OMAP_DOUBLE("Line Capture Switch", 0, LEFT_LINE_VOLUME_ADDR,
+ RIGHT_LINE_VOLUME_ADDR, LINE_INDEX, 0x00),
+ OMAP_DOUBLE("Line Capture Volume", 0, LEFT_LINE_VOLUME_ADDR,
+ RIGHT_LINE_VOLUME_ADDR, LINE_INDEX, INPUT_VOLUME_MASK),
+ OMAP_BOOL("Mic Playback Switch", 0, ANALOG_AUDIO_CONTROL_ADDR,
+ AAC_INDEX, STE_ENABLED, 0),
+ OMAP_SINGLE("Mic Playback Volume", 0, ANALOG_AUDIO_CONTROL_ADDR,
+ AAC_INDEX, 5, SIDETONE_MASK),
+ OMAP_BOOL("Mic Capture Switch", 0, ANALOG_AUDIO_CONTROL_ADDR,
+ AAC_INDEX, MICM_MUTED, 1),
+ OMAP_BOOL("Mic Booster Playback Switch", 0, ANALOG_AUDIO_CONTROL_ADDR,
+ AAC_INDEX, MICB_20DB, 0),
+ OMAP_MUX("Capture Source", ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX,
+ INSEL_MIC),
+};
+
+#ifdef CONFIG_PM
+
+void snd_omap_suspend_mixer(void)
+{
+ /* Saves current values to wake-up correctly */
+ omap_pm_regs[LINE_INDEX].l_reg = omap_regs[LINE_INDEX].l_reg;
+ omap_pm_regs[LINE_INDEX].r_reg = omap_regs[LINE_INDEX].l_reg;
+ omap_pm_regs[LINE_INDEX].sw = omap_regs[LINE_INDEX].sw;
+
+ omap_pm_regs[AAC_INDEX].l_reg = omap_regs[AAC_INDEX].l_reg;
+
+ omap_pm_regs[PCM_INDEX].l_reg = omap_regs[PCM_INDEX].l_reg;
+ omap_pm_regs[PCM_INDEX].r_reg = omap_regs[PCM_INDEX].r_reg;
+ omap_pm_regs[PCM_INDEX].sw = omap_regs[PCM_INDEX].sw;
+}
+
+void snd_omap_resume_mixer(void)
+{
+ /* Line's saved values */
+ omap_regs[LINE_INDEX].l_reg = omap_pm_regs[LINE_INDEX].l_reg;
+ omap_regs[LINE_INDEX].r_reg = omap_pm_regs[LINE_INDEX].l_reg;
+ omap_regs[LINE_INDEX].sw = omap_pm_regs[LINE_INDEX].sw;
+ SND_OMAP_WRITE(LEFT_LINE_VOLUME_ADDR, omap_pm_regs[LINE_INDEX].l_reg);
+ SND_OMAP_WRITE(RIGHT_LINE_VOLUME_ADDR, omap_pm_regs[LINE_INDEX].l_reg);
+
+ /* Analog Audio Control's saved values */
+ omap_regs[AAC_INDEX].l_reg = omap_pm_regs[AAC_INDEX].l_reg;
+ SND_OMAP_WRITE(ANALOG_AUDIO_CONTROL_ADDR, omap_regs[AAC_INDEX].l_reg);
+
+ /* Headphone's saved values */
+ omap_regs[PCM_INDEX].l_reg = omap_pm_regs[PCM_INDEX].l_reg;
+ omap_regs[PCM_INDEX].r_reg = omap_pm_regs[PCM_INDEX].r_reg;
+ omap_regs[PCM_INDEX].sw = omap_pm_regs[PCM_INDEX].sw;
+ SND_OMAP_WRITE(LEFT_CHANNEL_VOLUME_ADDR,
+ omap_pm_regs[PCM_INDEX].l_reg);
+ SND_OMAP_WRITE(RIGHT_CHANNEL_VOLUME_ADDR,
+ omap_pm_regs[PCM_INDEX].r_reg);
+}
+#endif
+
+void snd_omap_init_mixer(void)
+{
+ u16 vol_reg;
+
+ /* Line's default values */
+ omap_regs[LINE_INDEX].l_reg = DEFAULT_INPUT_VOLUME & INPUT_VOLUME_MASK;
+ omap_regs[LINE_INDEX].r_reg = DEFAULT_INPUT_VOLUME & INPUT_VOLUME_MASK;
+ omap_regs[LINE_INDEX].sw = 0;
+ SND_OMAP_WRITE(LEFT_LINE_VOLUME_ADDR,
+ DEFAULT_INPUT_VOLUME & INPUT_VOLUME_MASK);
+ SND_OMAP_WRITE(RIGHT_LINE_VOLUME_ADDR,
+ DEFAULT_INPUT_VOLUME & INPUT_VOLUME_MASK);
+
+ /* Analog Audio Control's default values */
+ omap_regs[AAC_INDEX].l_reg = DEFAULT_ANALOG_AUDIO_CONTROL;
+
+ /* Headphone's default values */
+ vol_reg = LZC_ON;
+ vol_reg &= ~OUTPUT_VOLUME_MASK;
+ vol_reg |= DEFAULT_OUTPUT_VOLUME;
+ omap_regs[PCM_INDEX].l_reg = DEFAULT_OUTPUT_VOLUME;
+ omap_regs[PCM_INDEX].r_reg = DEFAULT_OUTPUT_VOLUME;
+ omap_regs[PCM_INDEX].sw = 1;
+ SND_OMAP_WRITE(LEFT_CHANNEL_VOLUME_ADDR, vol_reg);
+ SND_OMAP_WRITE(RIGHT_CHANNEL_VOLUME_ADDR, vol_reg);
+}
+
+int snd_omap_mixer(struct snd_card_omap_codec *chip)
+{
+ struct snd_card *card;
+ unsigned int idx;
+ int err;
+
+ snd_assert(chip != NULL && chip->card != NULL, return -EINVAL);
+
+ card = chip->card;
+
+ strcpy(card->mixername, MIXER_NAME);
+
+ /* Registering alsa mixer controls */
+ for (idx = 0; idx < ARRAY_SIZE(snd_omap_controls); idx++) {
+ err = snd_ctl_add(card,
+ snd_ctl_new1(&snd_omap_controls[idx], chip));
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
--- /dev/null
+/*
+ * arch/arm/mach-omap1/omap-alsa-aic23.c
+ *
+ * Alsa codec Driver for AIC23 chip on OSK5912 platform board
+ *
+ * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ * Written by Daniel Petrini, David Cohen, Anderson Briglia
+ * {daniel.petrini, david.cohen, anderson.briglia}@indt.org.br
+ *
+ * Copyright (C) 2006 Mika Laitio <lamikr@cc.jyu.fi>
+ *
+ * Based in former alsa driver for osk and oss driver
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <linux/clk.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/aic23.h>
+
+#include <asm/arch/omap-alsa.h>
+#include "omap-alsa-aic23.h"
+
+static struct clk *aic23_mclk;
+
+/* aic23 related */
+static const struct aic23_samplerate_reg_info
+ rate_reg_info[NUMBER_SAMPLE_RATES_SUPPORTED] = {
+ {4000, 0x06, 1}, /* 4000 */
+ {8000, 0x06, 0}, /* 8000 */
+ {16000, 0x0C, 1}, /* 16000 */
+ {22050, 0x11, 1}, /* 22050 */
+ {24000, 0x00, 1}, /* 24000 */
+ {32000, 0x0C, 0}, /* 32000 */
+ {44100, 0x11, 0}, /* 44100 */
+ {48000, 0x00, 0}, /* 48000 */
+ {88200, 0x1F, 0}, /* 88200 */
+ {96000, 0x0E, 0}, /* 96000 */
+};
+
+/*
+ * Hardware capabilities
+ */
+
+ /*
+ * DAC USB-mode sampling rates (MCLK = 12 MHz)
+ * The rates and rate_reg_into MUST be in the same order
+ */
+static unsigned int rates[] = {
+ 4000, 8000, 16000, 22050,
+ 24000, 32000, 44100,
+ 48000, 88200, 96000,
+};
+
+static struct snd_pcm_hw_constraint_list aic23_hw_constraints_rates = {
+ .count = ARRAY_SIZE(rates),
+ .list = rates,
+ .mask = 0,
+};
+
+static struct snd_pcm_hardware aic23_snd_omap_alsa_playback = {
+ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE),
+ .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_KNOT),
+ .rate_min = 8000,
+ .rate_max = 96000,
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = 128 * 1024,
+ .period_bytes_min = 32,
+ .period_bytes_max = 8 * 1024,
+ .periods_min = 16,
+ .periods_max = 255,
+ .fifo_size = 0,
+};
+
+static struct snd_pcm_hardware aic23_snd_omap_alsa_capture = {
+ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE),
+ .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_KNOT),
+ .rate_min = 8000,
+ .rate_max = 96000,
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = 128 * 1024,
+ .period_bytes_min = 32,
+ .period_bytes_max = 8 * 1024,
+ .periods_min = 16,
+ .periods_max = 255,
+ .fifo_size = 0,
+};
+
+/*
+ * Codec/mcbsp init and configuration section
+ * codec dependent code.
+ */
+
+/* TLV320AIC23 is a write only device */
+void audio_aic23_write(u8 address, u16 data)
+{
+ aic23_write_value(address, data);
+}
+EXPORT_SYMBOL_GPL(audio_aic23_write);
+
+/*
+ * Sample rate changing
+ */
+void aic23_set_samplerate(long rate)
+{
+ u8 count = 0;
+ u16 data = 0;
+
+ /* Fix the rate if it has a wrong value */
+ if (rate >= 96000)
+ rate = 96000;
+ else if (rate >= 88200)
+ rate = 88200;
+ else if (rate >= 48000)
+ rate = 48000;
+ else if (rate >= 44100)
+ rate = 44100;
+ else if (rate >= 32000)
+ rate = 32000;
+ else if (rate >= 24000)
+ rate = 24000;
+ else if (rate >= 22050)
+ rate = 22050;
+ else if (rate >= 16000)
+ rate = 16000;
+ else if (rate >= 8000)
+ rate = 8000;
+ else
+ rate = 4000;
+
+ /* Search for the right sample rate */
+ /* Verify what happens if the rate is not supported
+ * now it goes to 96Khz */
+ while ((rate_reg_info[count].sample_rate != rate) &&
+ (count < (NUMBER_SAMPLE_RATES_SUPPORTED - 1))) {
+ count++;
+ }
+
+ data = (rate_reg_info[count].divider << CLKIN_SHIFT) |
+ (rate_reg_info[count].control << BOSR_SHIFT) | USB_CLK_ON;
+
+ audio_aic23_write(SAMPLE_RATE_CONTROL_ADDR, data);
+}
+
+inline void aic23_configure(void)
+{
+ /* Reset codec */
+ audio_aic23_write(RESET_CONTROL_ADDR, 0);
+
+ /* Initialize the AIC23 internal state */
+
+ /*
+ * Analog audio path control, DAC selected,
+ * delete INSEL_MIC for line-in
+ */
+ audio_aic23_write(ANALOG_AUDIO_CONTROL_ADDR,
+ DEFAULT_ANALOG_AUDIO_CONTROL);
+
+ /* Digital audio path control, de-emphasis control 44.1kHz */
+ audio_aic23_write(DIGITAL_AUDIO_CONTROL_ADDR, DEEMP_44K);
+
+ /* Digital audio interface, master/slave mode, I2S, 16 bit */
+#ifdef AIC23_MASTER
+ audio_aic23_write(DIGITAL_AUDIO_FORMAT_ADDR,
+ MS_MASTER | IWL_16 | FOR_DSP);
+#else
+ audio_aic23_write(DIGITAL_AUDIO_FORMAT_ADDR, IWL_16 | FOR_DSP);
+#endif
+
+ /* Enable digital interface */
+ audio_aic23_write(DIGITAL_INTERFACE_ACT_ADDR, ACT_ON);
+}
+
+/*
+ * OMAP MCBSP clock configuration and Power Management
+ *
+ * Here we have some functions that allow clock to be enabled and
+ * disabled only when needed. Besides doing clock configuration
+ * it allows turn on/turn off audio when necessary.
+ */
+/*
+ * Do clock framework mclk search
+ */
+void aic23_clock_setup(void)
+{
+ aic23_mclk = clk_get(0, "mclk");
+}
+
+/*
+ * Do some sanity check, set clock rate, starts it and
+ * turn codec audio on
+ */
+int aic23_clock_on(void)
+{
+ uint curRate;
+
+ if (clk_get_usecount(aic23_mclk) > 0) {
+ /* MCLK is already in use */
+ printk(KERN_WARNING
+ "MCLK in use at %d Hz. We change it to %d Hz\n",
+ (uint) clk_get_rate(aic23_mclk),
+ CODEC_CLOCK);
+ }
+ curRate = (uint)clk_get_rate(aic23_mclk);
+ if (curRate != CODEC_CLOCK) {
+ if (clk_set_rate(aic23_mclk, CODEC_CLOCK)) {
+ printk(KERN_ERR
+ "Cannot set MCLK for AIC23 CODEC\n");
+ return -ECANCELED;
+ }
+ }
+ clk_enable(aic23_mclk);
+
+ printk(KERN_DEBUG
+ "MCLK = %d [%d], usecount = %d\n",
+ (uint) clk_get_rate(aic23_mclk), CODEC_CLOCK,
+ clk_get_usecount(aic23_mclk));
+
+ /* Now turn the audio on */
+ audio_aic23_write(POWER_DOWN_CONTROL_ADDR,
+ ~DEVICE_POWER_OFF & ~OUT_OFF & ~DAC_OFF &
+ ~ADC_OFF & ~MIC_OFF & ~LINE_OFF);
+ return 0;
+}
+
+/*
+ * Do some sanity check, turn clock off and then turn
+ * codec audio off
+ */
+int aic23_clock_off(void)
+{
+ if (clk_get_usecount(aic23_mclk) > 0) {
+ if (clk_get_rate(aic23_mclk) != CODEC_CLOCK) {
+ printk(KERN_WARNING
+ "MCLK for audio should be %d Hz. But is %d Hz\n",
+ (uint) clk_get_rate(aic23_mclk),
+ CODEC_CLOCK);
+ }
+
+ clk_disable(aic23_mclk);
+ }
+
+ audio_aic23_write(POWER_DOWN_CONTROL_ADDR,
+ DEVICE_POWER_OFF | OUT_OFF | DAC_OFF |
+ ADC_OFF | MIC_OFF | LINE_OFF);
+ return 0;
+}
+
+int aic23_get_default_samplerate(void)
+{
+ return DEFAULT_SAMPLE_RATE;
+}
+
+static int __devinit snd_omap_alsa_aic23_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct omap_alsa_codec_config *codec_cfg;
+
+ codec_cfg = pdev->dev.platform_data;
+ if (codec_cfg != NULL) {
+ codec_cfg->hw_constraints_rates = &aic23_hw_constraints_rates;
+ codec_cfg->snd_omap_alsa_playback =
+ &aic23_snd_omap_alsa_playback;
+ codec_cfg->snd_omap_alsa_capture = &aic23_snd_omap_alsa_capture;
+ codec_cfg->codec_configure_dev = aic23_configure;
+ codec_cfg->codec_set_samplerate = aic23_set_samplerate;
+ codec_cfg->codec_clock_setup = aic23_clock_setup;
+ codec_cfg->codec_clock_on = aic23_clock_on;
+ codec_cfg->codec_clock_off = aic23_clock_off;
+ codec_cfg->get_default_samplerate =
+ aic23_get_default_samplerate;
+ ret = snd_omap_alsa_post_probe(pdev, codec_cfg);
+ } else
+ ret = -ENODEV;
+ return ret;
+}
+
+static struct platform_driver omap_alsa_driver = {
+ .probe = snd_omap_alsa_aic23_probe,
+ .remove = snd_omap_alsa_remove,
+ .suspend = snd_omap_alsa_suspend,
+ .resume = snd_omap_alsa_resume,
+ .driver = {
+ .name = "omap_alsa_mcbsp",
+ },
+};
+
+static int __init omap_alsa_aic23_init(void)
+{
+ int err;
+
+ ADEBUG();
+ err = platform_driver_register(&omap_alsa_driver);
+
+ return err;
+}
+
+static void __exit omap_alsa_aic23_exit(void)
+{
+ ADEBUG();
+
+ platform_driver_unregister(&omap_alsa_driver);
+}
+
+module_init(omap_alsa_aic23_init);
+module_exit(omap_alsa_aic23_exit);
--- /dev/null
+/*
+ * sound/arm/omap-alsa-aic23.h
+ *
+ * Alsa Driver for AIC23 codec on OSK5912 platform board
+ *
+ * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ * Written by Daniel Petrini, David Cohen, Anderson Briglia
+ * {daniel.petrini, david.cohen, anderson.briglia}@indt.org.br
+ *
+ * Copyright (C) 2006 Mika Laitio <lamikr@cc.jyu.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __OMAP_ALSA_AIC23_H
+#define __OMAP_ALSA_AIC23_H
+
+#include <asm/arch/dma.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <asm/arch/mcbsp.h>
+
+/* Define to set the AIC23 as the master w.r.t McBSP */
+#define AIC23_MASTER
+
+#define NUMBER_SAMPLE_RATES_SUPPORTED 10
+
+/*
+ * AUDIO related MACROS
+ */
+#ifndef DEFAULT_BITPERSAMPLE
+#define DEFAULT_BITPERSAMPLE 16
+#endif
+
+#define DEFAULT_SAMPLE_RATE 44100
+#define CODEC_CLOCK 12000000
+#define AUDIO_MCBSP OMAP_MCBSP1
+
+#define DEFAULT_OUTPUT_VOLUME 0x60
+#define DEFAULT_INPUT_VOLUME 0x00 /* 0 ==> mute line in */
+
+#define OUTPUT_VOLUME_MIN LHV_MIN
+#define OUTPUT_VOLUME_MAX LHV_MAX
+#define OUTPUT_VOLUME_RANGE (OUTPUT_VOLUME_MAX - OUTPUT_VOLUME_MIN)
+#define OUTPUT_VOLUME_MASK OUTPUT_VOLUME_MAX
+
+#define INPUT_VOLUME_MIN LIV_MIN
+#define INPUT_VOLUME_MAX LIV_MAX
+#define INPUT_VOLUME_RANGE (INPUT_VOLUME_MAX - INPUT_VOLUME_MIN)
+#define INPUT_VOLUME_MASK INPUT_VOLUME_MAX
+
+#define SIDETONE_MASK 0x1c0
+#define SIDETONE_0 0x100
+#define SIDETONE_6 0x000
+#define SIDETONE_9 0x040
+#define SIDETONE_12 0x080
+#define SIDETONE_18 0x0c0
+
+#define DEFAULT_ANALOG_AUDIO_CONTROL (DAC_SELECTED | STE_ENABLED | \
+ BYPASS_ON | INSEL_MIC | MICB_20DB)
+
+struct aic23_samplerate_reg_info {
+ u32 sample_rate;
+ u8 control; /* SR3, SR2, SR1, SR0 and BOSR */
+ u8 divider; /* if 0 CLKIN = MCLK, if 1 CLKIN = MCLK/2 */
+};
+
+extern int aic23_write_value(u8 reg, u16 value);
+
+/*
+ * Defines codec specific function pointers that can be used from the
+ * common omap-alsa base driver for all omap codecs. (tsc2101 and aic23)
+ */
+void audio_aic23_write(u8 address, u16 data);
+void define_codec_functions(struct omap_alsa_codec_config *codec_config);
+inline void aic23_configure(void);
+void aic23_set_samplerate(long rate);
+void aic23_clock_setup(void);
+int aic23_clock_on(void);
+int aic23_clock_off(void);
+int aic23_get_default_samplerate(void);
+
+#endif
--- /dev/null
+/*
+ * sound/arm/omap/omap-alsa-dma.c
+ *
+ * Common audio DMA handling for the OMAP processors
+ *
+ * Copyright (C) 2006 Mika Laitio <lamikr@cc.jyu.fi>
+ *
+ * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *
+ * Copyright (C) 2000, 2001 Nicolas Pitre <nico@cam.org>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * History:
+ *
+ * 2004-06-07 Sriram Kannan - Created new file from omap_audio_dma_intfc.c.
+ * This file will contain only the DMA interface
+ * and buffer handling of OMAP audio driver.
+ *
+ * 2004-06-22 Sriram Kannan - removed legacy code (auto-init). Self-linking
+ * of DMA logical channel.
+ *
+ * 2004-08-12 Nishanth Menon - Modified to integrate Audio requirements on
+ * 1610, 1710 platforms
+ *
+ * 2004-11-01 Nishanth Menon - 16xx platform code base modified to support
+ * multi channel chaining.
+ *
+ * 2004-12-15 Nishanth Menon - Improved 16xx platform channel logic
+ * introduced - tasklets, queue handling updated
+ *
+ * 2005-07-19 INdT Kernel Team - Alsa port. Creation of new file
+ * omap-alsa-dma.c based in omap-audio-dma-intfc.c
+ * oss file. Support for aic23 codec. Removal of
+ * buffer handling (Alsa does that), modifications
+ * in dma handling and port to alsa structures.
+ *
+ * 2005-12-18 Dirk Behme - Added L/R Channel Interchange fix as proposed
+ * by Ajaya Babu
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/poll.h>
+#include <linux/pm.h>
+#include <linux/errno.h>
+#include <linux/sound.h>
+#include <linux/soundcard.h>
+#include <linux/sysrq.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+
+#include <asm/hardware.h>
+#include <asm/semaphore.h>
+#include <asm/arch/dma.h>
+#include <asm/arch/mcbsp.h>
+#include <asm/arch/omap-alsa.h>
+
+#include "omap-alsa-dma.h"
+
+#undef DEBUG
+
+/*
+ * 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) \
+ do { \
+ __AUDIO_INCREMENT_QUEUE(s->dma_q_head); \
+ s->dma_q_count--; \
+ } while (0)
+#define AUDIO_INCREMENT_TAIL(s) \
+ do { \
+ __AUDIO_INCREMENT_QUEUE(s->dma_q_tail); \
+ s->dma_q_count++; \
+ } while (0)
+
+/* 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 */
+DEFINE_SPINLOCK(dma_list_lock);
+static char nr_linked_channels = 1;
+
+/* Module specific functions */
+
+static void sound_dma_irq_handler(int lch, u16 ch_status, void *data);
+static int audio_set_dma_params_play(int channel, dma_addr_t dma_ptr,
+ u_int dma_size);
+static int audio_set_dma_params_capture(int channel, dma_addr_t dma_ptr,
+ u_int dma_size);
+static int audio_start_dma_chain(struct audio_stream *s);
+
+/*
+ * DMA channel requests
+ */
+static void omap_sound_dma_link_lch(void *data)
+{
+
+ struct audio_stream *s = (struct audio_stream *) data;
+ int *chan = s->lch;
+ int i;
+
+ FN_IN;
+ if (s->linked) {
+ FN_OUT(1);
+ return;
+ }
+ for (i = 0; i < nr_linked_channels; i++) {
+ int cur_chan = chan[i];
+ int nex_chan =
+ ((nr_linked_channels - 1 ==
+ i) ? chan[0] : chan[i + 1]);
+ omap_dma_link_lch(cur_chan, nex_chan);
+ }
+ s->linked = 1;
+ FN_OUT(0);
+}
+
+int omap_request_alsa_sound_dma(int device_id, const char *device_name,
+ void *data, int **channels)
+{
+ int i, err = 0;
+ int *chan = NULL;
+ FN_IN;
+ if (unlikely((NULL == channels) || (NULL == device_name))) {
+ BUG();
+ return -EPERM;
+ }
+ /* Try allocate memory for the num channels */
+ *channels = kmalloc(sizeof(int) * nr_linked_channels, GFP_KERNEL);
+ chan = *channels;
+ if (NULL == chan) {
+ ERR("No Memory for channel allocs!\n");
+ FN_OUT(-ENOMEM);
+ return -ENOMEM;
+ }
+ spin_lock(&dma_list_lock);
+ for (i = 0; i < nr_linked_channels; i++) {
+ err = omap_request_dma(device_id,
+ device_name,
+ sound_dma_irq_handler,
+ data,
+ &chan[i]);
+
+ /* Handle Failure condition here */
+ if (err < 0) {
+ int j;
+
+ for (j = 0; j < i; j++)
+ omap_free_dma(chan[j]);
+
+ spin_unlock(&dma_list_lock);
+ kfree(chan);
+ *channels = NULL;
+ ERR("Error in requesting channel %d=0x%x\n", i,
+ err);
+ FN_OUT(err);
+ return err;
+ }
+ }
+
+ /* Chain the channels together */
+ if (!cpu_is_omap15xx())
+ omap_sound_dma_link_lch(data);
+
+ spin_unlock(&dma_list_lock);
+ FN_OUT(0);
+ return 0;
+}
+EXPORT_SYMBOL(omap_request_alsa_sound_dma);
+
+/*
+ * DMA channel requests Freeing
+ */
+static void omap_sound_dma_unlink_lch(void *data)
+{
+ struct audio_stream *s = (struct audio_stream *)data;
+ int *chan = s->lch;
+ int i;
+
+ FN_IN;
+ if (!s->linked) {
+ FN_OUT(1);
+ return;
+ }
+ for (i = 0; i < nr_linked_channels; i++) {
+ int cur_chan = chan[i];
+ int nex_chan =
+ ((nr_linked_channels - 1 ==
+ i) ? chan[0] : chan[i + 1]);
+ omap_dma_unlink_lch(cur_chan, nex_chan);
+ }
+ s->linked = 0;
+ FN_OUT(0);
+}
+
+int omap_free_alsa_sound_dma(void *data, int **channels)
+{
+ int i;
+ int *chan = NULL;
+
+ FN_IN;
+ if (unlikely(NULL == channels)) {
+ BUG();
+ return -EPERM;
+ }
+ if (unlikely(NULL == *channels)) {
+ BUG();
+ return -EPERM;
+ }
+ chan = (*channels);
+
+ if (!cpu_is_omap15xx())
+ omap_sound_dma_unlink_lch(data);
+ for (i = 0; i < nr_linked_channels; i++) {
+ int cur_chan = chan[i];
+ omap_stop_dma(cur_chan);
+ omap_free_dma(cur_chan);
+ }
+ kfree(*channels);
+ *channels = NULL;
+ FN_OUT(0);
+ return 0;
+}
+EXPORT_SYMBOL(omap_free_alsa_sound_dma);
+
+/*
+ * Stop all the DMA channels of the stream
+ */
+void omap_stop_alsa_sound_dma(struct audio_stream *s)
+{
+ int *chan = s->lch;
+ int i;
+
+ FN_IN;
+ if (unlikely(NULL == chan)) {
+ BUG();
+ return;
+ }
+ for (i = 0; i < nr_linked_channels; i++) {
+ int cur_chan = chan[i];
+ omap_stop_dma(cur_chan);
+ }
+ s->started = 0;
+ FN_OUT(0);
+ return;
+}
+EXPORT_SYMBOL(omap_stop_alsa_sound_dma);
+
+/*
+ * Clear any pending transfers
+ */
+void omap_clear_alsa_sound_dma(struct audio_stream *s)
+{
+ FN_IN;
+ omap_clear_dma(s->lch[s->dma_q_head]);
+ FN_OUT(0);
+ return;
+}
+EXPORT_SYMBOL(omap_clear_alsa_sound_dma);
+
+/*
+ * DMA related functions
+ */
+static int audio_set_dma_params_play(int channel, dma_addr_t dma_ptr,
+ u_int dma_size)
+{
+ int dt = 0x1; /* data type 16 */
+ int cen = 32; /* Stereo */
+ int cfn = dma_size / (2 * cen);
+
+ FN_IN;
+ omap_set_dma_dest_params(channel, 0x05, 0x00,
+ (OMAP1510_MCBSP1_BASE + 0x06),
+ 0, 0);
+ omap_set_dma_src_params(channel, 0x00, 0x01, dma_ptr,
+ 0, 0);
+ omap_set_dma_transfer_params(channel, dt, cen, cfn, 0x00, 0, 0);
+ FN_OUT(0);
+ return 0;
+}
+
+static int audio_set_dma_params_capture(int channel, dma_addr_t dma_ptr,
+ u_int dma_size)
+{
+ int dt = 0x1; /* data type 16 */
+ int cen = 32; /* stereo */
+ int cfn = dma_size / (2 * cen);
+
+ FN_IN;
+ omap_set_dma_src_params(channel, 0x05, 0x00,
+ (OMAP1510_MCBSP1_BASE + 0x02),
+ 0, 0);
+ omap_set_dma_dest_params(channel, 0x00, 0x01, dma_ptr, 0, 0);
+ omap_set_dma_transfer_params(channel, dt, cen, cfn, 0x00, 0, 0);
+ FN_OUT(0);
+ return 0;
+}
+
+static int audio_start_dma_chain(struct audio_stream *s)
+{
+ int channel = s->lch[s->dma_q_head];
+ FN_IN;
+ if (!s->started) {
+ s->hw_stop(); /* stops McBSP Interface */
+ omap_start_dma(channel);
+ s->started = 1;
+ s->hw_start(); /* start McBSP interface */
+ } else if (cpu_is_omap310())
+ omap_start_dma(channel);
+ /* else the dma itself will progress forward with out our help */
+ FN_OUT(0);
+ return 0;
+}
+
+/*
+ * Start DMA -
+ * Do the initial set of work to initialize all the channels as required.
+ * We shall then initate a transfer
+ */
+int omap_start_alsa_sound_dma(struct audio_stream *s,
+ dma_addr_t dma_ptr,
+ u_int dma_size)
+{
+ int ret = -EPERM;
+
+ FN_IN;
+
+ if (unlikely(dma_size > MAX_DMA_SIZE)) {
+ ERR("DmaSoundDma: Start: overflowed %d-%d\n", dma_size,
+ MAX_DMA_SIZE);
+ return -EOVERFLOW;
+ }
+
+ if (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;
+
+}
+EXPORT_SYMBOL(omap_start_alsa_sound_dma);
+
+/*
+ * 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 checking */
+ DPRINTK("lch=%d,status=0x%x, dma_status=%d, data=%p\n",
+ sound_curr_lch, ch_status, dma_status, data);
+
+ if (dma_status & (DCSR_ERROR)) {
+ OMAP_DMA_CCR_REG(sound_curr_lch) &= ~DCCR_EN;
+ ERR("DCSR_ERROR!\n");
+ FN_OUT(-1);
+ return;
+ }
+
+ if (ch_status & DCSR_END_BLOCK)
+ callback_omap_alsa_sound_dma(s);
+ FN_OUT(0);
+ return;
+}
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("Common DMA handling for Audio driver on OMAP processors");
+MODULE_LICENSE("GPL");
+
--- /dev/null
+/*
+ * linux/sound/arm/omap/omap-alsa-dma.h
+ *
+ * Common audio DMA handling for the OMAP processors
+ *
+ * Copyright (C) 2006 Mika Laitio <lamikr@cc.jyu.fi>
+ *
+ * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *
+ * Copyright (C) 2000, 2001 Nicolas Pitre <nico@cam.org>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * History:
+ *
+ *
+ * 2004/08/12 Nishanth Menon - Modified to integrate Audio requirements on
+ * 1610, 1710 platforms
+ *
+ * 2005/07/25 INdT Kernel Team - Renamed to omap-alsa-dma.h. Ported to Alsa.
+ */
+
+#ifndef __OMAP_AUDIO_ALSA_DMA_H
+#define __OMAP_AUDIO_ALSA_DMA_H
+
+#include <asm/arch/omap-alsa.h>
+
+/* Global data structures */
+
+typedef void (*dma_callback_t) (int lch, u16 ch_status, void *data);
+
+/* arch specific functions */
+
+void omap_clear_alsa_sound_dma(struct audio_stream *s);
+
+int omap_request_alsa_sound_dma(int device_id, const char *device_name,
+ void *data, int **channels);
+int omap_free_alsa_sound_dma(void *data, int **channels);
+
+int omap_start_alsa_sound_dma(struct audio_stream *s, dma_addr_t dma_ptr,
+ u_int dma_size);
+
+void omap_stop_alsa_sound_dma(struct audio_stream *s);
+
+#endif
--- /dev/null
+/*
+ * sound/arm/omap/omap-alsa-sx1-mixer.c
+ *
+ * Alsa codec Driver for Siemens SX1 board.
+ * based on omap-alsa-tsc2101-mixer.c
+ *
+ * Copyright (C) 2006 Vladimir Ananiev (vovan888 at gmail com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "omap-alsa-sx1.h"
+#include "omap-alsa-sx1-mixer.h"
+
+#include <linux/types.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+
+static int current_playback_target = PLAYBACK_TARGET_LOUDSPEAKER;
+static int current_rec_src = REC_SRC_SINGLE_ENDED_MICIN_HED;
+static int current_volume; /* current volume, we cant read it */
+static int current_fm_volume; /* current FM radio volume, we cant read it */
+
+/*
+ * Select SX1 recording source.
+ */
+static void set_record_source(int val)
+{
+ /* TODO Recording is done on McBSP2 and Mic only */
+ current_rec_src = val;
+}
+
+static int set_mixer_volume(int mixer_vol)
+{
+ int ret, i;
+ if ((mixer_vol < 0) || (mixer_vol > 9)) {
+ printk(KERN_ERR "Trying a bad mixer volume (%d)!\n", mixer_vol);
+ return -EPERM;
+ }
+ ret = (current_volume != mixer_vol);
+ current_volume = mixer_vol; /* set current volume, we cant read it */
+
+ i = cn_sx1snd_send(DAC_VOLUME_UPDATE, mixer_vol, 0);
+ if (i)
+ return i;
+ return ret;
+}
+
+static void set_loudspeaker_to_playback_target(void)
+{
+ /* TODO */
+ cn_sx1snd_send(DAC_SETAUDIODEVICE, SX1_DEVICE_SPEAKER, 0);
+
+ current_playback_target = PLAYBACK_TARGET_LOUDSPEAKER;
+}
+
+static void set_headphone_to_playback_target(void)
+{
+ /* TODO */
+ cn_sx1snd_send(DAC_SETAUDIODEVICE, SX1_DEVICE_HEADPHONE, 0);
+
+ current_playback_target = PLAYBACK_TARGET_HEADPHONE;
+}
+
+static void set_telephone_to_playback_target(void)
+{
+ /* TODO */
+ cn_sx1snd_send(DAC_SETAUDIODEVICE, SX1_DEVICE_PHONE, 0);
+
+ current_playback_target = PLAYBACK_TARGET_CELLPHONE;
+}
+
+static void set_telephone_to_record_source(void)
+{
+ cn_sx1snd_send(DAC_SETAUDIODEVICE, SX1_DEVICE_PHONE, 0);
+}
+
+static void init_playback_targets(void)
+{
+ set_loudspeaker_to_playback_target();
+ set_mixer_volume(DEFAULT_OUTPUT_VOLUME);
+}
+
+/*
+ * Initializes SX1 record source (to mic) and playback target (to loudspeaker)
+ */
+void snd_omap_init_mixer(void)
+{
+ /* Select headset to record source */
+ set_record_source(REC_SRC_SINGLE_ENDED_MICIN_HED);
+ /* Init loudspeaker as a default playback target*/
+ init_playback_targets();
+}
+
+/* ---------------------------------------------------------------------- */
+static int pcm_playback_target_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ static char *texts[PLAYBACK_TARGET_COUNT] = {
+ "Loudspeaker", "Headphone", "Cellphone"
+ };
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = PLAYBACK_TARGET_COUNT;
+ if (uinfo->value.enumerated.item > PLAYBACK_TARGET_COUNT - 1)
+ uinfo->value.enumerated.item = PLAYBACK_TARGET_COUNT - 1;
+
+ strcpy(uinfo->value.enumerated.name,
+ texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+static int pcm_playback_target_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = current_playback_target;
+ return 0;
+}
+
+static int pcm_playback_target_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret_val = 0;
+ int cur_val = ucontrol->value.integer.value[0];
+
+ if ((cur_val >= 0) &&
+ (cur_val < PLAYBACK_TARGET_COUNT) &&
+ (cur_val != current_playback_target)) {
+ if (cur_val == PLAYBACK_TARGET_LOUDSPEAKER) {
+ set_record_source(REC_SRC_SINGLE_ENDED_MICIN_HED);
+ set_loudspeaker_to_playback_target();
+ } else if (cur_val == PLAYBACK_TARGET_HEADPHONE) {
+ set_record_source(REC_SRC_SINGLE_ENDED_MICIN_HND);
+ set_headphone_to_playback_target();
+ } else if (cur_val == PLAYBACK_TARGET_CELLPHONE) {
+ set_telephone_to_record_source();
+ set_telephone_to_playback_target();
+ }
+ ret_val = 1;
+ }
+ return ret_val;
+}
+
+/*-----------------------------------------------------------*/
+static int pcm_playback_volume_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 9;
+ return 0;
+}
+
+static int pcm_playback_volume_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = current_volume;
+ return 0;
+}
+
+static int pcm_playback_volume_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return set_mixer_volume(ucontrol->value.integer.value[0]);
+}
+
+static int pcm_playback_switch_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+static int pcm_playback_switch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = 1;
+ return 0;
+}
+
+static int pcm_playback_switch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return 0;
+}
+
+/* ----------------------------------------------------------- */
+
+static int headset_playback_volume_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 9;
+ return 0;
+}
+
+static int headset_playback_volume_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = current_volume;
+ return 0;
+}
+
+static int headset_playback_volume_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return set_mixer_volume(ucontrol->value.integer.value[0]);
+}
+
+static int headset_playback_switch_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+static int headset_playback_switch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = 1;
+ return 0;
+}
+
+static int headset_playback_switch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ /* mute/unmute headset */
+#if 0
+ return adc_pga_unmute_control(ucontrol->value.integer.value[0],
+ TSC2101_HEADSET_GAIN_CTRL,
+ 15);
+#endif
+ return 0;
+}
+/* ----------------------------------------------------------- */
+static int fmradio_playback_volume_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 9;
+ return 0;
+}
+
+static int fmradio_playback_volume_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = current_fm_volume;
+ return 0;
+}
+
+static int fmradio_playback_volume_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret = current_fm_volume != ucontrol->value.integer.value[0];
+ int i;
+ current_fm_volume = ucontrol->value.integer.value[0];
+ i = cn_sx1snd_send(DAC_FMRADIO_OPEN, current_fm_volume, 0);
+ if (i)
+ return i;
+ return ret;
+}
+
+static int fmradio_playback_switch_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+static int fmradio_playback_switch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = 1;
+ return 0;
+}
+
+static int fmradio_playback_switch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ /* mute/unmute FM radio */
+ if (ucontrol->value.integer.value[0])
+ cn_sx1snd_send(DAC_FMRADIO_OPEN, current_fm_volume, 0);
+ else
+ cn_sx1snd_send(DAC_FMRADIO_CLOSE, 0, 0);
+
+ return 0;
+}
+/* ----------------------------------------------------------- */
+static int cellphone_input_switch_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+static int cellphone_input_switch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = 1;
+ return 0;
+}
+
+static int cellphone_input_switch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+#if 0
+ return adc_pga_unmute_control(ucontrol->value.integer.value[0],
+ TSC2101_BUZZER_GAIN_CTRL, 15);
+#endif
+ return 0;
+}
+/* ----------------------------------------------------------- */
+
+static int buzzer_input_switch_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+static int buzzer_input_switch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = 1;
+ return 0;
+}
+
+static int buzzer_input_switch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+#if 0
+ return adc_pga_unmute_control(ucontrol->value.integer.value[0],
+ TSC2101_BUZZER_GAIN_CTRL, 6);
+#endif
+ return 0;
+}
+/*-----------------------------------------------------------*/
+
+static struct snd_kcontrol_new egold_control[] __devinitdata = {
+ {
+ .name = "Playback Playback Route",
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = pcm_playback_target_info,
+ .get = pcm_playback_target_get,
+ .put = pcm_playback_target_put,
+ }, {
+ .name = "Master Playback Volume",
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = pcm_playback_volume_info,
+ .get = pcm_playback_volume_get,
+ .put = pcm_playback_volume_put,
+ }, {
+ .name = "Master Playback Switch",
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = pcm_playback_switch_info,
+ .get = pcm_playback_switch_get,
+ .put = pcm_playback_switch_put,
+ }, {
+ .name = "Headset Playback Volume",
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .index = 1,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = headset_playback_volume_info,
+ .get = headset_playback_volume_get,
+ .put = headset_playback_volume_put,
+ }, {
+ .name = "Headset Playback Switch",
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .index = 1,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = headset_playback_switch_info,
+ .get = headset_playback_switch_get,
+ .put = headset_playback_switch_put,
+ }, {
+ .name = "FM Playback Volume",
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .index = 2,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = fmradio_playback_volume_info,
+ .get = fmradio_playback_volume_get,
+ .put = fmradio_playback_volume_put,
+ }, {
+ .name = "FM Playback Switch",
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .index = 2,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = fmradio_playback_switch_info,
+ .get = fmradio_playback_switch_get,
+ .put = fmradio_playback_switch_put,
+ }, {
+ .name = "Cellphone Input Switch",
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = cellphone_input_switch_info,
+ .get = cellphone_input_switch_get,
+ .put = cellphone_input_switch_put,
+ }, {
+ .name = "Buzzer Input Switch",
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = buzzer_input_switch_info,
+ .get = buzzer_input_switch_get,
+ .put = buzzer_input_switch_put,
+ }
+};
+
+#ifdef CONFIG_PM
+void snd_omap_suspend_mixer(void)
+{
+}
+
+void snd_omap_resume_mixer(void)
+{
+ snd_omap_init_mixer();
+}
+#endif
+
+int snd_omap_mixer(struct snd_card_omap_codec *egold)
+{
+ int i = 0;
+ int err = 0;
+
+ if (!egold)
+ return -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(egold_control); i++) {
+ err = snd_ctl_add(egold->card,
+ snd_ctl_new1(&egold_control[i], egold->card));
+ if (err < 0)
+ return err;
+ }
+ return 0;
+}
--- /dev/null
+/*
+ * sound/arm/omap/omap-alsa-sx1-mixer.h
+ *
+ * Alsa codec Driver for Siemens SX1 board.
+ * based on omap-alsa-tsc2101-mixer.c
+ *
+ * Copyright (C) 2006 Vladimir Ananiev (vovan888 at gmail com)
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef OMAPALSASX1MIXER_H_
+#define OMAPALSASX1MIXER_H_
+
+#include "omap-alsa-dma.h"
+
+#define PLAYBACK_TARGET_COUNT 0x03
+#define PLAYBACK_TARGET_LOUDSPEAKER 0x00
+#define PLAYBACK_TARGET_HEADPHONE 0x01
+#define PLAYBACK_TARGET_CELLPHONE 0x02
+
+/* following are used for register 03h Mixer PGA control bits
+ D7-D5 for selecting record source */
+#define REC_SRC_TARGET_COUNT 0x08
+/* OSS code referred to MIXER_LINE */
+#define REC_SRC_SINGLE_ENDED_MICIN_HED 0x00
+/* OSS code referred to MIXER_MIC */
+#define REC_SRC_SINGLE_ENDED_MICIN_HND 0x01
+#define REC_SRC_SINGLE_ENDED_AUX1 0x02
+#define REC_SRC_SINGLE_ENDED_AUX2 0x03
+#define REC_SRC_MICIN_HED_AND_AUX1 0x04
+#define REC_SRC_MICIN_HED_AND_AUX2 0x05
+#define REC_SRC_MICIN_HND_AND_AUX1 0x06
+#define REC_SRC_MICIN_HND_AND_AUX2 0x07
+
+#define DEFAULT_OUTPUT_VOLUME 5 /* default output volume to dac dgc */
+#define DEFAULT_INPUT_VOLUME 2 /* default record volume */
+
+#endif
--- /dev/null
+/*
+ * Alsa codec Driver for Siemens SX1 board.
+ * based on omap-alsa-tsc2101.c and cn_test.c example by Evgeniy Polyakov
+ *
+ * Copyright (C) 2006 Vladimir Ananiev (vovan888 at gmail com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/delay.h>
+#include <linux/soundcard.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/connector.h>
+#include <linux/slab.h>
+#include <linux/pm.h>
+
+#include <asm/arch/dma.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/mcbsp.h>
+#include <asm/arch/omap-alsa.h>
+
+#include "omap-alsa-sx1.h"
+
+/* Connector implementation */
+static struct cb_id cn_sx1snd_id = { CN_IDX_SX1SND, CN_VAL_SX1SND };
+static char cn_sx1snd_name[] = "cn_sx1snd";
+
+static void cn_sx1snd_callback(void *data)
+{
+ struct cn_msg *msg = (struct cn_msg *)data;
+
+ printk(KERN_INFO
+ "%s: %lu: idx=%x, val=%x, seq=%u, ack=%u, len=%d: %s.\n",
+ __func__, jiffies, msg->id.idx, msg->id.val,
+ msg->seq, msg->ack, msg->len, (char *)msg->data);
+}
+
+/* Send IPC message to sound server */
+int cn_sx1snd_send(unsigned int cmd, unsigned int arg1, unsigned int arg2)
+{
+ struct cn_msg *m;
+ unsigned short data[3];
+ int err;
+
+ m = kzalloc(sizeof(*m) + sizeof(data), gfp_any());
+ if (!m)
+ return -1;
+
+ memcpy(&m->id, &cn_sx1snd_id, sizeof(m->id));
+ m->seq = 1;
+ m->len = sizeof(data);
+
+ data[0] = (unsigned short)cmd;
+ data[1] = (unsigned short)arg1;
+ data[2] = (unsigned short)arg2;
+
+ memcpy(m + 1, data, m->len);
+
+ err = cn_netlink_send(m, CN_IDX_SX1SND, gfp_any());
+ snd_printd("sent= %02X %02X %02X, err=%d\n", cmd, arg1, arg2, err);
+ kfree(m);
+
+ if (err == -ESRCH)
+ return -1; /* there are no listeners on socket */
+ return 0;
+}
+
+/* Hardware capabilities
+ *
+ * DAC USB-mode sampling rates (MCLK = 12 MHz)
+ * The rates and rate_reg_into MUST be in the same order
+ */
+static unsigned int rates[] = {
+ 8000, 11025, 12000,
+ 16000, 22050, 24000,
+ 32000, 44100, 48000,
+};
+
+static struct snd_pcm_hw_constraint_list egold_hw_constraints_rates = {
+ .count = ARRAY_SIZE(rates),
+ .list = rates,
+ .mask = 0,
+};
+
+static struct snd_pcm_hardware egold_snd_omap_alsa_playback = {
+ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE),
+ .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
+ SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_KNOT),
+ .rate_min = 8000,
+ .rate_max = 48000,
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = 128 * 1024,
+ .period_bytes_min = 32,
+ .period_bytes_max = 8 * 1024,
+ .periods_min = 16,
+ .periods_max = 255,
+ .fifo_size = 0,
+};
+
+static struct snd_pcm_hardware egold_snd_omap_alsa_capture = {
+ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE),
+ .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
+ SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_KNOT),
+ .rate_min = 8000,
+ .rate_max = 48000,
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = 128 * 1024,
+ .period_bytes_min = 32,
+ .period_bytes_max = 8 * 1024,
+ .periods_min = 16,
+ .periods_max = 255,
+ .fifo_size = 0,
+};
+
+static long current_rate = -1; /* current rate in egold format 0..8 */
+/*
+ * ALSA operations according to board file
+ */
+
+/*
+ * Sample rate changing
+ */
+static void egold_set_samplerate(long sample_rate)
+{
+ int egold_rate = 0;
+ int clkgdv = 0;
+ u16 srgr1, srgr2;
+
+ /* Set the sample rate */
+#if 0
+ /* fw15: 5005E490 - divs are different !!! */
+ clkgdv = CODEC_CLOCK / (sample_rate * (DEFAULT_BITPERSAMPLE * 2 - 1));
+#endif
+ switch (sample_rate) {
+ case 8000:
+ clkgdv = 71;
+ egold_rate = FRQ_8000;
+ break;
+ case 11025:
+ clkgdv = 51;
+ egold_rate = FRQ_11025;
+ break;
+ case 12000:
+ clkgdv = 47;
+ egold_rate = FRQ_12000;
+ break;
+ case 16000:
+ clkgdv = 35;
+ egold_rate = FRQ_16000;
+ break;
+ case 22050:
+ clkgdv = 25;
+ egold_rate = FRQ_22050;
+ break;
+ case 24000:
+ clkgdv = 23;
+ egold_rate = FRQ_24000;
+ break;
+ case 32000:
+ clkgdv = 17;
+ egold_rate = FRQ_32000;
+ break;
+ case 44100:
+ clkgdv = 12;
+ egold_rate = FRQ_44100;
+ break;
+ case 48000:
+ clkgdv = 11;
+ egold_rate = FRQ_48000;
+ break;
+ }
+
+ srgr1 = (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
+ srgr2 = ((FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1)));
+
+ OMAP_MCBSP_WRITE(OMAP1510_MCBSP1_BASE, SRGR2, srgr2);
+ OMAP_MCBSP_WRITE(OMAP1510_MCBSP1_BASE, SRGR1, srgr1);
+ current_rate = egold_rate;
+ snd_printd("set samplerate=%ld\n", sample_rate);
+
+}
+
+static void egold_configure(void)
+{
+}
+
+/*
+ * Omap MCBSP clock and Power Management configuration
+ *
+ * Here we have some functions that allows clock to be enabled and
+ * disabled only when needed. Besides doing clock configuration
+ * it allows turn on/turn off audio when necessary.
+ */
+
+/*
+ * Do clock framework mclk search
+ */
+static void egold_clock_setup(void)
+{
+ omap_request_gpio(OSC_EN);
+ omap_set_gpio_direction(OSC_EN, 0); /* output */
+ snd_printd("\n");
+}
+
+/*
+ * Do some sanity check, set clock rate, starts it and turn codec audio on
+ */
+static int egold_clock_on(void)
+{
+ omap_set_gpio_dataout(OSC_EN, 1);
+ egold_set_samplerate(44100); /* TODO */
+ cn_sx1snd_send(DAC_SETAUDIODEVICE, SX1_DEVICE_SPEAKER, 0);
+ cn_sx1snd_send(DAC_OPEN_DEFAULT, current_rate , 4);
+ snd_printd("\n");
+ return 0;
+}
+
+/*
+ * Do some sanity check, turn clock off and then turn codec audio off
+ */
+static int egold_clock_off(void)
+{
+ cn_sx1snd_send(DAC_CLOSE, 0 , 0);
+ cn_sx1snd_send(DAC_SETAUDIODEVICE, SX1_DEVICE_PHONE, 0);
+ omap_set_gpio_dataout(OSC_EN, 0);
+ snd_printd("\n");
+ return 0;
+}
+
+static int egold_get_default_samplerate(void)
+{
+ snd_printd("\n");
+ return DEFAULT_SAMPLE_RATE;
+}
+
+static int __init snd_omap_alsa_egold_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct omap_alsa_codec_config *codec_cfg;
+
+ codec_cfg = pdev->dev.platform_data;
+ if (!codec_cfg)
+ return -ENODEV;
+
+ codec_cfg->hw_constraints_rates = &egold_hw_constraints_rates;
+ codec_cfg->snd_omap_alsa_playback = &egold_snd_omap_alsa_playback;
+ codec_cfg->snd_omap_alsa_capture = &egold_snd_omap_alsa_capture;
+ codec_cfg->codec_configure_dev = egold_configure;
+ codec_cfg->codec_set_samplerate = egold_set_samplerate;
+ codec_cfg->codec_clock_setup = egold_clock_setup;
+ codec_cfg->codec_clock_on = egold_clock_on;
+ codec_cfg->codec_clock_off = egold_clock_off;
+ codec_cfg->get_default_samplerate = egold_get_default_samplerate;
+ ret = snd_omap_alsa_post_probe(pdev, codec_cfg);
+
+ snd_printd("\n");
+ return ret;
+}
+
+static struct platform_driver omap_alsa_driver = {
+ .probe = snd_omap_alsa_egold_probe,
+ .remove = snd_omap_alsa_remove,
+ .suspend = snd_omap_alsa_suspend,
+ .resume = snd_omap_alsa_resume,
+ .driver = {
+ .name = "omap_alsa_mcbsp",
+ },
+};
+
+static int __init omap_alsa_egold_init(void)
+{
+ int retval;
+
+ retval = cn_add_callback(&cn_sx1snd_id, cn_sx1snd_name,
+ cn_sx1snd_callback);
+ if (retval)
+ printk(KERN_WARNING "cn_sx1snd failed to register\n");
+ return platform_driver_register(&omap_alsa_driver);
+}
+
+static void __exit omap_alsa_egold_exit(void)
+{
+ cn_del_callback(&cn_sx1snd_id);
+ platform_driver_unregister(&omap_alsa_driver);
+}
+
+module_init(omap_alsa_egold_init);
+module_exit(omap_alsa_egold_exit);
--- /dev/null
+/*
+ * Based on omap-alsa-tsc2101.h
+ *
+ * Alsa Driver for Siemens SX1.
+ * Copyright (C) 2006 Vladimir Ananiev (vovan888 at gmail com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef OMAP_ALSA_SX1_H_
+#define OMAP_ALSA_SX1_H_
+
+#include <linux/types.h>
+
+#define NUMBER_SAMPLE_RATES_SUPPORTED 9
+
+/*
+ * AUDIO related MACROS
+ */
+#ifndef DEFAULT_BITPERSAMPLE
+#define DEFAULT_BITPERSAMPLE 16
+#endif
+
+#define DEFAULT_SAMPLE_RATE 44100
+/* fw15: 18356000 */
+#define CODEC_CLOCK 18359000
+/* McBSP for playing music */
+#define AUDIO_MCBSP OMAP_MCBSP1
+/* McBSP for record/play audio from phone and mic */
+#define AUDIO_MCBSP_PCM OMAP_MCBSP2
+/* gpio pin for enable/disable clock */
+#define OSC_EN 2
+
+/* Send IPC message to sound server */
+extern int cn_sx1snd_send(unsigned int cmd, unsigned int arg1,
+ unsigned int arg2);
+/* cmd for IPC_GROUP_DAC */
+#define DAC_VOLUME_UPDATE 0
+#define DAC_SETAUDIODEVICE 1
+#define DAC_OPEN_RING 2
+#define DAC_OPEN_DEFAULT 3
+#define DAC_CLOSE 4
+#define DAC_FMRADIO_OPEN 5
+#define DAC_FMRADIO_CLOSE 6
+#define DAC_PLAYTONE 7
+/* cmd for IPC_GROUP_PCM */
+#define PCM_PLAY (0+8)
+#define PCM_RECORD (1+8)
+#define PCM_CLOSE (2+8)
+
+/* for DAC_SETAUDIODEVICE */
+#define SX1_DEVICE_SPEAKER 0
+#define SX1_DEVICE_HEADPHONE 4
+#define SX1_DEVICE_PHONE 3
+/* frequencies for MdaDacOpenDefaultL, MdaDacOpenRingL */
+#define FRQ_8000 0
+#define FRQ_11025 1
+#define FRQ_12000 2
+#define FRQ_16000 3
+#define FRQ_22050 4
+#define FRQ_24000 5
+#define FRQ_32000 6
+#define FRQ_44100 7
+#define FRQ_48000 8
+
+#endif
--- /dev/null
+/*
+ * sound/arm/omap/omap-alsa-tsc2101-mixer.c
+ *
+ * Alsa Driver for TSC2101 codec for OMAP platform boards.
+ *
+ * Copyright (C) 2005 Mika Laitio <lamikr@cc.jyu.fi> and
+ * Everett Coleman II <gcc80x86@fuzzyneural.net>
+ *
+ * Board initialization code is based on the code in TSC2101 OSS driver.
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ * Written by Nishanth Menon and Sriram Kannan
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * History:
+ *
+ * 2006-03-01 Mika Laitio - Mixer for the tsc2101 driver used in omap boards.
+ * Can switch between headset and loudspeaker playback,
+ * mute and unmute dgc, set dgc volume. Record source switch,
+ * keyclick, buzzer and headset volume and handset volume control
+ * are still missing.
+ *
+ */
+
+#include "omap-alsa-tsc2101.h"
+#include "omap-alsa-tsc2101-mixer.h"
+
+#include <linux/spi/tsc2101.h>
+#include <linux/types.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+
+#ifdef DEBUG
+#define M_DPRINTK(ARGS...) \
+ do { \
+ printk(KERN_INFO "<%s>: ", __func__); \
+ printk(ARGS); \
+ } while (0)
+#else
+#define M_DPRINTK(ARGS...) /* nop */
+#endif
+
+#define CHECK_BIT(INDX, ARG) (((ARG) & TSC2101_BIT(INDX)) >> INDX)
+#define IS_UNMUTED(INDX, ARG) (((CHECK_BIT(INDX, ARG)) == 0))
+
+#define DGC_DALVL_EXTRACT(ARG) ((ARG & 0x7f00) >> 8)
+#define DGC_DARVL_EXTRACT(ARG) ((ARG & 0x007f))
+
+#define HGC_ADPGA_HED_EXTRACT(ARG) ((ARG & 0x7f00) >> 8)
+#define HNGC_ADPGA_HND_EXTRACT(ARG) ((ARG & 0x7f00) >> 8)
+#define BGC_ADPGA_BGC_EXTRACT(ARG) ((ARG & 0x7f00) >> 8)
+
+static int current_playback_target = PLAYBACK_TARGET_LOUDSPEAKER;
+static int current_rec_src = REC_SRC_SINGLE_ENDED_MICIN_HED;
+
+/*
+ * Simplified write for the tsc2101 audio registers.
+ */
+inline void omap_tsc2101_audio_write(u8 address, u16 data)
+{
+ tsc2101_write_sync(mcbsp_dev.tsc2101_dev, PAGE2_AUDIO_CODEC_REGISTERS,
+ address, data);
+}
+
+/*
+ * Simplified read for the tsc2101 audio registers.
+ */
+inline u16 omap_tsc2101_audio_read(u8 address)
+{
+ return (tsc2101_read_sync(mcbsp_dev.tsc2101_dev,
+ PAGE2_AUDIO_CODEC_REGISTERS, address));
+}
+
+/*
+ * For selecting tsc2101 recourd source.
+ */
+static void set_record_source(int val)
+{
+ u16 data;
+
+ /*
+ * Mute Analog Sidetone
+ * Analog sidetone gain db?
+ * Input selected by MICSEL connected to ADC
+ */
+ data = MPC_ASTMU | MPC_ASTG(0x45);
+ data &= ~MPC_MICSEL(7); /* clear all MICSEL bits */
+ data |= MPC_MICSEL(val);
+ data |= MPC_MICADC;
+ omap_tsc2101_audio_write(TSC2101_MIXER_PGA_CTRL, data);
+
+ current_rec_src = val;
+}
+
+/*
+ * Converts the Alsa mixer volume (0 - 100) to real
+ * Digital Gain Control (DGC) value that can be written
+ * or read from the TSC2101 registry.
+ *
+ * Note that the number "OUTPUT_VOLUME_MAX" is smaller than OUTPUT_VOLUME_MIN
+ * because DGC works as a volume decreaser. (The more bigger value is put
+ * to DGC, the more the volume of controlled channel is decreased)
+ *
+ * In addition the TCS2101 chip would allow the maximum
+ * volume reduction be 63.5 DB
+ * but according to some tests user can not hear anything with this chip
+ * when the volume is set to be less than 25 db.
+ * Therefore this function will return a value
+ * that means 38.5 db (63.5 db - 25 db)
+ * reduction in the channel volume, when mixer is set to 0.
+ * For mixer value 100, this will return a value that means
+ * 0 db volume reduction.
+ * ([mute_left_bit]0000000[mute_right_bit]0000000)
+ */
+int get_mixer_volume_as_dac_gain_control_volume(int vol)
+{
+ u16 retVal;
+
+ /* Convert 0 -> 100 volume to 0x7F(min) -> y(max) volume range */
+ retVal = ((vol * OUTPUT_VOLUME_RANGE) / 100) + OUTPUT_VOLUME_MAX;
+ /* invert the value for getting the proper range 0 min and 100 max */
+ retVal = OUTPUT_VOLUME_MIN - retVal;
+
+ return retVal;
+}
+
+/*
+ * Converts the Alsa mixer volume (0 - 100) to TSC2101
+ * Digital Gain Control (DGC) volume. Alsa mixer volume 0
+ * is converted to value meaning the volume reduction of -38.5 db
+ * and Alsa mixer volume 100 is converted to value meaning the
+ * reduction of 0 db.
+ */
+int set_mixer_volume_as_dac_gain_control_volume(int mixerVolL, int mixerVolR)
+{
+ u16 val;
+ int retVal;
+ int volL;
+ int volR;
+
+ if ((mixerVolL < 0) ||
+ (mixerVolL > 100) ||
+ (mixerVolR < 0) ||
+ (mixerVolR > 100)) {
+ printk(KERN_ERR "Trying a bad mixer volume as dac gain control"
+ " volume value, left (%d), right (%d)!\n", mixerVolL,
+ mixerVolR);
+ return -EPERM;
+ }
+ M_DPRINTK("mixer volume left = %d, right = %d\n", mixerVolL, mixerVolR);
+ volL = get_mixer_volume_as_dac_gain_control_volume(mixerVolL);
+ volR = get_mixer_volume_as_dac_gain_control_volume(mixerVolR);
+
+ val = omap_tsc2101_audio_read(TSC2101_DAC_GAIN_CTRL);
+ /* keep the old mute bit settings */
+ val &= ~(DGC_DALVL(OUTPUT_VOLUME_MIN) |
+ DGC_DARVL(OUTPUT_VOLUME_MIN));
+ val |= DGC_DALVL(volL) | DGC_DARVL(volR);
+ retVal = 2;
+ if (retVal)
+ omap_tsc2101_audio_write(TSC2101_DAC_GAIN_CTRL, val);
+
+ M_DPRINTK("to registry: left = %d, right = %d, total = %d\n",
+ DGC_DALVL_EXTRACT(val), DGC_DARVL_EXTRACT(val), val);
+ return retVal;
+}
+
+/*
+ * If unmuteLeft/unmuteRight == 0 --> mute
+ * If unmuteLeft/unmuteRight == 1 --> unmute
+ */
+int dac_gain_control_unmute(int unmuteLeft, int unmuteRight)
+{
+ u16 val;
+ int count;
+
+ count = 0;
+ val = omap_tsc2101_audio_read(TSC2101_DAC_GAIN_CTRL);
+ /*
+ * in alsa mixer 1 --> on, 0 == off. In tsc2101 registry 1 --> off,
+ * 0 --> on so if values are same, it's time to change the registry
+ * value.
+ */
+ if (unmuteLeft != IS_UNMUTED(15, val)) {
+ if (unmuteLeft == 0) {
+ /* mute --> turn bit on */
+ val = val | DGC_DALMU;
+ } else {
+ /* unmute --> turn bit off */
+ val = val & ~DGC_DALMU;
+ }
+ count++;
+ } /* L */
+ if (unmuteRight != IS_UNMUTED(7, val)) {
+ if (unmuteRight == 0) {
+ /* mute --> turn bit on */
+ val = val | DGC_DARMU;
+ } else {
+ /* unmute --> turn bit off */
+ val = val & ~DGC_DARMU;
+ }
+ count++;
+ } /* R */
+ if (count) {
+ omap_tsc2101_audio_write(TSC2101_DAC_GAIN_CTRL, val);
+ M_DPRINTK("changed value, is_unmuted left = %d, right = %d\n",
+ IS_UNMUTED(15, val),
+ IS_UNMUTED(7, val));
+ }
+ return count;
+}
+
+/*
+ * unmute: 0 --> mute, 1 --> unmute
+ * page2RegIndx: Registry index in tsc2101 page2.
+ * muteBitIndx: Index number for the bit in registry that indicates whether
+ * muted or unmuted.
+ */
+int adc_pga_unmute_control(int unmute, int page2regIndx, int muteBitIndx)
+{
+ int count;
+ u16 val;
+
+ count = 0;
+ val = omap_tsc2101_audio_read(page2regIndx);
+ /*
+ * in alsa mixer 1 --> on, 0 == off. In tsc2101 registry 1 --> off,
+ * 0 --> on so if the values are same, it's time to change the
+ * registry value...
+ */
+ if (unmute != IS_UNMUTED(muteBitIndx, val)) {
+ if (unmute == 0) {
+ /* mute --> turn bit on */
+ val = val | TSC2101_BIT(muteBitIndx);
+ } else {
+ /* unmute --> turn bit off */
+ val = val & ~TSC2101_BIT(muteBitIndx);
+ }
+ M_DPRINTK("changed value, is_unmuted = %d\n",
+ IS_UNMUTED(muteBitIndx, val));
+ count++;
+ }
+ if (count)
+ omap_tsc2101_audio_write(page2regIndx, val);
+
+ return count;
+}
+
+/*
+ * Converts the DGC registry value read from the TSC2101 registry to
+ * Alsa mixer volume format (0 - 100).
+ */
+int get_dac_gain_control_volume_as_mixer_volume(u16 vol)
+{
+ u16 retVal;
+
+ retVal = OUTPUT_VOLUME_MIN - vol;
+ retVal = ((retVal - OUTPUT_VOLUME_MAX) * 100) / OUTPUT_VOLUME_RANGE;
+ /* fix scaling error */
+ if ((retVal > 0) && (retVal < 100))
+ retVal++;
+
+ return retVal;
+}
+
+/*
+ * Converts the headset gain control volume (0 - 63.5 db)
+ * to Alsa mixer volume (0 - 100)
+ */
+int get_headset_gain_control_volume_as_mixer_volume(u16 registerVal)
+{
+ u16 retVal;
+
+ retVal = ((registerVal * 100) / INPUT_VOLUME_RANGE);
+ return retVal;
+}
+
+/*
+ * Converts the handset gain control volume (0 - 63.5 db)
+ * to Alsa mixer volume (0 - 100)
+ */
+int get_handset_gain_control_volume_as_mixer_volume(u16 registerVal)
+{
+ return get_headset_gain_control_volume_as_mixer_volume(registerVal);
+}
+
+/*
+ * Converts the Alsa mixer volume (0 - 100) to
+ * headset gain control volume (0 - 63.5 db)
+ */
+int get_mixer_volume_as_headset_gain_control_volume(u16 mixerVal)
+{
+ u16 retVal;
+
+ retVal = ((mixerVal * INPUT_VOLUME_RANGE) / 100) + INPUT_VOLUME_MIN;
+ return retVal;
+}
+
+/*
+ * Writes Alsa mixer volume (0 - 100) to TSC2101 headset volume registry in
+ * a TSC2101 format. (0 - 63.5 db)
+ * In TSC2101 OSS driver this functionality was controlled with "SET_LINE"
+ * parameter.
+ */
+int set_mixer_volume_as_headset_gain_control_volume(int mixerVol)
+{
+ int volume;
+ int retVal;
+ u16 val;
+
+ if (mixerVol < 0 || mixerVol > 100) {
+ M_DPRINTK("Trying a bad headset mixer volume value(%d)!\n",
+ mixerVol);
+ return -EPERM;
+ }
+ M_DPRINTK("mixer volume = %d\n", mixerVol);
+ /*
+ * Convert 0 -> 100 volume to 0x0(min) -> 0x7D(max) volume range
+ * NOTE: 0 is minimum volume and not mute
+ */
+ volume = get_mixer_volume_as_headset_gain_control_volume(mixerVol);
+ val = omap_tsc2101_audio_read(TSC2101_HEADSET_GAIN_CTRL);
+ /* preserve the old mute settings */
+ val &= ~(HGC_ADPGA_HED(INPUT_VOLUME_MAX));
+ val |= HGC_ADPGA_HED(volume);
+ omap_tsc2101_audio_write(TSC2101_HEADSET_GAIN_CTRL, val);
+ retVal = 1;
+
+ M_DPRINTK("to registry = %d\n", val);
+ return retVal;
+}
+
+/*
+ * Writes Alsa mixer volume (0 - 100) to TSC2101 handset volume registry in
+ * a TSC2101 format. (0 - 63.5 db)
+ * In TSC2101 OSS driver this functionality was controlled with
+ * "SET_MIC" parameter.
+ */
+int set_mixer_volume_as_handset_gain_control_volume(int mixerVol)
+{
+ int volume;
+ int retVal;
+ u16 val;
+
+ if (mixerVol < 0 || mixerVol > 100) {
+ M_DPRINTK("Trying a bad mic mixer volume value(%d)!\n",
+ mixerVol);
+ return -EPERM;
+ }
+ M_DPRINTK("mixer volume = %d\n", mixerVol);
+ /*
+ * Convert 0 -> 100 volume to 0x0(min) -> 0x7D(max) volume range
+ * NOTE: 0 is minimum volume and not mute
+ */
+ volume = get_mixer_volume_as_headset_gain_control_volume(mixerVol);
+ val = omap_tsc2101_audio_read(TSC2101_HANDSET_GAIN_CTRL);
+ /* preserve the old mute settigns */
+ val &= ~(HNGC_ADPGA_HND(INPUT_VOLUME_MAX));
+ val |= HNGC_ADPGA_HND(volume);
+ omap_tsc2101_audio_write(TSC2101_HANDSET_GAIN_CTRL, val);
+ retVal = 1;
+
+ M_DPRINTK("to registry = %d\n", val);
+ return retVal;
+}
+
+void set_loudspeaker_to_playback_target(void)
+{
+ /* power down SPK1, SPK2 and loudspeaker */
+ omap_tsc2101_audio_write(TSC2101_CODEC_POWER_CTRL,
+ CPC_SP1PWDN | CPC_SP2PWDN | CPC_LDAPWDF);
+ /*
+ * ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled
+ * 1dB AGC hysteresis
+ * MICes bias 2V
+ */
+ omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_4, AC4_MB_HED(0));
+
+ /*
+ * DAC left and right routed to SPK1/SPK2
+ * SPK1/SPK2 unmuted
+ * Keyclicks routed to SPK1/SPK2 */
+ omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_5,
+ AC5_DIFFIN |
+ AC5_DAC2SPK1(3) | AC5_AST2SPK1 | AC5_KCL2SPK1 |
+ AC5_DAC2SPK2(3) | AC5_AST2SPK2 | AC5_KCL2SPK2);
+
+ /*
+ * routing selected to SPK1 goes also to OUT8P/OUT8N. (loudspeaker)
+ * analog sidetone routed to loudspeaker
+ * buzzer pga routed to loudspeaker
+ * keyclick routing to loudspeaker
+ * cellphone input routed to loudspeaker
+ * mic selection (control register 04h/page2) routed to cell phone
+ * output (CP_OUT)
+ * routing selected for SPK1 goes also to cellphone output (CP_OUT)
+ * OUT8P/OUT8N (loudspeakers) unmuted (0 = unmuted)
+ * Cellphone output is not muted (0 = unmuted)
+ * Enable loudspeaker short protection control (0 = enable protection)
+ * VGND short protection control (0 = enable protection)
+ */
+ omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_6,
+ AC6_SPL2LSK | AC6_AST2LSK | AC6_BUZ2LSK | AC6_KCL2LSK |
+ AC6_CPI2LSK | AC6_MIC2CPO | AC6_SPL2CPO);
+ current_playback_target = PLAYBACK_TARGET_LOUDSPEAKER;
+}
+
+void set_headphone_to_playback_target(void)
+{
+ /* power down SPK1, SPK2 and loudspeaker */
+ omap_tsc2101_audio_write(TSC2101_CODEC_POWER_CTRL,
+ CPC_SP1PWDN | CPC_SP2PWDN | CPC_LDAPWDF);
+ /*
+ * ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled
+ Â * 1dB AGC hysteresis
+ * MICes bias 2V
+ */
+ omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_4, AC4_MB_HED(0));
+
+ /*
+ * DAC left and right routed to SPK1/SPK2
+ * SPK1/SPK2 unmuted
+ * Keyclicks routed to SPK1/SPK2
+ */
+ omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_5,
+ AC5_DAC2SPK1(3) | AC5_AST2SPK1 | AC5_KCL2SPK1 |
+ AC5_DAC2SPK2(3) | AC5_AST2SPK2 | AC5_KCL2SPK2 |
+ AC5_HDSCPTC);
+
+ /* OUT8P/OUT8N muted, CPOUT muted */
+ omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_6,
+ AC6_MUTLSPK | AC6_MUTSPK2 | AC6_LDSCPTC |
+ AC6_VGNDSCPTC);
+ current_playback_target = PLAYBACK_TARGET_HEADPHONE;
+}
+
+void set_telephone_to_playback_target(void)
+{
+ /*
+ * 0110 1101 0101 1100
+ * power down MICBIAS_HED, Analog sidetone, SPK2, DAC,
+ * Driver virtual ground, loudspeaker. Values D2-d5 are flags.
+ */
+ omap_tsc2101_audio_write(TSC2101_CODEC_POWER_CTRL,
+ CPC_MBIAS_HED | CPC_ASTPWD | CPC_SP2PWDN | CPC_DAPWDN |
+ CPC_VGPWDN | CPC_LSPWDN);
+
+ /*
+ * 0010 1010 0100 0000
+ * ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled
+ * 1dB AGC hysteresis
+ * MICes bias 2V
+ */
+ omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_4,
+ AC4_MB_HND | AC4_MB_HED(0) | AC4_AGCHYS(1) |
+ AC4_BISTPD | AC4_ASSTPD | AC4_DASTPD);
+ printk(KERN_INFO "set_telephone_to_playback_target(), "
+ "TSC2101_AUDIO_CTRL_4 = %d\n",
+ omap_tsc2101_audio_read(TSC2101_AUDIO_CTRL_4));
+
+ /*
+ * 1110 0010 0000 0010
+ * DAC left and right routed to SPK1/SPK2
+ * SPK1/SPK2 unmuted
+ * keyclicks routed to SPK1/SPK2
+ */
+ omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_5,
+ AC5_DIFFIN | AC5_DAC2SPK1(3) |
+ AC5_CPI2SPK1 | AC5_MUTSPK2);
+
+ omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_6,
+ AC6_MIC2CPO | AC6_MUTLSPK |
+ AC6_LDSCPTC | AC6_VGNDSCPTC | AC6_CAPINTF);
+ current_playback_target = PLAYBACK_TARGET_CELLPHONE;
+}
+
+/*
+ * 1100 0101 1101 0000
+ *
+ * #define MPC_ASTMU TSC2101_BIT(15)
+ * #define MPC_ASTG(ARG) (((ARG) & 0x7F) << 8)
+ * #define MPC_MICSEL(ARG) (((ARG) & 0x07) << 5)
+ * #define MPC_MICADC TSC2101_BIT(4)
+ * #define MPC_CPADC TSC2101_BIT(3)
+ * #define MPC_ASTGF (0x01)
+ */
+static void set_telephone_to_record_source(void)
+{
+ u16 val;
+
+ /*
+ * D0 = 0:
+ * --> AGC is off for handset input.
+ * --> ADC PGA is controlled by the ADMUT_HDN + ADPGA_HND
+ * (D15, D14-D8)
+ * D4 - D1 = 0000
+ * --> AGC time constant for handset input,
+ * attack time = 8 mc, decay time = 100 ms
+ * D7 - D5 = 000
+ * --> AGC Target gain for handset input = -5.5 db
+ * D14 - D8 = 011 1100
+ * --> ADC handset PGA settings = 60 = 30 db
+ * D15 = 0
+ * --> Handset input ON (unmuted)
+ */
+ val = 0x3c00; /* 0011 1100 0000 0000 = 60 = 30 */
+ omap_tsc2101_audio_write(TSC2101_HANDSET_GAIN_CTRL, val);
+
+ /*
+ * D0 = 0
+ * --> AGC is off for headset/Aux input
+ * --> ADC headset/Aux PGA is contoller by
+ * ADMUT_HED + ADPGA_HED
+ * (D15, D14-D8)
+ * D4 - D1 = 0000
+ * --> Agc constant for headset/Aux input,
+ * attack time = 8 mc, decay time = 100 ms
+ * D7 - D5 = 000
+ * --> AGC target gain for headset input = -5.5 db
+ * D14 - D8 = 000 0000
+ * --> Adc headset/AUX pga settings = 0 db
+ * D15 = 1
+ * --> Headset/AUX input muted
+ *
+ * Mute headset aux input
+ */
+ val = 0x8000; /* 1000 0000 0000 0000 */
+ omap_tsc2101_audio_write(TSC2101_HEADSET_GAIN_CTRL, val);
+ set_record_source(REC_SRC_MICIN_HND_AND_AUX1);
+
+ /*
+ * hacks start
+ * D0 = flag, Headset/Aux or handset PGA flag
+ * --> & with 1 (= 1 -->gain applied == pga
+ * register settings)
+ * D1 = 0, DAC channel PGA soft stepping control
+ * --> 0.5 db change every WCLK
+ * D2 = flag, DAC right channel PGA flag
+ * --> & with 1
+ * D3 = flag, DAC left channel PGA flag
+ * -- > & with 1
+ * D7 - D4 = 0001, keyclick length
+ * --> 4 periods key clicks
+ * D10 - D8 = 100, keyclick frequency
+ * --> 1 kHz,
+ * D11 = 0, Headset/Aux or handset soft stepping control
+ * --> 0,5 db change every WCLK or ADWS
+ * D14 -D12 = 100, Keyclick applitude control
+ * --> Medium amplitude
+ * D15 = 0, keyclick disabled
+ */
+ val = omap_tsc2101_audio_read(TSC2101_AUDIO_CTRL_2);
+ val = val & 0x441d;
+ val = val | 0x4410; /* D14, D10, D4 bits == 1 */
+ omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_2, val);
+
+ /*
+ * D0 = 0 (reserved, write always 0)
+ * D1 = flag,
+ * --> & with 1
+ * D2 - D5 = 0000 (reserved, write always 0000)
+ * D6 = 1
+ * --> MICBIAS_HND = 2.0 v
+ * D8 - D7 = 00
+ * --> MICBIAS_HED = 3.3 v
+ * D10 - D9 = 01,
+ * --> Mic AGC hysteric selection = 2 db
+ * D11 = 1,
+ * --> Disable buzzer PGA soft stepping
+ * D12 = 0,
+ * --> Enable CELL phone PGA soft stepping control
+ * D13 = 1
+ * --> Disable analog sidetone soft
+ * stepping control
+ * D14 = 0
+ * --> Enable DAC PGA soft stepping control
+ * D15 = 0,
+ * --> Enable headset/Aux or Handset soft
+ * stepping control
+ */
+ val = omap_tsc2101_audio_read(TSC2101_AUDIO_CTRL_4);
+ val = val & 0x2a42; /* 0010 1010 0100 0010 */
+ val = val | 0x2a40; /* bits D13, D11, D9, D6 == 1 */
+ omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_4, val);
+ printk(KERN_INFO "set_telephone_to_record_source(), "
+ "TSC2101_AUDIO_CTRL_4 = %d\n",
+ omap_tsc2101_audio_read(TSC2101_AUDIO_CTRL_4));
+ /*
+ * D0 = 0
+ * --> reserved, write always = 0
+ * D1 = flag, read only
+ * --> & with 1
+ * D5 - D2 = 1111, Buzzer input PGA settings
+ * --> 0 db
+ * D6 = 1,
+ * --> power down buzzer input pga
+ * D7 = flag, read only
+ * --> & with 1
+ * D14 - D8 = 101 1101
+ * --> 12 DB
+ * D15 = 0
+ * --> power up cell phone input PGA
+ */
+ val = omap_tsc2101_audio_read(TSC2101_BUZZER_GAIN_CTRL);
+ val = val & 0x5dfe;
+ /* bits, D14, D12, D11, D10, D8, D6, D5,D4,D3,D2 */
+ val = val | 0x5dfe;
+ omap_tsc2101_audio_write(TSC2101_BUZZER_GAIN_CTRL, val);
+
+ /*
+ * D6 - D0 = 000 1001
+ * --> -4.5 db for DAC right channel volume control
+ * D7 = 1
+ * --> DAC right channel muted
+ * D14 - D8 = 000 1001
+ * --> -4.5 db for DAC left channel volume control
+ * D15 = 1
+ * --> DAC left channel muted
+ */
+ /* val = omap_tsc2101_audio_read(TSC2101_DAC_GAIN_CTRL); */
+ val = 0x8989;
+ omap_tsc2101_audio_write(TSC2101_DAC_GAIN_CTRL, val);
+
+ /*
+ * 0000 0000 0100 0000
+ *
+ * D1 - D0 = 0
+ * --> GPIO 1 pin output is three stated
+ * D2 = 0
+ * --> Disaple GPIO2 for CLKOUT mode
+ * D3 = 0
+ * --> Disable GPUI1 for interrupt detection
+ * D4 = 0
+ * --> Disable GPIO2 for headset detection interrupt
+ * D5 = reserved, always 0
+ * D7 - D6 = 01
+ * --> 8 ms clitch detection
+ * D8 = reserved, write only 0
+ * D10 -D9 = 00
+ * --> 16 ms de-bouncing
+ * for glitch detection during headset detection
+ * D11 = flag for button press
+ * D12 = flag for headset detection
+ * D14-D13 = 00
+ * --> type of headset detected = 00 == no stereo
+ * headset deected
+ * D15 = 0
+ * --> Disable headset detection
+ */
+ val = 0x40;
+ omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_7, val);
+}
+
+/*
+ * Checks whether the headset is detected.
+ * If headset is detected, the type is returned. Type can be
+ * 0x01 = stereo headset detected
+ * 0x02 = cellurar headset detected
+ * 0x03 = stereo + cellurar headset detected
+ * If headset is not detected 0 is returned.
+ */
+u16 get_headset_detected(void)
+{
+ u16 curDetected;
+ u16 curType;
+ u16 curVal;
+
+ curType = 0; /* not detected */
+ curVal = omap_tsc2101_audio_read(TSC2101_AUDIO_CTRL_7);
+ curDetected = curVal & AC7_HDDETFL;
+ if (curDetected) {
+ printk(KERN_INFO "headset detected, checking type from %d \n",
+ curVal);
+ curType = ((curVal & 0x6000) >> 13);
+ printk(KERN_INFO "headset type detected = %d \n", curType);
+ } else {
+ printk(KERN_INFO "headset not detected\n");
+ }
+ return curType;
+}
+
+void init_playback_targets(void)
+{
+ u16 val;
+
+ set_loudspeaker_to_playback_target();
+ /*
+ * Left line input volume control
+ * = SET_LINE in the OSS driver
+ */
+ set_mixer_volume_as_headset_gain_control_volume(DEFAULT_INPUT_VOLUME);
+
+ /*
+ * Set headset to be controllable by handset mixer
+ * AGC enable for handset input
+ * Handset input not muted
+ */
+ val = omap_tsc2101_audio_read(TSC2101_HANDSET_GAIN_CTRL);
+ val = val | HNGC_AGCEN_HND;
+ val = val & ~HNGC_ADMUT_HND;
+ omap_tsc2101_audio_write(TSC2101_HANDSET_GAIN_CTRL, val);
+
+ /*
+ * mic input volume control
+ * SET_MIC in the OSS driver
+ */
+ set_mixer_volume_as_handset_gain_control_volume(DEFAULT_INPUT_VOLUME);
+
+ /*
+ * Left/Right headphone channel volume control
+ * Zero-cross detect on
+ */
+ set_mixer_volume_as_dac_gain_control_volume(DEFAULT_OUTPUT_VOLUME,
+ DEFAULT_OUTPUT_VOLUME);
+ /* unmute */
+ dac_gain_control_unmute(1, 1);
+}
+
+/*
+ * Initializes tsc2101 recourd source (to line) and playback target
+ * (to loudspeaker)
+ */
+void snd_omap_init_mixer(void)
+{
+ FN_IN;
+
+ /* Headset/Hook switch detect enabled */
+ omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_7, AC7_DETECT);
+
+ /* Select headset to record source (MIC_INHED)*/
+ set_record_source(REC_SRC_SINGLE_ENDED_MICIN_HED);
+ /* Init loudspeaker as a default playback target*/
+ init_playback_targets();
+
+ FN_OUT(0);
+}
+
+static int __pcm_playback_target_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ static char *texts[PLAYBACK_TARGET_COUNT] = {
+ "Loudspeaker", "Headphone", "Cellphone"
+ };
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = PLAYBACK_TARGET_COUNT;
+ if (uinfo->value.enumerated.item > PLAYBACK_TARGET_COUNT - 1)
+ uinfo->value.enumerated.item = PLAYBACK_TARGET_COUNT - 1;
+
+ strcpy(uinfo->value.enumerated.name,
+ texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+static int __pcm_playback_target_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = current_playback_target;
+ return 0;
+}
+
+static int __pcm_playback_target_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int retVal;
+ int curVal;
+
+ retVal = 0;
+ curVal = ucontrol->value.integer.value[0];
+ if ((curVal >= 0) &&
+ (curVal < PLAYBACK_TARGET_COUNT) &&
+ (curVal != current_playback_target)) {
+ if (curVal == PLAYBACK_TARGET_LOUDSPEAKER) {
+ set_record_source(REC_SRC_SINGLE_ENDED_MICIN_HED);
+ set_loudspeaker_to_playback_target();
+ } else if (curVal == PLAYBACK_TARGET_HEADPHONE) {
+ set_record_source(REC_SRC_SINGLE_ENDED_MICIN_HND);
+ set_headphone_to_playback_target();
+ } else if (curVal == PLAYBACK_TARGET_CELLPHONE) {
+ set_telephone_to_record_source();
+ set_telephone_to_playback_target();
+ }
+ retVal = 1;
+ }
+ return retVal;
+}
+
+static int __pcm_playback_volume_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 2;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 100;
+ return 0;
+}
+
+/*
+ * Alsa mixer interface function for getting the volume read from the DGC in a
+ * 0 -100 alsa mixer format.
+ */
+static int __pcm_playback_volume_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u16 volL;
+ u16 volR;
+ u16 val;
+
+ val = omap_tsc2101_audio_read(TSC2101_DAC_GAIN_CTRL);
+ M_DPRINTK("registry value = %d!\n", val);
+ volL = DGC_DALVL_EXTRACT(val);
+ volR = DGC_DARVL_EXTRACT(val);
+ /* make sure that other bits are not on */
+ volL = volL & ~DGC_DALMU;
+ volR = volR & ~DGC_DARMU;
+
+ volL = get_dac_gain_control_volume_as_mixer_volume(volL);
+ volR = get_dac_gain_control_volume_as_mixer_volume(volR);
+
+ ucontrol->value.integer.value[0] = volL; /* L */
+ ucontrol->value.integer.value[1] = volR; /* R */
+
+ M_DPRINTK("mixer volume left = %ld, right = %ld\n",
+ ucontrol->value.integer.value[0],
+ ucontrol->value.integer.value[1]);
+ return 0;
+}
+
+static int __pcm_playback_volume_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return set_mixer_volume_as_dac_gain_control_volume(
+ ucontrol->value.integer.value[0],
+ ucontrol->value.integer.value[1]);
+}
+
+static int __pcm_playback_switch_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 2;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+/*
+ * When DGC_DALMU (bit 15) is 1, the left channel is muted.
+ * When DGC_DALMU is 0, left channel is not muted.
+ * Same logic apply also for the right channel.
+ */
+static int __pcm_playback_switch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u16 val = omap_tsc2101_audio_read(TSC2101_DAC_GAIN_CTRL);
+
+ ucontrol->value.integer.value[0] = IS_UNMUTED(15, val); /* left */
+ ucontrol->value.integer.value[1] = IS_UNMUTED(7, val); /* right */
+ return 0;
+}
+
+static int __pcm_playback_switch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return dac_gain_control_unmute(ucontrol->value.integer.value[0],
+ ucontrol->value.integer.value[1]);
+}
+
+static int __headset_playback_volume_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 100;
+ return 0;
+}
+
+static int __headset_playback_volume_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u16 val;
+ u16 vol;
+
+ val = omap_tsc2101_audio_read(TSC2101_HEADSET_GAIN_CTRL);
+ M_DPRINTK("registry value = %d\n", val);
+ vol = HGC_ADPGA_HED_EXTRACT(val);
+ vol = vol & ~HGC_ADMUT_HED;
+
+ vol = get_headset_gain_control_volume_as_mixer_volume(vol);
+ ucontrol->value.integer.value[0] = vol;
+
+ M_DPRINTK("mixer volume returned = %ld\n",
+ ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int __headset_playback_volume_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return set_mixer_volume_as_headset_gain_control_volume(
+ ucontrol->value.integer.value[0]);
+}
+
+static int __headset_playback_switch_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+/*
+ * When HGC_ADMUT_HED (bit 15) is 1, the headset is muted.
+ * When HGC_ADMUT_HED is 0, headset is not muted.
+ */
+static int __headset_playback_switch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u16 val = omap_tsc2101_audio_read(TSC2101_HEADSET_GAIN_CTRL);
+ ucontrol->value.integer.value[0] = IS_UNMUTED(15, val);
+ return 0;
+}
+
+static int __headset_playback_switch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ /* mute/unmute headset */
+ return adc_pga_unmute_control(ucontrol->value.integer.value[0],
+ TSC2101_HEADSET_GAIN_CTRL,
+ 15);
+}
+
+static int __handset_playback_volume_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 100;
+ return 0;
+}
+
+static int __handset_playback_volume_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u16 val;
+ u16 vol;
+
+ val = omap_tsc2101_audio_read(TSC2101_HANDSET_GAIN_CTRL);
+ M_DPRINTK("registry value = %d\n", val);
+ vol = HNGC_ADPGA_HND_EXTRACT(val);
+ vol = vol & ~HNGC_ADMUT_HND;
+ vol = get_handset_gain_control_volume_as_mixer_volume(vol);
+ ucontrol->value.integer.value[0] = vol;
+
+ M_DPRINTK("mixer volume returned = %ld\n",
+ ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int __handset_playback_volume_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return set_mixer_volume_as_handset_gain_control_volume(
+ ucontrol->value.integer.value[0]);
+}
+
+static int __handset_playback_switch_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+/*
+ * When HNGC_ADMUT_HND (bit 15) is 1, the handset is muted.
+ * When HNGC_ADMUT_HND is 0, handset is not muted.
+ */
+static int __handset_playback_switch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u16 val = omap_tsc2101_audio_read(TSC2101_HANDSET_GAIN_CTRL);
+ ucontrol->value.integer.value[0] = IS_UNMUTED(15, val);
+ return 0;
+}
+
+static int __handset_playback_switch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ /* handset mute/unmute */
+ return adc_pga_unmute_control(ucontrol->value.integer.value[0],
+ TSC2101_HANDSET_GAIN_CTRL,
+ 15);
+}
+
+static int __cellphone_input_switch_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+/*
+ * When BGC_MUT_CP (bit 15) = 1, power down cellphone input pga.
+ * When BGC_MUT_CP = 0, power up cellphone input pga.
+ */
+static int __cellphone_input_switch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u16 val = omap_tsc2101_audio_read(TSC2101_BUZZER_GAIN_CTRL);
+ ucontrol->value.integer.value[0] = IS_UNMUTED(15, val);
+ return 0;
+}
+
+static int __cellphone_input_switch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return adc_pga_unmute_control(ucontrol->value.integer.value[0],
+ TSC2101_BUZZER_GAIN_CTRL,
+ 15);
+}
+
+static int __buzzer_input_switch_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+/*
+ * When BGC_MUT_BU (bit 6) = 1, power down cellphone input pga.
+ * When BGC_MUT_BU = 0, power up cellphone input pga.
+ */
+static int __buzzer_input_switch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u16 val = omap_tsc2101_audio_read(TSC2101_BUZZER_GAIN_CTRL);
+ ucontrol->value.integer.value[0] = IS_UNMUTED(6, val);
+ return 0;
+}
+
+static int __buzzer_input_switch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return adc_pga_unmute_control(ucontrol->value.integer.value[0],
+ TSC2101_BUZZER_GAIN_CTRL,
+ 6);
+}
+
+static struct snd_kcontrol_new tsc2101_control[] __devinitdata = {
+ {
+ .name = "Target Playback Route",
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = __pcm_playback_target_info,
+ .get = __pcm_playback_target_get,
+ .put = __pcm_playback_target_put,
+ }, {
+ .name = "Master Playback Volume",
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = __pcm_playback_volume_info,
+ .get = __pcm_playback_volume_get,
+ .put = __pcm_playback_volume_put,
+ }, {
+ .name = "Master Playback Switch",
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = __pcm_playback_switch_info,
+ .get = __pcm_playback_switch_get,
+ .put = __pcm_playback_switch_put,
+ }, {
+ .name = "Headset Playback Volume",
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = __headset_playback_volume_info,
+ .get = __headset_playback_volume_get,
+ .put = __headset_playback_volume_put,
+ }, {
+ .name = "Headset Playback Switch",
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = __headset_playback_switch_info,
+ .get = __headset_playback_switch_get,
+ .put = __headset_playback_switch_put,
+ }, {
+ .name = "Handset Playback Volume",
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = __handset_playback_volume_info,
+ .get = __handset_playback_volume_get,
+ .put = __handset_playback_volume_put,
+ }, {
+ .name = "Handset Playback Switch",
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = __handset_playback_switch_info,
+ .get = __handset_playback_switch_get,
+ .put = __handset_playback_switch_put,
+ }, {
+ .name = "Cellphone Input Switch",
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = __cellphone_input_switch_info,
+ .get = __cellphone_input_switch_get,
+ .put = __cellphone_input_switch_put,
+ }, {
+ .name = "Buzzer Input Switch",
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = __buzzer_input_switch_info,
+ .get = __buzzer_input_switch_get,
+ .put = __buzzer_input_switch_put,
+ }
+};
+
+#ifdef CONFIG_PM
+
+void snd_omap_suspend_mixer(void)
+{
+}
+
+void snd_omap_resume_mixer(void)
+{
+ snd_omap_init_mixer();
+}
+#endif
+
+int snd_omap_mixer(struct snd_card_omap_codec *tsc2101)
+{
+ int i = 0;
+ int err = 0;
+
+ if (!tsc2101)
+ return -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(tsc2101_control); i++) {
+ err = snd_ctl_add(tsc2101->card,
+ snd_ctl_new1(&tsc2101_control[i],
+ tsc2101->card));
+ if (err < 0)
+ return err;
+ }
+ return 0;
+}
--- /dev/null
+/*
+ * sound/arm/omap/omap-alsa-tsc2101-mixer.h
+ *
+ * Alsa Driver for TSC2101 codec for OMAP platform boards.
+ *
+ * Copyright (C) 2005 Mika Laitio <lamikr@cc.jyu.fi> and
+ * Everett Coleman II <gcc80x86@fuzzyneural.net>
+ *
+ * Based on the ideas in omap-aic23.c and sa11xx-uda1341.c
+ * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ * Copyright (C) 2002 Tomas Kasparek <tomas.kasparek@seznam.cz>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * History:
+ *
+ * 2006-03-01 Mika Laitio - Mixer for the tsc2101 driver used in omap boards.
+ * Can switch between headset and loudspeaker playback,
+ * mute and unmute dgc, set dgc volume. Record source switch,
+ * keyclick, buzzer and headset volume and handset volume control
+ * are still missing.
+ */
+
+#ifndef OMAPALSATSC2101MIXER_H_
+#define OMAPALSATSC2101MIXER_H_
+
+#include <asm/hardware/tsc2101.h>
+#include "omap-alsa-dma.h"
+
+/* tsc2101 DAC gain control volume specific */
+#define OUTPUT_VOLUME_MIN 0x7F /* 1111111 = -63.5 DB */
+#define OUTPUT_VOLUME_MAX 0x32 /* 110010 */
+#define OUTPUT_VOLUME_RANGE (OUTPUT_VOLUME_MIN - OUTPUT_VOLUME_MAX)
+
+/* use input vol of 75 for 0dB gain */
+#define INPUT_VOLUME_MIN 0x0
+#define INPUT_VOLUME_MAX 0x7D
+#define INPUT_VOLUME_RANGE (INPUT_VOLUME_MAX - INPUT_VOLUME_MIN)
+
+#define PLAYBACK_TARGET_COUNT 0x03
+#define PLAYBACK_TARGET_LOUDSPEAKER 0x00
+#define PLAYBACK_TARGET_HEADPHONE 0x01
+#define PLAYBACK_TARGET_CELLPHONE 0x02
+
+/*
+ * Following are used for register 03h Mixer PGA control bits D7-D5 for
+ * selecting record source
+ */
+#define REC_SRC_TARGET_COUNT 0x08
+/* oss code referred to MIXER_LINE */
+#define REC_SRC_SINGLE_ENDED_MICIN_HED 0x00
+/* oss code referred to MIXER_MIC */
+#define REC_SRC_SINGLE_ENDED_MICIN_HND 0x01
+#define REC_SRC_SINGLE_ENDED_AUX1 0x02
+#define REC_SRC_SINGLE_ENDED_AUX2 0x03
+#define REC_SRC_MICIN_HED_AND_AUX1 0x04
+#define REC_SRC_MICIN_HED_AND_AUX2 0x05
+#define REC_SRC_MICIN_HND_AND_AUX1 0x06
+#define REC_SRC_MICIN_HND_AND_AUX2 0x07
+
+/* default output volume to dac dgc */
+#define DEFAULT_OUTPUT_VOLUME 90
+/* default record volume */
+#define DEFAULT_INPUT_VOLUME 20
+
+#define TSC2101_AUDIO_CODEC_REGISTERS_PAGE2 (2)
+
+extern struct mcbsp_dev_info mcbsp_dev;
+
+#endif /*OMAPALSATSC2101MIXER_H_*/
--- /dev/null
+/*
+ * sound/arm/omap/omap-alsa-tsc2101.c
+ *
+ * Alsa codec Driver for TSC2101 chip for OMAP platform boards.
+ * Code obtained from oss omap drivers
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ * Written by Nishanth Menon and Sriram Kannan
+ *
+ * Copyright (C) 2006 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ * Alsa modularization by Daniel Petrini (d.pensator@gmail.com)
+ *
+ * Copyright (C) 2006 Mika Laitio <lamikr@cc.jyu.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/delay.h>
+#include <linux/soundcard.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/spi/tsc2101.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#ifdef CONFIG_PM
+#include <linux/pm.h>
+#endif
+
+#include <asm/mach-types.h>
+#include <asm/arch/dma.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/mcbsp.h>
+#include <asm/hardware/tsc2101.h>
+#include <asm/arch/omap-alsa.h>
+
+#include "omap-alsa-tsc2101.h"
+
+struct mcbsp_dev_info mcbsp_dev;
+
+static struct clk *tsc2101_mclk;
+
+/* #define DUMP_TSC2101_AUDIO_REGISTERS */
+#undef DUMP_TSC2101_AUDIO_REGISTERS
+
+/*
+ * Hardware capabilities
+ */
+
+/*
+ * DAC USB-mode sampling rates (MCLK = 12 MHz)
+ * The rates and rate_reg_into MUST be in the same order
+ */
+static unsigned int rates[] = {
+ 7350, 8000, 8018, 8727,
+ 8820, 9600, 11025, 12000,
+ 14700, 16000, 22050, 24000,
+ 29400, 32000, 44100, 48000,
+};
+
+static struct snd_pcm_hw_constraint_list tsc2101_hw_constraints_rates = {
+ .count = ARRAY_SIZE(rates),
+ .list = rates,
+ .mask = 0,
+};
+
+static const struct tsc2101_samplerate_reg_info
+ rate_reg_info[NUMBER_SAMPLE_RATES_SUPPORTED] = {
+ /* Div 6 */
+ {7350, 7, 1},
+ {8000, 7, 0},
+ /* Div 5.5 */
+ {8018, 6, 1},
+ {8727, 6, 0},
+ /* Div 5 */
+ {8820, 5, 1},
+ {9600, 5, 0},
+ /* Div 4 */
+ {11025, 4, 1},
+ {12000, 4, 0},
+ /* Div 3 */
+ {14700, 3, 1},
+ {16000, 3, 0},
+ /* Div 2 */
+ {22050, 2, 1},
+ {24000, 2, 0},
+ /* Div 1.5 */
+ {29400, 1, 1},
+ {32000, 1, 0},
+ /* Div 1 */
+ {44100, 0, 1},
+ {48000, 0, 0},
+};
+
+static struct snd_pcm_hardware tsc2101_snd_omap_alsa_playback = {
+ .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID,
+#ifdef CONFIG_MACH_OMAP_H6300
+ .formats = SNDRV_PCM_FMTBIT_S8,
+#else
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+#endif
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
+ SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_KNOT,
+ .rate_min = 7350,
+ .rate_max = 48000,
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = 128 * 1024,
+ .period_bytes_min = 32,
+ .period_bytes_max = 8 * 1024,
+ .periods_min = 16,
+ .periods_max = 255,
+ .fifo_size = 0,
+};
+
+static struct snd_pcm_hardware tsc2101_snd_omap_alsa_capture = {
+ .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
+ SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_KNOT,
+ .rate_min = 7350,
+ .rate_max = 48000,
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = 128 * 1024,
+ .period_bytes_min = 32,
+ .period_bytes_max = 8 * 1024,
+ .periods_min = 16,
+ .periods_max = 255,
+ .fifo_size = 0,
+};
+
+/*
+ * Simplified write for tsc2101 audio registers.
+ */
+inline void tsc2101_audio_write(u8 address, u16 data)
+{
+ tsc2101_write_sync(mcbsp_dev.tsc2101_dev, PAGE2_AUDIO_CODEC_REGISTERS,
+ address, data);
+}
+
+/*
+ * Simplified read for tsc2101 audio registers.
+ */
+inline u16 tsc2101_audio_read(u8 address)
+{
+ return (tsc2101_read_sync(mcbsp_dev.tsc2101_dev,
+ PAGE2_AUDIO_CODEC_REGISTERS, address));
+}
+
+#ifdef DUMP_TSC2101_AUDIO_REGISTERS
+void dump_tsc2101_audio_reg(void)
+{
+ dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+ "TSC2101_AUDIO_CTRL_1 = 0x%04x\n",
+ tsc2101_audio_read(TSC2101_AUDIO_CTRL_1));
+ dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+ "TSC2101_HEADSET_GAIN_CTRL = 0x%04x\n",
+ tsc2101_audio_read(TSC2101_HEADSET_GAIN_CTRL));
+ dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+ "TSC2101_DAC_GAIN_CTRL = 0x%04x\n",
+ tsc2101_audio_read(TSC2101_DAC_GAIN_CTRL));
+ dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+ "TSC2101_MIXER_PGA_CTRL = 0x%04x\n",
+ tsc2101_audio_read(TSC2101_MIXER_PGA_CTRL));
+ dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+ "TSC2101_AUDIO_CTRL_2 = 0x%04x\n",
+ tsc2101_audio_read(TSC2101_AUDIO_CTRL_2));
+ dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+ "TSC2101_CODEC_POWER_CTRL = 0x%04x\n",
+ tsc2101_audio_read(TSC2101_CODEC_POWER_CTRL));
+ dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+ "TSC2101_AUDIO_CTRL_3 = 0x%04x\n",
+ tsc2101_audio_read(TSC2101_AUDIO_CTRL_3));
+ dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+ "TSC2101_LCH_BASS_BOOST_N0 = 0x%04x\n",
+ tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_N0));
+ dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+ "TSC2101_LCH_BASS_BOOST_N1 = 0x%04x\n",
+ tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_N1));
+ dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+ "TSC2101_LCH_BASS_BOOST_N2 = 0x%04x\n",
+ tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_N2));
+ dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+ "TSC2101_LCH_BASS_BOOST_N3 = 0x%04x\n",
+ tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_N3));
+ dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+ "TSC2101_LCH_BASS_BOOST_N4 = 0x%04x\n",
+ tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_N4));
+ dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+ "TSC2101_LCH_BASS_BOOST_N5 = 0x%04x\n",
+ tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_N5));
+ dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+ "TSC2101_LCH_BASS_BOOST_D1 = 0x%04x\n",
+ tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_D1));
+ dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+ "TSC2101_LCH_BASS_BOOST_D2 = 0x%04x\n",
+ tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_D2));
+ dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+ "TSC2101_LCH_BASS_BOOST_D4 = 0x%04x\n",
+ tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_D4));
+ dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+ "TSC2101_LCH_BASS_BOOST_D5 = 0x%04x\n",
+ tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_D5));
+
+ dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+ "TSC2101_RCH_BASS_BOOST_N0 = 0x%04x\n",
+ tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_N0));
+ dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+ "TSC2101_RCH_BASS_BOOST_N1 = 0x%04x\n",
+ tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_N1));
+ dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+ "TSC2101_RCH_BASS_BOOST_N2 = 0x%04x\n",
+ tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_N2));
+ dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+ "TSC2101_RCH_BASS_BOOST_N3 = 0x%04x\n",
+ tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_N3));
+ dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+ "TSC2101_RCH_BASS_BOOST_N4 = 0x%04x\n",
+ tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_N4));
+ dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+ "TSC2101_RCH_BASS_BOOST_N5 = 0x%04x\n",
+ tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_N5));
+ dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+ "TSC2101_RCH_BASS_BOOST_D1 = 0x%04x\n",
+ tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_D1));
+ dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+ "TSC2101_RCH_BASS_BOOST_D2 = 0x%04x\n",
+ tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_D2));
+ dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+ "TSC2101_RCH_BASS_BOOST_D4 = 0x%04x\n",
+ tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_D4));
+ dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+ "TSC2101_RCH_BASS_BOOST_D5 = 0x%04x\n",
+ tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_D5));
+
+ dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+ "TSC2101_PLL_PROG_1 = 0x%04x\n",
+ tsc2101_audio_read(TSC2101_PLL_PROG_1));
+ dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+ "TSC2101_PLL_PROG_1 = 0x%04x\n",
+ tsc2101_audio_read(TSC2101_PLL_PROG_2));
+ dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+ "TSC2101_AUDIO_CTRL_4 = 0x%04x\n",
+ tsc2101_audio_read(TSC2101_AUDIO_CTRL_4));
+ dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+ "TSC2101_HANDSET_GAIN_CTRL = 0x%04x\n",
+ tsc2101_audio_read(TSC2101_HANDSET_GAIN_CTRL));
+ dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+ "TSC2101_BUZZER_GAIN_CTRL = 0x%04x\n",
+ tsc2101_audio_read(TSC2101_BUZZER_GAIN_CTRL));
+ dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+ "TSC2101_AUDIO_CTRL_5 = 0x%04x\n",
+ tsc2101_audio_read(TSC2101_AUDIO_CTRL_5));
+ dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+ "TSC2101_AUDIO_CTRL_6 = 0x%04x\n",
+ tsc2101_audio_read(TSC2101_AUDIO_CTRL_6));
+ dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+ "TSC2101_AUDIO_CTRL_7 = 0x%04x\n",
+ tsc2101_audio_read(TSC2101_AUDIO_CTRL_7));
+ dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+ "TSC2101_GPIO_CTRL = 0x%04x\n",
+ tsc2101_audio_read(TSC2101_GPIO_CTRL));
+ dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+ "TSC2101_AGC_CTRL = 0x%04x\n",
+ tsc2101_audio_read(TSC2101_AGC_CTRL));
+ dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+ "TSC2101_POWERDOWN_STS = 0x%04x\n",
+ tsc2101_audio_read(TSC2101_POWERDOWN_STS));
+ dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+ "TSC2101_MIC_AGC_CONTROL = 0x%04x\n",
+ tsc2101_audio_read(TSC2101_MIC_AGC_CONTROL));
+ dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+ "TSC2101_CELL_AGC_CONTROL = 0x%04x\n",
+ tsc2101_audio_read(TSC2101_CELL_AGC_CONTROL));
+}
+#endif
+
+/*
+ * ALSA operations according to board file
+ */
+
+/*
+ * Sample rate changing
+ */
+void tsc2101_set_samplerate(long sample_rate)
+{
+ u8 count = 0;
+ u16 data = 0;
+ int clkgdv = 0;
+
+ u16 srgr1, srgr2;
+ /* wait for any frame to complete */
+ udelay(125);
+ ADEBUG();
+
+ sample_rate = sample_rate;
+ /* Search for the right sample rate */
+ while ((rate_reg_info[count].sample_rate != sample_rate) &&
+ (count < NUMBER_SAMPLE_RATES_SUPPORTED)) {
+ count++;
+ }
+ if (count == NUMBER_SAMPLE_RATES_SUPPORTED) {
+ printk(KERN_ERR "Invalid Sample Rate %d requested\n",
+ (int) sample_rate);
+ return;
+ }
+
+ /* Set AC1 */
+ data = tsc2101_audio_read(TSC2101_AUDIO_CTRL_1);
+ /* Clear prev settings */
+ data &= ~(AC1_DACFS(0x07) | AC1_ADCFS(0x07));
+ data |= AC1_DACFS(rate_reg_info[count].divisor) |
+ AC1_ADCFS(rate_reg_info[count].divisor);
+ tsc2101_audio_write(TSC2101_AUDIO_CTRL_1, data);
+
+ /* Set the AC3 */
+ data = tsc2101_audio_read(TSC2101_AUDIO_CTRL_3);
+ /*Clear prev settings */
+ data &= ~(AC3_REFFS | AC3_SLVMS);
+ data |= (rate_reg_info[count].fs_44kHz) ? AC3_REFFS : 0;
+#ifdef TSC_MASTER
+ data |= AC3_SLVMS;
+#endif /* #ifdef TSC_MASTER */
+ tsc2101_audio_write(TSC2101_AUDIO_CTRL_3, data);
+
+ /*
+ * Program the PLLs. This code assumes that the 12 Mhz MCLK is in use.
+ * If MCLK rate is something else, these values must be changed.
+ * See the tsc2101 specification for the details.
+ */
+ if (rate_reg_info[count].fs_44kHz) {
+ /* samplerate = (44.1kHZ / x), where x is int. */
+ tsc2101_audio_write(TSC2101_PLL_PROG_1, PLL1_PLLSEL |
+ /* PVAL 1; I_VAL 7 */
+ PLL1_PVAL(1) | PLL1_I_VAL(7));
+ /* D_VAL 5264 */
+ tsc2101_audio_write(TSC2101_PLL_PROG_2, PLL2_D_VAL(0x1490));
+ } else {
+ /* samplerate = (48.kHZ / x), where x is int. */
+ tsc2101_audio_write(TSC2101_PLL_PROG_1, PLL1_PLLSEL |
+ /* PVAL 1; I_VAL 8 */
+ PLL1_PVAL(1) | PLL1_I_VAL(8));
+ /* D_VAL 1920 */
+ tsc2101_audio_write(TSC2101_PLL_PROG_2, PLL2_D_VAL(0x780));
+ }
+
+ /* Set the sample rate */
+#ifndef TSC_MASTER
+ clkgdv = CODEC_CLOCK / (sample_rate * (DEFAULT_BITPERSAMPLE * 2 - 1));
+ if (clkgdv)
+ srgr1 = (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
+ else
+ return (1);
+
+ /* Stereo Mode */
+ srgr2 = (CLKSM | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1));
+#else
+ srgr1 = (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
+ srgr2 = ((GSYNC | CLKSP | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1)));
+
+#endif /* end of #ifdef TSC_MASTER */
+ OMAP_MCBSP_WRITE(OMAP1610_MCBSP1_BASE, SRGR2, srgr2);
+ OMAP_MCBSP_WRITE(OMAP1610_MCBSP1_BASE, SRGR1, srgr1);
+}
+
+void tsc2101_configure(void)
+{
+}
+
+/*
+ * Omap MCBSP clock and Power Management configuration
+ *
+ * Here we have some functions that allows clock to be enabled and
+ * disabled only when needed. Besides doing clock configuration
+ * it allows turn on/turn off audio when necessary.
+ */
+
+/*
+ * Do clock framework mclk search
+ */
+void tsc2101_clock_setup(void)
+{
+ tsc2101_mclk = clk_get(0, "mclk");
+}
+
+/*
+ * Do some sanity check, set clock rate, starts it and turn codec audio on
+ */
+int tsc2101_clock_on(void)
+{
+ int curUseCount;
+ uint curRate;
+ int err;
+
+ curUseCount = clk_get_usecount(tsc2101_mclk);
+ DPRINTK("clock use count = %d\n", curUseCount);
+ if (curUseCount > 0) {
+ /* MCLK is already in use */
+ printk(KERN_WARNING
+ "MCLK already in use at %d Hz. We change it to %d Hz\n",
+ (uint) clk_get_rate(tsc2101_mclk),
+ CODEC_CLOCK);
+ }
+ curRate = (uint)clk_get_rate(tsc2101_mclk);
+ if (curRate != CODEC_CLOCK) {
+ err = clk_set_rate(tsc2101_mclk, CODEC_CLOCK);
+ if (err) {
+ printk(KERN_WARNING "Cannot set MCLK clock rate for "
+ "TSC2101 CODEC, error code = %d\n", err);
+ return -ECANCELED;
+ }
+ }
+ err = clk_enable(tsc2101_mclk);
+ curRate = (uint)clk_get_rate(tsc2101_mclk);
+ curUseCount = clk_get_usecount(tsc2101_mclk);
+ DPRINTK("MCLK = %d [%d], usecount = %d, clk_enable retval = %d\n",
+ curRate,
+ CODEC_CLOCK,
+ curUseCount,
+ err);
+
+ /* Now turn the audio on */
+ tsc2101_write_sync(mcbsp_dev.tsc2101_dev, PAGE2_AUDIO_CODEC_REGISTERS,
+ TSC2101_CODEC_POWER_CTRL,
+ 0x0000);
+ return 0;
+}
+
+/*
+ * Do some sanity check, turn clock off and then turn codec audio off
+ */
+int tsc2101_clock_off(void)
+{
+ int curUseCount;
+ int curRate;
+
+ curUseCount = clk_get_usecount(tsc2101_mclk);
+ DPRINTK("clock use count = %d\n", curUseCount);
+ if (curUseCount > 0) {
+ curRate = clk_get_rate(tsc2101_mclk);
+ DPRINTK("clock rate = %d\n", curRate);
+ if (curRate != CODEC_CLOCK) {
+ printk(KERN_WARNING
+ "MCLK for audio should be %d Hz. But is %d Hz\n",
+ (uint) clk_get_rate(tsc2101_mclk),
+ CODEC_CLOCK);
+ }
+ clk_disable(tsc2101_mclk);
+ DPRINTK("clock disabled\n");
+ }
+ tsc2101_audio_write(TSC2101_CODEC_POWER_CTRL,
+ ~(CPC_SP1PWDN | CPC_SP2PWDN | CPC_BASSBC));
+ DPRINTK("audio codec off\n");
+ return 0;
+}
+
+int tsc2101_get_default_samplerate(void)
+{
+ return DEFAULT_SAMPLE_RATE;
+}
+
+static int __devinit snd_omap_alsa_tsc2101_probe(struct platform_device *pdev)
+{
+ struct spi_device *tsc2101;
+ int ret;
+ struct omap_alsa_codec_config *codec_cfg;
+
+ tsc2101 = dev_get_drvdata(&pdev->dev);
+ if (tsc2101 == NULL) {
+ dev_err(&pdev->dev, "no platform data\n");
+ return -ENODEV;
+ }
+ if (strncmp(tsc2101->modalias, "tsc2101", 8) != 0) {
+ dev_err(&pdev->dev, "tsc2101 not found\n");
+ return -EINVAL;
+ }
+ mcbsp_dev.mcbsp_dev = pdev;
+ mcbsp_dev.tsc2101_dev = tsc2101;
+
+ codec_cfg = pdev->dev.platform_data;
+ if (codec_cfg != NULL) {
+ codec_cfg->hw_constraints_rates =
+ &tsc2101_hw_constraints_rates;
+ codec_cfg->snd_omap_alsa_playback =
+ &tsc2101_snd_omap_alsa_playback;
+ codec_cfg->snd_omap_alsa_capture =
+ &tsc2101_snd_omap_alsa_capture;
+ codec_cfg->codec_configure_dev = tsc2101_configure;
+ codec_cfg->codec_set_samplerate = tsc2101_set_samplerate;
+ codec_cfg->codec_clock_setup = tsc2101_clock_setup;
+ codec_cfg->codec_clock_on = tsc2101_clock_on;
+ codec_cfg->codec_clock_off = tsc2101_clock_off;
+ codec_cfg->get_default_samplerate =
+ tsc2101_get_default_samplerate;
+ ret = snd_omap_alsa_post_probe(pdev, codec_cfg);
+ } else
+ ret = -ENODEV;
+ return ret;
+}
+
+static struct platform_driver omap_alsa_driver = {
+ .probe = snd_omap_alsa_tsc2101_probe,
+ .remove = snd_omap_alsa_remove,
+ .suspend = snd_omap_alsa_suspend,
+ .resume = snd_omap_alsa_resume,
+ .driver = {
+ .name = "omap_alsa_mcbsp",
+ },
+};
+
+static int __init omap_alsa_tsc2101_init(void)
+{
+ ADEBUG();
+#ifdef DUMP_TSC2101_AUDIO_REGISTERS
+ printk(KERN_INFO "omap_alsa_tsc2101_init()\n");
+ dump_tsc2101_audio_reg();
+#endif
+ return platform_driver_register(&omap_alsa_driver);
+}
+
+static void __exit omap_alsa_tsc2101_exit(void)
+{
+ ADEBUG();
+#ifdef DUMP_TSC2101_AUDIO_REGISTERS
+ printk(KERN_INFO "omap_alsa_tsc2101_exit()\n");
+ dump_tsc2101_audio_reg();
+#endif
+ platform_driver_unregister(&omap_alsa_driver);
+}
+
+module_init(omap_alsa_tsc2101_init);
+module_exit(omap_alsa_tsc2101_exit);
--- /dev/null
+/*
+ * sound/arm/omap/omap-alsa-tsc2101.h
+ *
+ * Alsa Driver for TSC2101 codec for OMAP platform boards.
+ *
+ * Based on former omap-aic23.h and tsc2101 OSS drivers.
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ * Written by Nishanth Menon and Sriram Kannan
+ *
+ * Copyright (C) 2006 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ * Alsa modularization by Daniel Petrini (d.pensator@gmail.com)
+ *
+ * Copyright (C) 2006 Mika Laitio <lamikr@cc.jyu.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef OMAP_ALSA_TSC2101_H_
+#define OMAP_ALSA_TSC2101_H_
+
+#include <linux/types.h>
+
+/* Define to set the tsc as the master w.r.t McBSP or EAC */
+#define TSC_MASTER
+
+#define NUMBER_SAMPLE_RATES_SUPPORTED 16
+
+/*
+ * AUDIO related MACROS
+ */
+#ifndef DEFAULT_BITPERSAMPLE
+#define DEFAULT_BITPERSAMPLE 16
+#endif
+
+#define DEFAULT_SAMPLE_RATE 44100
+
+/* FIXME codec clock rate is board-specific */
+#define CODEC_CLOCK 12000000
+
+#define PAGE2_AUDIO_CODEC_REGISTERS (2)
+
+struct mcbsp_dev_info {
+ struct platform_device *mcbsp_dev;
+ struct spi_device *tsc2101_dev;
+};
+
+struct tsc2101_samplerate_reg_info {
+ u16 sample_rate;
+ u8 divisor;
+ u8 fs_44kHz; /* if 0 48 khz, if 1 44.1 khz fsref */
+};
+
+/*
+ * Defines codec specific function pointers that can be used from the
+ * common omap-alse base driver for all omap codecs. (tsc2101 and aic23)
+ */
+inline void tsc2101_configure(void);
+void tsc2101_set_samplerate(long rate);
+void tsc2101_clock_setup(void);
+int tsc2101_clock_on(void);
+int tsc2101_clock_off(void);
+int tsc2101_get_default_samplerate(void);
+
+#endif /*OMAP_ALSA_TSC2101_H_*/
--- /dev/null
+/*
+ * sound/arm/omap/omap-alsa-tsc2102-mixer.c
+ *
+ * Alsa mixer driver for TSC2102 chip for OMAP platforms.
+ *
+ * Copyright (c) 2006 Andrzej Zaborowski <balrog@zabor.org>
+ * Code based on the TSC2101 ALSA driver.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/types.h>
+#include <linux/spi/tsc2102.h>
+
+#include <asm/arch/omap-alsa.h>
+
+#include <sound/initval.h>
+#include <sound/control.h>
+
+#include "omap-alsa-tsc2102.h"
+#include "omap-alsa-dma.h"
+
+static int vol[2], mute[2], filter[2];
+
+/*
+ * Converts the Alsa mixer volume (0 - 100) to actual Digital
+ * Gain Control (DGC) value that can be written or read from the
+ * TSC2102 registers.
+ *
+ * Note that the number "OUTPUT_VOLUME_MAX" is smaller than
+ * OUTPUT_VOLUME_MIN because DGC works as a volume decreaser. (The
+ * higher the value sent to DAC, the more the volume of controlled
+ * channel is decreased)
+ */
+static void set_dac_gain_stereo(int left_ch, int right_ch)
+{
+ int lch, rch;
+
+ if (left_ch > 100)
+ vol[0] = 100;
+ else if (left_ch < 0)
+ vol[0] = 0;
+ else
+ vol[0] = left_ch;
+ lch = OUTPUT_VOLUME_MIN - vol[0] *
+ (OUTPUT_VOLUME_MIN - OUTPUT_VOLUME_MAX) / 100;
+
+ if (right_ch > 100)
+ vol[1] = 100;
+ else if (right_ch < 0)
+ vol[1] = 0;
+ else
+ vol[1] = right_ch;
+ rch = OUTPUT_VOLUME_MIN - vol[1] *
+ (OUTPUT_VOLUME_MIN - OUTPUT_VOLUME_MAX) / 100;
+
+ tsc2102_set_volume(lch, rch);
+}
+
+void init_playback_targets(void)
+{
+ set_dac_gain_stereo(DEFAULT_OUTPUT_VOLUME, DEFAULT_OUTPUT_VOLUME);
+
+ /* Unmute */
+ tsc2102_set_mute(0, 0);
+
+ mute[0] = 0;
+ mute[1] = 0;
+ filter[0] = 0;
+ filter[1] = 0;
+}
+
+/*
+ * Initializes TSC 2102 and playback target.
+ */
+void snd_omap_init_mixer(void)
+{
+ FN_IN;
+
+ init_playback_targets();
+
+ FN_OUT(0);
+}
+
+static int __pcm_playback_volume_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 2;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 100;
+ return 0;
+}
+
+static int __pcm_playback_volume_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = vol[0]; /* L */
+ ucontrol->value.integer.value[1] = vol[1]; /* R */
+
+ return 0;
+}
+
+static int __pcm_playback_volume_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ set_dac_gain_stereo(
+ ucontrol->value.integer.value[0], /* L */
+ ucontrol->value.integer.value[1]); /* R */
+ return 1;
+}
+
+static int __pcm_playback_switch_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 2;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+static int __pcm_playback_switch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = !mute[0]; /* L */
+ ucontrol->value.integer.value[1] = !mute[1]; /* R */
+
+ return 0;
+}
+
+static int __pcm_playback_switch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ mute[0] = (ucontrol->value.integer.value[0] == 0); /* L */
+ mute[1] = (ucontrol->value.integer.value[1] == 0); /* R */
+
+ tsc2102_set_mute(mute[0], mute[1]);
+ return 1;
+}
+
+static int __pcm_playback_deemphasis_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+static int __pcm_playback_deemphasis_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = filter[0];
+ return 0;
+}
+
+static int __pcm_playback_deemphasis_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ filter[0] = (ucontrol->value.integer.value[0] > 0);
+
+ tsc2102_set_deemphasis(filter[0]);
+ return 1;
+}
+
+static int __pcm_playback_bassboost_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+static int __pcm_playback_bassboost_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = filter[1];
+ return 0;
+}
+
+static int __pcm_playback_bassboost_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ filter[1] = (ucontrol->value.integer.value[0] > 0);
+
+ tsc2102_set_bassboost(filter[1]);
+ return 1;
+}
+
+static struct snd_kcontrol_new tsc2102_controls[] __devinitdata = {
+ {
+ .name = "Master Playback Volume",
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = __pcm_playback_volume_info,
+ .get = __pcm_playback_volume_get,
+ .put = __pcm_playback_volume_put,
+ },
+ {
+ .name = "Master Playback Switch",
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = __pcm_playback_switch_info,
+ .get = __pcm_playback_switch_get,
+ .put = __pcm_playback_switch_put,
+ },
+ {
+ .name = "De-emphasis Filter Switch",
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = __pcm_playback_deemphasis_info,
+ .get = __pcm_playback_deemphasis_get,
+ .put = __pcm_playback_deemphasis_put,
+ },
+ {
+ .name = "Bass-boost Filter Switch",
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = __pcm_playback_bassboost_info,
+ .get = __pcm_playback_bassboost_get,
+ .put = __pcm_playback_bassboost_put,
+ },
+};
+
+#ifdef CONFIG_PM
+void snd_omap_suspend_mixer(void)
+{
+ /* Nothing to do */
+}
+
+void snd_omap_resume_mixer(void)
+{
+ /* The chip was reset, restore the last used values */
+ set_dac_gain_stereo(vol[0], vol[1]);
+
+ tsc2102_set_mute(mute[0], mute[1]);
+ tsc2102_set_deemphasis(filter[0]);
+ tsc2102_set_bassboost(filter[1]);
+}
+#endif
+
+int snd_omap_mixer(struct snd_card_omap_codec *tsc2102)
+{
+ int i, err;
+
+ if (!tsc2102)
+ return -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(tsc2102_controls); i++) {
+ err = snd_ctl_add(tsc2102->card,
+ snd_ctl_new1(&tsc2102_controls[i],
+ tsc2102->card));
+
+ if (err < 0)
+ return err;
+ }
+ return 0;
+}
--- /dev/null
+/*
+ * sound/arm/omap/omap-alsa-tsc2102.c
+ *
+ * Alsa codec driver for TSC2102 chip for OMAP platforms.
+ *
+ * Copyright (c) 2006 Andrzej Zaborowski <balrog@zabor.org>
+ * Code based on the TSC2101 ALSA driver.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/delay.h>
+#include <linux/soundcard.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/spi/tsc2102.h>
+
+#include <asm/arch/dma.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/omap-alsa.h>
+
+#include "omap-alsa-tsc2102.h"
+
+static struct clk *tsc2102_bclk;
+
+/*
+ * Hardware capabilities
+ */
+
+/* DAC sampling rates (BCLK = 12 MHz) */
+static unsigned int rates[] = {
+ 7350, 8000, 8820, 9600, 11025, 12000, 14700,
+ 16000, 22050, 24000, 29400, 32000, 44100, 48000,
+};
+
+static struct snd_pcm_hw_constraint_list tsc2102_hw_constraints_rates = {
+ .count = ARRAY_SIZE(rates),
+ .list = rates,
+ .mask = 0,
+};
+
+static struct snd_pcm_hardware tsc2102_snd_omap_alsa_playback = {
+ .info = SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_KNOT,
+ .rate_min = 7350,
+ .rate_max = 48000,
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = 128 * 1024,
+ .period_bytes_min = 32,
+ .period_bytes_max = 8 * 1024,
+ .periods_min = 16,
+ .periods_max = 255,
+ .fifo_size = 0,
+};
+
+#ifdef DUMP_TSC2102_AUDIO_REGISTERS
+static void dump_tsc2102_audio_regs(void)
+{
+ printk(KERN_INFO "TSC2102_AUDIO1_CTRL = 0x%04x\n",
+ tsc2102_read_sync(TSC2102_AUDIO1_CTRL));
+ printk(KERN_INFO "TSC2102_DAC_GAIN_CTRL = 0x%04x\n",
+ tsc2102_read_sync(TSC2102_DAC_GAIN_CTRL));
+ printk(KERN_INFO "TSC2102_AUDIO2_CTRL = 0x%04x\n",
+ tsc2102_read_sync(TSC2102_AUDIO2_CTRL));
+ printk(KERN_INFO "TSC2102_DAC_POWER_CTRL = 0x%04x\n",
+ tsc2102_read_sync(TSC2102_DAC_POWER_CTRL));
+ printk(KERN_INFO "TSC2102_AUDIO3_CTRL = 0x%04x\n",
+ tsc2102_read_sync(TSC2102_AUDIO_CTRL_3));
+ printk(KERN_INFO "TSC2102_LCH_BASS_BOOST_N0 = 0x%04x\n",
+ tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_N0));
+ printk(KERN_INFO "TSC2102_LCH_BASS_BOOST_N1 = 0x%04x\n",
+ tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_N1));
+ printk(KERN_INFO "TSC2102_LCH_BASS_BOOST_N2 = 0x%04x\n",
+ tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_N2));
+ printk(KERN_INFO "TSC2102_LCH_BASS_BOOST_N3 = 0x%04x\n",
+ tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_N3));
+ printk(KERN_INFO "TSC2102_LCH_BASS_BOOST_N4 = 0x%04x\n",
+ tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_N4));
+ printk(KERN_INFO "TSC2102_LCH_BASS_BOOST_N5 = 0x%04x\n",
+ tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_N5));
+ printk(KERN_INFO "TSC2102_LCH_BASS_BOOST_D1 = 0x%04x\n",
+ tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_D1));
+ printk(KERN_INFO "TSC2102_LCH_BASS_BOOST_D2 = 0x%04x\n",
+ tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_D2));
+ printk(KERN_INFO "TSC2102_LCH_BASS_BOOST_D4 = 0x%04x\n",
+ tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_D4));
+ printk(KERN_INFO "TSC2102_LCH_BASS_BOOST_D5 = 0x%04x\n",
+ tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_D5));
+ printk(KERN_INFO "TSC2102_RCH_BASS_BOOST_N0 = 0x%04x\n",
+ tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_N0));
+ printk(KERN_INFO "TSC2102_RCH_BASS_BOOST_N1 = 0x%04x\n",
+ tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_N1));
+ printk(KERN_INFO "TSC2102_RCH_BASS_BOOST_N2 = 0x%04x\n",
+ tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_N2));
+ printk(KERN_INFO "TSC2102_RCH_BASS_BOOST_N3 = 0x%04x\n",
+ tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_N3));
+ printk(KERN_INFO "TSC2102_RCH_BASS_BOOST_N4 = 0x%04x\n",
+ tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_N4));
+ printk(KERN_INFO "TSC2102_RCH_BASS_BOOST_N5 = 0x%04x\n",
+ tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_N5));
+ printk(KERN_INFO "TSC2102_RCH_BASS_BOOST_D1 = 0x%04x\n",
+ tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_D1));
+ printk(KERN_INFO "TSC2102_RCH_BASS_BOOST_D2 = 0x%04x\n",
+ tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_D2));
+ printk(KERN_INFO "TSC2102_RCH_BASS_BOOST_D4 = 0x%04x\n",
+ tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_D4));
+ printk(KERN_INFO "TSC2102_RCH_BASS_BOOST_D5 = 0x%04x\n",
+ tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_D5));
+ printk(KERN_INFO "TSC2102_PLL1_CTRL = 0x%04x\n",
+ tsc2102_read_sync(TSC2102_PLL1_CTRL));
+ printk(KERN_INFO "TSC2102_PLL2_CTRL = 0x%04x\n",
+ tsc2102_read_sync(TSC2102_PLL2_CTRL));
+ printk(KERN_INFO "TSC2102_AUDIO4_CTRL = 0x%04x\n",
+ tsc2102_read_sync(TSC2102_AUDIO4_CTRL));
+}
+#endif
+
+/*
+ * ALSA operations according to board file
+ */
+
+static long current_rate;
+
+/*
+ * Sample rate changing
+ */
+static void tsc2102_set_samplerate(long sample_rate)
+{
+ int clkgdv = 0;
+ u16 srgr1, srgr2;
+
+ if (sample_rate == current_rate)
+ return;
+ current_rate = 0;
+
+ if (tsc2102_set_rate(sample_rate))
+ return;
+
+ /* Set the sample rate */
+#ifndef TSC_MASTER
+ clkgdv = CODEC_CLOCK / (sample_rate * (DEFAULT_BITPERSAMPLE * 2 - 1));
+ if (clkgdv)
+ srgr1 = (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
+ else
+ return;
+
+ /* Stereo Mode */
+ srgr2 = CLKSM | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1);
+#else
+ srgr1 = FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv);
+ srgr2 = GSYNC | CLKSP | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1);
+#endif
+ OMAP_MCBSP_WRITE(OMAP1510_MCBSP1_BASE, SRGR2, srgr2);
+ OMAP_MCBSP_WRITE(OMAP1510_MCBSP1_BASE, SRGR1, srgr1);
+ current_rate = sample_rate;
+}
+
+static void tsc2102_configure(void)
+{
+ tsc2102_dac_power(1);
+
+#ifdef TSC_MASTER
+ tsc2102_set_i2s_master(1);
+#else
+ tsc2102_set_i2s_master(0);
+#endif
+}
+
+/*
+ * Omap McBSP clock and Power Management configuration
+ *
+ * Here we have some functions that allow clock to be enabled and
+ * disabled only when needed. Besides doing clock configuration
+ * they allow turn audio on and off when necessary.
+ */
+
+/*
+ * Do clock framework bclk search
+ */
+static void tsc2102_clock_setup(void)
+{
+ tsc2102_bclk = clk_get(0, "bclk");
+}
+
+/*
+ * Do some sanity checks, set clock rate, start it.
+ */
+static int tsc2102_clock_on(void)
+{
+ int err;
+
+ if (clk_get_usecount(tsc2102_bclk) > 0 &&
+ clk_get_rate(tsc2102_bclk) != CODEC_CLOCK) {
+ /* BCLK is already in use */
+ printk(KERN_WARNING
+ "BCLK already in use at %d Hz. We change it to %d Hz\n",
+ (uint) clk_get_rate(tsc2102_bclk), CODEC_CLOCK);
+
+ err = clk_set_rate(tsc2102_bclk, CODEC_CLOCK);
+ if (err)
+ printk(KERN_WARNING "Cannot set BCLK clock rate "
+ "for TSC2102 codec, error code = %d\n", err);
+ }
+
+ clk_enable(tsc2102_bclk);
+ return 0;
+}
+
+/*
+ * Turn off the audio codec and then stop the clock.
+ */
+static int tsc2102_clock_off(void)
+{
+ DPRINTK("clock use count = %d\n", clk_get_usecount(tsc2102_bclk));
+
+ clk_disable(tsc2102_bclk);
+ return 0;
+}
+
+static int tsc2102_get_default_samplerate(void)
+{
+ return DEFAULT_SAMPLE_RATE;
+}
+
+static int snd_omap_alsa_tsc2102_suspend(
+ struct platform_device *pdev, pm_message_t state)
+{
+ tsc2102_dac_power(0);
+ current_rate = 0;
+
+ return snd_omap_alsa_suspend(pdev, state);
+}
+
+static int snd_omap_alsa_tsc2102_resume(struct platform_device *pdev)
+{
+ tsc2102_dac_power(1);
+
+#ifdef TSC_MASTER
+ tsc2102_set_i2s_master(1);
+#else
+ tsc2102_set_i2s_master(0);
+#endif
+
+ return snd_omap_alsa_resume(pdev);
+}
+
+static int __init snd_omap_alsa_tsc2102_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct omap_alsa_codec_config *codec_cfg = pdev->dev.platform_data;
+
+ if (codec_cfg) {
+ codec_cfg->hw_constraints_rates =
+ &tsc2102_hw_constraints_rates;
+ codec_cfg->snd_omap_alsa_playback =
+ &tsc2102_snd_omap_alsa_playback;
+ codec_cfg->codec_configure_dev = tsc2102_configure;
+ codec_cfg->codec_set_samplerate = tsc2102_set_samplerate;
+ codec_cfg->codec_clock_setup = tsc2102_clock_setup;
+ codec_cfg->codec_clock_on = tsc2102_clock_on;
+ codec_cfg->codec_clock_off = tsc2102_clock_off;
+ codec_cfg->get_default_samplerate =
+ tsc2102_get_default_samplerate;
+ ret = snd_omap_alsa_post_probe(pdev, codec_cfg);
+ } else
+ ret = -ENODEV;
+
+ return ret;
+}
+
+static int snd_omap_alsa_tsc2102_remove(struct platform_device *pdev)
+{
+ tsc2102_dac_power(0);
+
+ return snd_omap_alsa_remove(pdev);
+}
+
+static struct platform_driver omap_alsa_driver = {
+ .probe = snd_omap_alsa_tsc2102_probe,
+ .remove = snd_omap_alsa_tsc2102_remove,
+ .suspend = snd_omap_alsa_tsc2102_suspend,
+ .resume = snd_omap_alsa_tsc2102_resume,
+ .driver = {
+ .name = "tsc2102-alsa",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init omap_alsa_tsc2102_init(void)
+{
+ int err;
+
+ ADEBUG();
+ err = platform_driver_register(&omap_alsa_driver);
+
+ return err;
+}
+
+static void __exit omap_alsa_tsc2102_exit(void)
+{
+ ADEBUG();
+ platform_driver_unregister(&omap_alsa_driver);
+}
+
+module_init(omap_alsa_tsc2102_init);
+module_exit(omap_alsa_tsc2102_exit);
--- /dev/null
+/*
+ * sound/arm/omap/omap-alsa-tsc2102.h
+ *
+ * Alsa codec driver for TSC2102 chip for OMAP platforms.
+ *
+ * Copyright (c) 2006 Andrzej Zaborowski <balrog@zabor.org>
+ * Code based on the TSC2101 ALSA driver.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef OMAP_ALSA_TSC2102_H_
+#define OMAP_ALSA_TSC2102_H_
+
+/* Define to set the tsc as the master w.r.t McBSP */
+#define TSC_MASTER
+
+/*
+ * Audio related macros
+ */
+#ifndef DEFAULT_BITPERSAMPLE
+#define DEFAULT_BITPERSAMPLE 16
+#endif
+
+#define DEFAULT_SAMPLE_RATE 44100
+
+/* FIXME codec clock rate is board-specific */
+#define CODEC_CLOCK 12000000
+
+/*
+ * ALSA mixer related macros
+ */
+#define OUTPUT_VOLUME_MIN 0x7f /* 1111111 = -63.5 dB */
+#define OUTPUT_VOLUME_MAX 0x00 /* 0000000 */
+#define OUTPUT_VOLUME_RANGE (OUTPUT_VOLUME_MIN - OUTPUT_VOLUME_MAX)
+
+#define DEFAULT_OUTPUT_VOLUME 90 /* Default output volume */
+
+#endif /* OMAP_ALSA_TSC2102_H_ */
--- /dev/null
+/*
+ * sound/arm/omap-alsa.c
+ *
+ * Alsa Driver for OMAP
+ *
+ * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ * Written by Daniel Petrini, David Cohen, Anderson Briglia
+ * {daniel.petrini, david.cohen, anderson.briglia}@indt.org.br
+ *
+ * Copyright (C) 2006 Mika Laitio <lamikr@cc.jyu.fi>
+ *
+ * Based on sa11xx-uda1341.c,
+ * Copyright (C) 2002 Tomas Kasparek <tomas.kasparek@seznam.cz>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * History:
+ *
+ * 2005-07-29 INdT Kernel Team - Alsa driver for omap osk. Creation of new
+ * file omap-aic23.c
+ *
+ * 2005-12-18 Dirk Behme - Added L/R Channel Interchange fix as proposed
+ * by Ajaya Babu
+ *
+ */
+
+#include <linux/platform_device.h>
+#ifdef CONFIG_PM
+#include <linux/pm.h>
+#endif
+#include <sound/core.h>
+#include <sound/pcm.h>
+
+#include <asm/arch/omap-alsa.h>
+#include "omap-alsa-dma.h"
+
+MODULE_AUTHOR("Mika Laitio");
+MODULE_AUTHOR("Daniel Petrini");
+MODULE_AUTHOR("David Cohen");
+MODULE_AUTHOR("Anderson Briglia");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("OMAP driver for ALSA");
+MODULE_ALIAS("omap_alsa_mcbsp.1");
+
+static char *id;
+static struct snd_card_omap_codec *alsa_codec;
+static struct omap_alsa_codec_config *alsa_codec_config;
+
+/*
+ * HW interface start and stop helper functions
+ */
+static int audio_ifc_start(void)
+{
+ omap_mcbsp_start(AUDIO_MCBSP);
+ return 0;
+}
+
+static int audio_ifc_stop(void)
+{
+ omap_mcbsp_stop(AUDIO_MCBSP);
+ return 0;
+}
+
+static void omap_alsa_audio_init(struct snd_card_omap_codec *omap_alsa)
+{
+ /* Setup DMA stuff */
+ omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].id = "Alsa omap out";
+ omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].stream_id =
+ SNDRV_PCM_STREAM_PLAYBACK;
+ omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].dma_dev =
+ OMAP_DMA_MCBSP1_TX;
+ omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].hw_start =
+ audio_ifc_start;
+ omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].hw_stop =
+ audio_ifc_stop;
+
+ omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].id = "Alsa omap in";
+ omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].stream_id =
+ SNDRV_PCM_STREAM_CAPTURE;
+ omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].dma_dev =
+ OMAP_DMA_MCBSP1_RX;
+ omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].hw_start =
+ audio_ifc_start;
+ omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].hw_stop =
+ audio_ifc_stop;
+}
+
+/*
+ * DMA functions
+ * Depends on omap-alsa-dma.c functions and (omap) dma.c
+ */
+static int audio_dma_request(struct audio_stream *s,
+ void (*callback) (void *))
+{
+ int err;
+ ADEBUG();
+
+ err = omap_request_alsa_sound_dma(s->dma_dev, s->id, s, &s->lch);
+ if (err < 0)
+ printk(KERN_ERR "Unable to grab audio dma 0x%x\n", s->dma_dev);
+ return err;
+}
+
+static int audio_dma_free(struct audio_stream *s)
+{
+ int err = 0;
+ ADEBUG();
+
+ err = omap_free_alsa_sound_dma(s, &s->lch);
+ if (err < 0)
+ printk(KERN_ERR "Unable to free audio dma channels!\n");
+ return err;
+}
+
+/*
+ * This function should calculate the current position of the dma in the
+ * buffer. It will help alsa middle layer to continue update the buffer.
+ * Its correctness is crucial for good functioning.
+ */
+static u_int audio_get_dma_pos(struct audio_stream *s)
+{
+ struct snd_pcm_substream *substream = s->stream;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ unsigned int offset;
+ unsigned long flags;
+ dma_addr_t count;
+ ADEBUG();
+
+ /* this must be called w/ interrupts locked as requested in dma.c */
+ spin_lock_irqsave(&s->dma_lock, flags);
+
+ /* For the current period let's see where we are */
+ count = omap_get_dma_src_addr_counter(s->lch[s->dma_q_head]);
+
+ spin_unlock_irqrestore(&s->dma_lock, flags);
+
+ /* Now, the position related to the end of that period */
+ offset = bytes_to_frames(runtime, s->offset) -
+ bytes_to_frames(runtime, count);
+
+ if (offset >= runtime->buffer_size)
+ offset = 0;
+
+ return offset;
+}
+
+/*
+ * this stops the dma and clears the dma ptrs
+ */
+static void audio_stop_dma(struct audio_stream *s)
+{
+ unsigned long flags;
+ ADEBUG();
+
+ spin_lock_irqsave(&s->dma_lock, flags);
+ s->active = 0;
+ s->period = 0;
+ s->periods = 0;
+
+ /* this stops the dma channel and clears the buffer ptrs */
+ omap_stop_alsa_sound_dma(s);
+
+ omap_clear_alsa_sound_dma(s);
+
+ spin_unlock_irqrestore(&s->dma_lock, flags);
+}
+
+/*
+ * Main dma routine, requests dma according where you are in main alsa buffer
+ */
+static void audio_process_dma(struct audio_stream *s)
+{
+ struct snd_pcm_substream *substream = s->stream;
+ struct snd_pcm_runtime *runtime;
+ unsigned int dma_size;
+ unsigned int offset;
+ int ret;
+
+ ADEBUG();
+ runtime = substream->runtime;
+ if (s->active) {
+ dma_size = frames_to_bytes(runtime, runtime->period_size);
+ offset = dma_size * s->period;
+ snd_assert(dma_size <= DMA_BUF_SIZE, return);
+ /*
+ * On omap1510 based devices, we need to call the stop_dma
+ * before calling the start_dma or we will not receive the
+ * irq from DMA after the first transfered/played buffer.
+ * (invocation of callback_omap_alsa_sound_dma() method).
+ */
+ if (cpu_is_omap1510())
+ omap_stop_alsa_sound_dma(s);
+
+ ret = omap_start_alsa_sound_dma(s,
+ (dma_addr_t)runtime->dma_area + offset,
+ dma_size);
+ if (ret) {
+ printk(KERN_ERR "audio_process_dma: cannot"
+ " queue DMA buffer (%i)\n", ret);
+ return;
+ }
+
+ s->period++;
+ s->period %= runtime->periods;
+ s->periods++;
+ s->offset = offset;
+ }
+}
+
+/*
+ * This is called when dma IRQ occurs at the end of each transmited block
+ */
+void callback_omap_alsa_sound_dma(void *data)
+{
+ struct audio_stream *s = data;
+
+ ADEBUG();
+ /*
+ * If we are getting a callback for an active stream then we inform
+ * the PCM middle layer we've finished a period
+ */
+ if (s->active)
+ snd_pcm_period_elapsed(s->stream);
+
+ spin_lock(&s->dma_lock);
+ if (s->periods > 0)
+ s->periods--;
+
+ audio_process_dma(s);
+ spin_unlock(&s->dma_lock);
+}
+
+/*
+ * Alsa section
+ * PCM settings and callbacks
+ */
+static int snd_omap_alsa_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_card_omap_codec *chip =
+ snd_pcm_substream_chip(substream);
+ int stream_id = substream->pstr->stream;
+ struct audio_stream *s = &chip->s[stream_id];
+ int err = 0;
+
+ ADEBUG();
+ /* note local interrupts are already disabled in the midlevel code */
+ spin_lock(&s->dma_lock);
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ /* requested stream startup */
+ s->active = 1;
+ audio_process_dma(s);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ /* requested stream shutdown */
+ audio_stop_dma(s);
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+ spin_unlock(&s->dma_lock);
+
+ return err;
+}
+
+static int snd_omap_alsa_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_card_omap_codec *chip = snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct audio_stream *s = &chip->s[substream->pstr->stream];
+
+ ADEBUG();
+ /* set requested samplerate */
+ alsa_codec_config->codec_set_samplerate(runtime->rate);
+ chip->samplerate = runtime->rate;
+
+ s->period = 0;
+ s->periods = 0;
+
+ return 0;
+}
+
+static snd_pcm_uframes_t
+snd_omap_alsa_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_card_omap_codec *chip = snd_pcm_substream_chip(substream);
+
+ ADEBUG();
+ return audio_get_dma_pos(&chip->s[substream->pstr->stream]);
+}
+
+static int snd_card_omap_alsa_open(struct snd_pcm_substream *substream)
+{
+ struct snd_card_omap_codec *chip =
+ snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ int stream_id = substream->pstr->stream;
+ int err;
+
+ ADEBUG();
+ chip->s[stream_id].stream = substream;
+ alsa_codec_config->codec_clock_on();
+ if (stream_id == SNDRV_PCM_STREAM_PLAYBACK)
+ runtime->hw = *(alsa_codec_config->snd_omap_alsa_playback);
+ else
+ runtime->hw = *(alsa_codec_config->snd_omap_alsa_capture);
+
+ err = snd_pcm_hw_constraint_integer(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+ if (err < 0)
+ return err;
+
+ err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+ alsa_codec_config->hw_constraints_rates);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static int snd_card_omap_alsa_close(struct snd_pcm_substream *substream)
+{
+ struct snd_card_omap_codec *chip = snd_pcm_substream_chip(substream);
+
+ ADEBUG();
+ alsa_codec_config->codec_clock_off();
+ chip->s[substream->pstr->stream].stream = NULL;
+
+ return 0;
+}
+
+/* HW params & free */
+static int snd_omap_alsa_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ return snd_pcm_lib_malloc_pages(substream,
+ params_buffer_bytes(hw_params));
+}
+
+static int snd_omap_alsa_hw_free(struct snd_pcm_substream *substream)
+{
+ return snd_pcm_lib_free_pages(substream);
+}
+
+/* pcm operations */
+static struct snd_pcm_ops snd_card_omap_alsa_playback_ops = {
+ .open = snd_card_omap_alsa_open,
+ .close = snd_card_omap_alsa_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_omap_alsa_hw_params,
+ .hw_free = snd_omap_alsa_hw_free,
+ .prepare = snd_omap_alsa_prepare,
+ .trigger = snd_omap_alsa_trigger,
+ .pointer = snd_omap_alsa_pointer,
+};
+
+static struct snd_pcm_ops snd_card_omap_alsa_capture_ops = {
+ .open = snd_card_omap_alsa_open,
+ .close = snd_card_omap_alsa_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_omap_alsa_hw_params,
+ .hw_free = snd_omap_alsa_hw_free,
+ .prepare = snd_omap_alsa_prepare,
+ .trigger = snd_omap_alsa_trigger,
+ .pointer = snd_omap_alsa_pointer,
+};
+
+/*
+ * Alsa init and exit section
+ * Inits pcm alsa structures, allocate the alsa buffer, suspend, resume
+ */
+static int __init snd_card_omap_alsa_pcm(struct snd_card_omap_codec *omap_alsa,
+ int device)
+{
+ struct snd_pcm *pcm;
+ int err;
+
+ ADEBUG();
+ err = snd_pcm_new(omap_alsa->card, "OMAP PCM", device, 1, 1, &pcm);
+ if (err < 0)
+ return err;
+
+ /* sets up initial buffer with continuous allocation */
+ snd_pcm_lib_preallocate_pages_for_all(pcm,
+ SNDRV_DMA_TYPE_CONTINUOUS,
+ snd_dma_continuous_data
+ (GFP_KERNEL),
+ 128 * 1024, 128 * 1024);
+
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ &snd_card_omap_alsa_playback_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+ &snd_card_omap_alsa_capture_ops);
+ pcm->private_data = omap_alsa;
+ pcm->info_flags = 0;
+ strcpy(pcm->name, "omap alsa pcm");
+
+ omap_alsa_audio_init(omap_alsa);
+
+ /* setup DMA controller */
+ audio_dma_request(&omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK],
+ callback_omap_alsa_sound_dma);
+ audio_dma_request(&omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE],
+ callback_omap_alsa_sound_dma);
+
+ omap_alsa->pcm = pcm;
+
+ return 0;
+}
+
+
+#ifdef CONFIG_PM
+/*
+ * Driver suspend/resume - calls alsa functions. Some hints from aaci.c
+ */
+int snd_omap_alsa_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct snd_card_omap_codec *chip;
+ struct snd_card *card = platform_get_drvdata(pdev);
+
+ if (card->power_state != SNDRV_CTL_POWER_D3hot) {
+ chip = card->private_data;
+ if (chip->card->power_state != SNDRV_CTL_POWER_D3hot) {
+ snd_power_change_state(chip->card,
+ SNDRV_CTL_POWER_D3hot);
+ snd_pcm_suspend_all(chip->pcm);
+ /* Mutes and turn clock off */
+ alsa_codec_config->codec_clock_off();
+ snd_omap_suspend_mixer();
+ }
+ }
+ return 0;
+}
+
+int snd_omap_alsa_resume(struct platform_device *pdev)
+{
+ struct snd_card_omap_codec *chip;
+ struct snd_card *card = platform_get_drvdata(pdev);
+
+ if (card->power_state != SNDRV_CTL_POWER_D0) {
+ chip = card->private_data;
+ if (chip->card->power_state != SNDRV_CTL_POWER_D0) {
+ snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0);
+ alsa_codec_config->codec_clock_on();
+ snd_omap_resume_mixer();
+ }
+ }
+ return 0;
+}
+
+#endif /* CONFIG_PM */
+
+void snd_omap_alsa_free(struct snd_card *card)
+{
+ struct snd_card_omap_codec *chip = card->private_data;
+ ADEBUG();
+
+ /*
+ * Turn off codec after it is done.
+ * Can't do it immediately, since it may still have
+ * buffered data.
+ */
+ schedule_timeout_interruptible(2);
+
+ omap_mcbsp_stop(AUDIO_MCBSP);
+ omap_mcbsp_free(AUDIO_MCBSP);
+
+ audio_dma_free(&chip->s[SNDRV_PCM_STREAM_PLAYBACK]);
+ audio_dma_free(&chip->s[SNDRV_PCM_STREAM_CAPTURE]);
+}
+
+/* module init & exit */
+
+/*
+ * Inits alsa soudcard structure.
+ * Called by the probe method in codec after function pointers has been set.
+ */
+int snd_omap_alsa_post_probe(struct platform_device *pdev,
+ struct omap_alsa_codec_config *config)
+{
+ int err = 0;
+ int def_rate;
+ struct snd_card *card;
+
+ ADEBUG();
+ alsa_codec_config = config;
+
+ alsa_codec_config->codec_clock_setup();
+ alsa_codec_config->codec_clock_on();
+
+ omap_mcbsp_request(AUDIO_MCBSP);
+ omap_mcbsp_stop(AUDIO_MCBSP);
+ omap_mcbsp_config(AUDIO_MCBSP, alsa_codec_config->mcbsp_regs_alsa);
+ omap_mcbsp_start(AUDIO_MCBSP);
+
+ if (alsa_codec_config && alsa_codec_config->codec_configure_dev)
+ alsa_codec_config->codec_configure_dev();
+
+ alsa_codec_config->codec_clock_off();
+
+ /* register the soundcard */
+ card = snd_card_new(-1, id, THIS_MODULE, sizeof(alsa_codec));
+ if (card == NULL)
+ goto nodev1;
+
+ alsa_codec = kcalloc(1, sizeof(*alsa_codec), GFP_KERNEL);
+ if (alsa_codec == NULL)
+ goto nodev2;
+
+ card->private_data = (void *)alsa_codec;
+ card->private_free = snd_omap_alsa_free;
+
+ alsa_codec->card = card;
+ def_rate = alsa_codec_config->get_default_samplerate();
+ alsa_codec->samplerate = def_rate;
+
+ spin_lock_init(&alsa_codec->s[0].dma_lock);
+ spin_lock_init(&alsa_codec->s[1].dma_lock);
+
+ /* mixer */
+ err = snd_omap_mixer(alsa_codec);
+ if (err < 0)
+ goto nodev3;
+
+ /* PCM */
+ err = snd_card_omap_alsa_pcm(alsa_codec, 0);
+ if (err < 0)
+ goto nodev3;
+
+ strcpy(card->driver, "OMAP_ALSA");
+ strcpy(card->shortname, alsa_codec_config->name);
+ sprintf(card->longname, alsa_codec_config->name);
+
+ snd_omap_init_mixer();
+ snd_card_set_dev(card, &pdev->dev);
+
+ err = snd_card_register(card);
+ if (err == 0) {
+ printk(KERN_INFO "audio support initialized\n");
+ platform_set_drvdata(pdev, card);
+ return 0;
+ }
+
+nodev3:
+ kfree(alsa_codec);
+nodev2:
+ snd_card_free(card);
+nodev1:
+ omap_mcbsp_stop(AUDIO_MCBSP);
+ omap_mcbsp_free(AUDIO_MCBSP);
+
+ return err;
+}
+
+int snd_omap_alsa_remove(struct platform_device *pdev)
+{
+ struct snd_card *card = platform_get_drvdata(pdev);
+ struct snd_card_omap_codec *chip = card->private_data;
+
+ snd_card_free(card);
+
+ alsa_codec = NULL;
+ card->private_data = NULL;
+ kfree(chip);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
obj-$(CONFIG_SOUND_OSS) += sound.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 <linux/mutex.h>
+
+#include <asm/uaccess.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/mcbsp.h>
+#include <asm/arch/fpga.h>
+#include <asm/arch/aic23.h>
+#include <asm/arch/clock.h>
+
+#include "omap-audio.h"
+#include "omap-audio-dma-intfc.h"
+
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#define PROC_START_FILE "driver/aic23-audio-start"
+#define PROC_STOP_FILE "driver/aic23-audio-stop"
+#endif
+
+//#define DEBUG
+
+#ifdef DEBUG
+#define DPRINTK(ARGS...) printk("<%s>: ",__FUNCTION__);printk(ARGS)
+#else
+#define DPRINTK( x... )
+#endif
+
+#define CODEC_NAME "AIC23"
+
+#if CONFIG_MACH_OMAP_OSK
+#define PLATFORM_NAME "OMAP OSK"
+#elif CONFIG_MACH_OMAP_INNOVATOR
+#define PLATFORM_NAME "OMAP INNOVATOR"
+#else
+#error "Unsupported plattform"
+#endif
+
+/* Define to set the AIC23 as the master w.r.t McBSP */
+#define AIC23_MASTER
+
+#define CODEC_CLOCK 12000000
+
+/*
+ * AUDIO related MACROS
+ */
+#define DEFAULT_BITPERSAMPLE 16
+#define AUDIO_RATE_DEFAULT 44100
+
+/* Select the McBSP For Audio */
+#define AUDIO_MCBSP OMAP_MCBSP1
+
+#define REC_MASK (SOUND_MASK_LINE | SOUND_MASK_MIC)
+#define DEV_MASK (REC_MASK | SOUND_MASK_VOLUME)
+
+#define SET_VOLUME 1
+#define SET_LINE 2
+
+#define DEFAULT_OUTPUT_VOLUME 93
+#define DEFAULT_INPUT_VOLUME 0 /* 0 ==> mute line in */
+
+#define OUTPUT_VOLUME_MIN LHV_MIN
+#define OUTPUT_VOLUME_MAX LHV_MAX
+#define OUTPUT_VOLUME_RANGE (OUTPUT_VOLUME_MAX - OUTPUT_VOLUME_MIN)
+#define OUTPUT_VOLUME_MASK OUTPUT_VOLUME_MAX
+
+#define INPUT_VOLUME_MIN LIV_MIN
+#define INPUT_VOLUME_MAX LIV_MAX
+#define INPUT_VOLUME_RANGE (INPUT_VOLUME_MAX - INPUT_VOLUME_MIN)
+#define INPUT_VOLUME_MASK INPUT_VOLUME_MAX
+
+#define NUMBER_SAMPLE_RATES_SUPPORTED 9
+
+/*
+ * HW interface start and stop helper functions
+ */
+static int audio_ifc_start(void)
+{
+ omap_mcbsp_start(AUDIO_MCBSP);
+ return 0;
+}
+
+static int audio_ifc_stop(void)
+{
+ omap_mcbsp_stop(AUDIO_MCBSP);
+ return 0;
+}
+
+static audio_stream_t output_stream = {
+ .id = "AIC23 out",
+ .dma_dev = OMAP_DMA_MCBSP1_TX,
+ .input_or_output = FMODE_WRITE,
+ .hw_start = audio_ifc_start,
+ .hw_stop = audio_ifc_stop
+};
+
+static audio_stream_t input_stream = {
+ .id = "AIC23 in",
+ .dma_dev = OMAP_DMA_MCBSP1_RX,
+ .input_or_output = FMODE_READ,
+ .hw_start = audio_ifc_start,
+ .hw_stop = audio_ifc_stop
+};
+
+static struct clk *aic23_mclk = 0;
+
+static int audio_dev_id, mixer_dev_id;
+
+static struct aic23_local_info {
+ u8 volume;
+ u16 volume_reg;
+ u8 line;
+ u8 mic;
+ u16 input_volume_reg;
+ int mod_cnt;
+} aic23_local;
+
+struct sample_rate_reg_info {
+ u32 sample_rate;
+ u8 control; /* SR3, SR2, SR1, SR0 and BOSR */
+ u8 divider; /* if 0 CLKIN = MCLK, if 1 CLKIN = MCLK/2 */
+};
+
+/* To Store the default sample rate */
+static long audio_samplerate = AUDIO_RATE_DEFAULT;
+
+/* DAC USB-mode sampling rates (MCLK = 12 MHz) */
+static const struct sample_rate_reg_info
+reg_info[NUMBER_SAMPLE_RATES_SUPPORTED] = {
+ {96000, 0x0E, 0},
+ {88200, 0x1F, 0},
+ {48000, 0x00, 0},
+ {44100, 0x11, 0},
+ {32000, 0x0C, 0},
+ {24000, 0x00, 1},
+ {16000, 0x0C, 1},
+ { 8000, 0x06, 0},
+ { 4000, 0x06, 1},
+};
+
+static struct omap_mcbsp_reg_cfg initial_config = {
+ .spcr2 = FREE | FRST | GRST | XRST | XINTM(3),
+ .spcr1 = RINTM(3) | RRST,
+ .rcr2 = RPHASE | RFRLEN2(OMAP_MCBSP_WORD_8) |
+ RWDLEN2(OMAP_MCBSP_WORD_16) | RDATDLY(0),
+ .rcr1 = RFRLEN1(OMAP_MCBSP_WORD_8) | RWDLEN1(OMAP_MCBSP_WORD_16),
+ .xcr2 = XPHASE | XFRLEN2(OMAP_MCBSP_WORD_8) |
+ XWDLEN2(OMAP_MCBSP_WORD_16) | XDATDLY(0) | XFIG,
+ .xcr1 = XFRLEN1(OMAP_MCBSP_WORD_8) | XWDLEN1(OMAP_MCBSP_WORD_16),
+ .srgr1 = FWID(DEFAULT_BITPERSAMPLE - 1),
+ .srgr2 = GSYNC | CLKSP | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1),
+#ifndef AIC23_MASTER
+ /* configure McBSP to be the I2S master */
+ .pcr0 = FSXM | FSRM | CLKXM | CLKRM | CLKXP | CLKRP,
+#else
+ /* configure McBSP to be the I2S slave */
+ .pcr0 = CLKXP | CLKRP,
+#endif /* AIC23_MASTER */
+};
+
+static void omap_aic23_initialize(void *dummy);
+static void omap_aic23_shutdown(void *dummy);
+static int omap_aic23_ioctl(struct inode *inode, struct file *file,
+ uint cmd, ulong arg);
+static int omap_aic23_probe(void);
+#ifdef MODULE
+static void omap_aic23_remove(void);
+#endif
+static int omap_aic23_suspend(void);
+static int omap_aic23_resume(void);
+static inline void aic23_configure(void);
+static int mixer_open(struct inode *inode, struct file *file);
+static int mixer_release(struct inode *inode, struct file *file);
+static int mixer_ioctl(struct inode *inode, struct file *file, uint cmd,
+ ulong arg);
+
+#ifdef CONFIG_PROC_FS
+static int codec_start(char *buf, char **start, off_t offset, int count,
+ int *eof, void *data);
+static int codec_stop(char *buf, char **start, off_t offset, int count,
+ int *eof, void *data);
+#endif
+
+
+/* File Op structure for mixer */
+static struct file_operations omap_mixer_fops = {
+ .open = mixer_open,
+ .release = mixer_release,
+ .ioctl = mixer_ioctl,
+ .owner = THIS_MODULE
+};
+
+/* To store characteristic info regarding the codec for the audio driver */
+static audio_state_t aic23_state = {
+ .output_stream = &output_stream,
+ .input_stream = &input_stream,
+/* .need_tx_for_rx = 1, //Once the Full Duplex works */
+ .need_tx_for_rx = 0,
+ .hw_init = omap_aic23_initialize,
+ .hw_shutdown = omap_aic23_shutdown,
+ .client_ioctl = omap_aic23_ioctl,
+ .hw_probe = omap_aic23_probe,
+ .hw_remove = __exit_p(omap_aic23_remove),
+ .hw_suspend = omap_aic23_suspend,
+ .hw_resume = omap_aic23_resume,
+};
+
+/* This will be defined in the audio.h */
+static struct file_operations *omap_audio_fops;
+
+extern int aic23_write_value(u8 reg, u16 value);
+
+/* TLV320AIC23 is a write only device */
+static __inline__ void audio_aic23_write(u8 address, u16 data)
+{
+ aic23_write_value(address, data);
+}
+
+static int aic23_update(int flag, int val)
+{
+ u16 volume;
+
+ /* Ignore separate left/right channel for now,
+ even the codec does support it. */
+ val &= 0xff;
+
+ if (val < 0 || val > 100) {
+ printk(KERN_ERR "Trying a bad volume value(%d)!\n",val);
+ return -EPERM;
+ }
+
+ switch (flag) {
+ case SET_VOLUME:
+ // Convert 0 -> 100 volume to 0x00 (LHV_MIN) -> 0x7f (LHV_MAX)
+ // volume range
+ volume = ((val * OUTPUT_VOLUME_RANGE) / 100) + OUTPUT_VOLUME_MIN;
+
+ // R/LHV[6:0] 1111111 (+6dB) to 0000000 (-73dB) in 1db steps,
+ // default 1111001 (0dB)
+ aic23_local.volume_reg &= ~OUTPUT_VOLUME_MASK;
+ aic23_local.volume_reg |= volume;
+ audio_aic23_write(LEFT_CHANNEL_VOLUME_ADDR, aic23_local.volume_reg);
+ audio_aic23_write(RIGHT_CHANNEL_VOLUME_ADDR, aic23_local.volume_reg);
+ break;
+
+ case SET_LINE:
+ // Convert 0 -> 100 volume to 0x0 (LIV_MIN) -> 0x1f (LIV_MAX)
+ // volume range
+ volume = ((val * INPUT_VOLUME_RANGE) / 100) + INPUT_VOLUME_MIN;
+
+ // R/LIV[4:0] 11111 (+12dB) to 00000 (-34.5dB) in 1.5dB steps,
+ // default 10111 (0dB)
+ aic23_local.input_volume_reg &= ~INPUT_VOLUME_MASK;
+ aic23_local.input_volume_reg |= volume;
+ audio_aic23_write(LEFT_LINE_VOLUME_ADDR, aic23_local.input_volume_reg);
+ audio_aic23_write(RIGHT_LINE_VOLUME_ADDR, aic23_local.input_volume_reg);
+ break;
+ }
+ return 0;
+}
+
+static int mixer_open(struct inode *inode, struct file *file)
+{
+ /* Any mixer specific initialization */
+
+ return 0;
+}
+
+static int mixer_release(struct inode *inode, struct file *file)
+{
+ /* Any mixer specific Un-initialization */
+
+ return 0;
+}
+
+static int
+mixer_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
+{
+ int val;
+ int ret = 0;
+ int nr = _IOC_NR(cmd);
+
+ /*
+ * We only accept mixer (type 'M') ioctls.
+ */
+ if (_IOC_TYPE(cmd) != 'M')
+ return -EINVAL;
+
+ DPRINTK(" 0x%08x\n", cmd);
+
+ if (cmd == SOUND_MIXER_INFO) {
+ struct mixer_info mi;
+
+ strncpy(mi.id, "AIC23", sizeof(mi.id));
+ strncpy(mi.name, "TI AIC23", sizeof(mi.name));
+ mi.modify_counter = aic23_local.mod_cnt;
+ return copy_to_user((void *)arg, &mi, sizeof(mi));
+ }
+
+ if (_IOC_DIR(cmd) & _IOC_WRITE) {
+ ret = get_user(val, (int *)arg);
+ if (ret)
+ goto out;
+
+
+ switch (nr) {
+ case SOUND_MIXER_VOLUME:
+ aic23_local.volume = val;
+ aic23_local.mod_cnt++;
+ ret = aic23_update(SET_VOLUME, val);
+ break;
+
+ case SOUND_MIXER_LINE:
+ aic23_local.line = val;
+ aic23_local.mod_cnt++;
+ ret = aic23_update(SET_LINE, val);
+ break;
+
+ case SOUND_MIXER_MIC:
+ aic23_local.mic = val;
+ aic23_local.mod_cnt++;
+ ret = aic23_update(SET_LINE, val);
+ break;
+
+ case SOUND_MIXER_RECSRC:
+ break;
+
+ default:
+ ret = -EINVAL;
+ }
+ }
+
+ if (ret == 0 && _IOC_DIR(cmd) & _IOC_READ) {
+ ret = 0;
+
+ switch (nr) {
+ case SOUND_MIXER_VOLUME:
+ val = aic23_local.volume;
+ break;
+ case SOUND_MIXER_LINE:
+ val = aic23_local.line;
+ break;
+ case SOUND_MIXER_MIC:
+ val = aic23_local.mic;
+ break;
+ case SOUND_MIXER_RECSRC:
+ val = REC_MASK;
+ break;
+ case SOUND_MIXER_RECMASK:
+ val = REC_MASK;
+ break;
+ case SOUND_MIXER_DEVMASK:
+ val = DEV_MASK;
+ break;
+ case SOUND_MIXER_CAPS:
+ val = 0;
+ break;
+ case SOUND_MIXER_STEREODEVS:
+ val = 0;
+ break;
+ default:
+ val = 0;
+ ret = -EINVAL;
+ break;
+ }
+
+ if (ret == 0)
+ ret = put_user(val, (int *)arg);
+ }
+out:
+ return ret;
+
+}
+
+int omap_set_samplerate(long sample_rate)
+{
+ u8 count = 0;
+ u16 data = 0;
+ /* wait for any frame to complete */
+ udelay(125);
+
+ /* Search for the right sample rate */
+ while ((reg_info[count].sample_rate != sample_rate) &&
+ (count < NUMBER_SAMPLE_RATES_SUPPORTED)) {
+ count++;
+ }
+ if (count == NUMBER_SAMPLE_RATES_SUPPORTED) {
+ printk(KERN_ERR "Invalid Sample Rate %d requested\n",
+ (int)sample_rate);
+ return -EPERM;
+ }
+
+ if (machine_is_omap_innovator()) {
+ /* set the CODEC clock input source to 12.000MHz */
+ fpga_write(fpga_read(OMAP1510_FPGA_POWER) & ~0x01,
+ OMAP1510_FPGA_POWER);
+ }
+
+ data = (reg_info[count].divider << CLKIN_SHIFT) |
+ (reg_info[count].control << BOSR_SHIFT) | USB_CLK_ON;
+
+ audio_aic23_write(SAMPLE_RATE_CONTROL_ADDR, data);
+
+ audio_samplerate = sample_rate;
+
+#ifndef AIC23_MASTER
+ {
+ int clkgdv = 0;
+ /*
+ Set Sample Rate at McBSP
+
+ Formula :
+ Codec System Clock = CODEC_CLOCK, or half if clock_divider = 1;
+ clkgdv = ((Codec System Clock / (SampleRate * BitsPerSample * 2)) - 1);
+
+ FWID = BitsPerSample - 1;
+ FPER = (BitsPerSample * 2) - 1;
+ */
+ if (reg_info[count].divider)
+ clkgdv = CODEC_CLOCK / 2;
+ else
+ clkgdv = CODEC_CLOCK;
+
+ clkgdv = (clkgdv / (sample_rate * DEFAULT_BITPERSAMPLE * 2)) - 1;
+
+ initial_config.srgr1 = (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
+
+ initial_config.srgr2 =
+ (CLKSM | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1));
+
+ omap_mcbsp_config(AUDIO_MCBSP, &initial_config);
+ }
+#endif /* AIC23_MASTER */
+
+ return 0;
+}
+
+static void omap_aic23_initialize(void *dummy)
+{
+ DPRINTK("entry\n");
+
+ /* initialize with default sample rate */
+ audio_samplerate = AUDIO_RATE_DEFAULT;
+
+ omap_mcbsp_request(AUDIO_MCBSP);
+
+ /* if configured, then stop mcbsp */
+ omap_mcbsp_stop(AUDIO_MCBSP);
+
+ omap_mcbsp_config(AUDIO_MCBSP, &initial_config);
+ omap_mcbsp_start(AUDIO_MCBSP);
+ aic23_configure();
+
+ DPRINTK("exit\n");
+}
+
+static void omap_aic23_shutdown(void *dummy)
+{
+ /*
+ Turn off codec after it is done.
+ Can't do it immediately, since it may still have
+ buffered data.
+
+ Wait 20ms (arbitrary value) and then turn it off.
+ */
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(2);
+
+ omap_mcbsp_stop(AUDIO_MCBSP);
+ omap_mcbsp_free(AUDIO_MCBSP);
+
+ audio_aic23_write(RESET_CONTROL_ADDR, 0);
+ audio_aic23_write(POWER_DOWN_CONTROL_ADDR, 0xff);
+}
+
+static inline void aic23_configure()
+{
+ /* Reset codec */
+ audio_aic23_write(RESET_CONTROL_ADDR, 0);
+
+ /* Initialize the AIC23 internal state */
+
+ /* Left/Right line input volume control */
+ aic23_local.line = DEFAULT_INPUT_VOLUME;
+ aic23_local.mic = DEFAULT_INPUT_VOLUME;
+ aic23_update(SET_LINE, DEFAULT_INPUT_VOLUME);
+
+ /* Left/Right headphone channel volume control */
+ /* Zero-cross detect on */
+ aic23_local.volume_reg = LZC_ON;
+ aic23_update(SET_VOLUME, aic23_local.volume);
+
+ /* Analog audio path control, DAC selected, delete INSEL_MIC for line in */
+ audio_aic23_write(ANALOG_AUDIO_CONTROL_ADDR, DAC_SELECTED | INSEL_MIC);
+
+ /* Digital audio path control, de-emphasis control 44.1kHz */
+ audio_aic23_write(DIGITAL_AUDIO_CONTROL_ADDR, DEEMP_44K);
+
+ /* Power control, everything is on */
+ audio_aic23_write(POWER_DOWN_CONTROL_ADDR, 0);
+
+ /* Digital audio interface, master/slave mode, I2S, 16 bit */
+#ifdef AIC23_MASTER
+ audio_aic23_write(DIGITAL_AUDIO_FORMAT_ADDR, MS_MASTER | IWL_16 | FOR_DSP);
+#else
+ audio_aic23_write(DIGITAL_AUDIO_FORMAT_ADDR, IWL_16 | FOR_DSP);
+#endif /* AIC23_MASTER */
+
+ /* Enable digital interface */
+ audio_aic23_write(DIGITAL_INTERFACE_ACT_ADDR, ACT_ON);
+
+ /* clock configuration */
+ omap_set_samplerate(audio_samplerate);
+}
+
+static int
+omap_aic23_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
+{
+ long val;
+ int ret = 0;
+
+ DPRINTK(" 0x%08x\n", cmd);
+
+ /*
+ * These are platform dependent ioctls which are not handled by the
+ * generic omap-audio module.
+ */
+ switch (cmd) {
+ case SNDCTL_DSP_STEREO:
+ ret = get_user(val, (int *)arg);
+ if (ret)
+ return ret;
+ /* the AIC23 is stereo only */
+ ret = (val == 0) ? -EINVAL : 1;
+ return put_user(ret, (int *)arg);
+
+ case SNDCTL_DSP_CHANNELS:
+ case SOUND_PCM_READ_CHANNELS:
+ /* the AIC23 is stereo only */
+ return put_user(2, (long *)arg);
+
+ case SNDCTL_DSP_SPEED:
+ ret = get_user(val, (long *)arg);
+ if (ret)
+ break;
+ ret = omap_set_samplerate(val);
+ if (ret)
+ break;
+ /* fall through */
+
+ case SOUND_PCM_READ_RATE:
+ return put_user(audio_samplerate, (long *)arg);
+
+ case SOUND_PCM_READ_BITS:
+ case SNDCTL_DSP_SETFMT:
+ case SNDCTL_DSP_GETFMTS:
+ /* we can do 16-bit only */
+ return put_user(AFMT_S16_LE, (long *)arg);
+
+ default:
+ /* Maybe this is meant for the mixer (As per OSS Docs) */
+ return mixer_ioctl(inode, file, cmd, arg);
+ }
+
+ return ret;
+}
+
+static int omap_aic23_probe(void)
+{
+ /* Get the fops from audio oss driver */
+ if (!(omap_audio_fops = audio_get_fops())) {
+ printk(KERN_ERR "Unable to get the file operations for AIC23 OSS driver\n");
+ audio_unregister_codec(&aic23_state);
+ return -EPERM;
+ }
+
+ aic23_local.volume = DEFAULT_OUTPUT_VOLUME;
+
+ /* register devices */
+ audio_dev_id = register_sound_dsp(omap_audio_fops, -1);
+ mixer_dev_id = register_sound_mixer(&omap_mixer_fops, -1);
+
+#ifdef CONFIG_PROC_FS
+ create_proc_read_entry(PROC_START_FILE, 0 /* default mode */ ,
+ NULL /* parent dir */ ,
+ codec_start, NULL /* client data */ );
+
+ create_proc_read_entry(PROC_STOP_FILE, 0 /* default mode */ ,
+ NULL /* parent dir */ ,
+ codec_stop, NULL /* client data */ );
+#endif
+
+ /* Announcement Time */
+ printk(KERN_INFO PLATFORM_NAME " " CODEC_NAME
+ " audio support initialized\n");
+ return 0;
+}
+
+#ifdef MODULE
+static void __exit omap_aic23_remove(void)
+{
+ /* Un-Register the codec with the audio driver */
+ unregister_sound_dsp(audio_dev_id);
+ unregister_sound_mixer(mixer_dev_id);
+
+#ifdef CONFIG_PROC_FS
+ remove_proc_entry(PROC_START_FILE, NULL);
+ remove_proc_entry(PROC_STOP_FILE, NULL);
+#endif
+}
+#endif /* MODULE */
+
+static int omap_aic23_suspend(void)
+{
+ /* Empty for the moment */
+ return 0;
+}
+
+static int omap_aic23_resume(void)
+{
+ /* Empty for the moment */
+ return 0;
+}
+
+static int __init audio_aic23_init(void)
+{
+
+ int err = 0;
+
+ if (machine_is_omap_h2() || machine_is_omap_h3())
+ return -ENODEV;
+
+ mutex_init(&aic23_state.mutex);
+
+ if (machine_is_omap_osk()) {
+ /* Set MCLK to be clock input for AIC23 */
+ aic23_mclk = clk_get(0, "mclk");
+
+ if(clk_get_rate( aic23_mclk) != CODEC_CLOCK){
+ /* MCLK ist not at CODEC_CLOCK */
+ if( clk_get_usecount(aic23_mclk) > 0 ){
+ /* MCLK is already in use */
+ printk(KERN_WARNING "MCLK in use at %d Hz. We change it to %d Hz\n",
+ (uint)clk_get_rate( aic23_mclk), CODEC_CLOCK);
+ }
+ if( clk_set_rate( aic23_mclk, CODEC_CLOCK ) ){
+ printk(KERN_ERR "Cannot set MCLK for AIC23 CODEC\n");
+ return -ECANCELED;
+ }
+ }
+
+ clk_enable( aic23_mclk );
+
+ DPRINTK("MCLK = %d [%d], usecount = %d\n",(uint)clk_get_rate( aic23_mclk ),
+ CODEC_CLOCK, clk_get_usecount( aic23_mclk));
+ }
+
+ if (machine_is_omap_innovator()) {
+ u8 fpga;
+ /*
+ Turn on chip select for CODEC (shared with touchscreen).
+ Don't turn it back off, in case touch screen needs it.
+ */
+ fpga = fpga_read(OMAP1510_FPGA_TOUCHSCREEN);
+ fpga |= 0x4;
+ fpga_write(fpga, OMAP1510_FPGA_TOUCHSCREEN);
+ }
+
+ /* register the codec with the audio driver */
+ if ((err = audio_register_codec(&aic23_state))) {
+ printk(KERN_ERR
+ "Failed to register AIC23 driver with Audio OSS Driver\n");
+ }
+
+ return err;
+}
+
+static void __exit audio_aic23_exit(void)
+{
+ (void)audio_unregister_codec(&aic23_state);
+ return;
+}
+
+#ifdef CONFIG_PROC_FS
+static int codec_start(char *buf, char **start, off_t offset, int count,
+ int *eof, void *data)
+{
+ void *foo = NULL;
+
+ omap_aic23_initialize(foo);
+
+ printk("AIC23 codec initialization done.\n");
+ return 0;
+}
+static int codec_stop(char *buf, char **start, off_t offset, int count,
+ int *eof, void *data)
+{
+ void *foo = NULL;
+
+ omap_aic23_shutdown(foo);
+
+ printk("AIC23 codec shutdown.\n");
+ return 0;
+}
+#endif /* CONFIG_PROC_FS */
+
+module_init(audio_aic23_init);
+module_exit(audio_aic23_exit);
+
+MODULE_AUTHOR("Dirk Behme <dirk.behme@de.bosch.com>");
+MODULE_DESCRIPTION("Glue audio driver for the TI AIC23 codec.");
+MODULE_LICENSE("GPL");
--- /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/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/poll.h>
+#include <linux/pm.h>
+#include <linux/errno.h>
+#include <linux/sound.h>
+#include <linux/soundcard.h>
+#include <linux/sysrq.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/completion.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/semaphore.h>
+
+#include <asm/arch/dma.h>
+#include "omap-audio-dma-intfc.h"
+
+#include <asm/arch/mcbsp.h>
+
+#include "omap-audio.h"
+
+#undef DEBUG
+//#define DEBUG
+#ifdef DEBUG
+#define DPRINTK(ARGS...) printk(KERN_INFO "<%s>: ",__FUNCTION__);printk(ARGS)
+#define FN_IN printk(KERN_INFO "[%s]: start\n", __FUNCTION__)
+#define FN_OUT(n) printk(KERN_INFO "[%s]: end(%u)\n",__FUNCTION__, n)
+#else
+
+#define DPRINTK( x... )
+#define FN_IN
+#define FN_OUT(x)
+#endif
+
+#define ERR(ARGS...) printk(KERN_ERR "{%s}-ERROR: ", __FUNCTION__);printk(ARGS);
+
+#define AUDIO_NAME "omap-audio"
+#define AUDIO_NBFRAGS_DEFAULT 8
+#define AUDIO_FRAGSIZE_DEFAULT 8192
+
+#define AUDIO_ACTIVE(state) ((state)->rd_ref || (state)->wr_ref)
+
+#define SPIN_ADDR (dma_addr_t)0
+#define SPIN_SIZE 2048
+
+/* Channel Queue Handling macros
+ * tail always points to the current free entry
+ * Head always points to the current entry being used
+ * end is either head or tail
+ */
+
+#define AUDIO_QUEUE_INIT(s) s->dma_q_head = s->dma_q_tail = s->dma_q_count = 0;
+#define AUDIO_QUEUE_FULL(s) (nr_linked_channels == s->dma_q_count)
+#define AUDIO_QUEUE_LAST(s) (1 == s->dma_q_count)
+#define AUDIO_QUEUE_EMPTY(s) (0 == s->dma_q_count)
+#define __AUDIO_INCREMENT_QUEUE(end) ((end)=((end)+1) % nr_linked_channels)
+#define AUDIO_INCREMENT_HEAD(s) __AUDIO_INCREMENT_QUEUE(s->dma_q_head); s->dma_q_count--;
+#define AUDIO_INCREMENT_TAIL(s) __AUDIO_INCREMENT_QUEUE(s->dma_q_tail); s->dma_q_count++;
+
+/* DMA buffer fragmentation sizes */
+#define MAX_DMA_SIZE 0x1000000
+#define CUT_DMA_SIZE 0x1000
+/* TODO: To be moved to more appropriate location */
+#define DCSR_ERROR 0x3
+#define DCSR_SYNC_SET (1 << 6)
+
+#define DCCR_FS (1 << 5)
+#define DCCR_PRIO (1 << 6)
+#define DCCR_EN (1 << 7)
+#define DCCR_AI (1 << 8)
+#define DCCR_REPEAT (1 << 9)
+/* if 0 the channel works in 3.1 compatible mode*/
+#define DCCR_N31COMP (1 << 10)
+#define DCCR_EP (1 << 11)
+#define DCCR_SRC_AMODE_BIT 12
+#define DCCR_SRC_AMODE_MASK (0x3<<12)
+#define DCCR_DST_AMODE_BIT 14
+#define DCCR_DST_AMODE_MASK (0x3<<14)
+#define AMODE_CONST 0x0
+#define AMODE_POST_INC 0x1
+#define AMODE_SINGLE_INDEX 0x2
+#define AMODE_DOUBLE_INDEX 0x3
+
+/**************************** DATA STRUCTURES *****************************************/
+
+static spinlock_t dma_list_lock = SPIN_LOCK_UNLOCKED;
+
+struct audio_isr_work_item {
+ int current_lch;
+ u16 ch_status;
+ audio_stream_t *s;
+};
+
+static char work_item_running = 0;
+static char nr_linked_channels = 1;
+static struct audio_isr_work_item work1, work2;
+
+
+/*********************************** MODULE SPECIFIC FUNCTIONS PROTOTYPES *************/
+
+static void audio_dsr_handler(unsigned long);
+static DECLARE_TASKLET(audio_isr_work1, audio_dsr_handler,
+ (unsigned long)&work1);
+static DECLARE_TASKLET(audio_isr_work2, audio_dsr_handler,
+ (unsigned long)&work2);
+
+static void sound_dma_irq_handler(int lch, u16 ch_status, void *data);
+static void audio_dma_callback(int lch, u16 ch_status, void *data);
+static int omap_start_sound_dma(audio_stream_t * s, dma_addr_t dma_ptr,
+ u_int size);
+static int audio_set_dma_params_play(int channel, dma_addr_t dma_ptr,
+ u_int dma_size);
+static int audio_set_dma_params_capture(int channel, dma_addr_t dma_ptr,
+ u_int dma_size);
+static int audio_start_dma_chain(audio_stream_t * s);
+
+/*********************************** GLOBAL FUNCTIONS DEFINTIONS ***********************/
+
+/***************************************************************************************
+ *
+ * Buffer creation/destruction
+ *
+ **************************************************************************************/
+int audio_setup_buf(audio_stream_t * s)
+{
+ int frag;
+ int dmasize = 0;
+ char *dmabuf = NULL;
+ dma_addr_t dmaphys = 0;
+ FN_IN;
+ if (s->buffers) {
+ FN_OUT(1);
+ return -EBUSY;
+ }
+ s->buffers = kmalloc(sizeof(audio_buf_t) * s->nbfrags, GFP_KERNEL);
+ if (!s->buffers)
+ goto err;
+ memset(s->buffers, 0, sizeof(audio_buf_t) * s->nbfrags);
+ for (frag = 0; frag < s->nbfrags; frag++) {
+ audio_buf_t *b = &s->buffers[frag];
+ /*
+ * Let's allocate non-cached memory for DMA buffers.
+ * We try to allocate all memory at once.
+ * If this fails (a common reason is memory fragmentation),
+ * then we allocate more smaller buffers.
+ */
+ if (!dmasize) {
+ dmasize = (s->nbfrags - frag) * s->fragsize;
+ do {
+ dmabuf =
+ dma_alloc_coherent(NULL, dmasize, &dmaphys,
+ 0);
+ if (!dmabuf)
+ dmasize -= s->fragsize;
+ }
+ while (!dmabuf && dmasize);
+ if (!dmabuf)
+ goto err;
+ b->master = dmasize;
+ memzero(dmabuf, dmasize);
+ }
+ b->data = dmabuf;
+ b->dma_addr = dmaphys;
+ dmabuf += s->fragsize;
+ dmaphys += s->fragsize;
+ dmasize -= s->fragsize;
+ }
+ s->usr_head = s->dma_head = s->dma_tail = 0;
+ AUDIO_QUEUE_INIT(s);
+ s->started = 0;
+ s->bytecount = 0;
+ s->fragcount = 0;
+ init_completion(&s->wfc);
+ s->wfc.done = s->nbfrags;
+ FN_OUT(0);
+ return 0;
+ err:
+ audio_discard_buf(s);
+ FN_OUT(1);
+ return -ENOMEM;
+}
+
+void audio_discard_buf(audio_stream_t * s)
+{
+ FN_IN;
+ /* ensure DMA isn't using those buffers */
+ audio_reset(s);
+ if (s->buffers) {
+ int frag;
+ for (frag = 0; frag < s->nbfrags; frag++) {
+ if (!s->buffers[frag].master)
+ continue;
+ dma_free_coherent(NULL,
+ s->buffers[frag].master,
+ s->buffers[frag].data,
+ s->buffers[frag].dma_addr);
+ }
+ kfree(s->buffers);
+ s->buffers = NULL;
+ }
+ FN_OUT(0);
+}
+
+/***************************************************************************************
+ *
+ * DMA channel requests
+ *
+ **************************************************************************************/
+static void omap_sound_dma_link_lch(void *data)
+{
+ audio_stream_t *s = (audio_stream_t *) data;
+ int *chan = s->lch;
+ int i;
+
+ FN_IN;
+ if (s->linked) {
+ FN_OUT(1);
+ return;
+ }
+ for (i = 0; i < nr_linked_channels; i++) {
+ int cur_chan = chan[i];
+ int nex_chan =
+ ((nr_linked_channels - 1 ==
+ i) ? chan[0] : chan[i + 1]);
+ omap_dma_link_lch(cur_chan, nex_chan);
+ }
+ s->linked = 1;
+ FN_OUT(0);
+}
+
+int
+omap_request_sound_dma(int device_id, const char *device_name, void *data,
+ int **channels)
+{
+ int i, err = 0;
+ int *chan = NULL;
+ FN_IN;
+ if (unlikely((NULL == channels) || (NULL == device_name))) {
+ BUG();
+ return -EPERM;
+ }
+ /* Try allocate memory for the num channels */
+ *channels =
+ (int *)kmalloc(sizeof(int) * nr_linked_channels,
+ GFP_KERNEL);
+ chan = *channels;
+ if (NULL == chan) {
+ ERR("No Memory for channel allocs!\n");
+ FN_OUT(-ENOMEM);
+ return -ENOMEM;
+ }
+ spin_lock(&dma_list_lock);
+ for (i = 0; i < nr_linked_channels; i++) {
+ err =
+ omap_request_dma(device_id, device_name,
+ sound_dma_irq_handler, data, &chan[i]);
+ /* Handle Failure condition here */
+ if (err < 0) {
+ int j;
+ for (j = 0; j < i; j++) {
+ omap_free_dma(chan[j]);
+ }
+ spin_unlock(&dma_list_lock);
+ kfree(chan);
+ *channels = NULL;
+ ERR("Error in requesting channel %d=0x%x\n", i, err);
+ FN_OUT(err);
+ return err;
+ }
+ }
+
+ /* Chain the channels together */
+ if (!cpu_is_omap15xx())
+ omap_sound_dma_link_lch(data);
+
+ spin_unlock(&dma_list_lock);
+ FN_OUT(0);
+ return 0;
+}
+
+/***************************************************************************************
+ *
+ * DMA channel requests Freeing
+ *
+ **************************************************************************************/
+static void omap_sound_dma_unlink_lch(void *data)
+{
+ audio_stream_t *s = (audio_stream_t *) data;
+ int *chan = s->lch;
+ int i;
+
+ FN_IN;
+ if (!s->linked) {
+ FN_OUT(1);
+ return;
+ }
+ for (i = 0; i < nr_linked_channels; i++) {
+ int cur_chan = chan[i];
+ int nex_chan =
+ ((nr_linked_channels - 1 ==
+ i) ? chan[0] : chan[i + 1]);
+ omap_dma_unlink_lch(cur_chan, nex_chan);
+ }
+ s->linked = 0;
+ FN_OUT(0);
+}
+
+int omap_free_sound_dma(void *data, int **channels)
+{
+ int i;
+ int *chan = NULL;
+ FN_IN;
+ if (unlikely(NULL == channels)) {
+ BUG();
+ return -EPERM;
+ }
+ if (unlikely(NULL == *channels)) {
+ BUG();
+ return -EPERM;
+ }
+ chan = (*channels);
+
+ if (!cpu_is_omap15xx())
+ omap_sound_dma_unlink_lch(data);
+ for (i = 0; i < nr_linked_channels; i++) {
+ int cur_chan = chan[i];
+ omap_stop_dma(cur_chan);
+ omap_free_dma(cur_chan);
+ }
+ kfree(*channels);
+ *channels = NULL;
+ FN_OUT(0);
+ return 0;
+}
+
+/***************************************************************************************
+ *
+ * Process DMA requests - This will end up starting the transfer. Proper fragments of
+ * Transfers will be initiated.
+ *
+ **************************************************************************************/
+int audio_process_dma(audio_stream_t * s)
+{
+ int ret = 0;
+ unsigned long flags;
+ FN_IN;
+
+ /* Dont let the ISR over ride touching the in_use flag */
+ local_irq_save(flags);
+ if (1 == s->in_use) {
+ local_irq_restore(flags);
+ ERR("Called again while In Use\n");
+ return 0;
+ }
+ s->in_use = 1;
+ local_irq_restore(flags);
+
+ if (s->stopped)
+ goto spin;
+
+ if (s->dma_spinref > 0 && s->pending_frags) {
+ s->dma_spinref = 0;
+ DMA_CLEAR(s);
+ }
+ while (s->pending_frags) {
+ audio_buf_t *b = &s->buffers[s->dma_head];
+ u_int dma_size = s->fragsize - b->offset;
+ if (dma_size > MAX_DMA_SIZE)
+ dma_size = CUT_DMA_SIZE;
+ ret =
+ omap_start_sound_dma(s, b->dma_addr + b->offset, dma_size);
+ if (ret) {
+ goto process_out;
+ }
+ b->dma_ref++;
+ b->offset += dma_size;
+ if (b->offset >= s->fragsize) {
+ s->pending_frags--;
+ if (++s->dma_head >= s->nbfrags)
+ s->dma_head = 0;
+ }
+ }
+ spin:
+ if (s->spin_idle) {
+ int spincnt = 0;
+ ERR("we are spinning\n");
+ while (omap_start_sound_dma(s, SPIN_ADDR, SPIN_SIZE) == 0)
+ spincnt++;
+ /*
+ * Note: if there is still a data buffer being
+ * processed then the ref count is negative. This
+ * allows for the DMA termination to be accounted in
+ * the proper order. Of course dma_spinref can't be
+ * greater than 0 if dma_ref is not 0 since we kill
+ * the spinning above as soon as there is real data to process.
+ */
+ if (s->buffers && s->buffers[s->dma_tail].dma_ref)
+ spincnt = -spincnt;
+ s->dma_spinref += spincnt;
+ }
+
+ process_out:
+ s->in_use = 0;
+
+ FN_OUT(ret);
+ return ret;
+}
+
+/***************************************************************************************
+ *
+ * Prime Rx - Since the recieve buffer has no time limit as to when it would arrive,
+ * we need to prime it
+ *
+ **************************************************************************************/
+void audio_prime_rx(audio_state_t * state)
+{
+ audio_stream_t *is = state->input_stream;
+
+ FN_IN;
+ if (state->need_tx_for_rx) {
+ /*
+ * With some codecs like the Philips UDA1341 we must ensure
+ * there is an output stream at any time while recording since
+ * this is how the UDA1341 gets its clock from the SA1100.
+ * So while there is no playback data to send, the output DMA
+ * will spin with all zeroes. We use the cache flush special
+ * area for that.
+ */
+ state->output_stream->spin_idle = 1;
+ audio_process_dma(state->output_stream);
+ }
+ is->pending_frags = is->nbfrags;
+ init_completion(&is->wfc);
+ is->wfc.done = 0;
+
+ is->active = 1;
+ audio_process_dma(is);
+
+ FN_OUT(0);
+ return;
+}
+
+/***************************************************************************************
+ *
+ * set the fragment size
+ *
+ **************************************************************************************/
+int audio_set_fragments(audio_stream_t * s, int val)
+{
+ FN_IN;
+ if (s->active)
+ return -EBUSY;
+ if (s->buffers)
+ audio_discard_buf(s);
+ s->nbfrags = (val >> 16) & 0x7FFF;
+ val &= 0xFFFF;
+ if (val < 4)
+ val = 4;
+ if (val > 15)
+ val = 15;
+ s->fragsize = 1 << val;
+ if (s->nbfrags < 2)
+ s->nbfrags = 2;
+ if (s->nbfrags * s->fragsize > 128 * 1024)
+ s->nbfrags = 128 * 1024 / s->fragsize;
+ FN_OUT(0);
+ if (audio_setup_buf(s))
+ return -ENOMEM;
+ return val | (s->nbfrags << 16);
+
+}
+
+/***************************************************************************************
+ *
+ * Sync up the buffers before we shutdown, else under-run errors will happen
+ *
+ **************************************************************************************/
+int audio_sync(struct file *file)
+{
+ audio_state_t *state = file->private_data;
+ audio_stream_t *s = state->output_stream;
+ audio_buf_t *b;
+ u_int shiftval = 0;
+ unsigned long flags;
+
+ DECLARE_WAITQUEUE(wait, current);
+
+ FN_IN;
+
+ if (!(file->f_mode & FMODE_WRITE) || !s->buffers || s->mapped) {
+ FN_OUT(1);
+ return 0;
+ }
+
+ /*
+ * Send current buffer if it contains data. Be sure to send
+ * a full sample count.
+ */
+ b = &s->buffers[s->usr_head];
+ if (b->offset &= ~3) {
+ /* Wait for a buffer to become free */
+ if (wait_for_completion_interruptible(&s->wfc))
+ return 0;
+ /*
+ * HACK ALERT !
+ * To avoid increased complexity in the rest of the code
+ * where full fragment sizes are assumed, we cheat a little
+ * with the start pointer here and don't forget to restore
+ * it later.
+ */
+
+ /* As this is a last frag we need only one dma channel
+ * to complete. So it's need to unlink dma channels
+ * to avoid empty dma work.
+ */
+ if (!cpu_is_omap15xx() && AUDIO_QUEUE_EMPTY(s))
+ omap_sound_dma_unlink_lch(s);
+
+ shiftval = s->fragsize - b->offset;
+ b->offset = shiftval;
+ b->dma_addr -= shiftval;
+ b->data -= shiftval;
+ local_irq_save(flags);
+ s->bytecount -= shiftval;
+ if (++s->usr_head >= s->nbfrags)
+ s->usr_head = 0;
+
+ s->pending_frags++;
+ audio_process_dma(s);
+ local_irq_restore(flags);
+ }
+
+ /* Let's wait for all buffers to complete */
+ set_current_state(TASK_INTERRUPTIBLE);
+ add_wait_queue(&s->wq, &wait);
+ while ((s->pending_frags || (s->wfc.done < s->nbfrags))
+ && !signal_pending(current)) {
+ schedule();
+ set_current_state(TASK_INTERRUPTIBLE);
+ }
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&s->wq, &wait);
+
+ /* undo the pointer hack above */
+ if (shiftval) {
+ local_irq_save(flags);
+ b->dma_addr += shiftval;
+ b->data += shiftval;
+ /* ensure sane DMA code behavior if not yet processed */
+ if (b->offset != 0)
+ b->offset = s->fragsize;
+ local_irq_restore(flags);
+ }
+
+ FN_OUT(0);
+ return 0;
+}
+
+/***************************************************************************************
+ *
+ * Stop all the DMA channels of the stream
+ *
+ **************************************************************************************/
+void audio_stop_dma(audio_stream_t * s)
+{
+ int *chan = s->lch;
+ int i;
+ FN_IN;
+ if (unlikely(NULL == chan)) {
+ BUG();
+ return;
+ }
+ for (i = 0; i < nr_linked_channels; i++) {
+ int cur_chan = chan[i];
+ omap_stop_dma(cur_chan);
+ }
+ s->started = 0;
+ FN_OUT(0);
+ return;
+}
+
+/***************************************************************************************
+ *
+ * Get the dma posn
+ *
+ **************************************************************************************/
+u_int audio_get_dma_pos(audio_stream_t * s)
+{
+ audio_buf_t *b = &s->buffers[s->dma_tail];
+ u_int offset;
+
+ FN_IN;
+ if (b->dma_ref) {
+ offset = omap_get_dma_src_pos(s->lch[s->dma_q_head]) - b->dma_addr;
+ if (offset >= s->fragsize)
+ offset = s->fragsize - 4;
+ } else if (s->pending_frags) {
+ offset = b->offset;
+ } else {
+ offset = 0;
+ }
+ FN_OUT(offset);
+ return offset;
+}
+
+/***************************************************************************************
+ *
+ * Reset the audio buffers
+ *
+ **************************************************************************************/
+void audio_reset(audio_stream_t * s)
+{
+ FN_IN;
+ if (s->buffers) {
+ audio_stop_dma(s);
+ s->buffers[s->dma_head].offset = 0;
+ s->buffers[s->usr_head].offset = 0;
+ s->usr_head = s->dma_head;
+ s->pending_frags = 0;
+ init_completion(&s->wfc);
+ s->wfc.done = s->nbfrags;
+ }
+ s->active = 0;
+ s->stopped = 0;
+ s->started = 0;
+ FN_OUT(0);
+ return;
+}
+
+/***************************************************************************************
+ *
+ * Clear any pending transfers
+ *
+ **************************************************************************************/
+void omap_clear_sound_dma(audio_stream_t * s)
+{
+ FN_IN;
+ omap_clear_dma(s->lch[s->dma_q_head]);
+ FN_OUT(0);
+ return;
+}
+
+/***************************************************************************************
+ *
+ * DMA related functions
+ *
+ **************************************************************************************/
+static int audio_set_dma_params_play(int channel, dma_addr_t dma_ptr,
+ u_int dma_size)
+{
+ int dt = 0x1; /* data type 16 */
+ int cen = 32; /* Stereo */
+ int cfn = dma_size / (2 * cen);
+ unsigned long dest_start;
+ int dest_port = 0;
+ int sync_dev = 0;
+
+ FN_IN;
+
+ if (cpu_is_omap15xx() || cpu_is_omap16xx()) {
+ dest_start = AUDIO_MCBSP_DATAWRITE;
+ dest_port = OMAP_DMA_PORT_MPUI;
+ }
+ if (cpu_is_omap24xx()) {
+ dest_start = AUDIO_MCBSP_DATAWRITE;
+ sync_dev = AUDIO_DMA_TX;
+ }
+
+ omap_set_dma_dest_params(channel, dest_port, OMAP_DMA_AMODE_CONSTANT, dest_start, 0, 0);
+ omap_set_dma_src_params(channel, 0, OMAP_DMA_AMODE_POST_INC, dma_ptr, 0, 0);
+ omap_set_dma_transfer_params(channel, dt, cen, cfn, OMAP_DMA_SYNC_ELEMENT, sync_dev, 0);
+
+ FN_OUT(0);
+ return 0;
+}
+
+static int audio_set_dma_params_capture(int channel, dma_addr_t dma_ptr,
+ u_int dma_size)
+{
+ int dt = 0x1; /* data type 16 */
+ int cen = 16; /* mono */
+ int cfn = dma_size / (2 * cen);
+ unsigned long src_start;
+ int src_port = 0;
+ int sync_dev = 0;
+ int src_sync = 0;
+
+ FN_IN;
+
+ if (cpu_is_omap15xx() || cpu_is_omap16xx()) {
+ src_start = AUDIO_MCBSP_DATAREAD;
+ src_port = OMAP_DMA_PORT_MPUI;
+ }
+ if (cpu_is_omap24xx()) {
+ src_start = AUDIO_MCBSP_DATAREAD;
+ sync_dev = AUDIO_DMA_RX;
+ src_sync = 1;
+ }
+
+ omap_set_dma_src_params(channel, src_port, OMAP_DMA_AMODE_CONSTANT, src_start, 0, 0);
+ omap_set_dma_dest_params(channel, 0, OMAP_DMA_AMODE_POST_INC, dma_ptr, 0, 0);
+ omap_set_dma_transfer_params(channel, dt, cen, cfn, OMAP_DMA_SYNC_ELEMENT, sync_dev, src_sync);
+
+ FN_OUT(0);
+ return 0;
+}
+
+static int audio_start_dma_chain(audio_stream_t * s)
+{
+ int channel = s->lch[s->dma_q_head];
+ FN_IN;
+ if (!s->started) {
+ s->hw_stop(); /* stops McBSP Interface */
+ omap_start_dma(channel);
+ s->started = 1;
+ s->hw_start(); /* start McBSP interface */
+ }
+ /* else the dma itself will progress forward with out our help */
+ FN_OUT(0);
+ return 0;
+}
+
+/* Start DMA -
+ * Do the initial set of work to initialize all the channels as required.
+ * We shall then initate a transfer
+ */
+static int omap_start_sound_dma(audio_stream_t * s, dma_addr_t dma_ptr,
+ u_int dma_size)
+{
+ int ret = -EPERM;
+
+ FN_IN;
+ if (unlikely(dma_size > MAX_DMA_SIZE)) {
+ ERR("DmaSoundDma: Start: overflowed %d-%d\n", dma_size,
+ MAX_DMA_SIZE);
+ return -EOVERFLOW;
+ }
+
+ if (AUDIO_QUEUE_FULL(s)) {
+ ret = -2;
+ goto sound_out;
+ }
+
+ if (s->input_or_output == FMODE_WRITE)
+ /*playback */
+ {
+ ret =
+ audio_set_dma_params_play(s->lch[s->dma_q_tail], dma_ptr,
+ dma_size);
+ } else {
+ ret =
+ audio_set_dma_params_capture(s->lch[s->dma_q_tail], dma_ptr,
+ dma_size);
+ }
+ if (ret != 0) {
+ ret = -2; /* indicate queue full */
+ goto sound_out;
+ }
+ AUDIO_INCREMENT_TAIL(s);
+ ret = audio_start_dma_chain(s);
+ if (ret) {
+ ERR("dma start failed");
+ }
+ sound_out:
+ FN_OUT(ret);
+ return ret;
+
+}
+
+/***************************************************************************************
+ *
+ * ISR related functions
+ *
+ **************************************************************************************/
+/* The work item handler */
+static void audio_dsr_handler(unsigned long inData)
+{
+ void *data = (void *)inData;
+ struct audio_isr_work_item *work = data;
+ audio_stream_t *s = (work->s);
+ int sound_curr_lch = work->current_lch;
+ u16 ch_status = work->ch_status;
+
+ FN_IN;
+ DPRINTK("lch=%d,status=0x%x, data=%p as=%p\n", sound_curr_lch,
+ ch_status, data, s);
+ if (AUDIO_QUEUE_EMPTY(s)) {
+ ERR("Interrupt(%d) for empty queue(h=%d, T=%d)???\n",
+ sound_curr_lch, s->dma_q_head, s->dma_q_tail);
+ ERR("nbfrag=%d,pendfrags=%d,USR-H=%d, QH-%d QT-%d\n",
+ s->nbfrags, s->pending_frags, s->usr_head, s->dma_head,
+ s->dma_tail);
+ FN_OUT(-1);
+ return;
+ }
+
+ AUDIO_INCREMENT_HEAD(s); /* Empty the queue */
+
+ /* Try to fill again */
+ audio_dma_callback(sound_curr_lch, ch_status, s);
+ FN_OUT(0);
+
+}
+
+/* Macro to trace the IRQ calls - checks for multi-channel irqs */
+//#define IRQ_TRACE
+#ifdef IRQ_TRACE
+#define MAX_UP 10
+static char xyz[MAX_UP] = { 0 };
+static int h = 0;
+#endif
+
+/* ISRs have to be short and smart.. So we transfer every heavy duty stuff to the
+ * work item
+ */
+static void sound_dma_irq_handler(int sound_curr_lch, u16 ch_status, void *data)
+{
+ int dma_status = ch_status;
+ audio_stream_t *s = (audio_stream_t *) data;
+ FN_IN;
+#ifdef IRQ_TRACE
+ xyz[h++] = '0' + sound_curr_lch;
+ if (h == MAX_UP - 1) {
+ printk("%s-", xyz);
+ h = 0;
+ }
+#endif
+ DPRINTK("lch=%d,status=0x%x, dma_status=%d, data=%p\n", sound_curr_lch,
+ ch_status, dma_status, data);
+
+ if (dma_status & (DCSR_ERROR)) {
+ if (cpu_is_omap15xx() || cpu_is_omap16xx())
+ OMAP_DMA_CCR_REG(sound_curr_lch) &= ~DCCR_EN;
+ ERR("DCSR_ERROR!\n");
+ FN_OUT(-1);
+ return;
+ }
+
+ if (AUDIO_QUEUE_LAST(s))
+ audio_stop_dma(s);
+
+ /* Start the work item - we ping pong the work items */
+ if (!work_item_running) {
+ work1.current_lch = sound_curr_lch;
+ work1.ch_status = ch_status;
+ work1.s = s;
+ /* schedule tasklet 1 */
+ tasklet_schedule(&audio_isr_work1);
+ work_item_running = 1;
+ } else {
+ work2.current_lch = sound_curr_lch;
+ work2.ch_status = ch_status;
+ work2.s = s;
+ /* schedule tasklet 2 */
+ tasklet_schedule(&audio_isr_work2);
+ work_item_running = 0;
+ }
+ FN_OUT(0);
+ return;
+}
+
+/* The call back that handles buffer stuff */
+static void audio_dma_callback(int lch, u16 ch_status, void *data)
+{
+ audio_stream_t *s = data;
+ audio_buf_t *b = &s->buffers[s->dma_tail];
+ FN_IN;
+
+ if (s->dma_spinref > 0) {
+ s->dma_spinref--;
+ } else if (!s->buffers) {
+ printk(KERN_CRIT
+ "omap_audio: received DMA IRQ for non existent buffers!\n");
+ return;
+ } else if (b->dma_ref && --b->dma_ref == 0 && b->offset >= s->fragsize) {
+ /* This fragment is done */
+ b->offset = 0;
+ s->bytecount += s->fragsize;
+ s->fragcount++;
+ s->dma_spinref = -s->dma_spinref;
+
+ if (++s->dma_tail >= s->nbfrags)
+ s->dma_tail = 0;
+
+ if (!s->mapped)
+ complete(&s->wfc);
+ else
+ s->pending_frags++;
+
+ wake_up(&s->wq);
+ }
+
+ audio_process_dma(s);
+
+ FN_OUT(0);
+ return;
+}
+
+/*********************************************************************************
+ *
+ * audio_get_dma_callback(): return the dma interface call back function
+ *
+ *********************************************************************************/
+dma_callback_t audio_get_dma_callback(void)
+{
+ FN_IN;
+ FN_OUT(0);
+ return audio_dma_callback;
+}
+
+static int __init audio_dma_init(void)
+{
+ if (!cpu_is_omap15xx())
+ nr_linked_channels = 2;
+
+ return 0;
+}
+
+static void __exit audio_dma_exit(void)
+{
+ /* Nothing */
+}
+
+module_init(audio_dma_init);
+module_exit(audio_dma_exit);
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("Common DMA handling for Audio driver on OMAP processors");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(omap_clear_sound_dma);
+EXPORT_SYMBOL(omap_request_sound_dma);
+EXPORT_SYMBOL(omap_free_sound_dma);
+
+EXPORT_SYMBOL(audio_get_dma_callback);
+EXPORT_SYMBOL(audio_setup_buf);
+EXPORT_SYMBOL(audio_process_dma);
+EXPORT_SYMBOL(audio_prime_rx);
+EXPORT_SYMBOL(audio_set_fragments);
+EXPORT_SYMBOL(audio_sync);
+EXPORT_SYMBOL(audio_stop_dma);
+EXPORT_SYMBOL(audio_get_dma_pos);
+EXPORT_SYMBOL(audio_reset);
+EXPORT_SYMBOL(audio_discard_buf);
--- /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 <linux/mutex.h>
+
+#include <asm/uaccess.h>
+#include <asm/hardware.h>
+#include <asm/arch/dma.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+
+#include <asm/arch/mux.h>
+#include <asm/arch/io.h>
+#include <asm/mach-types.h>
+
+#include "omap-audio.h"
+#include "omap-audio-dma-intfc.h"
+#include <asm/arch/mcbsp.h>
+#ifdef CONFIG_ARCH_OMAP16XX
+#include <../drivers/ssi/omap-uwire.h>
+#include <asm/arch/dsp_common.h>
+#elif defined(CONFIG_ARCH_OMAP24XX)
+#else
+#error "Unsupported configuration"
+#endif
+
+#include <asm/hardware/tsc2101.h>
+#include <../drivers/ssi/omap-tsc2101.h>
+
+/***************************** MACROS ************************************/
+
+#define PROC_SUPPORT
+
+#ifdef PROC_SUPPORT
+#include <linux/proc_fs.h>
+#define PROC_START_FILE "driver/tsc2101-audio-start"
+#define PROC_STOP_FILE "driver/tsc2101-audio-stop"
+#endif
+
+#define CODEC_NAME "TSC2101"
+
+#ifdef CONFIG_ARCH_OMAP16XX
+#define PLATFORM_NAME "OMAP16XX"
+#elif defined(CONFIG_ARCH_OMAP24XX)
+#define PLATFORM_NAME "OMAP2"
+#endif
+
+/* Define to set the tsc as the master w.r.t McBSP */
+#define TSC_MASTER
+
+/*
+ * AUDIO related MACROS
+ */
+#define DEFAULT_BITPERSAMPLE 16
+#define AUDIO_RATE_DEFAULT 44100
+#define PAGE2_AUDIO_CODEC_REGISTERS (2)
+#define LEAVE_CS 0x80
+
+/* Select the McBSP For Audio */
+/* 16XX is MCBSP1 and 24XX is MCBSP2*/
+/* see include/asm-arm/arch-omap/mcbsp.h */
+#ifndef AUDIO_MCBSP
+#error "UnSupported Configuration"
+#endif
+
+#define REC_MASK (SOUND_MASK_LINE | SOUND_MASK_MIC)
+#define DEV_MASK (REC_MASK | SOUND_MASK_VOLUME)
+
+#define SET_VOLUME 1
+#define SET_LINE 2
+#define SET_MIC 3
+#define SET_RECSRC 4
+
+#define DEFAULT_VOLUME 93
+#define DEFAULT_INPUT_VOLUME 20 /* An minimal volume */
+
+/* Tsc Audio Specific */
+#define NUMBER_SAMPLE_RATES_SUPPORTED 16
+#define OUTPUT_VOLUME_MIN 0x7F
+#define OUTPUT_VOLUME_MAX 0x32
+#define OUTPUT_VOLUME_RANGE (OUTPUT_VOLUME_MIN - OUTPUT_VOLUME_MAX)
+#define OUTPUT_VOLUME_MASK OUTPUT_VOLUME_MIN
+#define DEFAULT_VOLUME_LEVEL OUTPUT_VOLUME_MAX
+
+/* use input vol of 75 for 0dB gain */
+#define INPUT_VOLUME_MIN 0x0
+#define INPUT_VOLUME_MAX 0x7D
+#define INPUT_VOLUME_RANGE (INPUT_VOLUME_MAX - INPUT_VOLUME_MIN)
+#define INPUT_VOLUME_MASK INPUT_VOLUME_MAX
+
+/*********** Debug Macros ********/
+/* To Generate a rather shrill tone -test the entire path */
+//#define TONE_GEN
+/* To Generate a tone for each keyclick - test the tsc,spi paths*/
+//#define TEST_KEYCLICK
+/* To dump the tsc registers for debug */
+//#define TSC_DUMP_REGISTERS
+
+#ifdef DPRINTK
+#undef DPRINTK
+#endif
+#undef DEBUG
+
+//#define DEBUG
+#ifdef DEBUG
+#define DPRINTK(ARGS...) printk(KERN_INFO "<%s>: ",__FUNCTION__);printk(ARGS)
+#define FN_IN printk(KERN_INFO "[%s]: start\n", __FUNCTION__)
+#define FN_OUT(n) printk(KERN_INFO "[%s]: end(%u)\n",__FUNCTION__, n)
+#else
+#define DPRINTK( x... )
+#define FN_IN
+#define FN_OUT(n)
+#endif
+
+/***************************** Data Structures **********************************/
+
+static int audio_ifc_start(void)
+{
+ omap_mcbsp_start(AUDIO_MCBSP);
+ return 0;
+}
+
+static int audio_ifc_stop(void)
+{
+ omap_mcbsp_stop(AUDIO_MCBSP);
+ return 0;
+}
+
+static audio_stream_t output_stream = {
+ .id = "TSC2101 out",
+ .dma_dev = AUDIO_DMA_TX,
+ .input_or_output = FMODE_WRITE,
+ .hw_start = audio_ifc_start,
+ .hw_stop = audio_ifc_stop,
+};
+
+static audio_stream_t input_stream = {
+ .id = "TSC2101 in",
+ .dma_dev = AUDIO_DMA_RX,
+ .input_or_output = FMODE_READ,
+ .hw_start = audio_ifc_start,
+ .hw_stop = audio_ifc_stop,
+};
+
+static int audio_dev_id, mixer_dev_id;
+
+typedef struct {
+ u8 volume;
+ u8 line;
+ u8 mic;
+ int recsrc;
+ int mod_cnt;
+} tsc2101_local_info;
+
+static tsc2101_local_info tsc2101_local = {
+ volume: DEFAULT_VOLUME,
+ line: DEFAULT_INPUT_VOLUME,
+ mic: DEFAULT_INPUT_VOLUME,
+ recsrc: SOUND_MASK_LINE,
+ mod_cnt: 0
+};
+
+struct sample_rate_reg_info {
+ u16 sample_rate;
+ u8 divisor;
+ u8 fs_44kHz; /* if 0 48 khz, if 1 44.1 khz fsref */
+};
+
+/* To Store the default sample rate */
+static long audio_samplerate = AUDIO_RATE_DEFAULT;
+
+static const struct sample_rate_reg_info
+ reg_info[NUMBER_SAMPLE_RATES_SUPPORTED] = {
+ /* Div 1 */
+ {48000, 0, 0},
+ {44100, 0, 1},
+ /* Div 1.5 */
+ {32000, 1, 0},
+ {29400, 1, 1},
+ /* Div 2 */
+ {24000, 2, 0},
+ {22050, 2, 1},
+ /* Div 3 */
+ {16000, 3, 0},
+ {14700, 3, 1},
+ /* Div 4 */
+ {12000, 4, 0},
+ {11025, 4, 1},
+ /* Div 5 */
+ {9600, 5, 0},
+ {8820, 5, 1},
+ /* Div 5.5 */
+ {8727, 6, 0},
+ {8018, 6, 1},
+ /* Div 6 */
+ {8000, 7, 0},
+ {7350, 7, 1},
+};
+
+static struct omap_mcbsp_reg_cfg initial_config = {
+ .spcr2 = FREE | FRST | GRST | XRST | XINTM(3),
+ .spcr1 = RINTM(3) | RRST,
+ .rcr2 = RPHASE | RFRLEN2(OMAP_MCBSP_WORD_8) |
+ RWDLEN2(OMAP_MCBSP_WORD_16) | RDATDLY(1),
+ .rcr1 = RFRLEN1(OMAP_MCBSP_WORD_8) | RWDLEN1(OMAP_MCBSP_WORD_16),
+ .xcr2 = XPHASE | XFRLEN2(OMAP_MCBSP_WORD_8) |
+ XWDLEN2(OMAP_MCBSP_WORD_16) | XDATDLY(1) | XFIG,
+ .xcr1 = XFRLEN1(OMAP_MCBSP_WORD_8) | XWDLEN1(OMAP_MCBSP_WORD_16),
+ .srgr1 = FWID(15),
+ .srgr2 = GSYNC | CLKSP | FSGM | FPER(31),
+
+ /* platform specific initialization */
+#ifdef CONFIG_MACH_OMAP_H2
+ .pcr0 = CLKXM | CLKRM | FSXP | FSRP | CLKXP | CLKRP,
+#elif defined(CONFIG_MACH_OMAP_H3) || defined(CONFIG_MACH_OMAP_H4) || defined(CONFIG_MACH_OMAP_APOLLON)
+
+#ifndef TSC_MASTER
+ .pcr0 = FSXM | FSRM | CLKXM | CLKRM | CLKXP | CLKRP,
+#else
+ .pcr0 = CLKRM | SCLKME | FSXP | FSRP | CLKXP | CLKRP,
+#endif /* tsc Master defs */
+
+#endif /* platform specific inits */
+};
+
+/***************************** MODULES SPECIFIC FUNCTION PROTOTYPES ********************/
+
+static void omap_tsc2101_initialize(void *dummy);
+
+static void omap_tsc2101_shutdown(void *dummy);
+
+static int omap_tsc2101_ioctl(struct inode *inode, struct file *file,
+ uint cmd, ulong arg);
+
+static int omap_tsc2101_probe(void);
+
+static void omap_tsc2101_remove(void);
+
+static int omap_tsc2101_suspend(void);
+
+static int omap_tsc2101_resume(void);
+
+static void tsc2101_configure(void);
+
+static int mixer_open(struct inode *inode, struct file *file);
+
+static int mixer_release(struct inode *inode, struct file *file);
+
+static int mixer_ioctl(struct inode *inode, struct file *file, uint cmd,
+ ulong arg);
+
+#ifdef TEST_KEYCLICK
+void tsc2101_testkeyclick(void);
+#endif
+
+#ifdef TONE_GEN
+void toneGen(void);
+#endif
+
+#ifdef TSC_DUMP_REGISTERS
+static void tsc2101_dumpRegisters(void);
+#endif
+
+#ifdef PROC_SUPPORT
+static int codec_start(char *buf, char **start, off_t offset, int count,
+ int *eof, void *data);
+
+static int codec_stop(char *buf, char **start, off_t offset, int count,
+ int *eof, void *data);
+
+static void tsc2101_start(void);
+#endif
+
+/******************** DATA STRUCTURES USING FUNCTION POINTERS **************************/
+
+/* File Op structure for mixer */
+static struct file_operations omap_mixer_fops = {
+ .open = mixer_open,
+ .release = mixer_release,
+ .ioctl = mixer_ioctl,
+ .owner = THIS_MODULE
+};
+
+/* To store characteristic info regarding the codec for the audio driver */
+static audio_state_t tsc2101_state = {
+ .output_stream = &output_stream,
+ .input_stream = &input_stream,
+/* .need_tx_for_rx = 1, //Once the Full Duplex works */
+ .need_tx_for_rx = 0,
+ .hw_init = omap_tsc2101_initialize,
+ .hw_shutdown = omap_tsc2101_shutdown,
+ .client_ioctl = omap_tsc2101_ioctl,
+ .hw_probe = omap_tsc2101_probe,
+ .hw_remove = omap_tsc2101_remove,
+ .hw_suspend = omap_tsc2101_suspend,
+ .hw_resume = omap_tsc2101_resume,
+};
+
+/* This will be defined in the Audio.h */
+static struct file_operations *omap_audio_fops;
+
+/***************************** MODULES SPECIFIC FUNCTIONs *******************************/
+
+/*********************************************************************************
+ *
+ * Simplified write for tsc Audio
+ *
+ *********************************************************************************/
+static __inline__ void audio_tsc2101_write(u8 address, u16 data)
+{
+ omap_tsc2101_write(PAGE2_AUDIO_CODEC_REGISTERS, address, data);
+}
+
+/*********************************************************************************
+ *
+ * Simplified read for tsc Audio
+ *
+ *********************************************************************************/
+static __inline__ u16 audio_tsc2101_read(u8 address)
+{
+ return (omap_tsc2101_read(PAGE2_AUDIO_CODEC_REGISTERS, address));
+}
+
+/*********************************************************************************
+ *
+ * tsc2101_update()
+ * Volume Adj etc
+ *
+ ********************************************************************************/
+static int tsc2101_update(int flag, int val)
+{
+ u16 volume;
+ u16 data;
+
+ FN_IN;
+ switch (flag) {
+ case SET_VOLUME:
+ if (val < 0 || val > 100) {
+ printk(KERN_ERR "Trying a bad volume value(%d)!\n", val);
+ return -EPERM;
+ }
+ /* Convert 0 -> 100 volume to 0x7F(min) -> y(max) volume range */
+ volume =
+ ((val * OUTPUT_VOLUME_RANGE) / 100) + OUTPUT_VOLUME_MAX;
+ /* invert the value for getting the proper range 0 min and 100 max */
+ volume = OUTPUT_VOLUME_MIN - volume;
+ data = audio_tsc2101_read(TSC2101_DAC_GAIN_CTRL);
+ data &=
+ ~(DGC_DALVL(OUTPUT_VOLUME_MIN) |
+ DGC_DARVL(OUTPUT_VOLUME_MIN));
+ data |= DGC_DALVL(volume) | DGC_DARVL(volume);
+ audio_tsc2101_write(TSC2101_DAC_GAIN_CTRL, data);
+ data = audio_tsc2101_read(TSC2101_DAC_GAIN_CTRL);
+
+ break;
+
+ case SET_LINE:
+ if (val < 0 || val > 100) {
+ printk(KERN_ERR "Trying a bad volume value(%d)!\n", val);
+ return -EPERM;
+ }
+ /* Convert 0 -> 100 volume to 0x0(min) -> 0x7D(max) volume range */
+ /* NOTE: 0 is minimum volume and not mute */
+ volume = ((val * INPUT_VOLUME_RANGE) / 100) + INPUT_VOLUME_MIN;
+ /* Handset Input not muted, AGC for Handset In off */
+ audio_tsc2101_write(TSC2101_HEADSET_GAIN_CTRL,
+ HGC_ADPGA_HED(volume));
+ break;
+
+ case SET_MIC:
+ if (val < 0 || val > 100) {
+ printk(KERN_ERR "Trying a bad volume value(%d)!\n", val);
+ return -EPERM;
+ }
+ /* Convert 0 -> 100 volume to 0x0(min) -> 0x7D(max) volume range */
+ /* NOTE: 0 is minimum volume and not mute */
+ volume = ((val * INPUT_VOLUME_RANGE) / 100) + INPUT_VOLUME_MIN;
+ /* Handset Input not muted, AGC for Handset In off */
+ audio_tsc2101_write(TSC2101_HANDSET_GAIN_CTRL,
+ HNGC_ADPGA_HND(volume));
+ break;
+
+ case SET_RECSRC:
+ /*
+ * If more than one recording device selected,
+ * disable the device that is currently in use.
+ */
+ if (hweight32(val) > 1)
+ val &= ~tsc2101_local.recsrc;
+
+ data = audio_tsc2101_read(TSC2101_MIXER_PGA_CTRL);
+ data &= ~MPC_MICSEL(7); /* clear all MICSEL bits */
+
+ if (val == SOUND_MASK_MIC) {
+ data |= MPC_MICSEL(1);
+ audio_tsc2101_write(TSC2101_MIXER_PGA_CTRL, data);
+ }
+ else if (val == SOUND_MASK_LINE) {
+ data |= MPC_MICSEL(0);
+ audio_tsc2101_write(TSC2101_MIXER_PGA_CTRL, data);
+ }
+ else {
+ printk(KERN_WARNING "omap1610-tsc2101: Wrong RECSRC"
+ " value specified\n");
+ return -EINVAL;
+ }
+ tsc2101_local.recsrc = val;
+ break;
+ default:
+ printk(KERN_WARNING "omap1610-tsc2101: Wrong tsc2101_update "
+ "flag specified\n");
+ break;
+ }
+
+ FN_OUT(0);
+ return 0;
+}
+
+/*********************************************************************************
+ *
+ * mixer_open()
+ *
+ ********************************************************************************/
+static int mixer_open(struct inode *inode, struct file *file)
+{
+ /* Any mixer specific initialization */
+
+ /* Initalize the tsc2101 */
+ omap_tsc2101_enable();
+
+ return 0;
+}
+
+/*********************************************************************************
+ *
+ * mixer_release()
+ *
+ ********************************************************************************/
+static int mixer_release(struct inode *inode, struct file *file)
+{
+ /* Any mixer specific Un-initialization */
+ omap_tsc2101_disable();
+
+ return 0;
+}
+
+/*********************************************************************************
+ *
+ * mixer_ioctl()
+ *
+ ********************************************************************************/
+static int
+mixer_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
+{
+ int val;
+ int gain;
+ int ret = 0;
+ int nr = _IOC_NR(cmd);
+
+ /*
+ * We only accept mixer (type 'M') ioctls.
+ */
+ FN_IN;
+ if (_IOC_TYPE(cmd) != 'M')
+ return -EINVAL;
+
+ DPRINTK(" 0x%08x\n", cmd);
+
+ if (cmd == SOUND_MIXER_INFO) {
+ struct mixer_info mi;
+
+ strncpy(mi.id, "TSC2101", sizeof(mi.id));
+ strncpy(mi.name, "TI TSC2101", sizeof(mi.name));
+ mi.modify_counter = tsc2101_local.mod_cnt;
+ FN_OUT(1);
+ return copy_to_user((void __user *)arg, &mi, sizeof(mi));
+ }
+
+ if (_IOC_DIR(cmd) & _IOC_WRITE) {
+ ret = get_user(val, (int __user *)arg);
+ if (ret)
+ goto out;
+
+ /* Ignore separate left/right channel for now,
+ * even the codec does support it.
+ */
+ gain = val & 255;
+
+ switch (nr) {
+ case SOUND_MIXER_VOLUME:
+ tsc2101_local.volume = val;
+ tsc2101_local.mod_cnt++;
+ ret = tsc2101_update(SET_VOLUME, gain);
+ break;
+
+ case SOUND_MIXER_LINE:
+ tsc2101_local.line = val;
+ tsc2101_local.mod_cnt++;
+ ret = tsc2101_update(SET_LINE, gain);
+ break;
+
+ case SOUND_MIXER_MIC:
+ tsc2101_local.mic = val;
+ tsc2101_local.mod_cnt++;
+ ret = tsc2101_update(SET_MIC, gain);
+ break;
+
+ case SOUND_MIXER_RECSRC:
+ if ((val & SOUND_MASK_LINE) ||
+ (val & SOUND_MASK_MIC)) {
+ if (tsc2101_local.recsrc != val) {
+ tsc2101_local.mod_cnt++;
+ tsc2101_update(SET_RECSRC, val);
+ }
+ }
+ else {
+ ret = -EINVAL;
+ }
+ break;
+
+ default:
+ ret = -EINVAL;
+ }
+ }
+
+ if (ret == 0 && _IOC_DIR(cmd) & _IOC_READ) {
+ ret = 0;
+
+ switch (nr) {
+ case SOUND_MIXER_VOLUME:
+ val = tsc2101_local.volume;
+ val = (tsc2101_local.volume << 8) |
+ tsc2101_local.volume;
+ break;
+ case SOUND_MIXER_LINE:
+ val = (tsc2101_local.line << 8) |
+ tsc2101_local.line;
+ break;
+ case SOUND_MIXER_MIC:
+ val = (tsc2101_local.mic << 8) |
+ tsc2101_local.mic;
+ break;
+ case SOUND_MIXER_RECSRC:
+ val = tsc2101_local.recsrc;
+ break;
+ case SOUND_MIXER_RECMASK:
+ val = REC_MASK;
+ break;
+ case SOUND_MIXER_DEVMASK:
+ val = DEV_MASK;
+ break;
+ case SOUND_MIXER_CAPS:
+ val = 0;
+ break;
+ case SOUND_MIXER_STEREODEVS:
+ val = SOUND_MASK_VOLUME;
+ break;
+ default:
+ val = 0;
+ printk(KERN_WARNING "omap1610-tsc2101: unknown mixer "
+ "read ioctl flag specified\n");
+ ret = -EINVAL;
+ break;
+ }
+
+ if (ret == 0)
+ ret = put_user(val, (int __user *)arg);
+ }
+ out:
+ FN_OUT(0);
+ return ret;
+
+}
+
+/*********************************************************************************
+ *
+ * omap_set_samplerate()
+ *
+ ********************************************************************************/
+static int omap_set_samplerate(long sample_rate)
+{
+ u8 count = 0;
+ u16 data = 0;
+ int clkgdv = 0;
+ /* wait for any frame to complete */
+ udelay(125);
+
+ /* Search for the right sample rate */
+ while ((reg_info[count].sample_rate != sample_rate) &&
+ (count < NUMBER_SAMPLE_RATES_SUPPORTED)) {
+ count++;
+ }
+ if (count == NUMBER_SAMPLE_RATES_SUPPORTED) {
+ printk(KERN_ERR "Invalid Sample Rate %d requested\n",
+ (int)sample_rate);
+ return -EPERM;
+ }
+
+ /* Set AC1 */
+ data = audio_tsc2101_read(TSC2101_AUDIO_CTRL_1);
+ /*Clear prev settings */
+ data &= ~(AC1_DACFS(0x07) | AC1_ADCFS(0x07));
+ data |=
+ AC1_DACFS(reg_info[count].divisor) | AC1_ADCFS(reg_info[count].
+ divisor);
+ audio_tsc2101_write(TSC2101_AUDIO_CTRL_1, data);
+
+ /* Set the AC3 */
+ data = audio_tsc2101_read(TSC2101_AUDIO_CTRL_3);
+ /*Clear prev settings */
+ data &= ~(AC3_REFFS | AC3_SLVMS);
+ data |= (reg_info[count].fs_44kHz) ? AC3_REFFS : 0;
+#ifdef TSC_MASTER
+ data |= AC3_SLVMS;
+#endif /* #ifdef TSC_MASTER */
+ audio_tsc2101_write(TSC2101_AUDIO_CTRL_3, data);
+
+ /* program the PLLs */
+ if (reg_info[count].fs_44kHz) {
+ /* 44.1 khz - 12 MHz Mclk */
+ audio_tsc2101_write(TSC2101_PLL_PROG_1, PLL1_PLLSEL | PLL1_PVAL(1) | PLL1_I_VAL(7)); /* PVAL 1; I_VAL 7 */
+ audio_tsc2101_write(TSC2101_PLL_PROG_2, PLL2_D_VAL(0x1490)); /* D_VAL 5264 */
+ } else {
+ /* 48 khz - 12 Mhz Mclk */
+ audio_tsc2101_write(TSC2101_PLL_PROG_1, PLL1_PLLSEL | PLL1_PVAL(1) | PLL1_I_VAL(8)); /* PVAL 1; I_VAL 8 */
+ audio_tsc2101_write(TSC2101_PLL_PROG_2, PLL2_D_VAL(0x780)); /* D_VAL 1920 */
+ }
+
+ audio_samplerate = sample_rate;
+
+ /* Set the sample rate */
+#ifndef TSC_MASTER
+ clkgdv =
+ DEFAULT_MCBSP_CLOCK / (sample_rate *
+ (DEFAULT_BITPERSAMPLE * 2 - 1));
+ if (clkgdv)
+ initial_config.srgr1 =
+ (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
+ else
+ return (1);
+
+ /* Stereo Mode */
+ initial_config.srgr2 =
+ (CLKSM | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1));
+#else
+ initial_config.srgr1 =
+ (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
+ initial_config.srgr2 =
+ ((GSYNC | CLKSP | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1)));
+
+#endif /* end of #ifdef TSC_MASTER */
+ omap_mcbsp_config(AUDIO_MCBSP, &initial_config);
+
+ return 0;
+}
+
+/*********************************************************************************
+ *
+ * omap_tsc2101_initialize() [hw_init() ]
+ *
+ ********************************************************************************/
+static void omap_tsc2101_initialize(void *dummy)
+{
+
+ DPRINTK("omap_tsc2101_initialize entry\n");
+
+ /* initialize with default sample rate */
+ audio_samplerate = AUDIO_RATE_DEFAULT;
+
+ omap_mcbsp_request(AUDIO_MCBSP);
+
+ /* if configured, then stop mcbsp */
+ omap_mcbsp_stop(AUDIO_MCBSP);
+
+ omap_tsc2101_enable();
+
+ omap_mcbsp_config(AUDIO_MCBSP, &initial_config);
+ omap_mcbsp_start(AUDIO_MCBSP);
+ tsc2101_configure();
+
+#ifdef TEST_KEYCLICK
+ tsc2101_testkeyclick();
+#endif
+
+#ifdef TONE_GEN
+ toneGen();
+#endif
+
+ DPRINTK("omap_tsc2101_initialize exit\n");
+}
+
+/*********************************************************************************
+ *
+ * omap_tsc2101_shutdown() [hw_shutdown() ]
+ *
+ ********************************************************************************/
+static void omap_tsc2101_shutdown(void *dummy)
+{
+ /*
+ Turn off codec after it is done.
+ Can't do it immediately, since it may still have
+ buffered data.
+
+ Wait 20ms (arbitrary value) and then turn it off.
+ */
+
+ FN_IN;
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(2);
+
+ omap_mcbsp_stop(AUDIO_MCBSP);
+ omap_mcbsp_free(AUDIO_MCBSP);
+
+ audio_tsc2101_write(TSC2101_CODEC_POWER_CTRL,
+ ~(CPC_SP1PWDN | CPC_SP2PWDN | CPC_BASSBC));
+
+ omap_tsc2101_disable();
+
+ FN_OUT(0);
+}
+
+/*********************************************************************************
+ *
+ * tsc2101_configure
+ *
+ ********************************************************************************/
+static void tsc2101_configure(void)
+{
+ FN_IN;
+
+ audio_tsc2101_write(TSC2101_CODEC_POWER_CTRL, 0x0000);
+
+ /*Mute Analog Sidetone */
+ /*Select MIC_INHED input for headset */
+ /*Cell Phone In not connected */
+ audio_tsc2101_write(TSC2101_MIXER_PGA_CTRL,
+ MPC_ASTMU | MPC_ASTG(0x40) | MPC_MICADC);
+
+ /* Set record source */
+ tsc2101_update(SET_RECSRC, tsc2101_local.recsrc);
+
+ /* ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled */
+ /* 1dB AGC hysteresis */
+ /* MICes bias 2V */
+ audio_tsc2101_write(TSC2101_AUDIO_CTRL_4, AC4_MB_HED(0));
+
+ /* Set codec output volume */
+ audio_tsc2101_write(TSC2101_DAC_GAIN_CTRL, 0x0000);
+
+ /* DAC left and right routed to SPK2 */
+ /* SPK1/2 unmuted */
+ audio_tsc2101_write(TSC2101_AUDIO_CTRL_5,
+ AC5_DAC2SPK1(3) | AC5_AST2SPK1 | AC5_KCL2SPK1 |
+ AC5_DAC2SPK2(3) | AC5_AST2SPK2 | AC5_KCL2SPK2 |
+ AC5_HDSCPTC);
+
+ /* OUT8P/N muted, CPOUT muted */
+
+ audio_tsc2101_write(TSC2101_AUDIO_CTRL_6,
+ AC6_MUTLSPK | AC6_MUTSPK2 | AC6_LDSCPTC |
+ AC6_VGNDSCPTC);
+
+ /* Headset/Hook switch detect disabled */
+ audio_tsc2101_write(TSC2101_AUDIO_CTRL_7, 0x0000);
+
+ /* Left line input volume control */
+ tsc2101_update(SET_LINE, tsc2101_local.line);
+
+ /* mic input volume control */
+ tsc2101_update(SET_MIC, tsc2101_local.mic);
+
+ /* Left/Right headphone channel volume control */
+ /* Zero-cross detect on */
+ tsc2101_update(SET_VOLUME, tsc2101_local.volume);
+
+ /* clock configuration */
+ omap_set_samplerate(audio_samplerate);
+
+#ifdef TSC_DUMP_REGISTERS
+ tsc2101_dumpRegisters();
+#endif
+
+ FN_OUT(0);
+}
+
+#ifdef PROC_SUPPORT
+static void tsc2101_start(void)
+{
+ FN_IN;
+
+ audio_tsc2101_write(TSC2101_CODEC_POWER_CTRL, 0x0000);
+
+ /*Mute Analog Sidetone */
+ /*Select MIC_INHED input for headset */
+ /*Cell Phone In not connected */
+ audio_tsc2101_write(TSC2101_MIXER_PGA_CTRL,
+ MPC_ASTMU | MPC_ASTG(0x40) | MPC_MICADC);
+
+ /* Set record source */
+ tsc2101_update(SET_RECSRC, tsc2101_local.recsrc);
+
+ /* ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled */
+ /* 1dB AGC hysteresis */
+ /* MICes bias 2V */
+ audio_tsc2101_write(TSC2101_AUDIO_CTRL_4, AC4_MB_HED(0));
+
+ /* Set codec output volume */
+ audio_tsc2101_write(TSC2101_DAC_GAIN_CTRL, 0x0000);
+
+ /* DAC left and right routed to SPK2 */
+ /* SPK1/2 unmuted */
+ audio_tsc2101_write(TSC2101_AUDIO_CTRL_5,
+ AC5_DAC2SPK1(3) | AC5_AST2SPK1 | AC5_KCL2SPK1 |
+ AC5_DAC2SPK2(3) | AC5_AST2SPK2 | AC5_KCL2SPK2 |
+ AC5_HDSCPTC);
+
+ /* OUT8P/N muted, CPOUT muted */
+
+ audio_tsc2101_write(TSC2101_AUDIO_CTRL_6,
+ AC6_MUTLSPK | AC6_MUTSPK2 | AC6_LDSCPTC |
+ AC6_VGNDSCPTC);
+
+ /* Headset/Hook switch detect disabled */
+ audio_tsc2101_write(TSC2101_AUDIO_CTRL_7, 0x0000);
+
+ /* Left line input volume control */
+ tsc2101_update(SET_LINE, tsc2101_local.line);
+
+ /* mic input volume control */
+ tsc2101_update(SET_MIC, tsc2101_local.mic);
+
+ /* Left/Right headphone channel volume control */
+ /* Zero-cross detect on */
+ tsc2101_update(SET_VOLUME, tsc2101_local.volume);
+
+ FN_OUT(0);
+
+}
+#endif
+
+/******************************************************************************************
+ *
+ * All generic ioctl's are handled by audio_ioctl() [File: omap-audio.c]. This
+ * routine handles some platform specific ioctl's
+ *
+ ******************************************************************************************/
+static int
+omap_tsc2101_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
+{
+ long val;
+ int ret = 0;
+
+ DPRINTK(" 0x%08x\n", cmd);
+
+ /*
+ * These are platform dependent ioctls which are not handled by the
+ * generic omap-audio module.
+ */
+ switch (cmd) {
+ case SNDCTL_DSP_STEREO:
+ ret = get_user(val, (int __user *)arg);
+ if (ret)
+ return ret;
+ /* the AIC23 is stereo only */
+ ret = (val == 0) ? -EINVAL : 1;
+ FN_OUT(1);
+ return put_user(ret, (int __user *)arg);
+
+ case SNDCTL_DSP_CHANNELS:
+ case SOUND_PCM_READ_CHANNELS:
+ /* the AIC23 is stereo only */
+ FN_OUT(2);
+ return put_user(2, (long __user *)arg);
+
+ case SNDCTL_DSP_SPEED:
+ ret = get_user(val, (long __user *)arg);
+ if (ret)
+ break;
+ ret = omap_set_samplerate(val);
+ if (ret)
+ break;
+ /* fall through */
+
+ case SOUND_PCM_READ_RATE:
+ FN_OUT(3);
+ return put_user(audio_samplerate, (long __user *)arg);
+
+ case SOUND_PCM_READ_BITS:
+ case SNDCTL_DSP_SETFMT:
+ case SNDCTL_DSP_GETFMTS:
+ /* we can do 16-bit only */
+ FN_OUT(4);
+ return put_user(AFMT_S16_LE, (long __user *)arg);
+
+ default:
+ /* Maybe this is meant for the mixer (As per OSS Docs) */
+ FN_OUT(5);
+ return mixer_ioctl(inode, file, cmd, arg);
+ }
+
+ FN_OUT(0);
+ return ret;
+}
+
+/*********************************************************************************
+ *
+ * module_probe for TSC2101
+ *
+ ********************************************************************************/
+static int omap_tsc2101_probe(void)
+{
+ FN_IN;
+
+ /* Get the fops from audio oss driver */
+ if (!(omap_audio_fops = audio_get_fops())) {
+ printk(KERN_ERR "Unable to Get the FOPs of Audio OSS driver\n");
+ audio_unregister_codec(&tsc2101_state);
+ return -EPERM;
+ }
+
+ /* register devices */
+ audio_dev_id = register_sound_dsp(omap_audio_fops, -1);
+ mixer_dev_id = register_sound_mixer(&omap_mixer_fops, -1);
+
+#ifdef PROC_SUPPORT
+ create_proc_read_entry(PROC_START_FILE, 0 /* default mode */ ,
+ NULL /* parent dir */ ,
+ codec_start, NULL /* client data */ );
+
+ create_proc_read_entry(PROC_STOP_FILE, 0 /* default mode */ ,
+ NULL /* parent dir */ ,
+ codec_stop, NULL /* client data */ );
+#endif
+
+ /* Announcement Time */
+ printk(KERN_INFO PLATFORM_NAME " " CODEC_NAME
+ " Audio support initialized\n");
+
+ FN_OUT(0);
+ return 0;
+}
+
+/*********************************************************************************
+ *
+ * Module Remove for TSC2101
+ *
+ ********************************************************************************/
+static void omap_tsc2101_remove(void)
+{
+ FN_IN;
+ /* Un-Register the codec with the audio driver */
+ unregister_sound_dsp(audio_dev_id);
+ unregister_sound_mixer(mixer_dev_id);
+
+#ifdef PROC_SUPPORT
+ remove_proc_entry(PROC_START_FILE, NULL);
+ remove_proc_entry(PROC_STOP_FILE, NULL);
+#endif
+ FN_OUT(0);
+
+}
+
+/*********************************************************************************
+ *
+ * Module Suspend for TSC2101
+ *
+ ********************************************************************************/
+static int omap_tsc2101_suspend(void)
+{
+
+ FN_OUT(0);
+ return 0;
+}
+
+/*********************************************************************************
+ *
+ * Module Resume for TSC2101
+ *
+ ********************************************************************************/
+static int omap_tsc2101_resume(void)
+{
+
+ FN_OUT(0);
+ return 0;
+}
+
+/*********************************************************************************
+ *
+ * module_init for TSC2101
+ *
+ ********************************************************************************/
+static int __init audio_tsc2101_init(void)
+{
+
+ int err = 0;
+ FN_IN;
+
+ if (machine_is_omap_osk() || machine_is_omap_innovator())
+ return -ENODEV;
+
+ mutex_init(&tsc2101_state.mutex);
+
+ /* register the codec with the audio driver */
+ if ((err = audio_register_codec(&tsc2101_state))) {
+ printk(KERN_ERR
+ "Failed to register TSC driver with Audio OSS Driver\n");
+ }
+ FN_OUT(err);
+ return err;
+}
+
+/*********************************************************************************
+ *
+ * module_exit for TSC2101
+ *
+ ********************************************************************************/
+static void __exit audio_tsc2101_exit(void)
+{
+
+ FN_IN;
+ (void)audio_unregister_codec(&tsc2101_state);
+ FN_OUT(0);
+ return;
+}
+
+/**************************** DEBUG FUNCTIONS ***********************************/
+
+/*********************************************************************************
+ * TEST_KEYCLICK:
+ * This is a test to generate various keyclick sound on tsc.
+ * verifies if the tsc and the spi interfaces are operational.
+ *
+ ********************************************************************************/
+#ifdef TEST_KEYCLICK
+void tsc2101_testkeyclick(void)
+{
+ u8 freq = 0;
+ u16 old_reg_val, reg_val;
+ u32 uDummyVal = 0;
+ u32 uTryVal = 0;
+
+ old_reg_val = audio_tsc2101_read(TSC2101_AUDIO_CTRL_2);
+
+ /* Keyclick active, max amplitude and longest key click len(32 period) */
+ printk(KERN_INFO " TESTING KEYCLICK\n Listen carefully NOW....\n");
+ printk(KERN_INFO " OLD REG VAL=0x%x\n", old_reg_val);
+ /* try all frequencies */
+ for (; freq < 8; freq++) {
+ /* Keyclick active, max amplitude and longest key click len(32 period) */
+ reg_val = old_reg_val | AC2_KCLAC(0x7) | AC2_KCLLN(0xF);
+ uDummyVal = 0;
+ uTryVal = 0;
+ printk(KERN_INFO "\n\nTrying frequency %d reg val= 0x%x\n",
+ freq, reg_val | AC2_KCLFRQ(freq) | AC2_KCLEN);
+ audio_tsc2101_write(TSC2101_AUDIO_CTRL_2,
+ reg_val | AC2_KCLFRQ(freq) | AC2_KCLEN);
+ printk("DONE. Wait 10 ms ...\n");
+ /* wait till the kclk bit is auto cleared! time out also to be considered. */
+ while (audio_tsc2101_read(TSC2101_AUDIO_CTRL_2) & AC2_KCLEN) {
+ udelay(3);
+ uTryVal++;
+ if (uTryVal > 2000) {
+ printk(KERN_ERR
+ "KEYCLICK TIMED OUT! freq val=%d, POSSIBLE ERROR!\n",
+ freq);
+ printk(KERN_INFO
+ "uTryVal == %d: Read back new reg val= 0x%x\n",
+ uTryVal,
+ audio_tsc2101_read
+ (TSC2101_AUDIO_CTRL_2));
+ /* clear */
+ audio_tsc2101_write(TSC2101_AUDIO_CTRL_2, 0x00);
+ break;
+ }
+ }
+ }
+ /* put the old value back */
+ audio_tsc2101_write(TSC2101_AUDIO_CTRL_2, old_reg_val);
+ printk(KERN_INFO " KEYCLICK TEST COMPLETE\n");
+
+} /* End of tsc2101_testkeyclick */
+
+#endif /* TEST_KEYCLICK */
+
+/*********************************************************************************
+ * TONEGEN:
+ * This is a test to generate a rather unpleasant sound..
+ * verifies if the mcbsp is active (requires MCBSP_DIRECT_RW to be active on McBSP)
+ *
+ ********************************************************************************/
+#ifdef TONE_GEN
+/* Generates a shrill tone */
+u16 tone[] = {
+ 0x0ce4, 0x0ce4, 0x1985, 0x1985, 0x25A1, 0x25A1, 0x30FD, 0x30FE,
+ 0x3B56, 0x3B55, 0x447A, 0x447A, 0x4C3B, 0x4C3C, 0x526D, 0x526C,
+ 0x56F1, 0x56F1, 0x59B1, 0x59B1, 0x5A9E, 0x5A9D, 0x59B1, 0x59B2,
+ 0x56F3, 0x56F2, 0x526D, 0x526D, 0x4C3B, 0x4C3B, 0x447C, 0x447C,
+ 0x3B5A, 0x3B59, 0x30FE, 0x30FE, 0x25A5, 0x25A6, 0x1989, 0x198A,
+ 0x0CE5, 0x0CE3, 0x0000, 0x0000, 0xF31C, 0xF31C, 0xE677, 0xE676,
+ 0xDA5B, 0xDA5B, 0xCF03, 0xCF03, 0xC4AA, 0xC4AA, 0xBB83, 0xBB83,
+ 0xB3C5, 0xB3C5, 0xAD94, 0xAD94, 0xA90D, 0xA90E, 0xA64F, 0xA64E,
+ 0xA562, 0xA563, 0xA64F, 0xA64F, 0xA910, 0xA90F, 0xAD93, 0xAD94,
+ 0xB3C4, 0xB3C4, 0xBB87, 0xBB86, 0xC4AB, 0xC4AB, 0xCF03, 0xCF03,
+ 0xDA5B, 0xDA5A, 0xE67B, 0xE67B, 0xF31B, 0xF3AC, 0x0000, 0x0000,
+ 0x0CE4, 0x0CE4, 0x1985, 0x1985, 0x25A1, 0x25A1, 0x30FD, 0x30FE,
+ 0x3B56, 0x3B55, 0x447A, 0x447A, 0x4C3B, 0x4C3C, 0x526D, 0x526C,
+ 0x56F1, 0x56F1, 0x59B1, 0x59B1, 0x5A9E, 0x5A9D, 0x59B1, 0x59B2,
+ 0x56F3, 0x56F2, 0x526D, 0x526D, 0x4C3B, 0x4C3B, 0x447C, 0x447C,
+ 0x3B5A, 0x3B59, 0x30FE, 0x30FE, 0x25A5, 0x25A6, 0x1989, 0x198A,
+ 0x0CE5, 0x0CE3, 0x0000, 0x0000, 0xF31C, 0xF31C, 0xE677, 0xE676,
+ 0xDA5B, 0xDA5B, 0xCF03, 0xCF03, 0xC4AA, 0xC4AA, 0xBB83, 0xBB83,
+ 0xB3C5, 0xB3C5, 0xAD94, 0xAD94, 0xA90D, 0xA90E, 0xA64F, 0xA64E,
+ 0xA562, 0xA563, 0xA64F, 0xA64F, 0xA910, 0xA90F, 0xAD93, 0xAD94,
+ 0xB3C4, 0xB3C4, 0xBB87, 0xBB86, 0xC4AB, 0xC4AB, 0xCF03, 0xCF03,
+ 0xDA5B, 0xDA5A, 0xE67B, 0xE67B, 0xF31B, 0xF3AC, 0x0000, 0x0000,
+ 0x0CE4, 0x0CE4, 0x1985, 0x1985, 0x25A1, 0x25A1, 0x30FD, 0x30FE,
+ 0x3B56, 0x3B55, 0x447A, 0x447A, 0x4C3B, 0x4C3C, 0x526D, 0x526C,
+ 0x56F1, 0x56F1, 0x59B1, 0x59B1, 0x5A9E, 0x5A9D, 0x59B1, 0x59B2,
+ 0x56F3, 0x56F2, 0x526D, 0x526D, 0x4C3B, 0x4C3B, 0x447C, 0x447C,
+ 0x3B5A, 0x3B59, 0x30FE, 0x30FE, 0x25A5, 0x25A6, 0x1989, 0x198A,
+ 0x0CE5, 0x0CE3, 0x0000, 0x0000, 0xF31C, 0xF31C, 0xE677, 0xE676,
+ 0xDA5B, 0xDA5B, 0xCF03, 0xCF03, 0xC4AA, 0xC4AA, 0xBB83, 0xBB83,
+ 0xB3C5, 0xB3C5, 0xAD94, 0xAD94, 0xA90D, 0xA90E, 0xA64F, 0xA64E,
+ 0xA562, 0xA563, 0xA64F, 0xA64F, 0xA910, 0xA90F, 0xAD93, 0xAD94,
+ 0xB3C4, 0xB3C4, 0xBB87, 0xBB86, 0xC4AB, 0xC4AB, 0xCF03, 0xCF03,
+ 0xDA5B, 0xDA5A, 0xE67B, 0xE67B, 0xF31B, 0xF3AC, 0x0000, 0x0000
+};
+
+void toneGen(void)
+{
+ int count = 0;
+ int ret = 0;
+ printk(KERN_INFO "TONE GEN TEST :");
+
+ for (count = 0; count < 5000; count++) {
+ int bytes;
+ for (bytes = 0; bytes < sizeof(tone) / 2; bytes++) {
+ ret = omap_mcbsp_pollwrite(AUDIO_MCBSP, tone[bytes]);
+ if (ret == -1) {
+ /* retry */
+ bytes--;
+ } else if (ret == -2) {
+ printk(KERN_INFO "ERROR:bytes=%d\n", bytes);
+ return;
+ }
+ }
+ }
+ printk(KERN_INFO "SUCCESS\n");
+}
+
+#endif /* End of TONE_GEN */
+
+/*********************************************************************************
+ *
+ * TSC_DUMP_REGISTERS:
+ * This will dump the entire register set of Page 2 tsc2101.
+ * Useful for major goof ups
+ *
+ ********************************************************************************/
+#ifdef TSC_DUMP_REGISTERS
+static void tsc2101_dumpRegisters(void)
+{
+ int i = 0;
+ u16 data = 0;
+ printk("TSC 2101 Register dump for Page 2 \n");
+ for (i = 0; i < 0x27; i++) {
+ data = audio_tsc2101_read(i);
+ printk(KERN_INFO "Register[%x]=0x%04x\n", i, data);
+
+ }
+}
+#endif /* End of #ifdef TSC_DUMP_REGISTERS */
+
+#ifdef PROC_SUPPORT
+static int codec_start(char *buf, char **start, off_t offset, int count,
+ int *eof, void *data)
+{
+ omap_tsc2101_enable();
+ tsc2101_start();
+ printk("Codec initialization done.\n");
+ return 0;
+}
+static int codec_stop(char *buf, char **start, off_t offset, int count,
+ int *eof, void *data)
+{
+
+ omap_tsc2101_disable();
+ audio_tsc2101_write(TSC2101_CODEC_POWER_CTRL,
+ ~(CPC_SP1PWDN | CPC_SP2PWDN | CPC_BASSBC));
+ printk("Codec shutdown.\n");
+ return 0;
+}
+#endif
+
+/*********************************************************************************
+ *
+ * Other misc management, registration etc
+ *
+ ********************************************************************************/
+module_init(audio_tsc2101_init);
+module_exit(audio_tsc2101_exit);
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION
+ ("Glue audio driver for the TI OMAP1610/OMAP1710 TSC2101 codec.");
+MODULE_LICENSE("GPL");
--- /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/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/poll.h>
+#include <linux/pm.h>
+#include <linux/errno.h>
+#include <linux/sound.h>
+#include <linux/soundcard.h>
+#include <linux/sysrq.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/completion.h>
+#include <linux/mutex.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+
+#include "omap-audio-dma-intfc.h"
+#include "omap-audio.h"
+
+/***************************** MACROS ************************************/
+
+#undef DEBUG
+//#define DEBUG
+#ifdef DEBUG
+#define DPRINTK printk
+#define FN_IN printk("[omap_audio.c:[%s] start\n", __FUNCTION__)
+#define FN_OUT(n) printk("[omap_audio.c:[%s] end(%d)\n", __FUNCTION__ , n)
+#else
+#define DPRINTK( x... )
+#define FN_IN
+#define FN_OUT(x)
+#endif
+
+#define OMAP_AUDIO_NAME "omap-audio"
+#define AUDIO_NBFRAGS_DEFAULT 8
+#define AUDIO_FRAGSIZE_DEFAULT 8192
+
+/* HACK ALERT!: These values will bave to be tuned as this is a trade off b/w
+ * Sampling Rate vs buffer size and delay we are prepared to do before giving up
+ */
+#define MAX_QUEUE_FULL_RETRIES 1000000
+#define QUEUE_WAIT_TIME 10
+
+#define AUDIO_ACTIVE(state) ((state)->rd_ref || (state)->wr_ref)
+
+#define SPIN_ADDR (dma_addr_t)0
+#define SPIN_SIZE 2048
+
+/***************************** MODULES SPECIFIC FUNCTION PROTOTYPES ********************/
+
+static int audio_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t * ppos);
+
+static int audio_read(struct file *file, char __user *buffer, size_t count,
+ loff_t * ppos);
+
+static int audio_mmap(struct file *file, struct vm_area_struct *vma);
+
+static unsigned int audio_poll(struct file *file,
+ struct poll_table_struct *wait);
+
+static loff_t audio_llseek(struct file *file, loff_t offset, int origin);
+
+static int audio_ioctl(struct inode *inode, struct file *file, uint cmd,
+ ulong arg);
+
+static int audio_open(struct inode *inode, struct file *file);
+
+static int audio_release(struct inode *inode, struct file *file);
+
+static int audio_probe(struct platform_device *pdev);
+
+static int audio_remove(struct platform_device *pdev);
+
+static void audio_shutdown(struct platform_device *pdev);
+
+static int audio_suspend(struct platform_device *pdev, pm_message_t mesg);
+
+static int audio_resume(struct platform_device *pdev);
+
+static void audio_free(struct device *dev);
+
+/***************************** Data Structures **********************************/
+
+/*
+ * The function pointer set to be registered by the codec.
+ */
+static audio_state_t audio_state = { NULL };
+
+/* DMA Call back function */
+static dma_callback_t audio_dma_callback = NULL;
+
+/* File Ops structure */
+static struct file_operations omap_audio_fops = {
+ .open = audio_open,
+ .release = audio_release,
+ .write = audio_write,
+ .read = audio_read,
+ .mmap = audio_mmap,
+ .poll = audio_poll,
+ .ioctl = audio_ioctl,
+ .llseek = audio_llseek,
+ .owner = THIS_MODULE
+};
+
+/* Driver information */
+static struct platform_driver omap_audio_driver = {
+ .probe = audio_probe,
+ .remove = audio_remove,
+ .suspend = audio_suspend,
+ .shutdown = audio_shutdown,
+ .resume = audio_resume,
+ .driver = {
+ .name = OMAP_AUDIO_NAME,
+ },
+};
+
+/* Device Information */
+static struct platform_device omap_audio_device = {
+ .name = OMAP_AUDIO_NAME,
+ .dev = {
+ .driver_data = &audio_state,
+ .release = audio_free,
+ },
+ .id = 0,
+};
+
+/***************************** GLOBAL FUNCTIONs **********************************/
+
+/* Power Management Functions for Linux Device Model */
+/* DEBUG PUPOSES ONLY! */
+#ifdef CONFIG_PM
+//#undef CONFIG_PM
+#endif
+
+#ifdef CONFIG_PM
+/*********************************************************************************
+ *
+ * audio_ldm_suspend(): Suspend operation
+ *
+ *********************************************************************************/
+static int audio_ldm_suspend(void *data)
+{
+ audio_state_t *state = data;
+
+ FN_IN;
+
+ /*
+ * Reject the suspend request if we are already actively transmitting data
+ * Rationale: We dont want to be suspended while in the middle of a call!
+ */
+ if (AUDIO_ACTIVE(state) && state->hw_init) {
+ printk(KERN_ERR "Audio device Active, Cannot Suspend");
+ return -EPERM;
+#if 0
+ /* NOTE:
+ * This Piece of code is commented out in hope
+ * That one day we would need to suspend the device while
+ * audio operations are in progress and resume the operations
+ * once the resume is done.
+ * This is just a sample implementation of how it could be done.
+ * Currently NOT SUPPORTED
+ */
+ audio_stream_t *is = state->input_stream;
+ audio_stream_t *os = state->output_stream;
+ int stopstate;
+ if (is && is->buffers) {
+ printk("IS Suspend\n");
+ stopstate = is->stopped;
+ audio_stop_dma(is);
+ DMA_CLEAR(is);
+ is->dma_spinref = 0;
+ is->stopped = stopstate;
+ }
+ if (os && os->buffers) {
+ printk("OS Suspend\n");
+ stopstate = os->stopped;
+ audio_stop_dma(os);
+ DMA_CLEAR(os);
+ os->dma_spinref = 0;
+ os->stopped = stopstate;
+ }
+#endif
+ }
+
+ FN_OUT(0);
+ return 0;
+}
+
+/*********************************************************************************
+ *
+ * audio_ldm_resume(): Resume Operations
+ *
+ *********************************************************************************/
+static int audio_ldm_resume(void *data)
+{
+ audio_state_t *state = data;
+
+ FN_IN;
+ if (AUDIO_ACTIVE(state) && state->hw_init) {
+ /* Should never occur - since we never suspend with active state */
+ BUG();
+ return -EPERM;
+#if 0
+ /* NOTE:
+ * This Piece of code is commented out in hope
+ * That one day we would need to suspend the device while
+ * audio operations are in progress and resume the operations
+ * once the resume is done.
+ * This is just a sample implementation of how it could be done.
+ * Currently NOT SUPPORTED
+ */
+ audio_stream_t *is = state->input_stream;
+ audio_stream_t *os = state->output_stream;
+ if (os && os->buffers) {
+ printk("OS Resume\n");
+ audio_reset(os);
+ audio_process_dma(os);
+ }
+ if (is && is->buffers) {
+ printk("IS Resume\n");
+ audio_reset(is);
+ audio_process_dma(is);
+ }
+#endif
+ }
+ FN_OUT(0);
+ return 0;
+}
+#endif /* End of #ifdef CONFIG_PM */
+
+/*********************************************************************************
+ *
+ * audio_free(): The Audio driver release function
+ * This is a dummy function required by the platform driver
+ *
+ *********************************************************************************/
+static void audio_free(struct device *dev)
+{
+ /* Nothing to Release! */
+}
+
+/*********************************************************************************
+ *
+ * audio_probe(): The Audio driver probe function
+ * WARNING!!!! : It is expected that the codec would have registered with us by now
+ *
+ *********************************************************************************/
+static int audio_probe(struct platform_device *pdev)
+{
+ int ret;
+ FN_IN;
+ if (!audio_state.hw_probe) {
+ printk(KERN_ERR "Probe Function Not Registered\n");
+ return -ENODEV;
+ }
+ ret = audio_state.hw_probe();
+ FN_OUT(ret);
+ return ret;
+}
+
+/*********************************************************************************
+ *
+ * audio_remove() Function to handle removal operations
+ *
+ *********************************************************************************/
+static int audio_remove(struct platform_device *pdev)
+{
+ FN_IN;
+ if (audio_state.hw_remove) {
+ audio_state.hw_remove();
+ }
+ FN_OUT(0);
+ return 0;
+}
+
+/*********************************************************************************
+ *
+ * audio_shutdown(): Function to handle shutdown operations
+ *
+ *********************************************************************************/
+static void audio_shutdown(struct platform_device *pdev)
+{
+ FN_IN;
+ if (audio_state.hw_cleanup) {
+ audio_state.hw_cleanup();
+ }
+ FN_OUT(0);
+ return;
+}
+
+/*********************************************************************************
+ *
+ * audio_suspend(): Function to handle suspend operations
+ *
+ *********************************************************************************/
+static int audio_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+ int ret = 0;
+
+#ifdef CONFIG_PM
+ void *data = pdev->dev.driver_data;
+ FN_IN;
+ if (audio_state.hw_suspend) {
+ ret = audio_ldm_suspend(data);
+ if (ret == 0)
+ ret = audio_state.hw_suspend();
+ }
+ if (ret) {
+ printk(KERN_INFO "Audio Suspend Failed \n");
+ } else {
+ printk(KERN_INFO "Audio Suspend Success \n");
+ }
+#endif /* CONFIG_PM */
+
+ FN_OUT(ret);
+ return ret;
+}
+
+/*********************************************************************************
+ *
+ * audio_resume(): Function to handle resume operations
+ *
+ *********************************************************************************/
+static int audio_resume(struct platform_device *pdev)
+{
+ int ret = 0;
+
+#ifdef CONFIG_PM
+ void *data = pdev->dev.driver_data;
+ FN_IN;
+ if (audio_state.hw_resume) {
+ ret = audio_ldm_resume(data);
+ if (ret == 0)
+ ret = audio_state.hw_resume();
+ }
+ if (ret) {
+ printk(KERN_INFO " Audio Resume Failed \n");
+ } else {
+ printk(KERN_INFO " Audio Resume Success \n");
+ }
+#endif /* CONFIG_PM */
+
+ FN_OUT(ret);
+ return ret;
+}
+
+/*********************************************************************************
+ *
+ * audio_get_fops(): Return the fops required to get the function pointers of
+ * OMAP Audio Driver
+ *
+ *********************************************************************************/
+struct file_operations *audio_get_fops(void)
+{
+ FN_IN;
+ FN_OUT(0);
+ return &omap_audio_fops;
+}
+
+/*********************************************************************************
+ *
+ * audio_register_codec(): Register a Codec fn points using this function
+ * WARNING!!!!! : Codecs should ensure that they do so! no sanity checks
+ * during runtime is done due to obvious performance
+ * penalties.
+ *
+ *********************************************************************************/
+int audio_register_codec(audio_state_t * codec_state)
+{
+ int ret;
+ FN_IN;
+
+ /* We dont handle multiple codecs now */
+ if (audio_state.hw_init) {
+ printk(KERN_ERR " Codec Already registered\n");
+ return -EPERM;
+ }
+
+ /* Grab the dma Callback */
+ audio_dma_callback = audio_get_dma_callback();
+ if (!audio_dma_callback) {
+ printk(KERN_ERR "Unable to get call back function\n");
+ return -EPERM;
+ }
+
+ /* Sanity checks */
+ if (!codec_state) {
+ printk(KERN_ERR "NULL ARGUMENT!\n");
+ return -EPERM;
+ }
+
+ if (!codec_state->hw_probe || !codec_state->hw_init
+ || !codec_state->hw_shutdown || !codec_state->client_ioctl) {
+ printk(KERN_ERR
+ "Required Fn Entry point Missing probe=%p init=%p,down=%p,ioctl=%p!\n",
+ codec_state->hw_probe, codec_state->hw_init,
+ codec_state->hw_shutdown, codec_state->client_ioctl);
+ return -EPERM;
+ }
+
+ memcpy(&audio_state, codec_state, sizeof(audio_state_t));
+ mutex_init(&audio_state.mutex);
+
+ ret = platform_device_register(&omap_audio_device);
+ if (ret != 0) {
+ printk(KERN_ERR "Platform dev_register failed =%d\n", ret);
+ ret = -ENODEV;
+ goto register_out;
+ }
+
+ ret = platform_driver_register(&omap_audio_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Device Register failed =%d\n", ret);
+ ret = -ENODEV;
+ platform_device_unregister(&omap_audio_device);
+ goto register_out;
+ }
+
+ register_out:
+
+ FN_OUT(ret);
+ return ret;
+}
+
+/*********************************************************************************
+ *
+ * audio_unregister_codec(): Un-Register a Codec using this function
+ *
+ *********************************************************************************/
+int audio_unregister_codec(audio_state_t * codec_state)
+{
+ FN_IN;
+
+ /* We dont handle multiple codecs now */
+ if (!audio_state.hw_init) {
+ printk(KERN_ERR " No Codec registered\n");
+ return -EPERM;
+ }
+ /* Security check */
+ if (audio_state.hw_init != codec_state->hw_init) {
+ printk(KERN_ERR
+ " Attempt to unregister codec which was not registered with us\n");
+ return -EPERM;
+ }
+
+ platform_driver_unregister(&omap_audio_driver);
+ platform_device_unregister(&omap_audio_device);
+
+ memset(&audio_state, 0, sizeof(audio_state_t));
+
+ FN_OUT(0);
+ return 0;
+}
+
+/***************************** MODULES SPECIFIC FUNCTION *************************/
+
+/*********************************************************************************
+ *
+ * audio_write(): Exposed to write() call
+ *
+ *********************************************************************************/
+static int
+audio_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t * ppos)
+{
+ const char __user *buffer0 = buffer;
+ audio_state_t *state = file->private_data;
+ audio_stream_t *s = state->output_stream;
+ int chunksize, ret = 0;
+
+ DPRINTK("audio_write: count=%d\n", count);
+ if (*ppos != file->f_pos) {
+ printk("FPOS not ppos ppos=0x%x fpos =0x%x\n", (u32) * ppos,
+ (u32) file->f_pos);
+ return -ESPIPE;
+ }
+ if (s->mapped) {
+ printk("s already mapped\n");
+ return -ENXIO;
+ }
+ if (!s->buffers && audio_setup_buf(s)) {
+ printk("NO MEMORY\n");
+ return -ENOMEM;
+ }
+
+ while (count > 0) {
+ audio_buf_t *b = &s->buffers[s->usr_head];
+
+ /* Wait for a buffer to become free */
+ if (file->f_flags & O_NONBLOCK) {
+ ret = -EAGAIN;
+ if (!s->wfc.done)
+ break;
+ }
+ ret = -ERESTARTSYS;
+ if (wait_for_completion_interruptible(&s->wfc))
+ break;
+
+ /* Feed the current buffer */
+ chunksize = s->fragsize - b->offset;
+ if (chunksize > count)
+ chunksize = count;
+ DPRINTK("write %d to %d\n", chunksize, s->usr_head);
+ if (copy_from_user(b->data + b->offset, buffer, chunksize)) {
+ printk(KERN_ERR "Audio: CopyFrom User failed \n");
+ complete(&s->wfc);
+ return -EFAULT;
+ }
+
+ buffer += chunksize;
+ count -= chunksize;
+ b->offset += chunksize;
+
+ if (b->offset < s->fragsize) {
+ complete(&s->wfc);
+ break;
+ }
+
+ /* Update pointers and send current fragment to DMA */
+ b->offset = 0;
+ if (++s->usr_head >= s->nbfrags)
+ s->usr_head = 0;
+ /* Add the num of frags pending */
+ s->pending_frags++;
+ s->active = 1;
+
+ audio_process_dma(s);
+
+ }
+
+ if ((buffer - buffer0))
+ ret = buffer - buffer0;
+ DPRINTK("audio_write: return=%d\n", ret);
+ return ret;
+}
+
+/*********************************************************************************
+ *
+ * audio_read(): Exposed as read() function
+ *
+ *********************************************************************************/
+static int
+audio_read(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
+{
+ char __user *buffer0 = buffer;
+ audio_state_t *state = file->private_data;
+ audio_stream_t *s = state->input_stream;
+ int chunksize, ret = 0;
+ unsigned long flags;
+
+ DPRINTK("audio_read: count=%d\n", count);
+
+ if (*ppos != file->f_pos) {
+ printk("AudioRead - FPOS not ppos ppos=0x%x fpos =0x%x\n",
+ (u32) * ppos, (u32) file->f_pos);
+ return -ESPIPE;
+ }
+ if (s->mapped) {
+ printk("AudioRead - s already mapped\n");
+ return -ENXIO;
+ }
+
+ if (!s->active) {
+ if (!s->buffers && audio_setup_buf(s)) {
+ printk("AudioRead - No Memory\n");
+ return -ENOMEM;
+ }
+ audio_prime_rx(state);
+ }
+
+ while (count > 0) {
+ audio_buf_t *b = &s->buffers[s->usr_head];
+
+ /* Wait for a buffer to become full */
+ if (file->f_flags & O_NONBLOCK) {
+ ret = -EAGAIN;
+ if (!s->wfc.done)
+ break;
+ }
+ ret = -ERESTARTSYS;
+ if (wait_for_completion_interruptible(&s->wfc))
+ break;
+
+ /* Grab data from the current buffer */
+ chunksize = s->fragsize - b->offset;
+ if (chunksize > count)
+ chunksize = count;
+ DPRINTK("read %d from %d\n", chunksize, s->usr_head);
+ if (copy_to_user(buffer, b->data + b->offset, chunksize)) {
+ complete(&s->wfc);
+ return -EFAULT;
+ }
+ buffer += chunksize;
+ count -= chunksize;
+ b->offset += chunksize;
+ if (b->offset < s->fragsize) {
+ complete(&s->wfc);
+ break;
+ }
+
+ /* Update pointers and return current fragment to DMA */
+ local_irq_save(flags);
+ b->offset = 0;
+ if (++s->usr_head >= s->nbfrags)
+ s->usr_head = 0;
+
+ s->pending_frags++;
+ local_irq_restore(flags);
+ audio_process_dma(s);
+
+ }
+
+ if ((buffer - buffer0))
+ ret = buffer - buffer0;
+ DPRINTK("audio_read: return=%d\n", ret);
+ return ret;
+}
+
+/*********************************************************************************
+ *
+ * audio_mmap(): Exposed as mmap Function
+ * !!WARNING: Still under development
+ *
+ *********************************************************************************/
+static int audio_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ audio_state_t *state = file->private_data;
+ audio_stream_t *s;
+ unsigned long size, vma_addr;
+ int i, ret;
+
+ FN_IN;
+ if (vma->vm_pgoff != 0)
+ return -EINVAL;
+
+ if (vma->vm_flags & VM_WRITE) {
+ if (!state->wr_ref)
+ return -EINVAL;;
+ s = state->output_stream;
+ } else if (vma->vm_flags & VM_READ) {
+ if (!state->rd_ref)
+ return -EINVAL;
+ s = state->input_stream;
+ } else
+ return -EINVAL;
+
+ if (s->mapped)
+ return -EINVAL;
+ size = vma->vm_end - vma->vm_start;
+ if (size != s->fragsize * s->nbfrags)
+ return -EINVAL;
+ if (!s->buffers && audio_setup_buf(s))
+ return -ENOMEM;
+ vma_addr = vma->vm_start;
+ for (i = 0; i < s->nbfrags; i++) {
+ audio_buf_t *buf = &s->buffers[i];
+ if (!buf->master)
+ continue;
+ ret =
+ remap_pfn_range(vma, vma_addr, buf->dma_addr >> PAGE_SHIFT,
+ buf->master, vma->vm_page_prot);
+ if (ret)
+ return ret;
+ vma_addr += buf->master;
+ }
+ s->mapped = 1;
+
+ FN_OUT(0);
+ return 0;
+}
+
+/*********************************************************************************
+ *
+ * audio_poll(): Exposed as poll function
+ *
+ *********************************************************************************/
+static unsigned int
+audio_poll(struct file *file, struct poll_table_struct *wait)
+{
+ audio_state_t *state = file->private_data;
+ audio_stream_t *is = state->input_stream;
+ audio_stream_t *os = state->output_stream;
+ unsigned int mask = 0;
+
+ DPRINTK("audio_poll(): mode=%s%s\n",
+ (file->f_mode & FMODE_READ) ? "r" : "",
+ (file->f_mode & FMODE_WRITE) ? "w" : "");
+
+ if (file->f_mode & FMODE_READ) {
+ /* Start audio input if not already active */
+ if (!is->active) {
+ if (!is->buffers && audio_setup_buf(is))
+ return -ENOMEM;
+ audio_prime_rx(state);
+ }
+ poll_wait(file, &is->wq, wait);
+ }
+
+ if (file->f_mode & FMODE_WRITE) {
+ if (!os->buffers && audio_setup_buf(os))
+ return -ENOMEM;
+ poll_wait(file, &os->wq, wait);
+ }
+
+ if (file->f_mode & FMODE_READ)
+ if ((is->mapped && is->bytecount > 0) ||
+ (!is->mapped && is->wfc.done > 0))
+ mask |= POLLIN | POLLRDNORM;
+
+ if (file->f_mode & FMODE_WRITE)
+ if ((os->mapped && os->bytecount > 0) ||
+ (!os->mapped && os->wfc.done > 0))
+ mask |= POLLOUT | POLLWRNORM;
+
+ DPRINTK("audio_poll() returned mask of %s%s\n",
+ (mask & POLLIN) ? "r" : "", (mask & POLLOUT) ? "w" : "");
+
+ FN_OUT(mask);
+ return mask;
+}
+
+/*********************************************************************************
+ *
+ * audio_llseek(): Exposed as lseek() function.
+ *
+ *********************************************************************************/
+static loff_t audio_llseek(struct file *file, loff_t offset, int origin)
+{
+ FN_IN;
+ FN_OUT(0);
+ return -ESPIPE;
+}
+
+/*********************************************************************************
+ *
+ * audio_ioctl(): Handles generic ioctls. If there is a request for something this
+ * fn cannot handle, its then given to client specific ioctl routine, that will take
+ * up platform specific requests
+ *
+ *********************************************************************************/
+static int
+audio_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
+{
+ audio_state_t *state = file->private_data;
+ audio_stream_t *os = state->output_stream;
+ audio_stream_t *is = state->input_stream;
+ long val;
+
+ DPRINTK(__FILE__ " audio_ioctl 0x%08x\n", cmd);
+
+ /* dispatch based on command */
+ switch (cmd) {
+ case OSS_GETVERSION:
+ return put_user(SOUND_VERSION, (int __user *)arg);
+
+ case SNDCTL_DSP_GETBLKSIZE:
+ if (file->f_mode & FMODE_WRITE)
+ return put_user(os->fragsize, (int __user *)arg);
+ else
+ return put_user(is->fragsize, (int __user *)arg);
+
+ case SNDCTL_DSP_GETCAPS:
+ val = DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP;
+ if (is && os)
+ val |= DSP_CAP_DUPLEX;
+ FN_OUT(1);
+ return put_user(val, (int __user *)arg);
+
+ case SNDCTL_DSP_SETFRAGMENT:
+ if (get_user(val, (long __user *)arg)) {
+ FN_OUT(2);
+ return -EFAULT;
+ }
+ if (file->f_mode & FMODE_READ) {
+ int ret = audio_set_fragments(is, val);
+ if (ret < 0) {
+ FN_OUT(3);
+ return ret;
+ }
+ ret = put_user(ret, (int __user *)arg);
+ if (ret) {
+ FN_OUT(4);
+ return ret;
+ }
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ int ret = audio_set_fragments(os, val);
+ if (ret < 0) {
+ FN_OUT(5);
+ return ret;
+ }
+ ret = put_user(ret, (int __user *)arg);
+ if (ret) {
+ FN_OUT(6);
+ return ret;
+ }
+ }
+ FN_OUT(7);
+ return 0;
+
+ case SNDCTL_DSP_SYNC:
+ FN_OUT(8);
+ return audio_sync(file);
+
+ case SNDCTL_DSP_SETDUPLEX:
+ FN_OUT(9);
+ return 0;
+
+ case SNDCTL_DSP_POST:
+ FN_OUT(10);
+ return 0;
+
+ case SNDCTL_DSP_GETTRIGGER:
+ val = 0;
+ if (file->f_mode & FMODE_READ && is->active && !is->stopped)
+ val |= PCM_ENABLE_INPUT;
+ if (file->f_mode & FMODE_WRITE && os->active && !os->stopped)
+ val |= PCM_ENABLE_OUTPUT;
+ FN_OUT(11);
+ return put_user(val, (int __user *)arg);
+
+ case SNDCTL_DSP_SETTRIGGER:
+ if (get_user(val, (int __user *)arg)) {
+ FN_OUT(12);
+ return -EFAULT;
+ }
+ if (file->f_mode & FMODE_READ) {
+ if (val & PCM_ENABLE_INPUT) {
+ unsigned long flags;
+ if (!is->active) {
+ if (!is->buffers && audio_setup_buf(is)) {
+ FN_OUT(13);
+ return -ENOMEM;
+ }
+ audio_prime_rx(state);
+ }
+ local_irq_save(flags);
+ is->stopped = 0;
+ local_irq_restore(flags);
+ audio_process_dma(is);
+
+ } else {
+ audio_stop_dma(is);
+ }
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ if (val & PCM_ENABLE_OUTPUT) {
+ unsigned long flags;
+ if (!os->buffers && audio_setup_buf(os)) {
+ FN_OUT(14);
+ return -ENOMEM;
+ }
+ local_irq_save(flags);
+ if (os->mapped && !os->pending_frags) {
+ os->pending_frags = os->nbfrags;
+ init_completion(&os->wfc);
+ os->wfc.done = 0;
+ os->active = 1;
+ }
+ os->stopped = 0;
+ local_irq_restore(flags);
+ audio_process_dma(os);
+
+ } else {
+ audio_stop_dma(os);
+ }
+ }
+ FN_OUT(15);
+ return 0;
+
+ case SNDCTL_DSP_GETOPTR:
+ case SNDCTL_DSP_GETIPTR:
+ {
+ count_info inf = { 0, };
+ audio_stream_t *s =
+ (cmd == SNDCTL_DSP_GETOPTR) ? os : is;
+ int bytecount, offset;
+ unsigned long flags;
+
+ if ((s == is && !(file->f_mode & FMODE_READ)) ||
+ (s == os && !(file->f_mode & FMODE_WRITE))) {
+ FN_OUT(16);
+ return -EINVAL;
+ }
+ if (s->active) {
+ local_irq_save(flags);
+ offset = audio_get_dma_pos(s);
+ inf.ptr = s->dma_tail * s->fragsize + offset;
+ bytecount = s->bytecount + offset;
+ s->bytecount = -offset;
+ inf.blocks = s->fragcount;
+ s->fragcount = 0;
+ local_irq_restore(flags);
+ if (bytecount < 0)
+ bytecount = 0;
+ inf.bytes = bytecount;
+ }
+ FN_OUT(17);
+ return copy_to_user((void __user *)arg, &inf, sizeof(inf));
+ }
+
+ case SNDCTL_DSP_GETOSPACE:
+ case SNDCTL_DSP_GETISPACE:
+ {
+ audio_buf_info inf = { 0, };
+ audio_stream_t *s =
+ (cmd == SNDCTL_DSP_GETOSPACE) ? os : is;
+
+ if ((s == is && !(file->f_mode & FMODE_READ)) ||
+ (s == os && !(file->f_mode & FMODE_WRITE))) {
+ FN_OUT(18);
+ return -EINVAL;
+ }
+ if (!s->buffers && audio_setup_buf(s)) {
+ FN_OUT(19);
+ return -ENOMEM;
+ }
+ inf.bytes = s->wfc.done * s->fragsize;
+
+ inf.fragments = inf.bytes / s->fragsize;
+ inf.fragsize = s->fragsize;
+ inf.fragstotal = s->nbfrags;
+ FN_OUT(20);
+ return copy_to_user((void __user *)arg, &inf, sizeof(inf));
+ }
+
+ case SNDCTL_DSP_NONBLOCK:
+ file->f_flags |= O_NONBLOCK;
+ FN_OUT(21);
+ return 0;
+
+ case SNDCTL_DSP_RESET:
+ if (file->f_mode & FMODE_READ) {
+ audio_reset(is);
+ if (state->need_tx_for_rx) {
+ unsigned long flags;
+ local_irq_save(flags);
+ os->spin_idle = 0;
+ local_irq_restore(flags);
+ }
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ audio_reset(os);
+ }
+ FN_OUT(22);
+ return 0;
+
+ default:
+ /*
+ * Let the client of this module handle the
+ * non generic ioctls
+ */
+ FN_OUT(23);
+ return state->client_ioctl(inode, file, cmd, arg);
+ }
+
+ FN_OUT(0);
+ return 0;
+}
+
+/*********************************************************************************
+ *
+ * audio_open(): Exposed as open() function
+ *
+ *********************************************************************************/
+static int audio_open(struct inode *inode, struct file *file)
+{
+ audio_state_t *state = (&audio_state);
+ audio_stream_t *os = state->output_stream;
+ audio_stream_t *is = state->input_stream;
+ int err, need_tx_dma;
+ static unsigned char tsc2101_init_flag = 0;
+
+ FN_IN;
+
+ /* Lock the module */
+ if (!try_module_get(THIS_MODULE)) {
+ printk(KERN_CRIT "Failed to get module\n");
+ return -ESTALE;
+ }
+ /* Lock the codec module */
+ if (!try_module_get(state->owner)) {
+ printk(KERN_CRIT "Failed to get codec module\n");
+ module_put(THIS_MODULE);
+ return -ESTALE;
+ }
+
+ mutex_lock(&state->mutex);
+
+ /* access control */
+ err = -ENODEV;
+ if ((file->f_mode & FMODE_WRITE) && !os)
+ goto out;
+ if ((file->f_mode & FMODE_READ) && !is)
+ goto out;
+ err = -EBUSY;
+ if ((file->f_mode & FMODE_WRITE) && state->wr_ref)
+ goto out;
+ if ((file->f_mode & FMODE_READ) && state->rd_ref)
+ goto out;
+ err = -EINVAL;
+ if ((file->f_mode & FMODE_READ) && state->need_tx_for_rx && !os)
+ goto out;
+
+ /* request DMA channels */
+ need_tx_dma = ((file->f_mode & FMODE_WRITE) ||
+ ((file->f_mode & FMODE_READ) && state->need_tx_for_rx));
+ if (state->wr_ref || (state->rd_ref && state->need_tx_for_rx))
+ need_tx_dma = 0;
+ if (need_tx_dma) {
+ DMA_REQUEST(err, os, audio_dma_callback);
+ if (err < 0)
+ goto out;
+ }
+ if (file->f_mode & FMODE_READ) {
+ DMA_REQUEST(err, is, audio_dma_callback);
+ if (err < 0) {
+ if (need_tx_dma)
+ DMA_FREE(os);
+ goto out;
+ }
+ }
+
+ /* now complete initialisation */
+ if (!AUDIO_ACTIVE(state)) {
+ if (state->hw_init && !tsc2101_init_flag) {
+ state->hw_init(state->data);
+ tsc2101_init_flag = 0;
+
+ }
+
+ }
+
+ if ((file->f_mode & FMODE_WRITE)) {
+ state->wr_ref = 1;
+ audio_reset(os);
+ os->fragsize = AUDIO_FRAGSIZE_DEFAULT;
+ os->nbfrags = AUDIO_NBFRAGS_DEFAULT;
+ os->mapped = 0;
+ init_waitqueue_head(&os->wq);
+ }
+
+ if (file->f_mode & FMODE_READ) {
+ state->rd_ref = 1;
+ audio_reset(is);
+ is->fragsize = AUDIO_FRAGSIZE_DEFAULT;
+ is->nbfrags = AUDIO_NBFRAGS_DEFAULT;
+ is->mapped = 0;
+ init_waitqueue_head(&is->wq);
+ }
+
+ file->private_data = state;
+ err = 0;
+
+ out:
+ mutex_unlock(&state->mutex);
+ if (err) {
+ module_put(state->owner);
+ module_put(THIS_MODULE);
+ }
+ FN_OUT(err);
+ return err;
+}
+
+/*********************************************************************************
+ *
+ * audio_release(): Exposed as release function()
+ *
+ *********************************************************************************/
+static int audio_release(struct inode *inode, struct file *file)
+{
+ audio_state_t *state = file->private_data;
+ audio_stream_t *os = state->output_stream;
+ audio_stream_t *is = state->input_stream;
+
+ FN_IN;
+
+ mutex_lock(&state->mutex);
+
+ if (file->f_mode & FMODE_READ) {
+ audio_discard_buf(is);
+ DMA_FREE(is);
+ is->dma_spinref = 0;
+ if (state->need_tx_for_rx) {
+ os->spin_idle = 0;
+ if (!state->wr_ref) {
+ DMA_FREE(os);
+ os->dma_spinref = 0;
+ }
+ }
+ state->rd_ref = 0;
+ }
+
+ if (file->f_mode & FMODE_WRITE) {
+ audio_sync(file);
+ audio_discard_buf(os);
+ if (!state->need_tx_for_rx || !state->rd_ref) {
+ DMA_FREE(os);
+ os->dma_spinref = 0;
+ }
+ state->wr_ref = 0;
+ }
+
+ if (!AUDIO_ACTIVE(state)) {
+ if (state->hw_shutdown)
+ state->hw_shutdown(state->data);
+ }
+
+ mutex_unlock(&state->mutex);
+
+ module_put(state->owner);
+ module_put(THIS_MODULE);
+
+ FN_OUT(0);
+ return 0;
+}
+
+EXPORT_SYMBOL(audio_register_codec);
+EXPORT_SYMBOL(audio_unregister_codec);
+EXPORT_SYMBOL(audio_get_fops);
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("Common audio handling for OMAP processors");
+MODULE_LICENSE("GPL");
--- /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 mutex mutex; /* to protect against races in attach() */
+} audio_state_t;
+
+#ifdef AUDIO_PM
+void audio_ldm_suspend(void *data);
+
+void audio_ldm_resume(void *data);
+
+#endif
+
+/* Register a Codec using this function */
+extern int audio_register_codec(audio_state_t * codec_state);
+/* Un-Register a Codec using this function */
+extern int audio_unregister_codec(audio_state_t * codec_state);
+/* Function to provide fops of omap audio driver */
+extern struct file_operations *audio_get_fops(void);
+/* Function to initialize the device info for audio driver */
+extern int audio_dev_init(void);
+/* Function to un-initialize the device info for audio driver */
+void audio_dev_uninit(void);
+
+#endif /* End of #ifndef __OMAP_AUDIO_H */