--- /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.
+
+------------------------------------------------------------------
+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.
+
+ *************************************************************
+
+ NOTICE: these OMAP-specific interfaces are deprecated/obsolete.
+
+ See Documentation/gpio.txt for information on the standard
+ cross-platform GPIO interface. All new code should use those
+ calls instead of the ones described here.
+
+ The only exception to that policy is the omap_cfg_reg() call,
+ which isn't a GPIO-specific interface; it configures how chip
+ functions are multiplexed to pins, with GPIO being only one
+ of those functions.
+
+ *************************************************************
+
+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>
# 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/staging/Kconfig"
+if ARCH_OMAP
+source "drivers/cbus/Kconfig"
+source "drivers/dsp/dspgateway/Kconfig"
+endif
+
endmenu
source "fs/Kconfig"
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
--- /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.27-rc7-omap1
+# Wed Sep 24 18:43:59 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_HAVE_LATENCYTOP_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_GENERIC_HARDIRQS_NO__DO_IRQ=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_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+# CONFIG_GROUP_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_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_EFFICIENT_UNALIGNED_ACCESS is not set
+# CONFIG_HAVE_IOREMAP_PROT is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+# CONFIG_HAVE_ARCH_TRACEHOOK is not set
+# CONFIG_HAVE_DMA_ATTRS is not set
+# CONFIG_USE_GENERIC_SMP_HELPERS is not set
+CONFIG_HAVE_CLK=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+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
+# CONFIG_BLK_DEV_INTEGRITY 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_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_KIRKWOOD is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 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_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 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_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=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+# CONFIG_MACH_OMAP_GENERIC is not set
+
+#
+# OMAP Core Type
+#
+CONFIG_ARCH_OMAP24XX=y
+# CONFIG_ARCH_OMAP2420 is not set
+CONFIG_ARCH_OMAP2430=y
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_2430SDP is not set
+CONFIG_MACH_OMAP2EVM=y
+CONFIG_OMAP_TICK_GPTIMER=1
+
+#
+# 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 is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_PREEMPT=y
+CONFIG_HZ=100
+# CONFIG_AEABI is not set
+CONFIG_ARCH_FLATMEM_HAS_HOLES=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_PAGEFLAGS_EXTENDED=y
+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
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# 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
+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 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=y
+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=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_NDISC_NODETYPE=y
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_IPV6_MROUTE 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_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
+# CONFIG_MTD_AR7_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_OMAP2=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=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_OMAP_STI is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE 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_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# 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 is not set
+# CONFIG_DM9000 is not set
+# CONFIG_ENC28J60 is not set
+CONFIG_SMC911X=y
+# 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 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=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_LM8323 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_INEXIO 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_TSC2005 is not set
+# CONFIG_TOUCHSCREEN_TSC2102 is not set
+# CONFIG_TOUCHSCREEN_TSC210X is not set
+# CONFIG_TOUCHSCREEN_UCB1400 is not set
+# CONFIG_TOUCHSCREEN_TOUCHIT213 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_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER 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
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_AT24 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 is not set
+# CONFIG_SENSORS_TLV320AIC23 is not set
+# CONFIG_GPIOEXPANDER_OMAP is not set
+CONFIG_TWL4030_CORE=y
+CONFIG_TWL4030_GPIO=y
+# CONFIG_TWL4030_MADC is not set
+# CONFIG_TWL4030_USB is not set
+# 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_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
+CONFIG_SPI=y
+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_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_GPIO_SYSFS is not set
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+CONFIG_GPIO_TWL4030=y
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 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
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+CONFIG_DAB=y
+
+#
+# Graphics support
+#
+# 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=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_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# 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=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
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_UNSAFE_RESUME=y
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD Host Controller Drivers
+#
+# CONFIG_MMC_SDHCI is not set
+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
+# CONFIG_DMADEVICES is not set
+
+#
+# Voltage and Current regulators
+#
+# CONFIG_REGULATOR is not set
+# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_BQ24022 is not set
+# CONFIG_UIO is not set
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+# CONFIG_OMAP_DSP 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_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_OMFS_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 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# 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 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
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+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 is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_LATENCYTOP is not set
+CONFIG_HAVE_FTRACE=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+# CONFIG_FTRACE is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_PREEMPT_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_DEBUG_USER 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_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 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_GENERIC_FIND_FIRST_BIT is not set
+# CONFIG_GENERIC_FIND_NEXT_BIT is not set
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+CONFIG_CRC_T10DIF=m
+# 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
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.27-rc8
-# Wed Oct 1 17:14:22 2008
+# Linux kernel version: 2.6.27-omap1
+# Fri Oct 17 14:05:39 2008
#
CONFIG_ARM=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
#
# CONFIG_OMAP_DEBUG_POWERDOMAIN is not set
# CONFIG_OMAP_DEBUG_CLOCKDOMAIN is not set
+# CONFIG_OMAP_SMARTREFLEX 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
#
# OMAP Board Type
#
+# CONFIG_MACH_OMAP_LDP is not set
+# CONFIG_MACH_OMAP_3430SDP is not set
+# CONFIG_MACH_OMAP3EVM is not set
CONFIG_MACH_OMAP3_BEAGLE=y
+# CONFIG_MACH_OVERO is not set
+CONFIG_OMAP_TICK_GPTIMER=12
#
# Boot options
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
-CONFIG_VMSPLIT_3G=y
-# CONFIG_VMSPLIT_2G is not set
-# CONFIG_VMSPLIT_1G is not set
-CONFIG_PAGE_OFFSET=0xC0000000
# CONFIG_PREEMPT is not set
CONFIG_HZ=128
CONFIG_AEABI=y
# CONFIG_KEXEC is not set
#
-# CPU Power Management
+# CPU Frequency scaling
#
# CONFIG_CPU_FREQ is not set
-# CONFIG_CPU_IDLE is not set
#
# Floating point emulation
#
# Power management options
#
-# CONFIG_PM is not set
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+# CONFIG_SUSPEND is not set
+# CONFIG_APM_EMULATION is not set
CONFIG_ARCH_SUSPEND_POSSIBLE=y
CONFIG_NET=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_OMAP2=y
CONFIG_MTD_NAND_IDS=y
# CONFIG_MTD_NAND_DISKONCHIP is not set
# CONFIG_MTD_NAND_NANDSIM is not set
# CONFIG_I2C_GPIO is not set
# CONFIG_I2C_OCORES is not set
CONFIG_I2C_OMAP=y
+# CONFIG_I2C2_OMAP_BEAGLE is not set
# CONFIG_I2C_SIMTEC 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_MADC is not set
+CONFIG_TWL4030_USB=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_GPIO_MAX732X is not set
# CONFIG_GPIO_PCA953X is not set
# CONFIG_GPIO_PCF857X is not set
+CONFIG_GPIO_TWL4030=y
#
# PCI GPIO expanders:
# CONFIG_W1 is not set
# CONFIG_POWER_SUPPLY is not set
# CONFIG_HWMON is not set
-# CONFIG_THERMAL is not set
-# CONFIG_THERMAL_HWMON is not set
# CONFIG_WATCHDOG is not set
#
#
# CONFIG_MFD_CORE is not set
# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
# CONFIG_HTC_EGPIO is not set
# CONFIG_HTC_PASIC3 is not set
-# CONFIG_UCB1400_CORE is not set
+CONFIG_TWL4030_CORE=y
# CONFIG_MFD_TMIO is not set
# CONFIG_MFD_T7L66XB is not set
# CONFIG_MFD_TC6387XB is not set
#
# CONFIG_VGASTATE is not set
# CONFIG_VIDEO_OUTPUT_CONTROL is not set
-# CONFIG_FB 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_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# 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=4
# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
#
# 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=y
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+# CONFIG_LOGO is not set
# CONFIG_SOUND is not set
# CONFIG_HID_SUPPORT 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_ARCH_HAS_EHCI=y
CONFIG_USB=y
# CONFIG_USB_DEBUG is not set
# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
CONFIG_USB_DEVICEFS=y
CONFIG_USB_DEVICE_CLASS=y
# CONFIG_USB_DYNAMIC_MINORS is not set
-# CONFIG_USB_OTG is not set
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_OTG=y
# CONFIG_USB_OTG_WHITELIST is not set
# CONFIG_USB_OTG_BLACKLIST_HUB is not set
CONFIG_USB_MON=y
# USB Host Controller Drivers
#
# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_EHCI_HCD is not set
# CONFIG_USB_ISP116X_HCD is not set
# CONFIG_USB_ISP1760_HCD is not set
# CONFIG_USB_OHCI_HCD is not set
#
# OMAP 343x high speed USB support
#
-CONFIG_USB_MUSB_HOST=y
+# CONFIG_USB_MUSB_HOST is not set
# CONFIG_USB_MUSB_PERIPHERAL is not set
-# CONFIG_USB_MUSB_OTG is not set
-# CONFIG_USB_GADGET_MUSB_HDRC 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_GADGET_FSL_USB2 is not set
# CONFIG_USB_GADGET_NET2280 is not set
# CONFIG_USB_GADGET_PXA25X is not set
-CONFIG_USB_GADGET_M66592=y
-CONFIG_USB_M66592=y
+# CONFIG_USB_GADGET_M66592 is not set
# CONFIG_USB_GADGET_PXA27X is not set
# CONFIG_USB_GADGET_GOKU is not set
# CONFIG_USB_GADGET_LH7A40X is not set
# MMC/SD Host Controller Drivers
#
# CONFIG_MMC_SDHCI is not set
-# CONFIG_MMC_OMAP is not set
-# CONFIG_MEMSTICK is not set
-# CONFIG_ACCESSIBILITY is not set
+CONFIG_MMC_OMAP_HS=y
# CONFIG_NEW_LEDS is not set
CONFIG_RTC_LIB=y
CONFIG_RTC_CLASS=y
# CONFIG_RTC_DRV_PCF8563 is not set
# CONFIG_RTC_DRV_PCF8583 is not set
# CONFIG_RTC_DRV_M41T80 is not set
+CONFIG_RTC_DRV_TWL4030=y
# CONFIG_RTC_DRV_S35390A is not set
# CONFIG_RTC_DRV_FM3130 is not set
# CONFIG_REGULATOR_BQ24022 is not set
# CONFIG_UIO is not set
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
#
# File systems
#
--- /dev/null
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.27-omap1
+# Fri Oct 17 14:06:41 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_HAVE_LATENCYTOP_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_GENERIC_HARDIRQS_NO__DO_IRQ=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_EFFICIENT_UNALIGNED_ACCESS is not set
+# CONFIG_HAVE_IOREMAP_PROT is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+# CONFIG_HAVE_ARCH_TRACEHOOK is not set
+# CONFIG_HAVE_DMA_ATTRS is not set
+# CONFIG_USE_GENERIC_SMP_HELPERS is not set
+CONFIG_HAVE_CLK=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+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
+# CONFIG_BLK_DEV_INTEGRITY 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_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_KIRKWOOD is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 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_POWERDOMAIN is not set
+# CONFIG_OMAP_DEBUG_CLOCKDOMAIN is not set
+CONFIG_OMAP_SMARTREFLEX=y
+# CONFIG_OMAP_SMARTREFLEX_TESTING is not set
+CONFIG_OMAP_RESET_CLOCKS=y
+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 is not set
+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_LDP is not set
+# CONFIG_MACH_OMAP_3430SDP is not set
+CONFIG_MACH_OMAP3EVM=y
+# CONFIG_MACH_OMAP3_BEAGLE is not set
+# CONFIG_MACH_OVERO is not set
+CONFIG_OMAP_TICK_GPTIMER=1
+
+#
+# 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_FLATMEM_HAS_HOLES=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_PAGEFLAGS_EXTENDED=y
+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=y
+
+#
+# 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_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
+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=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_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=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_OMAP2=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=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 is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_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_SCSI_DH is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# 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 is not set
+# CONFIG_DM9000 is not set
+# CONFIG_ENC28J60 is not set
+CONFIG_SMC911X=y
+# 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 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
+
+#
+# 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_LM8323 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_INEXIO 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_TSC2005 is not set
+# CONFIG_TOUCHSCREEN_TSC2102 is not set
+# CONFIG_TOUCHSCREEN_TSC210X is not set
+# CONFIG_TOUCHSCREEN_UCB1400 is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+# CONFIG_TOUCHSCREEN_TOUCHIT213 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_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# 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
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_AT24 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 is not set
+# CONFIG_SENSORS_TLV320AIC23 is not set
+# CONFIG_TWL4030_MADC is not set
+CONFIG_TWL4030_USB=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
+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_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+# CONFIG_GPIO_SYSFS is not set
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+CONFIG_GPIO_TWL4030=y
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 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_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+CONFIG_TWL4030_CORE=y
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+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_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# 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=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+# 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 is not set
+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_OTG=y
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+CONFIG_USB_MON=y
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_EHCI_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_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_DEBUG is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM 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_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# 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_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_ISIGHTFW is not set
+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_PXA25X is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_PXA27X 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 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_USB_CDC_COMPOSITE 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
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD Host Controller Drivers
+#
+# CONFIG_MMC_SDHCI is not set
+CONFIG_MMC_OMAP_HS=m
+# CONFIG_MMC_SPI is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+
+#
+# Voltage and Current regulators
+#
+# CONFIG_REGULATOR is not set
+# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_BQ24022 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=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_OMFS_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_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# 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_FRAME_WARN=1024
+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_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS 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_MEMORY_INIT 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_LATENCYTOP is not set
+CONFIG_HAVE_FTRACE=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+# CONFIG_FTRACE is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB 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_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 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_GENERIC_FIND_FIRST_BIT is not set
+# CONFIG_GENERIC_FIND_NEXT_BIT is not set
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF 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
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.28-rc7
-# Fri Dec 5 11:54:09 2008
+# Linux kernel version: 2.6.28-rc3-omap1
+# Wed Nov 5 22:02:43 2008
#
CONFIG_ARM=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
#
# CONFIG_OMAP_DEBUG_POWERDOMAIN is not set
# CONFIG_OMAP_DEBUG_CLOCKDOMAIN is not set
+# CONFIG_OMAP_SMARTREFLEX 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=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
#
# OMAP Board Type
#
-# CONFIG_MACH_OMAP3_BEAGLE is not set
# CONFIG_MACH_OMAP_LDP is not set
+# CONFIG_MACH_OMAP_3430SDP is not set
+# CONFIG_MACH_OMAP3EVM is not set
+# CONFIG_MACH_OMAP3_BEAGLE is not set
# CONFIG_MACH_OVERO is not set
CONFIG_MACH_OMAP3_PANDORA=y
+CONFIG_OMAP_TICK_GPTIMER=12
#
# Boot options
#
# Power management options
#
-# CONFIG_PM is not set
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+# CONFIG_SUSPEND is not set
+# CONFIG_APM_EMULATION is not set
CONFIG_ARCH_SUSPEND_POSSIBLE=y
CONFIG_NET=y
# CONFIG_MTD_NAND_ECC_SMC is not set
# CONFIG_MTD_NAND_MUSEUM_IDS is not set
# CONFIG_MTD_NAND_GPIO is not set
+CONFIG_MTD_NAND_OMAP2=y
CONFIG_MTD_NAND_IDS=y
# CONFIG_MTD_NAND_DISKONCHIP is not set
# CONFIG_MTD_NAND_NANDSIM is not set
# CONFIG_KEYBOARD_XTKBD is not set
# CONFIG_KEYBOARD_NEWTON is not set
# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_LM8323 is not set
# CONFIG_KEYBOARD_GPIO is not set
CONFIG_INPUT_MOUSE=y
# CONFIG_MOUSE_PS2 is not set
# CONFIG_TOUCHSCREEN_PENMOUNT is not set
# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_TSC2005 is not set
+# CONFIG_TOUCHSCREEN_TSC2102 is not set
+# CONFIG_TOUCHSCREEN_TSC210X is not set
# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
# CONFIG_INPUT_MISC 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_MADC is not set
+CONFIG_TWL4030_USB=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
# 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_ARCH_REQUIRE_GPIOLIB=y
# CONFIG_DEBUG_GPIO is not set
# CONFIG_GPIO_SYSFS is not set
-#
-# Memory mapped GPIO expanders:
-#
-
#
# I2C GPIO expanders:
#
# CONFIG_THERMAL is not set
# CONFIG_THERMAL_HWMON is not set
# CONFIG_WATCHDOG is not set
-CONFIG_SSB_POSSIBLE=y
#
# Sonics Silicon Backplane
#
+CONFIG_SSB_POSSIBLE=y
# CONFIG_SSB is not set
#
# CONFIG_HTC_EGPIO is not set
# CONFIG_HTC_PASIC3 is not set
CONFIG_TWL4030_CORE=y
+CONFIG_TWL4030_POWER=y
# CONFIG_MFD_TMIO is not set
# CONFIG_MFD_T7L66XB is not set
# CONFIG_MFD_TC6387XB is not set
#
# CONFIG_VGASTATE is not set
# CONFIG_VIDEO_OUTPUT_CONTROL is not set
-# CONFIG_FB is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT 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_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME 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=4
# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
#
# 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=y
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+# CONFIG_LOGO is not set
# CONFIG_SOUND is not set
CONFIG_HID_SUPPORT=y
CONFIG_HID=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_ARCH_HAS_EHCI=y
CONFIG_USB=y
# CONFIG_USB_DEBUG is not set
# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
CONFIG_USB_DEVICEFS=y
CONFIG_USB_DEVICE_CLASS=y
# CONFIG_USB_DYNAMIC_MINORS is not set
-# CONFIG_USB_OTG is not set
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_OTG=y
# CONFIG_USB_OTG_WHITELIST is not set
# CONFIG_USB_OTG_BLACKLIST_HUB is not set
CONFIG_USB_MON=y
# USB Host Controller Drivers
#
# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_EHCI_HCD is not set
# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_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
#
# OMAP 343x high speed USB support
#
-CONFIG_USB_MUSB_HOST=y
+# CONFIG_USB_MUSB_HOST is not set
# CONFIG_USB_MUSB_PERIPHERAL is not set
-# CONFIG_USB_MUSB_OTG is not set
-# CONFIG_USB_GADGET_MUSB_HDRC 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_TMC is not set
#
-# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed;
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
#
#
-# see USB_STORAGE Help for more information
+# may also be needed; see USB_STORAGE Help for more information
#
# CONFIG_USB_STORAGE is not set
# CONFIG_USB_LIBUSUAL is not set
# CONFIG_USB_GADGET_ATMEL_USBA is not set
# CONFIG_USB_GADGET_FSL_USB2 is not set
# CONFIG_USB_GADGET_LH7A40X is not set
-CONFIG_USB_GADGET_OMAP=y
-CONFIG_USB_OMAP=y
+# CONFIG_USB_GADGET_OMAP is not set
# CONFIG_USB_GADGET_PXA25X is not set
# CONFIG_USB_GADGET_PXA27X is not set
# CONFIG_USB_GADGET_S3C2410 is not set
# CONFIG_USB_GADGET_NET2280 is not set
# CONFIG_USB_GADGET_GOKU is not set
# CONFIG_USB_GADGET_DUMMY_HCD is not set
-# CONFIG_USB_GADGET_DUALSPEED is not set
+CONFIG_USB_GADGET_DUALSPEED=y
# CONFIG_USB_ZERO is not set
CONFIG_USB_ETH=y
CONFIG_USB_ETH_RNDIS=y
# MMC/SD/SDIO Host Controller Drivers
#
# CONFIG_MMC_SDHCI is not set
-# CONFIG_MMC_OMAP is not set
+CONFIG_MMC_OMAP_HS=y
# CONFIG_MMC_SPI is not set
# CONFIG_MEMSTICK is not set
# CONFIG_ACCESSIBILITY is not set
CONFIG_RTC_DRV_TWL4030=y
# CONFIG_RTC_DRV_S35390A is not set
# CONFIG_RTC_DRV_FM3130 is not set
-# CONFIG_RTC_DRV_RX8581 is not set
#
# SPI RTC drivers
#
# CONFIG_RTC_DRV_M41T94 is not set
# CONFIG_RTC_DRV_DS1305 is not set
-# CONFIG_RTC_DRV_DS1390 is not set
# CONFIG_RTC_DRV_MAX6902 is not set
# CONFIG_RTC_DRV_R9701 is not set
# CONFIG_RTC_DRV_RS5C348 is not set
# on-CPU RTC drivers
#
# CONFIG_DMADEVICES is not set
+
+#
+# Voltage and Current regulators
+#
# CONFIG_REGULATOR is not set
+# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_BQ24022 is not set
# CONFIG_UIO is not set
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
#
# File systems
#
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.23-rc6-omap1
-# Tue Sep 18 11:47:37 2007
+# Linux kernel version: 2.6.27-omap1
+# Fri Oct 17 13:59:37 2008
#
CONFIG_ARM=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
# CONFIG_NO_IOPORT is not set
CONFIG_GENERIC_HARDIRQS=y
CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_HARDIRQS_SW_RESEND=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_GENERIC_HARDIRQS_NO__DO_IRQ=y
CONFIG_VECTORS_BASE=0xffff0000
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
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_CGROUPS is not set
+# CONFIG_GROUP_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_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_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_EFFICIENT_UNALIGNED_ACCESS is not set
+# CONFIG_HAVE_IOREMAP_PROT is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+# CONFIG_HAVE_ARCH_TRACEHOOK is not set
+# CONFIG_HAVE_DMA_ATTRS is not set
+# CONFIG_USE_GENERIC_SMP_HELPERS is not set
+CONFIG_HAVE_CLK=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
CONFIG_MODULE_UNLOAD=y
# CONFIG_MODULE_FORCE_UNLOAD is not set
CONFIG_MODVERSIONS=y
# CONFIG_BLK_DEV_IO_TRACE is not set
# CONFIG_LSF is not set
# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
#
# IO Schedulers
# CONFIG_DEFAULT_CFQ is not set
# CONFIG_DEFAULT_NOOP is not set
CONFIG_DEFAULT_IOSCHED="anticipatory"
+CONFIG_CLASSIC_RCU=y
#
# System Type
# 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_IXP2000 is not set
# CONFIG_ARCH_IXP4XX is not set
# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KIRKWOOD is not set
# CONFIG_ARCH_KS8695 is not set
# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 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_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_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 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_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 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
+# CONFIG_MACH_OMAP2EVM is not set
+CONFIG_OMAP_TICK_GPTIMER=1
#
# Boot options
#
# CONFIG_PCI_SYSCALL is not set
# CONFIG_ARCH_SUPPORTS_MSI is not set
-
-#
-# PCCARD (PCMCIA/CardBus) support
-#
# CONFIG_PCCARD is not set
#
# 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=y
CONFIG_HZ=100
CONFIG_AEABI=y
CONFIG_OABI_COMPAT=y
+CONFIG_ARCH_FLATMEM_HAS_HOLES=y
# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_FLATMEM_MANUAL=y
CONFIG_FLATMEM=y
CONFIG_FLAT_NODE_MEM_MAP=y
# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
CONFIG_SPLIT_PTLOCK_CPUS=4
# CONFIG_RESOURCES_64BIT is not set
CONFIG_ZONE_DMA_FLAG=1
# 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_SUSPEND_FREEZER=y
# CONFIG_APM_EMULATION is not set
-
-#
-# Networking
-#
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
CONFIG_NET=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_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_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_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
#
#
# 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
#
# Generic Driver Options
#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_FW_LOADER is not set
# CONFIG_MTD_REDBOOT_PARTS is not set
CONFIG_MTD_CMDLINE_PARTS=y
# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
#
# User Modules And Translation Layers
# 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_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_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=16384
-CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_BLK_DEV_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 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
#
# SCSI device support
# 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_SCSI_DH 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_SMC911X 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
#
# CONFIG_WLAN_PRE80211 is not set
# CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS is not set
#
# USB Network Adapters
# 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_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
# CONFIG_KEYBOARD_STOWAWAY is not set
# CONFIG_KEYBOARD_OMAP is not set
CONFIG_KEYBOARD_TWL4030=y
+# CONFIG_KEYBOARD_LM8323 is not set
# CONFIG_KEYBOARD_GPIO is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_INPUT_JOYSTICK is not set
# CONFIG_TOUCHSCREEN_GUNZE is not set
# CONFIG_TOUCHSCREEN_ELO is not set
# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_INEXIO 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_TOUCHSCREEN_UCB1400 is not set
# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
# CONFIG_INPUT_MISC is not set
#
# Character devices
#
CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
CONFIG_VT_CONSOLE=y
CONFIG_HW_CONSOLE=y
# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
# CONFIG_SERIAL_NONSTANDARD is not set
#
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_I2C=y
CONFIG_I2C_BOARDINFO=y
CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
#
-# I2C Algorithms
+# I2C Hardware Bus support
#
-# CONFIG_I2C_ALGOBIT is not set
-# CONFIG_I2C_ALGOPCF is not set
-# CONFIG_I2C_ALGOPCA is not set
#
-# I2C Hardware Bus support
+# I2C system bus drivers (mostly embedded / system-on-chip)
#
# 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
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
# CONFIG_I2C_TAOS_EVM is not set
-# CONFIG_I2C_STUB is not set
# CONFIG_I2C_TINY_USB is not set
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM 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_AT24 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 is not set
# CONFIG_SENSORS_TLV320AIC23 is not set
# CONFIG_GPIOEXPANDER_OMAP is not set
-CONFIG_TWL4030_CORE=y
-CONFIG_TWL4030_GPIO=y
+# CONFIG_TWL4030_MADC is not set
+# CONFIG_TWL4030_USB is not set
+# 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_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
# CONFIG_SPI_TSC2301 is not set
# CONFIG_SPI_SPIDEV is not set
# CONFIG_SPI_TLE62X0 is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+# CONFIG_GPIO_SYSFS is not set
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+CONFIG_GPIO_TWL4030=y
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
# CONFIG_HWMON is not set
-CONFIG_MISC_DEVICES=y
-# CONFIG_EEPROM_93CX6 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_CORE is not set
# CONFIG_MFD_SM501 is not set
-# CONFIG_NEW_LEDS is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+CONFIG_TWL4030_CORE=y
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
#
# Multimedia devices
#
+
+#
+# Multimedia core support
+#
# CONFIG_VIDEO_DEV is not set
# CONFIG_DVB_CORE is not set
-CONFIG_DAB=y
-# CONFIG_USB_DABUSB is not set
+# CONFIG_VIDEO_MEDIA is not set
#
-# Graphics support
+# Multimedia drivers
#
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+CONFIG_DAB=y
+# CONFIG_USB_DABUSB is not set
#
-# Display device support
+# Graphics 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_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_FOREIGN_ENDIAN 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
# 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_VIRTUAL is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
#
# Console display driver support
# 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_HIDRAW is not set
#
# USB Input Devices
# 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_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
+CONFIG_USB_MON=y
#
# USB Host Controller Drivers
#
+# CONFIG_USB_C67X00_HCD is not set
# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_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_MUSB_PIO_ONLY is not set
CONFIG_USB_INVENTRA_DMA=y
# CONFIG_USB_TI_CPPI_DMA is not set
-CONFIG_USB_MUSB_LOGLEVEL=0
+# CONFIG_USB_MUSB_DEBUG is not set
#
# USB Device Class drivers
#
# CONFIG_USB_ACM is not set
# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
#
# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
# 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_ONETOUCH is not set
# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
# CONFIG_USB_LIBUSUAL is not set
#
#
# 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
#
# 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_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_ISIGHTFW is not set
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_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_PXA25X is not set
# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_PXA27X 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_FILE_STORAGE_TEST is not set
CONFIG_USB_G_SERIAL=m
# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_USB_G_PRINTER is not set
+# CONFIG_USB_CDC_COMPOSITE is not set
CONFIG_MMC=y
# CONFIG_MMC_DEBUG is not set
# CONFIG_MMC_UNSAFE_RESUME is not set
#
CONFIG_MMC_BLOCK=y
CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
#
# MMC/SD Host Controller Drivers
#
+# CONFIG_MMC_SDHCI is not set
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
+# CONFIG_DMADEVICES is not set
#
-# DMA Engine support
-#
-# CONFIG_DMA_ENGINE is not set
-
-#
-# DMA Clients
-#
-
-#
-# DMA Devices
+# Voltage and Current regulators
#
+# CONFIG_REGULATOR is not set
+# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_BQ24022 is not set
+# CONFIG_UIO is not set
#
# CBUS support
#
# CONFIG_CBUS is not set
+# CONFIG_OMAP_DSP is not set
#
# File systems
# 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_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_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
# CONFIG_FUSE_FS is not set
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
#
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_OMFS_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
-
-#
-# Network File Systems
-#
+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_NFSD 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_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_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_WARN_DEPRECATED=y
CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
CONFIG_MAGIC_SYSRQ=y
# CONFIG_UNUSED_SYMBOLS is not set
# CONFIG_DEBUG_FS is not set
CONFIG_DEBUG_KERNEL=y
# CONFIG_DEBUG_SHIRQ is not set
CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
CONFIG_SCHED_DEBUG=y
# CONFIG_SCHEDSTATS is not set
CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_OBJECTS is not set
# CONFIG_DEBUG_SLAB is not set
CONFIG_DEBUG_PREEMPT=y
# CONFIG_DEBUG_RT_MUTEXES is not set
# CONFIG_DEBUG_BUGVERBOSE is not set
# CONFIG_DEBUG_INFO is not set
# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT 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_BACKTRACE_SELF_TEST is not set
# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_HAVE_FTRACE=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+# CONFIG_FTRACE is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_PREEMPT_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB 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 is not set
#
#
# 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
-# CONFIG_CRYPTO_NULL 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_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 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_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_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_TEA is not set
-# CONFIG_CRYPTO_ARC4 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
# CONFIG_CRYPTO_KHAZAD is not set
-# CONFIG_CRYPTO_ANUBIS 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_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_LZO is not set
CONFIG_CRYPTO_HW=y
#
# Library routines
#
CONFIG_BITREVERSE=y
+# CONFIG_GENERIC_FIND_FIRST_BIT is not set
+# CONFIG_GENERIC_FIND_NEXT_BIT is not set
CONFIG_CRC_CCITT=y
# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
# CONFIG_CRC_ITU_T is not set
CONFIG_CRC32=y
# CONFIG_CRC7 is not set
--- /dev/null
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.27-omap1
+# Fri Oct 17 13:41:54 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_HAVE_LATENCYTOP_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_GENERIC_HARDIRQS_NO__DO_IRQ=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_EFFICIENT_UNALIGNED_ACCESS is not set
+# CONFIG_HAVE_IOREMAP_PROT is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+# CONFIG_HAVE_ARCH_TRACEHOOK is not set
+# CONFIG_HAVE_DMA_ATTRS is not set
+# CONFIG_USE_GENERIC_SMP_HELPERS is not set
+CONFIG_HAVE_CLK=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+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
+# CONFIG_BLK_DEV_INTEGRITY 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_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_KIRKWOOD is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 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_POWERDOMAIN is not set
+# CONFIG_OMAP_DEBUG_CLOCKDOMAIN is not set
+CONFIG_OMAP_SMARTREFLEX=y
+# CONFIG_OMAP_SMARTREFLEX_TESTING is not set
+CONFIG_OMAP_RESET_CLOCKS=y
+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_LDP is not set
+CONFIG_MACH_OMAP_3430SDP=y
+# CONFIG_MACH_OMAP3EVM is not set
+# CONFIG_MACH_OMAP3_BEAGLE is not set
+# CONFIG_MACH_OVERO is not set
+CONFIG_OMAP_TICK_GPTIMER=1
+
+#
+# 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_FLATMEM_HAS_HOLES=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_PAGEFLAGS_EXTENDED=y
+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_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
+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=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_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=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+CONFIG_MTD_NAND_ECC_SMC=y
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_OMAP2=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=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_OMAP_STI is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_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_SCSI_DH is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# 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_SMC911X 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
+# 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 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_LM8323 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_INEXIO 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_TSC2005 is not set
+# CONFIG_TOUCHSCREEN_TSC2102 is not set
+# CONFIG_TOUCHSCREEN_TSC210X is not set
+# CONFIG_TOUCHSCREEN_UCB1400 is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+# CONFIG_TOUCHSCREEN_TOUCHIT213 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_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# 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
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_AT24 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 is not set
+# CONFIG_SENSORS_TLV320AIC23 is not set
+# CONFIG_TWL4030_MADC is not set
+CONFIG_TWL4030_USB=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
+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_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+# CONFIG_GPIO_SYSFS is not set
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+CONFIG_GPIO_TWL4030=y
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 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_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+CONFIG_TWL4030_CORE=y
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+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_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# 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=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=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+# 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_OTG=y
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+CONFIG_USB_MON=y
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+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_ISP1760_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_DEBUG is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM 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_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# 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_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_ISIGHTFW is not set
+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_PXA25X is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_PXA27X 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 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_USB_CDC_COMPOSITE 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
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD Host Controller Drivers
+#
+# CONFIG_MMC_SDHCI is not set
+CONFIG_MMC_OMAP_HS=m
+# 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
+CONFIG_RTC_DRV_TWL4030=y
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_M41T94 is not set
+# CONFIG_RTC_DRV_DS1305 is not set
+# 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_DMADEVICES is not set
+
+#
+# Voltage and Current regulators
+#
+# CONFIG_REGULATOR is not set
+# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_BQ24022 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=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_OMFS_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_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# 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_FRAME_WARN=1024
+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_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS 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_MEMORY_INIT 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_LATENCYTOP is not set
+CONFIG_HAVE_FTRACE=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+# CONFIG_FTRACE is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB 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_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 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_GENERIC_FIND_FIRST_BIT is not set
+# CONFIG_GENERIC_FIND_NEXT_BIT is not set
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF 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
+# 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
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.27-rc5
-# Fri Oct 10 11:49:41 2008
+# Linux kernel version: 2.6.27-omap1
+# Fri Oct 17 17:56:45 2008
#
CONFIG_ARM=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
#
# CONFIG_OMAP_DEBUG_POWERDOMAIN is not set
# CONFIG_OMAP_DEBUG_CLOCKDOMAIN is not set
+# CONFIG_OMAP_SMARTREFLEX 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=y
CONFIG_OMAP_MUX_DEBUG=y
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 is not set
CONFIG_OMAP_32K_TIMER=y
CONFIG_OMAP_32K_TIMER_HZ=128
#
# OMAP Board Type
#
-# CONFIG_MACH_OMAP3_BEAGLE is not set
CONFIG_MACH_OMAP_LDP=y
+# CONFIG_MACH_OMAP_3430SDP is not set
+# CONFIG_MACH_OMAP3EVM is not set
+# CONFIG_MACH_OMAP3_BEAGLE is not set
# CONFIG_MACH_OVERO is not set
+CONFIG_OMAP_TICK_GPTIMER=1
#
# Boot options
#
# Power management options
#
-# CONFIG_PM is not set
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+# CONFIG_SUSPEND is not set
+# CONFIG_APM_EMULATION is not set
CONFIG_ARCH_SUSPEND_POSSIBLE=y
CONFIG_NET=y
# CONFIG_BLK_DEV_COW_COMMON is not set
CONFIG_BLK_DEV_LOOP=y
# CONFIG_BLK_DEV_CRYPTOLOOP 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_CDROM_PKTCDVD is not set
CONFIG_MISC_DEVICES=y
# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_OMAP_STI is not set
# CONFIG_ENCLOSURE_SERVICES is not set
CONFIG_HAVE_IDE=y
# CONFIG_IDE is not set
#
# Input Device Drivers
#
-# CONFIG_INPUT_KEYBOARD is not set
+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_LM8323 is not set
+CONFIG_KEYBOARD_GPIO=y
# CONFIG_INPUT_MOUSE is not set
# CONFIG_INPUT_JOYSTICK is not set
# CONFIG_INPUT_TABLET is not set
# CONFIG_TOUCHSCREEN_PENMOUNT is not set
# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_TSC2005 is not set
+# CONFIG_TOUCHSCREEN_TSC2102 is not set
+# CONFIG_TOUCHSCREEN_TSC210X is not set
# CONFIG_TOUCHSCREEN_UCB1400 is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
# CONFIG_INPUT_MISC is not set
#
# CONFIG_I2C_PARPORT_LIGHT is not set
# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
#
# Other I2C/SMBus bus drivers
# 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_MADC=y
+CONFIG_TWL4030_USB=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
# 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_ARCH_REQUIRE_GPIOLIB=y
# CONFIG_GPIO_MAX732X is not set
# CONFIG_GPIO_PCA953X is not set
# CONFIG_GPIO_PCF857X is not set
+CONFIG_GPIO_TWL4030=y
#
# PCI GPIO expanders:
#
# 1-wire Bus Masters
#
+# CONFIG_W1_MASTER_DS2490 is not set
# CONFIG_W1_MASTER_DS2482 is not set
# CONFIG_W1_MASTER_DS1WM is not set
+CONFIG_HDQ_MASTER_OMAP=y
# CONFIG_W1_MASTER_GPIO is not set
#
# CONFIG_W1_SLAVE_SMEM is not set
# CONFIG_W1_SLAVE_DS2433 is not set
# CONFIG_W1_SLAVE_DS2760 is not set
+CONFIG_W1_SLAVE_BQ27000=y
CONFIG_POWER_SUPPLY=y
# CONFIG_POWER_SUPPLY_DEBUG is not set
# CONFIG_PDA_POWER is not set
# CONFIG_BATTERY_DS2760 is not set
+# CONFIG_BATTERY_BQ27x00 is not set
+CONFIG_TWL4030_BCI_BATTERY=y
# 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_MFD_CORE is not set
# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
# CONFIG_HTC_EGPIO is not set
# CONFIG_HTC_PASIC3 is not set
+CONFIG_TWL4030_CORE=y
# CONFIG_MFD_TMIO is not set
# CONFIG_MFD_T7L66XB is not set
# CONFIG_MFD_TC6387XB is not set
# Multimedia drivers
#
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
+CONFIG_FB=y
+CONFIG_FIRMWARE_EDID=y
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT 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_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+CONFIG_FB_OMAP=y
+CONFIG_FB_OMAP_LCD_VGA=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=4
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=y
+# CONFIG_LCD_LTV350QV is not set
+# CONFIG_LCD_ILI9320 is not set
+# CONFIG_LCD_TDO24M is not set
+# CONFIG_LCD_VGG2432A4 is not set
+CONFIG_LCD_PLATFORM=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_CORGI is not set
#
# Display device 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=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
CONFIG_SOUND=y
CONFIG_SND=y
# CONFIG_SND_SEQUENCER is not set
# CONFIG_SND_SERIAL_U16550 is not set
# CONFIG_SND_MPU401 is not set
CONFIG_SND_ARM=y
+# 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 is not set
CONFIG_SND_SPI=y
+CONFIG_SND_USB=y
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_CAIAQ is not set
# CONFIG_SND_SOC is not set
# CONFIG_SOUND_PRIME is not set
CONFIG_HID_SUPPORT=y
CONFIG_HID=y
# CONFIG_HID_DEBUG is not set
# CONFIG_HIDRAW is not set
-# CONFIG_USB_SUPPORT 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 is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES 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_OTG=y
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+CONFIG_USB_MON=y
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_EHCI_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_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_DEBUG is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+# CONFIG_USB_STORAGE is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# 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_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
+# CONFIG_USB_ISIGHTFW is not set
+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_PXA25X is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_PXA27X 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 is not set
+# CONFIG_USB_GADGETFS is not set
+CONFIG_USB_FILE_STORAGE=m
+CONFIG_USB_FILE_STORAGE_TEST=y
+CONFIG_USB_G_SERIAL=m
+# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_USB_G_PRINTER is not set
+# CONFIG_USB_CDC_COMPOSITE is not set
CONFIG_MMC=y
# CONFIG_MMC_DEBUG is not set
# CONFIG_MMC_UNSAFE_RESUME is not set
# MMC/SD Host Controller Drivers
#
# CONFIG_MMC_SDHCI is not set
-# CONFIG_MMC_OMAP is not set
+CONFIG_MMC_OMAP_HS=y
# CONFIG_MMC_SPI is not set
# CONFIG_NEW_LEDS is not set
CONFIG_RTC_LIB=y
# CONFIG_RTC_DRV_PCF8563 is not set
# CONFIG_RTC_DRV_PCF8583 is not set
# CONFIG_RTC_DRV_M41T80 is not set
+CONFIG_RTC_DRV_TWL4030=y
# CONFIG_RTC_DRV_S35390A is not set
# CONFIG_RTC_DRV_FM3130 is not set
# CONFIG_REGULATOR_BQ24022 is not set
# CONFIG_UIO is not set
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
#
# File systems
#
# CONFIG_GENERIC_FIND_NEXT_BIT is not set
CONFIG_CRC_CCITT=y
# CONFIG_CRC16 is not set
-CONFIG_CRC_T10DIF=y
+# CONFIG_CRC_T10DIF is not set
# CONFIG_CRC_ITU_T is not set
CONFIG_CRC32=y
# CONFIG_CRC7 is not set
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.27-rc8
-# Fri Oct 3 11:50:34 2008
+# Linux kernel version: 2.6.27-omap1
+# Fri Oct 17 14:08:14 2008
#
CONFIG_ARM=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
CONFIG_ARCH_SUPPORTS_AOUT=y
CONFIG_ZONE_DMA=y
CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
-CONFIG_OPROFILE_ARMV7=y
CONFIG_VECTORS_BASE=0xffff0000
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
# CONFIG_OMAP_DEBUG_POWERDOMAIN is not set
# CONFIG_OMAP_DEBUG_CLOCKDOMAIN is not set
+CONFIG_OMAP_SMARTREFLEX=y
+# CONFIG_OMAP_SMARTREFLEX_TESTING 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=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
#
# OMAP Board Type
#
+# CONFIG_MACH_OMAP_LDP is not set
+# CONFIG_MACH_OMAP_3430SDP is not set
+# CONFIG_MACH_OMAP3EVM is not set
# CONFIG_MACH_OMAP3_BEAGLE is not set
CONFIG_MACH_OVERO=y
+CONFIG_OMAP_TICK_GPTIMER=1
#
# Boot options
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
-CONFIG_VMSPLIT_3G=y
-# CONFIG_VMSPLIT_2G is not set
-# CONFIG_VMSPLIT_1G is not set
-CONFIG_PAGE_OFFSET=0xC0000000
# CONFIG_PREEMPT is not set
CONFIG_HZ=128
CONFIG_AEABI=y
CONFIG_ATAGS_PROC=y
#
-# CPU Power Management
+# CPU Frequency scaling
#
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_TABLE=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
-# CONFIG_CPU_IDLE is not set
#
# Floating point emulation
#
# Power management options
#
-# CONFIG_PM is not set
+CONFIG_PM=y
+# 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
CONFIG_NET=y
CONFIG_BT_HCIBCM203X=y
CONFIG_BT_HCIBPA10X=y
# 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
# 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_OMAP2=y
CONFIG_MTD_NAND_IDS=y
# CONFIG_MTD_NAND_DISKONCHIP is not set
# CONFIG_MTD_NAND_NANDSIM is not set
# CONFIG_ATA_OVER_ETH is not set
CONFIG_MISC_DEVICES=y
CONFIG_EEPROM_93CX6=m
+# CONFIG_OMAP_STI is not set
# CONFIG_ENCLOSURE_SERVICES is not set
CONFIG_HAVE_IDE=y
# CONFIG_IDE is not set
# CONFIG_KEYBOARD_XTKBD is not set
# CONFIG_KEYBOARD_NEWTON is not set
# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_LM8323 is not set
# CONFIG_KEYBOARD_GPIO is not set
CONFIG_INPUT_MOUSE=y
CONFIG_MOUSE_PS2=y
# 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_MADC=m
+CONFIG_TWL4030_USB=y
+CONFIG_TWL4030_PWRBUTTON=y
+CONFIG_TWL4030_POWEROFF=y
# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_SENSORS_TSL2563 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
# 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_ARCH_REQUIRE_GPIOLIB=y
# CONFIG_GPIO_MAX732X is not set
# CONFIG_GPIO_PCA953X is not set
# CONFIG_GPIO_PCF857X is not set
+CONFIG_GPIO_TWL4030=y
#
# PCI GPIO expanders:
# CONFIG_POWER_SUPPLY_DEBUG is not set
# CONFIG_PDA_POWER is not set
# CONFIG_BATTERY_DS2760 is not set
+# CONFIG_BATTERY_BQ27x00 is not set
CONFIG_HWMON=y
# CONFIG_HWMON_VID is not set
# CONFIG_SENSORS_AD7414 is not set
# CONFIG_SENSORS_LM90 is not set
# CONFIG_SENSORS_LM92 is not set
# CONFIG_SENSORS_LM93 is not set
-# CONFIG_SENSORS_MAX1111 is not set
# CONFIG_SENSORS_MAX1619 is not set
# CONFIG_SENSORS_MAX6650 is not set
# CONFIG_SENSORS_PC87360 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_SENSORS_OMAP34XX=y
# CONFIG_HWMON_DEBUG_CHIP is not set
-# CONFIG_THERMAL is not set
-# CONFIG_THERMAL_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_MFD_CORE is not set
# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
# CONFIG_HTC_EGPIO is not set
# CONFIG_HTC_PASIC3 is not set
-# CONFIG_UCB1400_CORE is not set
+CONFIG_TWL4030_CORE=y
# CONFIG_MFD_TMIO is not set
# CONFIG_MFD_T7L66XB is not set
# CONFIG_MFD_TC6387XB is not set
# CONFIG_SOC_CAMERA is not set
# CONFIG_VIDEO_SH_MOBILE_CEU 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_CAPTURE_DRIVERS=y
#
# CONFIG_VGASTATE is not set
# CONFIG_VIDEO_OUTPUT_CONTROL is not set
-# CONFIG_FB 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_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FB_OMAP=y
+# CONFIG_FB_OMAP_031M3R is not set
+# CONFIG_FB_OMAP_048M3R is not set
+CONFIG_FB_OMAP_079M3R=y
+# CONFIG_FB_OMAP_092M9R is not set
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=8
# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
#
# 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=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_LOGO is not set
CONFIG_SOUND=y
CONFIG_SND=y
CONFIG_SND_TIMER=y
# CONFIG_SND_SERIAL_U16550 is not set
# CONFIG_SND_MPU401 is not set
CONFIG_SND_ARM=y
+# 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 is not set
CONFIG_SND_SPI=y
CONFIG_SND_USB=y
CONFIG_SND_USB_AUDIO=y
CONFIG_SND_USB_CAIAQ_INPUT=y
CONFIG_SND_SOC=y
CONFIG_SND_OMAP_SOC=y
+CONFIG_SND_OMAP_SOC_MCBSP=y
+CONFIG_SND_OMAP_SOC_OVERO=y
+CONFIG_SND_SOC_TWL4030=y
# CONFIG_SOUND_PRIME is not set
CONFIG_HID_SUPPORT=y
CONFIG_HID=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_ARCH_HAS_EHCI=y
CONFIG_USB=y
CONFIG_USB_DEBUG=y
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
CONFIG_USB_DEVICEFS=y
CONFIG_USB_DEVICE_CLASS=y
# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_SUSPEND=y
# CONFIG_USB_OTG is not set
# CONFIG_USB_OTG_WHITELIST is not set
# CONFIG_USB_OTG_BLACKLIST_HUB is not set
# USB Host Controller Drivers
#
# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_EHCI_HCD is not set
# CONFIG_USB_ISP116X_HCD is not set
# CONFIG_USB_ISP1760_HCD is not set
# CONFIG_USB_OHCI_HCD is not set
# MMC/SD Host Controller Drivers
#
# CONFIG_MMC_SDHCI is not set
-# CONFIG_MMC_OMAP is not set
+CONFIG_MMC_OMAP_HS=y
# CONFIG_MMC_SPI is not set
-# CONFIG_MEMSTICK is not set
-# CONFIG_ACCESSIBILITY 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 is not set
# CONFIG_LEDS_PCA9532 is not set
CONFIG_LEDS_GPIO=y
# CONFIG_LEDS_PCA955X is not set
# CONFIG_RTC_DRV_PCF8563 is not set
# CONFIG_RTC_DRV_PCF8583 is not set
# CONFIG_RTC_DRV_M41T80 is not set
+CONFIG_RTC_DRV_TWL4030=y
# CONFIG_RTC_DRV_S35390A is not set
# CONFIG_RTC_DRV_FM3130 is not set
# CONFIG_REGULATOR_BQ24022 is not set
# CONFIG_UIO is not set
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
#
# File systems
#
#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
*/
config MACH_OMAP_H3
bool "TI H3 Support"
depends on ARCH_OMAP1 && ARCH_OMAP16XX
-# select GPIOEXPANDER_OMAP
help
TI OMAP 1710 H3 board support. Say Y here if you have such
a board.
# 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/clk.h>
#include <mach/hardware.h>
#include <asm/gpio.h>
#include <asm/mach/flash.h>
#include <asm/mach/map.h>
+#include <mach/dma.h>
+#include <mach/gpio.h>
#include <mach/gpio-switch.h>
#include <mach/mux.h>
#include <mach/tc.h>
#include <mach/usb.h>
#include <mach/keypad.h>
#include <mach/common.h>
-#include <mach/mcbsp.h>
-#include <mach/omap-alsa.h>
static int h2_keymap[] = {
KEY(0, 0, KEY_LEFT),
.id = -1,
};
-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),
- .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),
-
- .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 = {
- .name = "omap_alsa_mcbsp",
- .id = 1,
- .dev = {
- .platform_data = &alsa_config,
- },
-};
-
static struct platform_device *h2_devices[] __initdata = {
&h2_nor_device,
&h2_nand_device,
&h2_irda_device,
&h2_kp_device,
&h2_lcd_device,
- &h2_mcbsp1_device,
};
static void __init h2_init_smc91x(void)
/* Irda */
#if defined(CONFIG_OMAP_IR) || defined(CONFIG_OMAP_IR_MODULE)
omap_writel(omap_readl(FUNC_MUX_CTRL_A) | 7, FUNC_MUX_CTRL_A);
- if (gpio_request(H2_IRDA_FIRSEL_GPIO_PIN, "IRDA mode") < 0)
- BUG();
- gpio_direction_output(H2_IRDA_FIRSEL_GPIO_PIN, 0);
- h2_irda_data.transceiver_mode = h2_transceiver_mode;
+ if (!(gpio_request(H2_IRDA_FIRSEL_GPIO_PIN, "irda firsel"))) {
+ gpio_direction_output(H2_IRDA_FIRSEL_GPIO_PIN);
+ h2_irda_data.transceiver_mode = h2_transceiver_mode;
+ }
#endif
platform_add_devices(h2_devices, ARRAY_SIZE(h2_devices));
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
#include <linux/input.h>
-#include <linux/spi/spi.h>
+#include <linux/clk.h>
+
#include <linux/i2c/tps65010.h>
+#include <linux/i2c/pcf857x.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 <mach/gpioexpander.h>
+#include <media/v4l2-int-device.h>
+
+#include <mach/gpio.h>
+#include <mach/gpio-switch.h>
#include <mach/irqs.h>
#include <mach/mux.h>
#include <mach/tc.h>
#include <mach/keypad.h>
#include <mach/dma.h>
#include <mach/common.h>
-#include <mach/mcbsp.h>
-#include <mach/omap-alsa.h>
#define H3_TS_GPIO 48
/* Select between the IrDA and aGPS module
*/
-static int h3_select_irda(struct device *dev, int state)
-{
- unsigned char expa;
- int err = 0;
- if ((err = read_gpio_expa(&expa, 0x26))) {
- printk(KERN_ERR "Error reading from I/O EXPANDER \n");
- return err;
- }
+static int gpio_irda_enable;
+static int gpio_irda_x;
+static int gpio_irda_fir;
- /* 'P6' enable/disable IRDA_TX and IRDA_RX */
- if (state & IR_SEL) { /* IrDA */
- if ((err = write_gpio_expa(expa | 0x40, 0x26))) {
- printk(KERN_ERR "Error writing to I/O EXPANDER \n");
- return err;
- }
- } else {
- if ((err = write_gpio_expa(expa & ~0x40, 0x26))) {
- printk(KERN_ERR "Error writing to I/O EXPANDER \n");
- return err;
- }
- }
- return err;
+static int h3_select_irda(struct device *dev, int state)
+{
+ gpio_set_value_cansleep(gpio_irda_enable, state & IR_SEL);
+ return 0;
}
static void set_trans_mode(struct work_struct *work)
struct omap_irda_config *irda_config =
container_of(work, struct omap_irda_config, gpio_expa.work);
int mode = irda_config->mode;
- unsigned char expa;
- int err = 0;
- if ((err = read_gpio_expa(&expa, 0x27)) != 0) {
- printk(KERN_ERR "Error reading from I/O expander\n");
- }
-
- expa &= ~0x03;
-
- if (mode & IR_SIRMODE) {
- expa |= 0x01;
- } else { /* MIR/FIR */
- expa |= 0x03;
- }
-
- if ((err = write_gpio_expa(expa, 0x27)) != 0) {
- printk(KERN_ERR "Error writing to I/O expander\n");
- }
+ gpio_set_value_cansleep(gpio_irda_x, 1);
+ gpio_set_value_cansleep(gpio_irda_fir, !(mode & IR_SIRMODE));
}
static int h3_transceiver_mode(struct device *dev, int mode)
.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, */
- },
-};
-
-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),
- .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),
-
- .pcr0 = CLKRM | SCLKME | FSXP | FSRP | CLKXP | CLKRP,
- /*.pcr0 = CLKXP | CLKRP,*/ /* mcbsp: slave */
-};
-
-static struct omap_alsa_codec_config alsa_config = {
- .name = "H3 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 h3_mcbsp1_device = {
- .name = "omap_alsa_mcbsp",
- .id = 1,
- .dev = {
- .platform_data = &alsa_config,
+ .platform_data = &tsc_platform_data,
},
};
&nand_device,
&smc91x_device,
&intlat_device,
- &h3_irda_device,
&h3_kp_device,
&h3_lcd_device,
- &h3_mcbsp1_device,
};
static struct omap_usb_config h3_usb_config __initdata = {
{ OMAP_TAG_LCD, &h3_lcd_config },
};
+#define H3_NAND_RB_GPIO_PIN 10
+
+static int nand_dev_ready(struct omap_nand_platform_data *data)
+{
+ return gpio_get_value(H3_NAND_RB_GPIO_PIN);
+}
+
+#if defined(CONFIG_VIDEO_OV9640) || defined(CONFIG_VIDEO_OV9640_MODULE)
+
+#include <../drivers/media/video/ov9640.h>
+
+/*
+ * 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 int h3_pcf_setup(struct i2c_client *client, int gpio,
+ unsigned ngpio, void *context)
+{
+ int status;
+
+ /* REVISIT someone with schematics should look up the rest
+ * of these signals, and configure them appropriately ...
+ * camera and audio seem to be involved, too.
+ */
+
+ /* P0 - ? */
+ gpio_irda_x = gpio + 0;
+ status = gpio_request(gpio_irda_x, "irda_x");
+ if (status < 0)
+ goto done;
+ status = gpio_direction_output(gpio_irda_x, 0);
+ if (status < 0)
+ goto done;
+
+ /* P1 - set if MIR/FIR */
+ gpio_irda_fir = gpio + 1;
+ status = gpio_request(gpio_irda_fir, "irda_fir");
+ if (status < 0)
+ goto done;
+ status = gpio_direction_output(gpio_irda_fir, 0);
+ if (status < 0)
+ goto done;
+
+ /* 'P6' enable/disable IRDA_TX and IRDA_RX ... default, off */
+ gpio_irda_enable = gpio + 6;
+ status = gpio_request(gpio_irda_enable, "irda_enable");
+ if (status < 0)
+ goto done;
+ status = gpio_direction_output(gpio_irda_enable, 0);
+ if (status < 0)
+ goto done;
+
+ /* register the IRDA device now that it can be operated */
+ status = platform_device_register(&h3_irda_device);
+
+done:
+ return status;
+}
+
+static struct pcf857x_platform_data h3_pcf_data = {
+ /* assign these GPIO numbers right after the MPUIO lines */
+ .gpio_base = OMAP_MAX_GPIO_LINES + 16,
+ .setup = h3_pcf_setup,
+};
+
static struct i2c_board_info __initdata h3_i2c_board_info[] = {
{
+ I2C_BOARD_INFO("pcf8574", 0x27),
+ .platform_data = &h3_pcf_data,
+ }, {
I2C_BOARD_INFO("tps65013", 0x48),
/* .irq = OMAP_GPIO_IRQ(??), */
},
+#if defined(CONFIG_VIDEO_OV9640) || defined(CONFIG_VIDEO_OV9640_MODULE)
{
- I2C_BOARD_INFO("isp1301_omap", 0x2d),
- .irq = OMAP_GPIO_IRQ(14),
+ I2C_BOARD_INFO("ov9640", 0x30),
+ .platform_data = &h3_ov9640_platform_data,
},
-};
-
-static struct omap_gpio_switch h3_gpio_switches[] __initdata = {
+#endif
{
- .name = "mmc_slot",
- .gpio = OMAP_MPUIO(1),
- .type = OMAP_GPIO_SWITCH_TYPE_COVER,
- .debounce_rising = 100,
- .debounce_falling = 0,
- .notify = h3_mmc_slot_cover_handler,
- .notify_data = NULL,
+ I2C_BOARD_INFO("isp1301_omap", 0x2d),
+ .irq = OMAP_GPIO_IRQ(14),
},
};
-#define H3_NAND_RB_GPIO_PIN 10
-
-static int nand_dev_ready(struct omap_nand_platform_data *data)
-{
- return gpio_get_value(H3_NAND_RB_GPIO_PIN);
-}
-
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));
#include <mach/usb.h>
#include <mach/keypad.h>
#include <mach/common.h>
-#include <mach/mcbsp.h>
-#include <mach/omap-alsa.h>
#include <mach/mmc.h>
static int innovator_keymap[] = {
.resource = &innovator_flash_resource,
};
-#define DEFAULT_BITPERSAMPLE 16
-
-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(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),
- /*.pcr0 = FSXM | FSRM | CLKXM | CLKRM | CLKXP | CLKRP,*/ /* mcbsp: master */
- .pcr0 = CLKXP | CLKRP, /* mcbsp: slave */
-};
-
-static struct omap_alsa_codec_config alsa_config = {
- .name = "OMAP Innovator AIC23",
- .mcbsp_regs_alsa = &mcbsp_regs,
- .codec_configure_dev = NULL, /* aic23_configure, */
- .codec_set_samplerate = NULL, /* aic23_set_samplerate, */
- .codec_clock_setup = NULL, /* aic23_clock_setup, */
- .codec_clock_on = NULL, /* aic23_clock_on, */
- .codec_clock_off = NULL, /* aic23_clock_off, */
- .get_default_samplerate = NULL, /* aic23_get_default_samplerate, */
-};
-
-static struct platform_device innovator_mcbsp1_device = {
- .name = "omap_alsa_mcbsp",
- .id = 1,
- .dev = {
- .platform_data = &alsa_config,
- },
-};
-
static struct resource innovator_kp_resources[] = {
[0] = {
.start = INT_KEYBOARD,
static struct platform_device *innovator1510_devices[] __initdata = {
&innovator_flash_device,
&innovator1510_smc91x_device,
- &innovator_mcbsp1_device,
&innovator_kp_device,
&innovator1510_lcd_device,
&innovator1510_spi_device,
#include <mach/keypad.h>
#include <mach/common.h>
#include <mach/dsp_common.h>
-#include <mach/aic23.h>
#include <mach/omapfb.h>
+#include <mach/hwa742.h>
#include <mach/lcd_mipid.h>
#include <mach/mmc.h>
},
};
+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 */
*/
static int audio_pwr_state = -1;
+static inline void aic23_power_up(void)
+{
+}
+static inline void aic23_power_down(void)
+{
+}
+
/*
* audio_pwr_up / down should be called under audio_pwr_lock
*/
omap_serial_init();
omap_register_i2c_bus(1, 100, NULL, 0);
omap_dsp_init();
+ hwa742_dev_init();
ads7846_dev_init();
mipid_dev_init();
nokia770_mmc_init();
#include <mach/mux.h>
#include <mach/tc.h>
#include <mach/common.h>
-#include <mach/mcbsp.h>
-#include <mach/omap-alsa.h>
static struct mtd_partition osk_partitions[] = {
/* bootloader (U-Boot, etc) in first sector */
.resource = osk5912_cf_resources,
};
-#define DEFAULT_BITPERSAMPLE 16
-
-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(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),
- /*.pcr0 = FSXM | FSRM | CLKXM | CLKRM | CLKXP | CLKRP,*/ /* mcbsp: master */
- .pcr0 = CLKXP | CLKRP, /* mcbsp: slave */
-};
-
-static struct omap_alsa_codec_config alsa_config = {
- .name = "OSK AIC23",
- .mcbsp_regs_alsa = &mcbsp_regs,
- .codec_configure_dev = NULL, /* aic23_configure, */
- .codec_set_samplerate = NULL, /* aic23_set_samplerate, */
- .codec_clock_setup = NULL, /* aic23_clock_setup, */
- .codec_clock_on = NULL, /* aic23_clock_on, */
- .codec_clock_off = NULL, /* aic23_clock_off, */
- .get_default_samplerate = NULL, /* aic23_get_default_samplerate, */
-};
-
-static struct platform_device osk5912_mcbsp1_device = {
- .name = "omap_alsa_mcbsp",
- .id = 1,
- .dev = {
- .platform_data = &alsa_config,
- },
-};
-
static struct platform_device *osk5912_devices[] __initdata = {
&osk5912_flash_device,
&osk5912_smc91x_device,
&osk5912_cf_device,
- &osk5912_mcbsp1_device,
};
static struct gpio_led tps_leds[] = {
.platform_data = &tps_board,
},
- /* TODO when driver support is ready:
- * - aic23 audio chip at 0x1a
- * - optionally on Mistral, ov9640 camera sensor at 0x30
- */
+ {
+ I2C_BOARD_INFO("tlv320aic23", 0x1B),
+ },
};
static void __init osk_init_smc91x(void)
#include <mach/irda.h>
#include <mach/keypad.h>
#include <mach/common.h>
-#include <mach/mcbsp.h>
-#include <mach/omap-alsa.h>
+#include <mach/gpio-switch.h>
static void __init omap_palmte_init_irq(void)
{
.pins[0] = 2,
};
-static struct omap_mmc_config palmte_mmc_config __initdata = {
- .mmc[0] = {
- .enabled = 1,
- .wp_pin = PALMTE_MMC_WP_GPIO,
- .power_pin = PALMTE_MMC_POWER_GPIO,
- .switch_pin = PALMTE_MMC_SWITCH_GPIO,
- },
-};
-
static struct omap_lcd_config palmte_lcd_config __initdata = {
.ctrl_name = "internal",
};
.enabled_uarts = (1 << 0) | (1 << 1) | (0 << 2),
};
-static struct omap_mcbsp_reg_cfg palmte_mcbsp1_regs = {
- .spcr2 = FRST | GRST | XRST | XINTM(3),
- .xcr2 = XDATDLY(1) | XFIG,
- .xcr1 = XWDLEN1(OMAP_MCBSP_WORD_32),
- .pcr0 = SCLKME | FSXP | CLKXP,
-};
-
-static struct omap_alsa_codec_config palmte_alsa_config = {
- .name = "TSC2102 audio",
- .mcbsp_regs_alsa = &palmte_mcbsp1_regs,
- .codec_configure_dev = NULL, /* tsc2102_configure, */
- .codec_set_samplerate = NULL, /* tsc2102_set_samplerate, */
- .codec_clock_setup = NULL, /* tsc2102_clock_setup, */
- .codec_clock_on = NULL, /* tsc2102_clock_on, */
- .codec_clock_off = NULL, /* tsc2102_clock_off, */
- .get_default_samplerate = NULL, /* tsc2102_get_default_samplerate, */
-};
-
#ifdef CONFIG_APM
/*
* Values measured in 10 minute intervals averaged over 10 samples.
}
}
+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);
#include <asm/mach/flash.h>
#include <mach/led.h>
-#include <mach/mcbsp.h>
#include <mach/gpio.h>
#include <mach/mux.h>
#include <mach/usb.h>
#include <mach/irda.h>
#include <mach/keypad.h>
#include <mach/common.h>
-#include <mach/omap-alsa.h>
#include <linux/spi/spi.h>
#include <linux/spi/ads7846.h>
.resource = &palmtt_flash_resource,
};
-#define DEFAULT_BITPERSAMPLE 16
-
-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(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),
- .pcr0 = CLKXP | CLKRP, /* mcbsp: slave */
-};
-
-static struct omap_alsa_codec_config alsa_config = {
- .name = "PalmTT AIC23",
- .mcbsp_regs_alsa = &mcbsp_regs,
- .codec_configure_dev = NULL, /* aic23_configure, */
- .codec_set_samplerate = NULL, /* aic23_set_samplerate, */
- .codec_clock_setup = NULL, /* aic23_clock_setup, */
- .codec_clock_on = NULL, /* aic23_clock_on, */
- .codec_clock_off = NULL, /* aic23_clock_off, */
- .get_default_samplerate = NULL, /* aic23_get_default_samplerate, */
-};
-
-static struct platform_device palmtt_mcbsp1_device = {
- .name = "omap_alsa_mcbsp",
- .id = 1,
- .dev = {
- .platform_data = &alsa_config,
- },
-};
-
static struct resource palmtt_kp_resources[] = {
[0] = {
.start = INT_KEYBOARD,
static struct platform_device *palmtt_devices[] __initdata = {
&palmtt_flash_device,
- &palmtt_mcbsp1_device,
&palmtt_kp_device,
&palmtt_lcd_device,
&palmtt_irda_device,
#include <asm/mach/map.h>
#include <asm/mach/flash.h>
-#include <mach/mcbsp.h>
#include <mach/gpio.h>
#include <mach/mux.h>
#include <mach/usb.h>
.id = -1,
};
-#define DEFAULT_BITPERSAMPLE 16
-
-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(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),
- .pcr0 = CLKXP | CLKRP, /* mcbsp: slave */
-};
-
-static struct omap_alsa_codec_config alsa_config = {
- .name = "PalmZ71 AIC23",
- .mcbsp_regs_alsa = &mcbsp_regs,
- .codec_configure_dev = NULL, /* aic23_configure */
- .codec_set_samplerate = NULL, /* aic23_set_samplerate */
- .codec_clock_setup = NULL, /* aic23_clock_setup */
- .codec_clock_on = NULL, /* aic23_clock_on */
- .codec_clock_off = NULL, /* aic23_clock_off */
- .get_default_samplerate = NULL, /* aic23_get_default_samplerate */
-};
-
-static struct platform_device palmz71_mcbsp1_device = {
- .name = "omap_alsa_mcbsp",
- .id = 1,
- .dev = {
- .platform_data = &alsa_config,
- },
-};
-
static struct omap_backlight_config palmz71_backlight_config = {
.default_intensity = 0xa0,
};
static struct platform_device *devices[] __initdata = {
&palmz71_rom_device,
&palmz71_kp_device,
- &palmz71_mcbsp1_device,
&palmz71_lcd_device,
&palmz71_irda_device,
&palmz71_spi_device,
#include <asm/mach/map.h>
#include <mach/gpio.h>
+#include <mach/gpio-switch.h>
#include <mach/mux.h>
#include <mach/irda.h>
#include <mach/usb.h>
#include <mach/tc.h>
#include <mach/board.h>
#include <mach/common.h>
-#include <mach/mcbsp.h>
-#include <mach/omap-alsa.h>
#include <mach/keypad.h>
/* Write to I2C device */
.resource = sx1_irda_resources,
};
-/*----------- McBSP & Sound -------------------------*/
-
-/* Playback interface - McBSP1 */
-static struct omap_mcbsp_reg_cfg mcbsp1_regs = {
- .spcr2 = XINTM(3), /* SPCR2=30 */
- .spcr1 = RINTM(3), /* SPCR1=30 */
- .rcr2 = 0, /* RCR2 =00 */
- .rcr1 = RFRLEN1(1) | RWDLEN1(OMAP_MCBSP_WORD_16), /* RCR1=140 */
- .xcr2 = 0, /* XCR2 = 0 */
- .xcr1 = XFRLEN1(1) | XWDLEN1(OMAP_MCBSP_WORD_16), /* XCR1 = 140 */
- .srgr1 = FWID(15) | CLKGDV(12), /* SRGR1=0f0c */
- .srgr2 = FSGM | FPER(31), /* SRGR2=101f */
- .pcr0 = FSXM | FSRM | CLKXM | CLKRM | FSXP | FSRP | CLKXP | CLKRP,
- /* PCR0 =0f0f */
-};
-
-static struct omap_alsa_codec_config sx1_alsa_config = {
- .name = "SX1 EGold",
- .mcbsp_regs_alsa = &mcbsp1_regs,
-};
-
-static struct platform_device sx1_mcbsp1_device = {
- .name = "omap_alsa_mcbsp",
- .id = 1,
- .dev = {
- .platform_data = &sx1_alsa_config,
- },
-};
-
/*----------- MTD -------------------------*/
static struct mtd_partition sx1_partitions[] = {
&sx1_flash_device,
&sx1_kp_device,
&sx1_lcd_device,
- &sx1_mcbsp1_device,
&sx1_irda_device,
};
/*-----------------------------------------*/
/* turn on USB power */
/* sx1_setusbpower(1); cant do it here because i2c is not ready */
- omap_request_gpio(1); /* A_IRDA_OFF */
- omap_request_gpio(11); /* A_SWITCH */
- omap_request_gpio(15); /* A_USB_ON */
+ gpio_request(1, "A_IRDA_OFF");
+ gpio_request(11, "A_SWITCH");
+ gpio_request(15, "A_USB_ON");
gpio_direction_output(1, 1); /*A_IRDA_OFF = 1 */
gpio_direction_output(11, 0); /*A_SWITCH = 0 */
gpio_direction_output(15, 0); /*A_USB_ON = 0 */
#include <linux/reboot.h>
#include <linux/serial_8250.h>
#include <linux/serial_reg.h>
-#include <linux/irq.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
* Omap1 specific clock functions
*-------------------------------------------------------------------------*/
-static void omap1_watchdog_recalc(struct clk * clk)
+static void omap1_watchdog_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage)
{
- clk->rate = clk->parent->rate / 14;
+ unsigned long new_rate;
+
+ new_rate = parent_rate / 14;
+
+ if (rate_storage == CURRENT_RATE)
+ clk->rate = new_rate;
+ else if (rate_storage == TEMP_RATE)
+ clk->temp_rate = new_rate;
}
-static void omap1_uart_recalc(struct clk * clk)
+static void omap1_uart_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage)
{
- unsigned int val = omap_readl(clk->enable_reg);
+ unsigned long new_rate;
+ unsigned int val = __raw_readl(clk->enable_reg);
+
if (val & clk->enable_bit)
- clk->rate = 48000000;
+ new_rate = 48000000;
else
- clk->rate = 12000000;
+ new_rate = 12000000;
+
+ if (rate_storage == CURRENT_RATE)
+ clk->rate = new_rate;
+ else if (rate_storage == TEMP_RATE)
+ clk->temp_rate = new_rate;
}
-static void omap1_sossi_recalc(struct clk *clk)
+static void omap1_sossi_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage)
{
+ unsigned long new_rate;
u32 div = omap_readl(MOD_CONF_CTRL_1);
div = (div >> 17) & 0x7;
div++;
- clk->rate = clk->parent->rate / div;
+ new_rate = clk->parent->rate / div;
+
+ if (rate_storage == CURRENT_RATE)
+ clk->rate = new_rate;
+ else if (rate_storage == TEMP_RATE)
+ clk->temp_rate = new_rate;
}
static int omap1_clk_enable_dsp_domain(struct clk *clk)
return dsor_exp;
}
-static void omap1_ckctl_recalc(struct clk * clk)
+static void omap1_ckctl_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage)
{
int dsor;
+ unsigned long new_rate;
/* Calculate divisor encoded as 2-bit exponent */
dsor = 1 << (3 & (omap_readw(ARM_CKCTL) >> clk->rate_offset));
- if (unlikely(clk->rate == clk->parent->rate / dsor))
+ new_rate = parent_rate / dsor;
+
+ if (unlikely(clk->rate == new_rate))
return; /* No change, quick exit */
- clk->rate = clk->parent->rate / dsor;
- if (unlikely(clk->flags & RATE_PROPAGATES))
- propagate_rate(clk);
+ if (rate_storage == CURRENT_RATE)
+ clk->rate = new_rate;
+ else if (rate_storage == TEMP_RATE)
+ clk->temp_rate = new_rate;
}
-static void omap1_ckctl_recalc_dsp_domain(struct clk * clk)
+static void omap1_ckctl_recalc_dsp_domain(struct clk *clk,
+ unsigned long parent_rate,
+ u8 rate_storage)
{
int dsor;
+ unsigned long new_rate;
/* Calculate divisor encoded as 2-bit exponent
*
dsor = 1 << (3 & (__raw_readw(DSP_CKCTL) >> clk->rate_offset));
omap1_clk_disable(&api_ck.clk);
- if (unlikely(clk->rate == clk->parent->rate / dsor))
+ new_rate = parent_rate / dsor;
+
+ if (unlikely(clk->rate == new_rate))
return; /* No change, quick exit */
- clk->rate = clk->parent->rate / dsor;
- if (unlikely(clk->flags & RATE_PROPAGATES))
- propagate_rate(clk);
+ if (rate_storage == CURRENT_RATE)
+ clk->rate = new_rate;
+ else if (rate_storage == TEMP_RATE)
+ clk->temp_rate = new_rate;
}
/* MPU virtual clock functions */
omap_sram_reprogram_clock(ptr->dpllctl_val, ptr->ckctl_val);
ck_dpll1.rate = ptr->pll_rate;
- propagate_rate(&ck_dpll1);
+ propagate_rate(&ck_dpll1, CURRENT_RATE);
return 0;
}
ret = 0;
}
- if (unlikely(ret == 0 && (clk->flags & RATE_PROPAGATES)))
- propagate_rate(clk);
-
return ret;
}
{
unsigned int val;
- val = omap_readl(clk->enable_reg);
+ val = __raw_readl(clk->enable_reg);
if (rate == 12000000)
val &= ~(1 << clk->enable_bit);
else if (rate == 48000000)
val |= (1 << clk->enable_bit);
else
return -EINVAL;
- omap_writel(val, clk->enable_reg);
+ __raw_writel(val, clk->enable_reg);
clk->rate = rate;
return 0;
else
ratio_bits = (dsor - 2) << 2;
- ratio_bits |= omap_readw(clk->enable_reg) & ~0xfd;
- omap_writew(ratio_bits, clk->enable_reg);
+ ratio_bits |= __raw_readw(clk->enable_reg) & ~0xfd;
+ __raw_writew(ratio_bits, clk->enable_reg);
return 0;
}
omap_writel(l, MOD_CONF_CTRL_1);
clk->rate = p_rate / (div + 1);
- if (unlikely(clk->flags & RATE_PROPAGATES))
- propagate_rate(clk);
return 0;
}
__u16 ratio_bits;
/* Determine current rate and ensure clock is based on 96MHz APLL */
- ratio_bits = omap_readw(clk->enable_reg) & ~1;
- omap_writew(ratio_bits, clk->enable_reg);
+ ratio_bits = __raw_readw(clk->enable_reg) & ~1;
+ __raw_writew(ratio_bits, clk->enable_reg);
ratio_bits = (ratio_bits & 0xfc) >> 2;
if (ratio_bits > 6)
}
if (clk->flags & ENABLE_REG_32BIT) {
- if (clk->flags & VIRTUAL_IO_ADDRESS) {
- regval32 = __raw_readl(clk->enable_reg);
- regval32 |= (1 << clk->enable_bit);
- __raw_writel(regval32, clk->enable_reg);
- } else {
- regval32 = omap_readl(clk->enable_reg);
- regval32 |= (1 << clk->enable_bit);
- omap_writel(regval32, clk->enable_reg);
- }
+ regval32 = __raw_readl(clk->enable_reg);
+ regval32 |= (1 << clk->enable_bit);
+ __raw_writel(regval32, clk->enable_reg);
} else {
- if (clk->flags & VIRTUAL_IO_ADDRESS) {
- regval16 = __raw_readw(clk->enable_reg);
- regval16 |= (1 << clk->enable_bit);
- __raw_writew(regval16, clk->enable_reg);
- } else {
- regval16 = omap_readw(clk->enable_reg);
- regval16 |= (1 << clk->enable_bit);
- omap_writew(regval16, clk->enable_reg);
- }
+ regval16 = __raw_readw(clk->enable_reg);
+ regval16 |= (1 << clk->enable_bit);
+ __raw_writew(regval16, clk->enable_reg);
}
return 0;
return;
if (clk->flags & ENABLE_REG_32BIT) {
- if (clk->flags & VIRTUAL_IO_ADDRESS) {
- regval32 = __raw_readl(clk->enable_reg);
- regval32 &= ~(1 << clk->enable_bit);
- __raw_writel(regval32, clk->enable_reg);
- } else {
- regval32 = omap_readl(clk->enable_reg);
- regval32 &= ~(1 << clk->enable_bit);
- omap_writel(regval32, clk->enable_reg);
- }
+ regval32 = __raw_readl(clk->enable_reg);
+ regval32 &= ~(1 << clk->enable_bit);
+ __raw_writel(regval32, clk->enable_reg);
} else {
- if (clk->flags & VIRTUAL_IO_ADDRESS) {
- regval16 = __raw_readw(clk->enable_reg);
- regval16 &= ~(1 << clk->enable_bit);
- __raw_writew(regval16, clk->enable_reg);
- } else {
- regval16 = omap_readw(clk->enable_reg);
- regval16 &= ~(1 << clk->enable_bit);
- omap_writew(regval16, clk->enable_reg);
- }
+ regval16 = __raw_readw(clk->enable_reg);
+ regval16 &= ~(1 << clk->enable_bit);
+ __raw_writew(regval16, clk->enable_reg);
}
}
{
int dsor_exp;
- if (clk->flags & RATE_FIXED)
- return clk->rate;
-
if (clk->flags & RATE_CKCTL) {
dsor_exp = calc_dsor_exp(clk, rate);
if (dsor_exp < 0)
ret = 0;
}
- if (unlikely(ret == 0 && (clk->flags & RATE_PROPAGATES)))
- propagate_rate(clk);
-
return ret;
}
}
/* Is the clock already disabled? */
- if (clk->flags & ENABLE_REG_32BIT) {
- if (clk->flags & VIRTUAL_IO_ADDRESS)
- regval32 = __raw_readl(clk->enable_reg);
- else
- regval32 = omap_readl(clk->enable_reg);
- } else {
- if (clk->flags & VIRTUAL_IO_ADDRESS)
- regval32 = __raw_readw(clk->enable_reg);
- else
- regval32 = omap_readw(clk->enable_reg);
- }
+ if (clk->flags & ENABLE_REG_32BIT)
+ regval32 = __raw_readl(clk->enable_reg);
+ else
+ regval32 = __raw_readw(clk->enable_reg);
if ((regval32 & (1 << clk->enable_bit)) == 0)
return;
}
}
}
- propagate_rate(&ck_dpll1);
+ propagate_rate(&ck_dpll1, CURRENT_RATE);
#else
/* Find the highest supported frequency and enable it */
if (omap1_select_table_rate(&virtual_ck_mpu, ~0)) {
omap_writew(0x2290, DPLL_CTL);
omap_writew(cpu_is_omap730() ? 0x3005 : 0x1005, ARM_CKCTL);
ck_dpll1.rate = 60000000;
- propagate_rate(&ck_dpll1);
+ propagate_rate(&ck_dpll1, CURRENT_RATE);
}
#endif
/* Cache rates for clocks connected to ck_ref (not dpll1) */
- propagate_rate(&ck_ref);
+ propagate_rate(&ck_ref, CURRENT_RATE);
printk(KERN_INFO "Clocking rate (xtal/DPLL1/MPU): "
"%ld.%01ld/%ld.%01ld/%ld.%01ld MHz\n",
ck_ref.rate / 1000000, (ck_ref.rate / 100000) % 10,
static int omap1_clk_enable_generic(struct clk * clk);
static void omap1_clk_disable_generic(struct clk * clk);
-static void omap1_ckctl_recalc(struct clk * clk);
-static void omap1_watchdog_recalc(struct clk * clk);
+static void omap1_ckctl_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage);
+static void omap1_watchdog_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage);
static int omap1_set_sossi_rate(struct clk *clk, unsigned long rate);
-static void omap1_sossi_recalc(struct clk *clk);
-static void omap1_ckctl_recalc_dsp_domain(struct clk * clk);
+static void omap1_sossi_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage);
+static void omap1_ckctl_recalc_dsp_domain(struct clk *clk,
+ unsigned long parent_rate,
+ u8 rate_storage);
static int omap1_clk_enable_dsp_domain(struct clk * clk);
static int omap1_clk_set_rate_dsp_domain(struct clk * clk, unsigned long rate);
static void omap1_clk_disable_dsp_domain(struct clk * clk);
static int omap1_set_uart_rate(struct clk * clk, unsigned long rate);
-static void omap1_uart_recalc(struct clk * clk);
+static void omap1_uart_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage);
static int omap1_clk_enable_uart_functional(struct clk * clk);
static void omap1_clk_disable_uart_functional(struct clk * clk);
static int omap1_set_ext_clk_rate(struct clk * clk, unsigned long rate);
.name = "ck_dpll1",
.parent = &ck_ref,
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- CLOCK_IN_OMAP310 | RATE_PROPAGATES | ALWAYS_ENABLED,
+ CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
.enable = &omap1_clk_enable_generic,
.disable = &omap1_clk_disable_generic,
};
.name = "ck_dpll1out",
.parent = &ck_dpll1,
.flags = CLOCK_IN_OMAP16XX | CLOCK_IDLE_CONTROL |
- ENABLE_REG_32BIT | RATE_PROPAGATES,
- .enable_reg = (void __iomem *)ARM_IDLECT2,
+ ENABLE_REG_32BIT,
+ .enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT2),
.enable_bit = EN_CKOUT_ARM,
.recalc = &followparent_recalc,
.enable = &omap1_clk_enable_generic,
.parent = &ck_dpll1out.clk,
.flags = CLOCK_IN_OMAP16XX | CLOCK_NO_IDLE_PARENT |
ENABLE_REG_32BIT,
- .enable_reg = (void __iomem *)MOD_CONF_CTRL_1,
+ .enable_reg = OMAP1_IO_ADDRESS(MOD_CONF_CTRL_1),
.enable_bit = 16,
.recalc = &omap1_sossi_recalc,
.set_rate = &omap1_set_sossi_rate,
.name = "arm_ck",
.parent = &ck_dpll1,
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- CLOCK_IN_OMAP310 | RATE_CKCTL | RATE_PROPAGATES |
- ALWAYS_ENABLED,
+ CLOCK_IN_OMAP310 | RATE_CKCTL | ALWAYS_ENABLED,
.rate_offset = CKCTL_ARMDIV_OFFSET,
.recalc = &omap1_ckctl_recalc,
.enable = &omap1_clk_enable_generic,
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
CLOCK_IN_OMAP310 | RATE_CKCTL |
CLOCK_IDLE_CONTROL,
- .enable_reg = (void __iomem *)ARM_IDLECT2,
+ .enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT2),
.enable_bit = EN_PERCK,
.rate_offset = CKCTL_PERDIV_OFFSET,
.recalc = &omap1_ckctl_recalc,
.name = "arm_gpio_ck",
.parent = &ck_dpll1,
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
- .enable_reg = (void __iomem *)ARM_IDLECT2,
+ .enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT2),
.enable_bit = EN_GPIOCK,
.recalc = &followparent_recalc,
.enable = &omap1_clk_enable_generic,
.parent = &ck_ref,
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
CLOCK_IN_OMAP310 | CLOCK_IDLE_CONTROL,
- .enable_reg = (void __iomem *)ARM_IDLECT2,
+ .enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT2),
.enable_bit = EN_XORPCK,
.recalc = &followparent_recalc,
.enable = &omap1_clk_enable_generic,
.parent = &ck_ref,
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
CLOCK_IN_OMAP310 | CLOCK_IDLE_CONTROL,
- .enable_reg = (void __iomem *)ARM_IDLECT2,
+ .enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT2),
.enable_bit = EN_TIMCK,
.recalc = &followparent_recalc,
.enable = &omap1_clk_enable_generic,
.parent = &ck_ref,
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
CLOCK_IN_OMAP310 | CLOCK_IDLE_CONTROL,
- .enable_reg = (void __iomem *)ARM_IDLECT2,
+ .enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT2),
.enable_bit = EN_WDTCK,
.recalc = &omap1_watchdog_recalc,
.enable = &omap1_clk_enable_generic,
.parent = &ck_dpll1,
.flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
RATE_CKCTL,
- .enable_reg = (void __iomem *)ARM_CKCTL,
+ .enable_reg = OMAP1_IO_ADDRESS(ARM_CKCTL),
.enable_bit = EN_DSPCK,
.rate_offset = CKCTL_DSPDIV_OFFSET,
.recalc = &omap1_ckctl_recalc,
.name = "dspper_ck",
.parent = &ck_dpll1,
.flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- RATE_CKCTL | VIRTUAL_IO_ADDRESS,
- .enable_reg = DSP_IDLECT2,
+ RATE_CKCTL,
+ .enable_reg = IOMEM(DSP_IDLECT2),
.enable_bit = EN_PERCK,
.rate_offset = CKCTL_PERDIV_OFFSET,
.recalc = &omap1_ckctl_recalc_dsp_domain,
static struct clk dspxor_ck = {
.name = "dspxor_ck",
.parent = &ck_ref,
- .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- VIRTUAL_IO_ADDRESS,
- .enable_reg = DSP_IDLECT2,
+ .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+ .enable_reg = IOMEM(DSP_IDLECT2),
.enable_bit = EN_XORPCK,
.recalc = &followparent_recalc,
.enable = &omap1_clk_enable_dsp_domain,
static struct clk dsptim_ck = {
.name = "dsptim_ck",
.parent = &ck_ref,
- .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- VIRTUAL_IO_ADDRESS,
- .enable_reg = DSP_IDLECT2,
+ .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+ .enable_reg = IOMEM(DSP_IDLECT2),
.enable_bit = EN_DSPTIMCK,
.recalc = &followparent_recalc,
.enable = &omap1_clk_enable_dsp_domain,
.parent = &ck_dpll1,
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
CLOCK_IN_OMAP730 | CLOCK_IN_OMAP310 |
- RATE_CKCTL | RATE_PROPAGATES |
+ RATE_CKCTL |
ALWAYS_ENABLED | CLOCK_IDLE_CONTROL,
.rate_offset = CKCTL_TCDIV_OFFSET,
.recalc = &omap1_ckctl_recalc,
.name = "l3_ocpi_ck",
.parent = &tc_ck.clk,
.flags = CLOCK_IN_OMAP16XX,
- .enable_reg = (void __iomem *)ARM_IDLECT3,
+ .enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT3),
.enable_bit = EN_OCPI_CK,
.recalc = &followparent_recalc,
.enable = &omap1_clk_enable_generic,
.name = "tc1_ck",
.parent = &tc_ck.clk,
.flags = CLOCK_IN_OMAP16XX,
- .enable_reg = (void __iomem *)ARM_IDLECT3,
+ .enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT3),
.enable_bit = EN_TC1_CK,
.recalc = &followparent_recalc,
.enable = &omap1_clk_enable_generic,
.name = "tc2_ck",
.parent = &tc_ck.clk,
.flags = CLOCK_IN_OMAP16XX,
- .enable_reg = (void __iomem *)ARM_IDLECT3,
+ .enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT3),
.enable_bit = EN_TC2_CK,
.recalc = &followparent_recalc,
.enable = &omap1_clk_enable_generic,
.parent = &tc_ck.clk,
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
CLOCK_IN_OMAP310 | CLOCK_IDLE_CONTROL,
- .enable_reg = (void __iomem *)ARM_IDLECT2,
+ .enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT2),
.enable_bit = EN_APICK,
.recalc = &followparent_recalc,
.enable = &omap1_clk_enable_generic,
.parent = &tc_ck.clk,
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 |
CLOCK_IDLE_CONTROL,
- .enable_reg = (void __iomem *)ARM_IDLECT2,
+ .enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT2),
.enable_bit = EN_LBCK,
.recalc = &followparent_recalc,
.enable = &omap1_clk_enable_generic,
.name = "lcd_ck",
.parent = &ck_dpll1,
.flags = CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP730 | RATE_CKCTL,
- .enable_reg = (void __iomem *)ARM_IDLECT2,
+ .enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT2),
.enable_bit = EN_LCDCK,
.rate_offset = CKCTL_LCDDIV_OFFSET,
.recalc = &omap1_ckctl_recalc,
.parent = &ck_dpll1,
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 |
RATE_CKCTL | CLOCK_IDLE_CONTROL,
- .enable_reg = (void __iomem *)ARM_IDLECT2,
+ .enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT2),
.enable_bit = EN_LCDCK,
.rate_offset = CKCTL_LCDDIV_OFFSET,
.recalc = &omap1_ckctl_recalc,
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 |
ENABLE_REG_32BIT | ALWAYS_ENABLED |
CLOCK_NO_IDLE_PARENT,
- .enable_reg = (void __iomem *)MOD_CONF_CTRL_0,
+ .enable_reg = OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0),
.enable_bit = 29, /* Chooses between 12MHz and 48MHz */
.set_rate = &omap1_set_uart_rate,
.recalc = &omap1_uart_recalc,
/* Direct from ULPD, no real parent */
.parent = &armper_ck.clk,
.rate = 48000000,
- .flags = CLOCK_IN_OMAP16XX | RATE_FIXED |
- ENABLE_REG_32BIT | CLOCK_NO_IDLE_PARENT,
- .enable_reg = (void __iomem *)MOD_CONF_CTRL_0,
+ .flags = CLOCK_IN_OMAP16XX | ENABLE_REG_32BIT |
+ CLOCK_NO_IDLE_PARENT,
+ .enable_reg = OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0),
.enable_bit = 29,
.enable = &omap1_clk_enable_uart_functional,
.disable = &omap1_clk_disable_uart_functional,
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
CLOCK_IN_OMAP310 | ENABLE_REG_32BIT |
ALWAYS_ENABLED | CLOCK_NO_IDLE_PARENT,
- .enable_reg = (void __iomem *)MOD_CONF_CTRL_0,
+ .enable_reg = OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0),
.enable_bit = 30, /* Chooses between 12MHz and 48MHz */
.set_rate = &omap1_set_uart_rate,
.recalc = &omap1_uart_recalc,
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 |
ENABLE_REG_32BIT | ALWAYS_ENABLED |
CLOCK_NO_IDLE_PARENT,
- .enable_reg = (void __iomem *)MOD_CONF_CTRL_0,
+ .enable_reg = OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0),
.enable_bit = 31, /* Chooses between 12MHz and 48MHz */
.set_rate = &omap1_set_uart_rate,
.recalc = &omap1_uart_recalc,
/* Direct from ULPD, no real parent */
.parent = &armper_ck.clk,
.rate = 48000000,
- .flags = CLOCK_IN_OMAP16XX | RATE_FIXED |
- ENABLE_REG_32BIT | CLOCK_NO_IDLE_PARENT,
- .enable_reg = (void __iomem *)MOD_CONF_CTRL_0,
+ .flags = CLOCK_IN_OMAP16XX | ENABLE_REG_32BIT |
+ CLOCK_NO_IDLE_PARENT,
+ .enable_reg = OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0),
.enable_bit = 31,
.enable = &omap1_clk_enable_uart_functional,
.disable = &omap1_clk_disable_uart_functional,
/* Direct from ULPD, no parent */
.rate = 6000000,
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- CLOCK_IN_OMAP310 | RATE_FIXED | ENABLE_REG_32BIT,
- .enable_reg = (void __iomem *)ULPD_CLOCK_CTRL,
+ CLOCK_IN_OMAP310 | ENABLE_REG_32BIT,
+ .enable_reg = OMAP1_IO_ADDRESS(ULPD_CLOCK_CTRL),
.enable_bit = USB_MCLK_EN_BIT,
.enable = &omap1_clk_enable_generic,
.disable = &omap1_clk_disable_generic,
/* Direct from ULPD, no parent */
.rate = 48000000, /* Actually 2 clocks, 12MHz and 48MHz */
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 |
- RATE_FIXED | ENABLE_REG_32BIT,
- .enable_reg = (void __iomem *)MOD_CONF_CTRL_0,
+ ENABLE_REG_32BIT,
+ .enable_reg = OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0),
.enable_bit = USB_HOST_HHC_UHOST_EN,
.enable = &omap1_clk_enable_generic,
.disable = &omap1_clk_disable_generic,
/* Direct from ULPD, no parent */
.rate = 48000000,
/* OTG_SYSCON_2.OTG_PADEN == 0 (not 1510-compatible) */
- .flags = CLOCK_IN_OMAP16XX |
- RATE_FIXED | ENABLE_REG_32BIT,
- .enable_reg = (void __iomem *)OTG_BASE + 0x08 /* OTG_SYSCON_2 */,
+ .flags = CLOCK_IN_OMAP16XX | ENABLE_REG_32BIT,
+ .enable_reg = OMAP1_IO_ADDRESS(OTG_BASE + 0x08), /* OTG_SYSCON_2 */
.enable_bit = 8 /* UHOST_EN */,
.enable = &omap1_clk_enable_generic,
.disable = &omap1_clk_disable_generic,
.name = "usb_dc_ck",
/* Direct from ULPD, no parent */
.rate = 48000000,
- .flags = CLOCK_IN_OMAP16XX | RATE_FIXED,
- .enable_reg = (void __iomem *)SOFT_REQ_REG,
+ .flags = CLOCK_IN_OMAP16XX,
+ .enable_reg = OMAP1_IO_ADDRESS(SOFT_REQ_REG),
.enable_bit = 4,
.enable = &omap1_clk_enable_generic,
.disable = &omap1_clk_disable_generic,
.name = "mclk",
/* Direct from ULPD, no parent. May be enabled by ext hardware. */
.rate = 12000000,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | RATE_FIXED,
- .enable_reg = (void __iomem *)SOFT_REQ_REG,
- .enable_bit = 6,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
+ .enable_reg = OMAP1_IO_ADDRESS(SOFT_REQ_REG),
+ .enable_bit = 6,
.enable = &omap1_clk_enable_generic,
.disable = &omap1_clk_disable_generic,
};
.name = "mclk",
/* Direct from ULPD, no parent. May be enabled by ext hardware. */
.flags = CLOCK_IN_OMAP16XX,
- .enable_reg = (void __iomem *)COM_CLK_DIV_CTRL_SEL,
+ .enable_reg = OMAP1_IO_ADDRESS(COM_CLK_DIV_CTRL_SEL),
.enable_bit = COM_ULPD_PLL_CLK_REQ,
.set_rate = &omap1_set_ext_clk_rate,
.round_rate = &omap1_round_ext_clk_rate,
.name = "bclk",
/* Direct from ULPD, no parent. May be enabled by ext hardware. */
.rate = 12000000,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | RATE_FIXED,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
.enable = &omap1_clk_enable_generic,
.disable = &omap1_clk_disable_generic,
};
.name = "bclk",
/* Direct from ULPD, no parent. May be enabled by ext hardware. */
.flags = CLOCK_IN_OMAP16XX,
- .enable_reg = (void __iomem *)SWD_CLK_DIV_CTRL_SEL,
+ .enable_reg = OMAP1_IO_ADDRESS(SWD_CLK_DIV_CTRL_SEL),
.enable_bit = SWD_ULPD_PLL_CLK_REQ,
.set_rate = &omap1_set_ext_clk_rate,
.round_rate = &omap1_round_ext_clk_rate,
.parent = &armper_ck.clk,
.rate = 48000000,
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- CLOCK_IN_OMAP310 | RATE_FIXED | ENABLE_REG_32BIT |
+ CLOCK_IN_OMAP310 | ENABLE_REG_32BIT |
CLOCK_NO_IDLE_PARENT,
- .enable_reg = (void __iomem *)MOD_CONF_CTRL_0,
+ .enable_reg = OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0),
.enable_bit = 23,
.enable = &omap1_clk_enable_generic,
.disable = &omap1_clk_disable_generic,
/* Functional clock is direct from ULPD, interface clock is ARMPER */
.parent = &armper_ck.clk,
.rate = 48000000,
- .flags = CLOCK_IN_OMAP16XX |
- RATE_FIXED | ENABLE_REG_32BIT | CLOCK_NO_IDLE_PARENT,
- .enable_reg = (void __iomem *)MOD_CONF_CTRL_0,
+ .flags = CLOCK_IN_OMAP16XX | ENABLE_REG_32BIT |
+ CLOCK_NO_IDLE_PARENT,
+ .enable_reg = OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0),
.enable_bit = 20,
.enable = &omap1_clk_enable_generic,
.disable = &omap1_clk_disable_generic,
static struct clk virtual_ck_mpu = {
.name = "mpu",
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- CLOCK_IN_OMAP310 | VIRTUAL_CLOCK | ALWAYS_ENABLED,
+ CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
.parent = &arm_ck, /* Is smarter alias for */
.recalc = &followparent_recalc,
.set_rate = &omap1_select_table_rate,
.name = "i2c_fck",
.id = 1,
.flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- VIRTUAL_CLOCK | CLOCK_NO_IDLE_PARENT |
- ALWAYS_ENABLED,
+ CLOCK_NO_IDLE_PARENT | ALWAYS_ENABLED,
.parent = &armxor_ck.clk,
.recalc = &followparent_recalc,
.enable = &omap1_clk_enable_generic,
static struct clk i2c_ick = {
.name = "i2c_ick",
.id = 1,
- .flags = CLOCK_IN_OMAP16XX |
- VIRTUAL_CLOCK | CLOCK_NO_IDLE_PARENT |
+ .flags = CLOCK_IN_OMAP16XX | CLOCK_NO_IDLE_PARENT |
ALWAYS_ENABLED,
.parent = &armper_ck.clk,
.recalc = &followparent_recalc,
};
static struct platform_device mbox_device = {
- .name = "mailbox",
+ .name = "omap1-mailbox",
.id = -1,
.num_resources = ARRAY_SIZE(mbox_resources),
.resource = mbox_resources,
/*
* Mailbox reservation modules for DSP
*
- * Copyright (C) 2006 Nokia Corporation
+ * Copyright (C) 2006-2008 Nokia Corporation
* Written by: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
*
* This file is subject to the terms and conditions of the GNU General Public
#include <mach/mailbox.h>
#include <mach/irqs.h>
+#define DRV_NAME "omap1-mailbox"
+
#define MAILBOX_ARM2DSP1 0x00
#define MAILBOX_ARM2DSP1b 0x04
#define MAILBOX_DSP2ARM1 0x08
#define MAILBOX_DSP2ARM1_Flag 0x1c
#define MAILBOX_DSP2ARM2_Flag 0x20
-unsigned long mbox_base;
+static void __iomem *mbox_base;
struct omap_mbox1_fifo {
unsigned long cmd;
struct omap_mbox1_fifo rx_fifo;
};
-static inline int mbox_read_reg(unsigned int reg)
+static inline int mbox_read_reg(size_t ofs)
{
- return __raw_readw(mbox_base + reg);
+ return __raw_readw(mbox_base + ofs);
}
-static inline void mbox_write_reg(unsigned int val, unsigned int reg)
+static inline void mbox_write_reg(u32 val, size_t ofs)
{
- __raw_writew(val, mbox_base + reg);
+ __raw_writew(val, mbox_base + ofs);
}
/* msg */
};
EXPORT_SYMBOL(mbox_dsp_info);
-static int __init omap1_mbox_probe(struct platform_device *pdev)
+static int __devinit omap1_mbox_probe(struct platform_device *pdev)
{
struct resource *res;
int ret = 0;
}
mbox_dsp_info.irq = res->start;
- ret = omap_mbox_register(&mbox_dsp_info);
-
- return ret;
+ return omap_mbox_register(&pdev->dev, &mbox_dsp_info);
}
-static int omap1_mbox_remove(struct platform_device *pdev)
+static int __devexit omap1_mbox_remove(struct platform_device *pdev)
{
omap_mbox_unregister(&mbox_dsp_info);
static struct platform_driver omap1_mbox_driver = {
.probe = omap1_mbox_probe,
- .remove = omap1_mbox_remove,
+ .remove = __devexit_p(omap1_mbox_remove),
.driver = {
- .name = "mailbox",
+ .name = DRV_NAME,
},
};
module_init(omap1_mbox_init);
module_exit(omap1_mbox_exit);
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("omap mailbox: omap1 architecture specific functions");
+MODULE_AUTHOR("Hiroshi DOYU" <Hiroshi.DOYU@nokia.com>);
+MODULE_ALIAS("platform:"DRV_NAME);
#include <linux/io.h>
#include <linux/platform_device.h>
+#include <mach/irqs.h>
#include <mach/dma.h>
#include <mach/irqs.h>
#include <mach/mux.h>
--- /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 <mach/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 <linux/io.h>
+#include <mach/mmu.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 */
depends on ARCH_OMAP24XX
select OMAP_DM_TIMER
select ARCH_OMAP_OTG
+ select CPU_V6
config ARCH_OMAP2430
bool "OMAP2430 support"
depends on ARCH_OMAP24XX
+ select ARCH_OMAP_OTG
+ select CPU_V6
config ARCH_OMAP34XX
bool "OMAP34xx Based System"
bool "OMAP3430 support"
depends on ARCH_OMAP3 && ARCH_OMAP34XX
select ARCH_OMAP_OTG
+ select CPU_V7
comment "OMAP Board Type"
depends on ARCH_OMAP2 || ARCH_OMAP3
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 && VIDEO_HELPER_CHIPS_AUTO
+ 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_NOKIA_N810_WIMAX
+ bool "Nokia N810 WiMAX"
+ depends on MACH_NOKIA_N800
+ select MACH_NOKIA_N810
+
+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
+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_LDP
+ bool "OMAP3 LDP board"
+ depends on ARCH_OMAP3 && ARCH_OMAP34XX
+
+config MACH_OMAP2EVM
+ bool "OMAP 2530 EVM board"
depends on ARCH_OMAP2 && ARCH_OMAP24XX
-config MACH_OMAP3_BEAGLE
- bool "OMAP3 BEAGLE board"
+config MACH_OMAP_3430SDP
+ bool "OMAP 3430 SDP board"
depends on ARCH_OMAP3 && ARCH_OMAP34XX
-config MACH_OMAP_LDP
- bool "OMAP3 LDP board"
+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
config MACH_OVERO
config MACH_OMAP3_PANDORA
bool "OMAP3 Pandora"
- depends on ARCH_OMAP3 && ARCH_OMAP34XX
\ No newline at end of file
+ depends on ARCH_OMAP3 && ARCH_OMAP34XX
#
# Common support
-obj-y := irq.o id.o io.o memory.o control.o prcm.o clock.o mux.o \
+obj-y := irq.o id.o io.o sdrc.o control.o prcm.o clock.o mux.o \
devices.o serial.o gpmc.o timer-gp.o powerdomain.o \
clockdomain.o
obj-$(CONFIG_ARCH_OMAP2430) += sram243x.o
obj-$(CONFIG_ARCH_OMAP3) += sram34xx.o
+# SMS/SDRC
+obj-$(CONFIG_ARCH_OMAP2) += sdrc2xxx.o
+# obj-$(CONFIG_ARCH_OMAP3) += sdrc3xxx.o
+
# Power Management
ifeq ($(CONFIG_PM),y)
obj-y += pm.o
+obj-$(CONFIG_ARCH_OMAP2) += pm24xx.o
obj-$(CONFIG_ARCH_OMAP24XX) += sleep24xx.o
+obj-$(CONFIG_ARCH_OMAP3) += pm34xx.o sleep34xx.o
+obj-$(CONFIG_PM_DEBUG) += pm-debug.o
endif
+# SmartReflex driver
+obj-$(CONFIG_OMAP_SMARTREFLEX) += smartreflex.o
+
# Clock framework
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_H4) += board-h4.o board-h4-mmc.o
obj-$(CONFIG_MACH_OMAP_2430SDP) += board-2430sdp.o \
+ board-2430sdp-flash.o \
+ mmc-twl4030.o \
+ usb-musb.o \
+ usb-ehci.o
+obj-$(CONFIG_MACH_OMAP2EVM) += board-omap2evm.o \
mmc-twl4030.o
-obj-$(CONFIG_MACH_OMAP_APOLLON) += board-apollon.o
+obj-$(CONFIG_MACH_OMAP_3430SDP) += board-3430sdp.o \
+ mmc-twl4030.o \
+ usb-musb.o \
+ usb-ehci.o \
+ board-3430sdp-flash.o
+obj-$(CONFIG_MACH_OMAP3EVM) += board-omap3evm.o \
+ mmc-twl4030.o \
+ usb-musb.o usb-ehci.o \
+ board-omap3evm-flash.o \
+ twl4030-generic-scripts.o
obj-$(CONFIG_MACH_OMAP3_BEAGLE) += board-omap3beagle.o \
- mmc-twl4030.o
+ usb-musb.o usb-ehci.o \
+ mmc-twl4030.o \
+ twl4030-generic-scripts.o
obj-$(CONFIG_MACH_OMAP_LDP) += board-ldp.o \
- mmc-twl4030.o
+ mmc-twl4030.o \
+ usb-musb.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
obj-$(CONFIG_MACH_OVERO) += board-overo.o \
- mmc-twl4030.o
+ mmc-twl4030.o \
+ usb-musb.o \
+ usb-ehci.o \
+ twl4030-generic-scripts.o
obj-$(CONFIG_MACH_OMAP3_PANDORA) += board-omap3pandora.o \
- mmc-twl4030.o
+ mmc-twl4030.o \
+ usb-musb.o \
+ usb-ehci.o
+
+# TUSB 6010 chips
+obj-$(CONFIG_MACH_OMAP2_TUSB6010) += usb-tusb6010.o
--- /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 <mach/onenand.h>
+#include <mach/board.h>
+#include <mach/gpmc.h>
+#include <mach/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)
+{
+ void __iomem *gpmc_base_add, *gpmc_cs_base_add;
+ unsigned char cs = 0;
+
+ gpmc_base_add = (__force void __iomem *)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 = gpmc_cs_base_add;
+ sdp_nand_data.gpmc_baseaddr = 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/i2c/twl4030.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/io.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/ads7846.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
#include <mach/gpio.h>
#include <mach/mux.h>
#include <mach/board.h>
+#include <mach/usb-musb.h>
#include <mach/common.h>
+#include <mach/keypad.h>
#include <mach/gpmc.h>
+#include <mach/mcspi.h>
+
#include "mmc-twl4030.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 */
{
},
};
+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 twl4030_keypad_data sdp2430_kp_data = {
+ .rows = 5,
+ .cols = 6,
+ .keymap = sdp2430_keymap,
+ .keymapsize = ARRAY_SIZE(sdp2430_keymap),
+ .rep = 1,
+};
+
+static int __init msecure_init(void)
+{
+ int ret = 0;
+
+#ifdef CONFIG_RTC_DRV_TWL4030
+ ret = gpio_request(TWL4030_MSECURE_GPIO, "msecure");
+ if (ret < 0) {
+ printk(KERN_ERR "msecure_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.
+ */
+ gpio_direction_output(TWL4030_MSECURE_GPIO, 1);
+out:
+#endif
+
+ return ret;
+}
+
static struct platform_device *sdp2430_devices[] __initdata = {
&sdp2430_smc91x_device,
&sdp2430_flash_device,
+ &sdp2430_lcd_device,
+};
+
+static void ads7846_dev_init(void)
+{
+ if (gpio_request(TS_GPIO, "ads7846 irq") < 0)
+ printk(KERN_ERR "can't get ads746 pen down GPIO\n");
+
+ gpio_direction_input(TS_GPIO);
+
+ omap_set_gpio_debounce(TS_GPIO, 1);
+ omap_set_gpio_debounce_time(TS_GPIO, 0xa);
+}
+
+static int ads7846_get_pendown_state(void)
+{
+ return !gpio_get_value(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)
static void __init omap_2430sdp_init_irq(void)
{
- omap2_init_common_hw();
+ omap2_init_common_hw(NULL);
omap_init_irq();
omap_gpio_init();
sdp2430_init_smc91x();
.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_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},
};
.irq_end = TWL4030_GPIO_IRQ_END,
};
+static struct twl4030_usb_data sdp2430_usb_data = {
+ .usb_mode = T2_USB_MODE_ULPI,
+};
+
+static struct twl4030_madc_platform_data sdp2430_madc_data = {
+ .irq_line = 1,
+};
+
static struct twl4030_platform_data sdp2430_twldata = {
.irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END,
/* platform_data for children goes here */
.gpio = &sdp2430_gpio_data,
+ .madc = &sdp2430_madc_data,
+ .keypad = &sdp2430_kp_data,
+ .usb = &sdp2430_usb_data,
};
static struct i2c_board_info __initdata sdp2430_i2c_boardinfo[] = {
omap_board_config = sdp2430_config;
omap_board_config_size = ARRAY_SIZE(sdp2430_config);
omap_serial_init();
+
+ msecure_init();
+
+ sdp2430_flash_init();
+ usb_musb_init();
+
+ spi_register_board_info(sdp2430_spi_board_info,
+ ARRAY_SIZE(sdp2430_spi_board_info));
+ ads7846_dev_init();
twl4030_mmc_init(mmc);
+
+ /* turn off secondary LCD backlight */
+ gpio_direction_output(SECONDARY_LCD_GPIO, 0);
}
static void __init omap_2430sdp_map_io(void)
--- /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 <mach/onenand.h>
+#include <mach/board.h>
+#include <mach/gpmc.h>
+#include <mach/nand.h>
+
+#define NAND_BLOCK_SIZE SZ_128K
+
+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;
+}
+
+static struct mtd_partition sdp_nand_partitions[] = {
+ /* All the partition sizes are listed in terms of NAND block size */
+ {
+ .name = "X-Loader-NAND",
+ .offset = 0,
+ .size = 4 * NAND_BLOCK_SIZE,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ },
+ {
+ .name = "U-Boot-NAND",
+ .offset = MTDPART_OFS_APPEND, /* Offset = 0x80000 */
+ .size = 4 * NAND_BLOCK_SIZE,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ },
+ {
+ .name = "Boot Env-NAND",
+ .offset = MTDPART_OFS_APPEND, /* Offset = 0x100000 */
+ .size = 2 * NAND_BLOCK_SIZE,
+ },
+ {
+ .name = "Kernel-NAND",
+ .offset = MTDPART_OFS_APPEND, /* Offset = 0x140000 */
+ .size = 32 * NAND_BLOCK_SIZE,
+ },
+ {
+ .name = "File System - NAND",
+ .size = MTDPART_SIZ_FULL,
+ .offset = MTDPART_OFS_APPEND, /* Offset = 0x540000 */
+ },
+};
+
+static struct omap_nand_platform_data sdp_nand_data = {
+ .parts = sdp_nand_partitions,
+ .nr_parts = ARRAY_SIZE(sdp_nand_partitions),
+ .nand_setup = NULL,
+ .dma_channel = -1, /* disable DMA in OMAP NAND driver */
+ .dev_ready = NULL,
+};
+
+static struct resource sdp_nand_resource = {
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device sdp_nand_device = {
+ .name = "omap2-nand",
+ .id = 0,
+ .dev = {
+ .platform_data = &sdp_nand_data,
+ },
+ .num_resources = 1,
+ .resource = &sdp_nand_resource,
+};
+
+
+/**
+ * sdp3430_flash_init - Identify devices connected to GPMC and register.
+ *
+ * @return - void.
+ */
+void __init sdp3430_flash_init(void)
+{
+ u8 cs = 0;
+ u8 nandcs = GPMC_CS_NUM + 1;
+ u8 onenandcs = GPMC_CS_NUM + 1;
+ unsigned long gpmc_base_add;
+
+ gpmc_base_add = OMAP34XX_GPMC_VIRT;
+
+ /* Configure start address and size of NOR device */
+ if (omap_rev() > 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_CONFIG1);
+
+ /*
+ * 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 oneNAND is configured
+ */
+ if ((ret & 0xC00) == 0x800) {
+ /* Found it!! */
+ if (nandcs > GPMC_CS_NUM)
+ nandcs = cs;
+ } else {
+ ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
+ if ((ret & 0x3F) == (ONENAND_MAP >> 24))
+ onenandcs = cs;
+ }
+ cs++;
+ }
+ if ((nandcs > GPMC_CS_NUM) && (onenandcs > GPMC_CS_NUM)) {
+ printk(KERN_INFO "NAND/OneNAND: Unable to find configuration "
+ " in GPMC\n ");
+ return;
+ }
+
+ if (nandcs < GPMC_CS_NUM) {
+ sdp_nand_data.cs = nandcs;
+ sdp_nand_data.gpmc_cs_baseaddr = (void *)(gpmc_base_add +
+ GPMC_CS0_BASE + nandcs*GPMC_CS_SIZE);
+ 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");
+ }
+
+ 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/spi/spi.h>
+#include <linux/spi/ads7846.h>
+#include <linux/i2c/twl4030.h>
+
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <mach/mcspi.h>
+#include <mach/gpio.h>
+#include <mach/mux.h>
+#include <mach/board.h>
+#include <mach/usb-musb.h>
+#include <mach/usb-ehci.h>
+#include <mach/common.h>
+#include <mach/keypad.h>
+#include <mach/dma.h>
+#include <mach/gpmc.h>
+
+#include <asm/io.h>
+#include <asm/delay.h>
+#include <mach/control.h>
+
+#include "sdram-qimonda-hyb18m512160af-6.h"
+#include "mmc-twl4030.h"
+
+#define CONFIG_DISABLE_HFCLK 1
+
+#define SDP3430_SMC91X_CS 3
+
+#define ENABLE_VAUX3_DEDICATED 0x03
+#define ENABLE_VAUX3_DEV_GRP 0x20
+
+
+#define TWL4030_MSECURE_GPIO 22
+
+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 twl4030_keypad_data sdp3430_kp_data = {
+ .rows = 5,
+ .cols = 6,
+ .keymap = sdp3430_keymap,
+ .keymapsize = ARRAY_SIZE(sdp3430_keymap),
+ .rep = 1,
+};
+
+static int ts_gpio;
+
+static int __init msecure_init(void)
+{
+ int ret = 0;
+
+#ifdef CONFIG_RTC_DRV_TWL4030
+ /* 3430ES2.0 doesn't have msecure/gpio-22 line connected to T2 */
+ if (omap_type() == OMAP2_DEVICE_TYPE_GP &&
+ omap_rev() < OMAP3430_REV_ES2_0) {
+ void __iomem *msecure_pad_config_reg = omap_ctrl_base_get() +
+ 0xA3C;
+ int mux_mask = 0x04;
+ u16 tmp;
+
+ ret = gpio_request(TWL4030_MSECURE_GPIO, "msecure");
+ if (ret < 0) {
+ printk(KERN_ERR "msecure_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.
+ */
+ tmp = __raw_readw(msecure_pad_config_reg);
+ tmp &= 0xF8; /* To enable mux mode 03/04 = GPIO_RTC */
+ tmp |= mux_mask;/* To enable mux mode 03/04 = GPIO_RTC */
+ __raw_writew(tmp, msecure_pad_config_reg);
+
+ gpio_direction_output(TWL4030_MSECURE_GPIO, 1);
+ }
+out:
+#endif
+ return ret;
+}
+
+/**
+ * @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 (gpio_request(ts_gpio, "ADS7846 pendown") < 0) {
+ printk(KERN_ERR "can't get ads746 pen down GPIO\n");
+ return;
+ }
+
+ gpio_direction_input(ts_gpio);
+
+ omap_set_gpio_debounce(ts_gpio, 1);
+ omap_set_gpio_debounce_time(ts_gpio, 0xa);
+}
+
+static int ads7846_get_pendown_state(void)
+{
+ return !gpio_get_value(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_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 (omap_rev() > OMAP3430_REV_ES1_0)
+ eth_gpio = OMAP34XX_ETHR_GPIO_IRQ_SDPV2;
+ else
+ eth_gpio = OMAP34XX_ETHR_GPIO_IRQ_SDPV1;
+
+ sdp3430_smc91x_resources[1].start = gpio_to_irq(eth_gpio);
+
+ if (gpio_request(eth_gpio, "SMC91x irq") < 0) {
+ printk(KERN_ERR "Failed to request GPIO%d for smc91x IRQ\n",
+ eth_gpio);
+ return;
+ }
+ gpio_direction_input(eth_gpio);
+}
+
+static void __init omap_3430sdp_init_irq(void)
+{
+ omap2_init_common_hw(hyb18m512160af6_sdrc_params);
+ 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_board_config_kernel sdp3430_config[] __initdata = {
+ { OMAP_TAG_UART, &sdp3430_uart_config },
+ { OMAP_TAG_LCD, &sdp3430_lcd_config },
+};
+
+static int sdp3430_batt_table[] = {
+/* 0 C*/
+30800, 29500, 28300, 27100,
+26000, 24900, 23900, 22900, 22000, 21100, 20300, 19400, 18700, 17900,
+17200, 16500, 15900, 15300, 14700, 14100, 13600, 13100, 12600, 12100,
+11600, 11200, 10800, 10400, 10000, 9630, 9280, 8950, 8620, 8310,
+8020, 7730, 7460, 7200, 6950, 6710, 6470, 6250, 6040, 5830,
+5640, 5450, 5260, 5090, 4920, 4760, 4600, 4450, 4310, 4170,
+4040, 3910, 3790, 3670, 3550
+};
+
+static struct twl4030_bci_platform_data sdp3430_bci_data = {
+ .battery_tmp_tbl = sdp3430_batt_table,
+ .tblsize = ARRAY_SIZE(sdp3430_batt_table),
+};
+
+static struct twl4030_gpio_platform_data sdp3430_gpio_data = {
+ .gpio_base = OMAP_MAX_GPIO_LINES,
+ .irq_base = TWL4030_GPIO_IRQ_BASE,
+ .irq_end = TWL4030_GPIO_IRQ_END,
+};
+
+static struct twl4030_usb_data sdp3430_usb_data = {
+ .usb_mode = T2_USB_MODE_ULPI,
+};
+
+static struct twl4030_madc_platform_data sdp3430_madc_data = {
+ .irq_line = 1,
+};
+
+
+static struct twl4030_ins __initdata sleep_on_seq[] = {
+/*
+ * Turn off VDD1 and VDD2.
+ */
+ {MSG_SINGULAR(DEV_GRP_P1, 0xf, RES_STATE_OFF), 4},
+ {MSG_SINGULAR(DEV_GRP_P1, 0x10, RES_STATE_OFF), 2},
+#ifdef CONFIG_DISABLE_HFCLK
+/*
+ * And also turn off the OMAP3 PLLs and the sysclk output.
+ */
+ {MSG_SINGULAR(DEV_GRP_P1, 0x7, RES_STATE_OFF), 3},
+ {MSG_SINGULAR(DEV_GRP_P1, 0x19, RES_STATE_OFF), 3},
+#endif
+};
+
+static struct twl4030_script sleep_on_script __initdata = {
+ .script = sleep_on_seq,
+ .size = ARRAY_SIZE(sleep_on_seq),
+ .flags = TRITON_SLEEP_SCRIPT,
+};
+
+static struct twl4030_ins wakeup_seq[] __initdata = {
+#ifndef CONFIG_DISABLE_HFCLK
+/*
+ * Wakeup VDD1 and VDD2.
+ */
+ {MSG_SINGULAR(DEV_GRP_P1, 0xf, RES_STATE_ACTIVE), 4},
+ {MSG_SINGULAR(DEV_GRP_P1, 0x10, RES_STATE_ACTIVE), 2},
+#else
+/*
+ * Reenable the OMAP3 PLLs.
+ * Wakeup VDD1 and VDD2.
+ * Reenable sysclk output.
+ */
+ {MSG_SINGULAR(DEV_GRP_P1, 0x7, RES_STATE_ACTIVE), 0x30},
+ {MSG_SINGULAR(DEV_GRP_P1, 0xf, RES_STATE_ACTIVE), 0x30},
+ {MSG_SINGULAR(DEV_GRP_P1, 0x10, RES_STATE_ACTIVE), 0x37},
+ {MSG_SINGULAR(DEV_GRP_P1, 0x19, RES_STATE_ACTIVE), 3},
+#endif /* #ifndef CONFIG_DISABLE_HFCLK */
+};
+
+static struct twl4030_script wakeup_script __initdata = {
+ .script = wakeup_seq,
+ .size = ARRAY_SIZE(wakeup_seq),
+ .flags = TRITON_WAKEUP12_SCRIPT | TRITON_WAKEUP3_SCRIPT,
+};
+
+static struct twl4030_ins wrst_seq[] __initdata = {
+/*
+ * Reset twl4030.
+ * Reset VDD1 regulator.
+ * Reset VDD2 regulator.
+ * Reset VPLL1 regulator.
+ * Enable sysclk output.
+ * Reenable twl4030.
+ */
+ {MSG_SINGULAR(DEV_GRP_NULL, 0x1b, RES_STATE_OFF), 2},
+ {MSG_SINGULAR(DEV_GRP_P1, 0xf, RES_STATE_WRST), 15},
+ {MSG_SINGULAR(DEV_GRP_P1, 0x10, RES_STATE_WRST), 15},
+ {MSG_SINGULAR(DEV_GRP_P1, 0x7, RES_STATE_WRST), 0x60},
+ {MSG_SINGULAR(DEV_GRP_P1, 0x19, RES_STATE_ACTIVE), 2},
+ {MSG_SINGULAR(DEV_GRP_NULL, 0x1b, RES_STATE_ACTIVE), 2},
+};
+static struct twl4030_script wrst_script __initdata = {
+ .script = wrst_seq,
+ .size = ARRAY_SIZE(wakeup_seq),
+ .flags = TRITON_WRST_SCRIPT,
+};
+
+static struct twl4030_script *twl4030_scripts[] __initdata = {
+ &sleep_on_script,
+ &wakeup_script,
+ &wrst_script,
+};
+
+static struct twl4030_power_data sdp3430_t2scripts_data __initdata = {
+ .scripts = twl4030_scripts,
+ .size = ARRAY_SIZE(twl4030_scripts),
+};
+
+static struct twl4030_platform_data sdp3430_twldata = {
+ .irq_base = TWL4030_IRQ_BASE,
+ .irq_end = TWL4030_IRQ_END,
+
+ /* platform_data for children goes here */
+ .bci = &sdp3430_bci_data,
+ .gpio = &sdp3430_gpio_data,
+ .madc = &sdp3430_madc_data,
+ .keypad = &sdp3430_kp_data,
+ .power = &sdp3430_t2scripts_data,
+ .usb = &sdp3430_usb_data,
+};
+
+static struct i2c_board_info __initdata sdp3430_i2c_boardinfo[] = {
+ {
+ I2C_BOARD_INFO("twl4030", 0x48),
+ .flags = I2C_CLIENT_WAKE,
+ .irq = INT_34XX_SYS_NIRQ,
+ .platform_data = &sdp3430_twldata,
+ },
+};
+
+static int __init omap3430_i2c_init(void)
+{
+ omap_register_i2c_bus(1, 2600, sdp3430_i2c_boardinfo,
+ ARRAY_SIZE(sdp3430_i2c_boardinfo));
+ omap_register_i2c_bus(2, 400, NULL, 0);
+ omap_register_i2c_bus(3, 400, NULL, 0);
+ return 0;
+}
+
+static struct twl4030_hsmmc_info mmc[] __initdata = {
+ {
+ .mmc = 1,
+ .wires = 8,
+ .gpio_cd = -EINVAL,
+ .gpio_wp = -EINVAL,
+ },
+ {
+ .mmc = 2,
+ .wires = 8,
+ .gpio_cd = -EINVAL,
+ .gpio_wp = -EINVAL,
+ },
+ {} /* Terminator */
+};
+
+extern void __init sdp3430_flash_init(void);
+
+static void __init omap_3430sdp_init(void)
+{
+ omap3430_i2c_init();
+ platform_add_devices(sdp3430_devices, ARRAY_SIZE(sdp3430_devices));
+ omap_board_config = sdp3430_config;
+ omap_board_config_size = ARRAY_SIZE(sdp3430_config);
+ if (omap_rev() > 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 = gpio_to_irq(ts_gpio);
+ spi_register_board_info(sdp3430_spi_board_info,
+ ARRAY_SIZE(sdp3430_spi_board_info));
+ ads7846_dev_init();
+ sdp3430_flash_init();
+ msecure_init();
+ omap_serial_init();
+ usb_musb_init();
+ usb_ehci_init();
+ twl4030_mmc_init(mmc);
+}
+
+static void __init omap_3430sdp_map_io(void)
+{
+ omap2_set_globals_343x();
+ omap2_map_common_io();
+}
+
+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 <mach/gpio.h>
+#include <mach/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 <linux/platform_device.h>
+
+#include <mach/gpio.h>
+#include <mach/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)
+{
+}
+
+/*
+ * Note: If you want to detect card feature, please assign GPIO 37
+ */
+static struct omap_mmc_platform_data mmc1_data = {
+ .nr_slots = 1,
+ .init = apollon_mmc_late_init,
+ .cleanup = apollon_mmc_cleanup,
+ .dma_mask = 0xffffffff,
+ .slots[0] = {
+ .wires = 4,
+
+ /*
+ * Use internal loop-back in MMC/SDIO Module Input Clock
+ * selection
+ */
+ .internal_clock = 1,
+
+ .set_power = apollon_mmc_set_power,
+ .set_bus_mode = apollon_mmc_set_bus_mode,
+ .ocr_mask = MMC_VDD_30_31 | MMC_VDD_31_32 |
+ MMC_VDD_32_33 | MMC_VDD_33_34,
+ .name = "mmcblk",
+ },
+};
+
+static struct omap_mmc_platform_data *mmc_data[OMAP24XX_NR_MMC];
+
+void __init apollon_mmc_init(void)
+{
+ mmc_data[0] = &mmc1_data;
+ omap2_init_mmc(mmc_data, OMAP24XX_NR_MMC);
+}
+
+#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 <mach/hardware.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <mach/board.h>
#include <mach/common.h>
#include <mach/gpmc.h>
-#include <mach/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[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = OMAP_GPIO_IRQ(APOLLON_ETHR_GPIO_IRQ),
- .end = OMAP_GPIO_IRQ(APOLLON_ETHR_GPIO_IRQ),
+ .start = gpio_to_irq(APOLLON_ETHR_GPIO_IRQ),
+ .end = gpio_to_irq(APOLLON_ETHR_GPIO_IRQ),
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
},
};
.id = -1,
};
-static struct omap_led_config apollon_led_config[] = {
+static struct gpio_led apollon_led_config[] = {
+ {
+ .name = "d2",
+ .gpio = LED0_GPIO13,
+ .default_trigger = "heartbeat",
+ },
{
- .cdev = {
- .name = "apollon:led0",
- },
- .gpio = LED0_GPIO13,
+ .name = "d3",
+ .gpio = LED1_GPIO14,
},
{
- .cdev = {
- .name = "apollon:led1",
- },
- .gpio = LED1_GPIO14,
+ .name = "d4",
+ .gpio = LED2_GPIO15,
},
{
- .cdev = {
- .name = "apollon:led2",
- },
- .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 (gpio_request(APOLLON_ETHR_GPIO_IRQ, "SMC91x 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;
}
gpio_direction_input(APOLLON_ETHR_GPIO_IRQ);
static void __init omap_apollon_init_irq(void)
{
- omap2_init_common_hw();
+ omap2_init_common_hw(NULL);
omap_init_irq();
omap_gpio_init();
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),
};
.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_USB, &apollon_usb_config },
{ OMAP_TAG_LCD, &apollon_lcd_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);
- gpio_direction_input(SW_ENTER_GPIO16);
- /* Up SW - AA12 */
- omap_cfg_reg(AA12_242X_GPIO17);
- omap_request_gpio(SW_UP_GPIO17);
- gpio_direction_input(SW_UP_GPIO17);
- /* Down SW - AA8 */
- omap_cfg_reg(AA8_242X_GPIO58);
- omap_request_gpio(SW_DOWN_GPIO58);
- gpio_direction_input(SW_DOWN_GPIO58);
-
- set_irq_type(OMAP_GPIO_IRQ(SW_ENTER_GPIO16), IRQ_TYPE_EDGE_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), IRQ_TYPE_EDGE_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), IRQ_TYPE_EDGE_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)
gpio_direction_output(12, 0);
}
-static void __init omap_apollon_init(void)
+static void __init apollon_tsc_init(void)
+{
+ /* TSC2101 */
+ omap_cfg_reg(N15_24XX_GPIO85);
+ gpio_request(85, "tsc2101 irq");
+ gpio_direction_input(85);
+
+ omap_cfg_reg(W14_24XX_SYS_CLKOUT); /* mclk */
+}
+
+static void __init apollon_cs_init(void)
{
- u32 v;
+ 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)
static void __init omap_generic_init_irq(void)
{
- omap2_init_common_hw();
+ omap2_init_common_hw(NULL);
omap_init_irq();
}
.enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
};
-static struct omap_board_config_kernel generic_config[] = {
+static struct omap_board_config_kernel generic_config[] __initdata = {
{ OMAP_TAG_UART, &generic_uart_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)
--- /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 <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/i2c/menelaus.h>
+
+#include <asm/mach-types.h>
+
+#include <mach/mmc.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 mmc1_data = {
+ .nr_slots = 2,
+ .switch_slot = h4_mmc_switch_slot,
+ .init = h4_mmc_late_init,
+ .cleanup = h4_mmc_cleanup,
+ .dma_mask = 0xffffffff,
+ .slots[0] = {
+ .wires = 4,
+ .set_power = h4_mmc_set_power,
+ .set_bus_mode = h4_mmc_set_bus_mode,
+ .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] = {
+ .wires = 4,
+ .set_power = h4_mmc_set_power,
+ .set_bus_mode = h4_mmc_set_bus_mode,
+ .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",
+ },
+};
+
+static struct omap_mmc_platform_data *mmc_data[OMAP24XX_NR_MMC];
+
+void __init h4_mmc_init(void)
+{
+ mmc_data[0] = &mmc1_data;
+ omap2_init_mmc(mmc_data, OMAP24XX_NR_MMC);
+}
+
+#else
+
+void __init h4_mmc_init(void)
+{
+}
+
+#endif
+
#include <linux/mtd/partitions.h>
#include <linux/delay.h>
#include <linux/workqueue.h>
-#include <linux/i2c.h>
-#include <linux/i2c/at24.h>
#include <linux/input.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+
+#include <linux/i2c/at24.h>
+#include <linux/i2c/menelaus.h>
+#include <linux/i2c/pcf857x.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/tsc210x.h>
+
+#include <media/v4l2-int-device.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
#include <asm/mach/flash.h>
#include <mach/control.h>
-#include <mach/gpio.h>
-#include <mach/gpioexpander.h>
#include <mach/mux.h>
#include <mach/usb.h>
#include <mach/irda.h>
#include <mach/board.h>
#include <mach/common.h>
#include <mach/keypad.h>
-#include <mach/menelaus.h>
#include <mach/dma.h>
#include <mach/gpmc.h>
.resource = &h4_flash_resource,
};
-/* Select between the IrDA and aGPS module
- */
+#if defined(CONFIG_OMAP_IR) || defined(CONFIG_OMAP_IR_MODULE)
+
+/* Select between the IrDA and aGPS module */
static int h4_select_irda(struct device *dev, int state)
{
- unsigned char expa;
- int err = 0;
-
- if ((err = read_gpio_expa(&expa, 0x21))) {
- printk(KERN_ERR "Error reading from I/O expander\n");
- return err;
- }
+ /* U192.P0 = high for IRDA; else AGPS */
+ gpio_set_value_cansleep(H4_GPIO_IRDA_AGPSn, state & IR_SEL);
- /* 'P6' enable/disable IRDA_TX and IRDA_RX */
- if (state & IR_SEL) { /* IrDa */
- if ((err = write_gpio_expa(expa | 0x01, 0x21))) {
- printk(KERN_ERR "Error writing to I/O expander\n");
- return err;
- }
- } else {
- if ((err = write_gpio_expa(expa & ~0x01, 0x21))) {
- printk(KERN_ERR "Error writing to I/O expander\n");
- return err;
- }
- }
- return err;
+ /* NOTE: UART3 can also hook up to a DB9 or to GSM ... */
+ return 0;
}
static void set_trans_mode(struct work_struct *work)
struct omap_irda_config *irda_config =
container_of(work, struct omap_irda_config, gpio_expa.work);
int mode = irda_config->mode;
- unsigned char expa;
- int err = 0;
-
- if ((err = read_gpio_expa(&expa, 0x20)) != 0) {
- printk(KERN_ERR "Error reading from I/O expander\n");
- }
-
- expa &= ~0x01;
- if (!(mode & IR_SIRMODE)) { /* MIR/FIR */
- expa |= 0x01;
- }
-
- if ((err = write_gpio_expa(expa, 0x20)) != 0) {
- printk(KERN_ERR "Error writing to I/O expander\n");
- }
+ /* U191.P0 = low for SIR; else MIR/FIR */
+ gpio_set_value_cansleep(H4_GPIO_IRDA_FIRSEL, !(mode & IR_SIRMODE));
}
static int h4_transceiver_mode(struct device *dev, int mode)
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 void __init omap_h4_init_irq(void)
{
- omap2_init_common_hw();
+ omap2_init_common_hw(NULL);
omap_init_irq();
omap_gpio_init();
h4_init_flash();
}
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_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_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 ((omap_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)
+{
+ /* power up the sensor? */
+ gpio_set_value_cansleep(H4_GPIO_CAM_MODULE_EN, power);
+
+ /* take it out of reset if it's not powered */
+ gpio_direction_output(H4_GPIO_CAM_RST, !power);
+
+ return 0;
+}
+
+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
+
+/* leave LCD powered off unless it will be used */
+#if defined(CONFIG_FB_OMAP) || defined(CONFIG_FB_OMAP_MODULE)
+#define LCD_ENABLED true
+#else
+#define LCD_ENABLED false
+#endif
+
+static struct gpio_led backlight_leds[] = {
+ {
+ .name = "lcd_h4",
+ .default_trigger = "backlight",
+ .gpio = H4_GPIO_LCD_ENBKL,
+ },
+ { },
+};
+
+static struct gpio_led_platform_data backlight_led_data = {
+ .num_leds = 1,
+ .leds = backlight_leds,
+};
+
+static struct platform_device h4_backlight_device = {
+ .name = "leds-gpio",
+ .id = 0,
+ .dev.platform_data = &backlight_led_data,
+};
+
+static int
+u191_setup(struct i2c_client *client, int gpio, unsigned ngpio, void *context)
+{
+ /* P0 = IRDA control, FIR/MIR vs SIR */
+ gpio_request(H4_GPIO_IRDA_FIRSEL, "irda_firsel");
+ gpio_direction_output(H4_GPIO_IRDA_FIRSEL, false);
+
+ /* P3 = camera sensor module PWDN */
+ gpio_request(H4_GPIO_CAM_MODULE_EN, "camera_en");
+ gpio_direction_output(H4_GPIO_CAM_MODULE_EN, false);
+
+ /* P7 = LCD_ENVDD ... controls power to LCD (including backlight)
+ * P5 = LCD_ENBKL ... switches backlight
+ */
+ gpio_request(H4_GPIO_LCD_ENVDD, "lcd_power");
+ gpio_direction_output(H4_GPIO_LCD_ENVDD, LCD_ENABLED);
+ if (LCD_ENABLED) {
+ h4_backlight_device.dev.parent = &client->dev;
+ platform_device_register(&h4_backlight_device);
+ }
+
+ /* P6 = AUDIO_ENVDD ... switch power to microphone */
+ gpio_request(H4_GPIO_AUDIO_ENVDD, "audio_power");
+ gpio_direction_output(H4_GPIO_AUDIO_ENVDD, true);
+
+ return 0;
+}
+
+
+static struct pcf857x_platform_data u191_platform_data = {
+ .gpio_base = H4_U191_GPIO_BASE,
+ .setup = u191_setup,
+};
+
+static int
+u192_setup(struct i2c_client *client, int gpio, unsigned ngpio, void *context)
+{
+ gpio_request(H4_GPIO_IRDA_AGPSn, "irda/agps");
+ gpio_direction_output(H4_GPIO_IRDA_AGPSn, false);
+
+ return 0;
+}
+
+static struct pcf857x_platform_data u192_platform_data = {
+ .gpio_base = H4_U192_GPIO_BASE,
+ .setup = u192_setup,
+};
+
+static int
+u193_setup(struct i2c_client *client, int gpio, unsigned ngpio, void *context)
+{
+ /* reset sensor */
+ gpio_request(H4_GPIO_CAM_RST, "camera_rst");
+ gpio_direction_output(H4_GPIO_CAM_RST, true);
+
+ return 0;
+}
+
+static struct pcf857x_platform_data u193_platform_data = {
+ .gpio_base = H4_U193_GPIO_BASE,
+ .setup = u193_setup,
};
static struct at24_platform_data m24c01 = {
};
static struct i2c_board_info __initdata h4_i2c_board_info[] = {
+ { /* U191 gpios */
+ I2C_BOARD_INFO("pcf8574", 0x20),
+ .platform_data = &u191_platform_data,
+ },
+ { /* U192 gpios */
+ I2C_BOARD_INFO("pcf8574", 0x21),
+ .platform_data = &u192_platform_data,
+ },
+ { /* U193 gpios */
+ I2C_BOARD_INFO("pcf8574", 0x22),
+ .platform_data = &u193_platform_data,
+ },
+ {
+ I2C_BOARD_INFO("rv5c387a", 0x32),
+ /* 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),
.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
{ /* EEPROM on mainboard */
I2C_BOARD_INFO("24c01", 0x52),
.platform_data = &m24c01,
}
#endif
- i2c_register_board_info(1, h4_i2c_board_info,
- ARRAY_SIZE(h4_i2c_board_info));
+#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)
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/input.h>
+#include <linux/gpio_keys.h>
#include <linux/workqueue.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <mach/gpio.h>
#include <mach/board.h>
#include <mach/common.h>
+#include <mach/keypad.h>
#include <mach/gpmc.h>
+#include <mach/usb-musb.h>
#include <asm/io.h>
#include <asm/delay.h>
#include "mmc-twl4030.h"
+
#define SDP3430_SMC91X_CS 3
+#define CONFIG_DISABLE_HFCLK 1
+
+#define ENABLE_VAUX1_DEDICATED 0x03
+#define ENABLE_VAUX1_DEV_GRP 0x20
+
+#define TWL4030_MSECURE_GPIO 22
static struct resource ldp_smc911x_resources[] = {
[0] = {
.resource = ldp_smc911x_resources,
};
+static int ldp_twl4030_keymap[] = {
+ KEY(0, 0, KEY_1),
+ KEY(1, 0, KEY_2),
+ KEY(2, 0, KEY_3),
+ KEY(0, 1, KEY_4),
+ KEY(1, 1, KEY_5),
+ KEY(2, 1, KEY_6),
+ KEY(3, 1, KEY_F5),
+ KEY(0, 2, KEY_7),
+ KEY(1, 2, KEY_8),
+ KEY(2, 2, KEY_9),
+ KEY(3, 2, KEY_F6),
+ KEY(0, 3, KEY_F7),
+ KEY(1, 3, KEY_0),
+ KEY(2, 3, KEY_F8),
+ PERSISTENT_KEY(4, 5),
+ KEY(4, 4, KEY_VOLUMEUP),
+ KEY(5, 5, KEY_VOLUMEDOWN),
+ 0
+};
+
+static struct twl4030_keypad_data ldp_kp_twl4030_data = {
+ .rows = 6,
+ .cols = 6,
+ .keymap = ldp_twl4030_keymap,
+ .keymapsize = ARRAY_SIZE(ldp_twl4030_keymap),
+ .rep = 1,
+};
+
+static struct gpio_keys_button ldp_gpio_keys_buttons[] = {
+ [0] = {
+ .code = KEY_ENTER,
+ .gpio = 101,
+ .desc = "enter sw",
+ .active_low = 1,
+ .debounce_interval = 30,
+ },
+ [1] = {
+ .code = KEY_F1,
+ .gpio = 102,
+ .desc = "func 1",
+ .active_low = 1,
+ .debounce_interval = 30,
+ },
+ [2] = {
+ .code = KEY_F2,
+ .gpio = 103,
+ .desc = "func 2",
+ .active_low = 1,
+ .debounce_interval = 30,
+ },
+ [3] = {
+ .code = KEY_F3,
+ .gpio = 104,
+ .desc = "func 3",
+ .active_low = 1,
+ .debounce_interval = 30,
+ },
+ [4] = {
+ .code = KEY_F4,
+ .gpio = 105,
+ .desc = "func 4",
+ .active_low = 1,
+ .debounce_interval = 30,
+ },
+ [5] = {
+ .code = KEY_LEFT,
+ .gpio = 106,
+ .desc = "left sw",
+ .active_low = 1,
+ .debounce_interval = 30,
+ },
+ [6] = {
+ .code = KEY_RIGHT,
+ .gpio = 107,
+ .desc = "right sw",
+ .active_low = 1,
+ .debounce_interval = 30,
+ },
+ [7] = {
+ .code = KEY_UP,
+ .gpio = 108,
+ .desc = "up sw",
+ .active_low = 1,
+ .debounce_interval = 30,
+ },
+ [8] = {
+ .code = KEY_DOWN,
+ .gpio = 109,
+ .desc = "down sw",
+ .active_low = 1,
+ .debounce_interval = 30,
+ },
+};
+
+static struct gpio_keys_platform_data ldp_gpio_keys = {
+ .buttons = ldp_gpio_keys_buttons,
+ .nbuttons = ARRAY_SIZE(ldp_gpio_keys_buttons),
+ .rep = 1,
+};
+
+static struct platform_device ldp_gpio_keys_device = {
+ .name = "gpio-keys",
+ .id = -1,
+ .dev = {
+ .platform_data = &ldp_gpio_keys,
+ },
+};
+
+static int ts_gpio;
+
+static int __init msecure_init(void)
+{
+ int ret = 0;
+
+#ifdef CONFIG_RTC_DRV_TWL4030
+ /* 3430ES2.0 doesn't have msecure/gpio-22 line connected to T2 */
+ if (omap_type() == OMAP2_DEVICE_TYPE_GP &&
+ omap_rev() < OMAP3430_REV_ES2_0) {
+ void __iomem *msecure_pad_config_reg =
+ omap_ctrl_base_get() + 0xA3C;
+ int mux_mask = 0x04;
+ u16 tmp;
+
+ ret = gpio_request(TWL4030_MSECURE_GPIO, "msecure");
+ if (ret < 0) {
+ printk(KERN_ERR "msecure_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.
+ */
+
+ tmp = __raw_readw(msecure_pad_config_reg);
+ tmp &= 0xF8; /* To enable mux mode 03/04 = GPIO_RTC */
+ tmp |= mux_mask;/* To enable mux mode 03/04 = GPIO_RTC */
+ __raw_writew(tmp, msecure_pad_config_reg);
+
+ gpio_direction_output(TWL4030_MSECURE_GPIO, 1);
+ }
+out:
+#endif
+ return ret;
+}
+
+/**
+ * @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 (gpio_request(ts_gpio, "ads7846 irq") < 0) {
+ printk(KERN_ERR "can't get ads746 pen down GPIO\n");
+ return;
+ }
+
+ gpio_direction_input(ts_gpio);
+
+ omap_set_gpio_debounce(ts_gpio, 1);
+ omap_set_gpio_debounce_time(ts_gpio, 0xa);
+}
+
+static int ads7846_get_pendown_state(void)
+{
+ return !gpio_get_value(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_VAUX1_DEDICATED, TWL4030_VAUX1_DEDICATED))
+ return -EIO;
+ if (ret != twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+ ENABLE_VAUX1_DEV_GRP, TWL4030_VAUX1_DEV_GRP))
+ return -EIO;
+ } else if (vaux_cntrl == VAUX_DISABLE) {
+ if (ret != twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+ 0x00, TWL4030_VAUX1_DEDICATED))
+ return -EIO;
+ if (ret != twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+ 0x00, TWL4030_VAUX1_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 ldp_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 ldp_lcd_device = {
+ .name = "ldp_lcd",
+ .id = -1,
+};
+
static struct platform_device *ldp_devices[] __initdata = {
&ldp_smc911x_device,
+ &ldp_lcd_device,
+ &ldp_gpio_keys_device,
};
static inline void __init ldp_init_smc911x(void)
ldp_smc911x_resources[1].start = OMAP_GPIO_IRQ(eth_gpio);
- if (omap_request_gpio(eth_gpio) < 0) {
+ if (gpio_request(eth_gpio, "smc911x irq") < 0) {
printk(KERN_ERR "Failed to request GPIO%d for smc911x IRQ\n",
eth_gpio);
return;
gpio_direction_input(eth_gpio);
}
+
static void __init omap_ldp_init_irq(void)
{
- omap2_init_common_hw();
+ omap2_init_common_hw(NULL);
omap_init_irq();
omap_gpio_init();
ldp_init_smc911x();
.enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
};
+static struct omap_lcd_config ldp_lcd_config __initdata = {
+ .ctrl_name = "internal",
+};
+
static struct omap_board_config_kernel ldp_config[] __initdata = {
{ OMAP_TAG_UART, &ldp_uart_config },
+ { OMAP_TAG_LCD, &ldp_lcd_config },
+};
+
+static int ldp_batt_table[] = {
+/* 0 C*/
+30800, 29500, 28300, 27100,
+26000, 24900, 23900, 22900, 22000, 21100, 20300, 19400, 18700, 17900,
+17200, 16500, 15900, 15300, 14700, 14100, 13600, 13100, 12600, 12100,
+11600, 11200, 10800, 10400, 10000, 9630, 9280, 8950, 8620, 8310,
+8020, 7730, 7460, 7200, 6950, 6710, 6470, 6250, 6040, 5830,
+5640, 5450, 5260, 5090, 4920, 4760, 4600, 4450, 4310, 4170,
+4040, 3910, 3790, 3670, 3550
+};
+
+static struct twl4030_ins __initdata sleep_on_seq[] = {
+/*
+ * Turn off VDD1 and VDD2.
+ */
+ {MSG_SINGULAR(DEV_GRP_P1, 0xf, RES_STATE_OFF), 4},
+ {MSG_SINGULAR(DEV_GRP_P1, 0x10, RES_STATE_OFF), 2},
+#ifdef CONFIG_DISABLE_HFCLK
+/*
+ * And also turn off the OMAP3 PLLs and the sysclk output.
+ */
+ {MSG_SINGULAR(DEV_GRP_P1, 0x7, RES_STATE_OFF), 3},
+ {MSG_SINGULAR(DEV_GRP_P1, 0x19, RES_STATE_OFF), 3},
+#endif
+};
+
+static struct twl4030_script sleep_on_script __initdata = {
+ .script = sleep_on_seq,
+ .size = ARRAY_SIZE(sleep_on_seq),
+ .flags = TRITON_SLEEP_SCRIPT,
+};
+
+static struct twl4030_ins wakeup_seq[] __initdata = {
+#ifndef CONFIG_DISABLE_HFCLK
+/*
+ * Wakeup VDD1 and VDD2.
+ */
+ {MSG_SINGULAR(DEV_GRP_P1, 0xf, RES_STATE_ACTIVE), 4},
+ {MSG_SINGULAR(DEV_GRP_P1, 0x10, RES_STATE_ACTIVE), 2},
+#else
+/*
+ * Reenable the OMAP3 PLLs.
+ * Wakeup VDD1 and VDD2.
+ * Reenable sysclk output.
+ */
+ {MSG_SINGULAR(DEV_GRP_P1, 0x7, RES_STATE_ACTIVE), 0x30},
+ {MSG_SINGULAR(DEV_GRP_P1, 0xf, RES_STATE_ACTIVE), 0x30},
+ {MSG_SINGULAR(DEV_GRP_P1, 0x10, RES_STATE_ACTIVE), 0x37},
+ {MSG_SINGULAR(DEV_GRP_P1, 0x19, RES_STATE_ACTIVE), 3},
+#endif /* #ifndef CONFIG_DISABLE_HFCLK */
+};
+
+static struct twl4030_script wakeup_script __initdata = {
+ .script = wakeup_seq,
+ .size = ARRAY_SIZE(wakeup_seq),
+ .flags = TRITON_WAKEUP12_SCRIPT | TRITON_WAKEUP3_SCRIPT,
+};
+
+static struct twl4030_ins wrst_seq[] __initdata = {
+/*
+ * Reset twl4030.
+ * Reset VDD1 regulator.
+ * Reset VDD2 regulator.
+ * Reset VPLL1 regulator.
+ * Enable sysclk output.
+ * Reenable twl4030.
+ */
+ {MSG_SINGULAR(DEV_GRP_NULL, 0x1b, RES_STATE_OFF), 2},
+ {MSG_SINGULAR(DEV_GRP_P1, 0xf, RES_STATE_WRST), 15},
+ {MSG_SINGULAR(DEV_GRP_P1, 0x10, RES_STATE_WRST), 15},
+ {MSG_SINGULAR(DEV_GRP_P1, 0x7, RES_STATE_WRST), 0x60},
+ {MSG_SINGULAR(DEV_GRP_P1, 0x19, RES_STATE_ACTIVE), 2},
+ {MSG_SINGULAR(DEV_GRP_NULL, 0x1b, RES_STATE_ACTIVE), 2},
+};
+
+static struct twl4030_script wrst_script __initdata = {
+ .script = wrst_seq,
+ .size = ARRAY_SIZE(wakeup_seq),
+ .flags = TRITON_WRST_SCRIPT,
+};
+
+static struct twl4030_script *twl4030_scripts[] __initdata = {
+ &sleep_on_script,
+ &wakeup_script,
+ &wrst_script,
+};
+
+static struct twl4030_power_data sdp3430_t2scripts_data __initdata = {
+ .scripts = twl4030_scripts,
+ .size = ARRAY_SIZE(twl4030_scripts),
+};
+
+static struct twl4030_bci_platform_data ldp_bci_data = {
+ .battery_tmp_tbl = ldp_batt_table,
+ .tblsize = ARRAY_SIZE(ldp_batt_table),
+};
+
+static struct twl4030_usb_data ldp_usb_data = {
+ .usb_mode = T2_USB_MODE_ULPI,
};
static struct twl4030_gpio_platform_data ldp_gpio_data = {
.irq_end = TWL4030_GPIO_IRQ_END,
};
+static struct twl4030_madc_platform_data ldp_madc_data = {
+ .irq_line = 1,
+};
+
static struct twl4030_platform_data ldp_twldata = {
.irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END,
/* platform_data for children goes here */
+ .bci = &ldp_bci_data,
+ .madc = &ldp_madc_data,
+ .usb = &ldp_usb_data,
+ .power = &sdp3430_t2scripts_data,
.gpio = &ldp_gpio_data,
+ .keypad = &ldp_kp_twl4030_data,
};
static struct i2c_board_info __initdata ldp_i2c_boardinfo[] = {
platform_add_devices(ldp_devices, ARRAY_SIZE(ldp_devices));
omap_board_config = ldp_config;
omap_board_config_size = ARRAY_SIZE(ldp_config);
+ ts_gpio = 54;
+ ldp_spi_board_info[0].irq = gpio_to_irq(ts_gpio);
+ spi_register_board_info(ldp_spi_board_info,
+ ARRAY_SIZE(ldp_spi_board_info));
+ msecure_init();
+ ads7846_dev_init();
omap_serial_init();
+ usb_musb_init();
twl4030_mmc_init(mmc);
}
--- /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 <mach/eac.h>
+
+#include <mach/dsp_common.h>
+
+void __init n800_audio_init(struct tsc2301_platform_data *tc)
+{
+}
+
+#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 <mach/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 <linux/gpio.h>
+#include <linux/i2c/menelaus.h>
+
+#include <media/v4l2-int-device.h>
+
+#include <asm/mach-types.h>
+
+#include <mach/board.h>
+
+#include <../drivers/cbus/retu.h>
+#include <../drivers/media/video/tcm825x.h>
+
+#include "board-n800.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_regs_n800[] = {
+ /* 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}
+};
+
+const static struct tcm825x_reg tcm825x_regs_n810[] = {
+ /* 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 */
+ {0xcf, 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);
+
+ gpio_set_value(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;
+
+ gpio_set_value(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)
+{
+ if (machine_is_nokia_n810())
+ return tcm825x_regs_n810;
+
+ return tcm825x_regs_n800;
+}
+
+#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;
+}
+
+static int tcm825x_is_upside_down(void)
+{
+ return machine_is_nokia_n810();
+}
+
+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,
+ .is_upside_down = tcm825x_is_upside_down,
+};
+
+void __init n800_cam_init(void)
+{
+ int r;
+
+ r = gpio_request(N800_CAM_SENSOR_RESET_GPIO, "TCM825x reset");
+ if (r < 0) {
+ printk(KERN_WARNING "%s: failed to request gpio\n",
+ __func__);
+ return;
+ }
+
+ gpio_direction_output(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 <mach/clock.h>
+#include <mach/board.h>
+#include <mach/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 <mach/onenand.h>
+#include <mach/board.h>
+#include <mach/gpmc.h>
+
+struct mtd_partition n800_partitions[ONENAND_MAX_PARTITIONS];
+
+int n800_onenand_setup(void __iomem *, int freq);
+
+static struct omap_onenand_platform_data n800_onenand_data = {
+ .cs = 0,
+ .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 int omap2_onenand_set_async_mode(int cs, void __iomem *onenand_base)
+{
+ struct gpmc_timings t;
+
+ const int t_cer = 15;
+ const int t_avdp = 12;
+ const int t_aavdh = 7;
+ const int t_ce = 76;
+ const int t_aa = 76;
+ const int t_oe = 20;
+ const int t_cez = 20; /* max of t_cez, t_oez */
+ const int t_ds = 30;
+ const int t_wpl = 40;
+ const int t_wph = 30;
+
+ memset(&t, 0, sizeof(t));
+ t.sync_clk = 0;
+ t.cs_on = 0;
+ t.adv_on = 0;
+
+ /* Read */
+ t.adv_rd_off = gpmc_round_ns_to_ticks(max_t(int, t_avdp, t_cer));
+ t.oe_on = t.adv_rd_off + gpmc_round_ns_to_ticks(t_aavdh);
+ t.access = t.adv_on + gpmc_round_ns_to_ticks(t_aa);
+ t.access = max_t(int, t.access, t.cs_on + gpmc_round_ns_to_ticks(t_ce));
+ t.access = max_t(int, t.access, t.oe_on + gpmc_round_ns_to_ticks(t_oe));
+ t.oe_off = t.access + gpmc_round_ns_to_ticks(1);
+ t.cs_rd_off = t.oe_off;
+ t.rd_cycle = t.cs_rd_off + gpmc_round_ns_to_ticks(t_cez);
+
+ /* Write */
+ t.adv_wr_off = t.adv_rd_off;
+ t.we_on = t.oe_on;
+ if (cpu_is_omap34xx()) {
+ t.wr_data_mux_bus = t.we_on;
+ t.wr_access = t.we_on + gpmc_round_ns_to_ticks(t_ds);
+ }
+ 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(t_wph);
+ t.wr_cycle = t.cs_wr_off + gpmc_round_ns_to_ticks(t_cez);
+
+ /* Configure GPMC for asynchronous read */
+ gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1,
+ GPMC_CONFIG1_DEVICESIZE_16 |
+ GPMC_CONFIG1_MUXADDDATA);
+
+ return gpmc_cs_set_timings(cs, &t);
+}
+
+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 set_onenand_cfg(void __iomem *onenand_base, int latency,
+ int sync_write, int hf)
+{
+ u32 reg;
+
+ 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;
+ if (sync_write)
+ reg |= ONENAND_SYS_CFG1_SYNC_WRITE;
+ else
+ reg &= ~ONENAND_SYS_CFG1_SYNC_WRITE;
+ if (hf)
+ reg |= ONENAND_SYS_CFG1_HF;
+ else
+ reg &= ~ONENAND_SYS_CFG1_HF;
+ omap2_onenand_writew(reg, onenand_base + ONENAND_REG_SYS_CFG1);
+}
+
+static int omap2_onenand_set_sync_mode(int cs, void __iomem *onenand_base,
+ int freq)
+{
+ struct gpmc_timings t;
+ const int t_cer = 15;
+ const int t_avdp = 12;
+ const int t_cez = 20; /* max of t_cez, t_oez */
+ const int t_ds = 30;
+ const int t_wpl = 40;
+ const int t_wph = 30;
+ int min_gpmc_clk_period, t_ces, t_avds, t_avdh, t_ach, t_aavdh, t_rdyo;
+ int tick_ns, div, fclk_offset_ns, fclk_offset, gpmc_clk_ns, latency;
+ int err, ticks_cez, sync_write = 0, first_time = 0, hf = 0;
+ u32 reg;
+
+ if (!freq) {
+ /* Very first call freq is not known */
+ err = omap2_onenand_set_async_mode(cs, onenand_base);
+ if (err)
+ return err;
+ 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;
+ case 4:
+ freq = 104;
+ break;
+ default:
+ freq = 54;
+ break;
+ }
+ first_time = 1;
+ }
+
+ switch (freq) {
+ case 83:
+ min_gpmc_clk_period = 12; /* 83 MHz */
+ t_ces = 5;
+ t_avds = 4;
+ t_avdh = 2;
+ t_ach = 6;
+ t_aavdh = 6;
+ t_rdyo = 9;
+ if (cpu_is_omap34xx())
+ sync_write = 1;
+ break;
+ case 66:
+ min_gpmc_clk_period = 15; /* 66 MHz */
+ t_ces = 6;
+ t_avds = 5;
+ t_avdh = 2;
+ t_ach = 6;
+ t_aavdh = 6;
+ t_rdyo = 11;
+ if (cpu_is_omap34xx())
+ sync_write = 1;
+ break;
+ default:
+ min_gpmc_clk_period = 18; /* 54 MHz */
+ t_ces = 7;
+ t_avds = 7;
+ t_avdh = 7;
+ t_ach = 9;
+ t_aavdh = 7;
+ t_rdyo = 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 < 15) /* >66Mhz */
+ hf = 1;
+ if (hf)
+ latency = 6;
+ else if (gpmc_clk_ns >= 25) /* 40 MHz*/
+ latency = 3;
+ else
+ latency = 4;
+
+ if (first_time)
+ set_onenand_cfg(onenand_base, latency, sync_write, hf);
+
+ 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 synchronous 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 = gpmc_ticks_to_ns(fclk_offset + gpmc_ns_to_ticks(t_ach));
+ 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;
+ ticks_cez = ((gpmc_ns_to_ticks(t_cez) + div - 1) / div) * div;
+ t.rd_cycle = gpmc_ticks_to_ns(fclk_offset + (latency + 1) * div +
+ ticks_cez);
+
+ /* Write */
+ if (sync_write) {
+ t.adv_wr_off = t.adv_rd_off;
+ t.we_on = 0;
+ t.we_off = t.cs_rd_off;
+ t.cs_wr_off = t.cs_rd_off;
+ t.wr_cycle = t.rd_cycle;
+ if (cpu_is_omap34xx()) {
+ t.wr_data_mux_bus = gpmc_ticks_to_ns(fclk_offset +
+ gpmc_ns_to_ticks(min_gpmc_clk_period +
+ t_rdyo));
+ t.wr_access = t.access;
+ }
+ } else {
+ t.adv_wr_off = gpmc_round_ns_to_ticks(max_t(int, t_avdp, t_cer));
+ t.we_on = t.adv_wr_off + gpmc_round_ns_to_ticks(t_aavdh);
+ 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(t_wph);
+ t.wr_cycle = t.cs_wr_off + gpmc_round_ns_to_ticks(t_cez);
+ if (cpu_is_omap34xx()) {
+ t.wr_data_mux_bus = t.we_on;
+ t.wr_access = t.we_on + gpmc_round_ns_to_ticks(t_ds);
+ }
+ }
+
+ /* 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 |
+ (sync_write ? GPMC_CONFIG1_WRITEMULTIPLE_SUPP : 0) |
+ (sync_write ? GPMC_CONFIG1_WRITETYPE_SYNC : 0) |
+ GPMC_CONFIG1_CLKACTIVATIONTIME(fclk_offset) |
+ GPMC_CONFIG1_PAGE_LEN(2) |
+ (cpu_is_omap34xx() ? 0 :
+ (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;
+
+ set_onenand_cfg(onenand_base, latency, sync_write, hf);
+
+ return 0;
+}
+
+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;
+
+ n800_onenand_data.gpio_irq = cpu_is_omap34xx() ? 65 : 26;
+
+ 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 <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/i2c/menelaus.h>
+
+#include <asm/mach-types.h>
+
+#include <mach/mmc.h>
+
+#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
+
+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
+ gpio_set_value(slot_switch_gpio, slot);
+ 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) {
+ gpio_set_value(n810_slot2_pw_vddf, 1);
+ udelay(30);
+ gpio_set_value(n810_slot2_pw_vdd, 1);
+ udelay(100);
+ } else {
+ gpio_set_value(n810_slot2_pw_vdd, 0);
+ msleep(50);
+ gpio_set_value(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();
+
+ gpio_free(slot_switch_gpio);
+
+ if (machine_is_nokia_n810()) {
+ gpio_free(n810_slot2_pw_vddf);
+ gpio_free(n810_slot2_pw_vdd);
+ }
+}
+
+/*
+ * MMC controller1 has two slots that are multiplexed via I2C.
+ * MMC controller2 is not in use.
+ */
+static struct omap_mmc_platform_data mmc1_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,
+ .dma_mask = 0xffffffff,
+ .slots[0] = {
+ .wires = 4,
+ .set_power = n800_mmc_set_power,
+ .set_bus_mode = n800_mmc_set_bus_mode,
+ .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_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",
+ },
+};
+
+static struct omap_mmc_platform_data *mmc_data[OMAP24XX_NR_MMC];
+
+void __init n800_mmc_init(void)
+
+{
+ if (machine_is_nokia_n810()) {
+ mmc1_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
+ */
+ mmc1_data.slots[1].name = "internal";
+ mmc1_data.slots[1].ban_openended = 1;
+ }
+
+ if (gpio_request(slot_switch_gpio, "MMC slot switch") < 0)
+ BUG();
+ gpio_direction_output(slot_switch_gpio, 0);
+
+ if (machine_is_nokia_n810()) {
+ if (gpio_request(n810_slot2_pw_vddf, "MMC slot 2 Vddf") < 0)
+ BUG();
+ gpio_direction_output(n810_slot2_pw_vddf, 0);
+
+ if (gpio_request(n810_slot2_pw_vdd, "MMC slot 2 Vdd") < 0)
+ BUG();
+ gpio_direction_output(n810_slot2_pw_vdd, 0);
+ }
+
+ mmc_data[0] = &mmc1_data;
+ omap2_init_mmc(mmc_data, OMAP24XX_NR_MMC);
+}
+#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/gpio.h>
+#include <linux/usb/musb.h>
+#include <mach/gpmc.h>
+#include <mach/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_eps_bits musb_eps[] = {
+ { "ep1_tx", 5, },
+ { "ep1_rx", 5, },
+ { "ep2_tx", 5, },
+ { "ep2_rx", 5, },
+ { "ep3_tx", 3, },
+ { "ep3_rx", 3, },
+ { "ep4_tx", 3, },
+ { "ep4_rx", 3, },
+ { "ep5_tx", 2, },
+ { "ep5_rx", 2, },
+ { "ep6_tx", 2, },
+ { "ep6_rx", 2, },
+ { "ep7_tx", 2, },
+ { "ep7_rx", 2, },
+ { "ep8_tx", 2, },
+ { "ep8_rx", 2, },
+ { "ep9_tx", 2, },
+ { "ep9_rx", 2, },
+ { "ep10_tx", 2, },
+ { "ep10_rx", 2, },
+ { "ep11_tx", 2, },
+ { "ep11_rx", 2, },
+ { "ep12_tx", 2, },
+ { "ep12_rx", 2, },
+ { "ep13_tx", 2, },
+ { "ep13_rx", 2, },
+ { "ep14_tx", 2, },
+ { "ep14_rx", 2, },
+ { "ep15_tx", 2, },
+ { "ep15_rx", 2, },
+};
+
+static struct musb_hdrc_config musb_config = {
+ .multipoint = 1,
+ .dyn_fifo = 1,
+ .soft_con = 1,
+ .dma = 1,
+ .num_eps = 16,
+ .dma_channels = 7,
+ .ram_bits = 12,
+ .eps_bits = musb_eps,
+};
+
+static struct musb_hdrc_platform_data tusb_data = {
+ .mode = BOARD_MODE,
+ .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",
+ .config = &musb_config,
+};
+
+/*
+ * 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) {
+ gpio_set_value(GPIO_TUSB_ENABLE, 1);
+ msleep(1);
+
+ /* Wait until TUSB6010 pulls INT pin down */
+ i = 100;
+ while (i && gpio_get_value(GPIO_TUSB_INT)) {
+ msleep(1);
+ i--;
+ }
+
+ if (!i) {
+ printk(KERN_ERR "tusb: powerup failed\n");
+ retval = -ENODEV;
+ }
+ } else {
+ gpio_set_value(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 = gpio_request(GPIO_TUSB_ENABLE, "TUSB6010 enable");
+ if (ret != 0) {
+ printk(KERN_ERR "Could not get TUSB power GPIO%i\n",
+ GPIO_TUSB_ENABLE);
+ return;
+ }
+ gpio_direction_output(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:
+ gpio_free(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 <linux/i2c/menelaus.h>
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <mach/gpio.h>
+#include <mach/usb.h>
+#include <mach/board.h>
+#include <mach/common.h>
+#include <mach/mcspi.h>
+#include <mach/lcd_mipid.h>
+#include <mach/clock.h>
+#include <mach/gpio-switch.h>
+#include <mach/omapfb.h>
+#include <mach/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(NULL);
+ omap_init_irq();
+ omap_gpio_init();
+
+#ifdef CONFIG_OMAP_STI
+ if (gpio_request(N800_STI_GPIO, "STI") < 0) {
+ printk(KERN_ERR "Failed to request GPIO %d for STI\n",
+ N800_STI_GPIO);
+ return;
+ }
+
+ gpio_direction_output(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");
+ gpio_set_value(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);
+ gpio_set_value(N800_BLIZZARD_POWERDOWN_GPIO, 1);
+}
+
+static void blizzard_power_down(struct device *dev)
+{
+ gpio_set_value(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 = gpio_request(N800_BLIZZARD_POWERDOWN_GPIO, "Blizzard pd");
+ if (r < 0)
+ return;
+ gpio_direction_output(N800_BLIZZARD_POWERDOWN_GPIO, 1);
+
+ blizzard_get_clocks();
+ omapfb_set_ctrl_platform_data(&n800_blizzard_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 },
+};
+
+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 = gpio_to_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 = gpio_to_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 (gpio_request(enable_gpio, "TEA5761 enable") < 0) {
+ printk(KERN_ERR "Can't request GPIO %d\n",
+ enable_gpio);
+ return -ENODEV;
+ }
+
+ gpio_direction_output(enable_gpio, 0);
+ udelay(50);
+ gpio_set_value(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_or_module n8x0_i2c_board_info_2[] = {
+ {
+ I2C_BOARD_INFO(TCM825X_NAME, TCM825X_I2C_ADDR),
+#if defined (CONFIG_VIDEO_TCM825X) || defined (CONFIG_VIDEO_TCM825X_MODULE)
+ .platform_data = &n800_tcm825x_platform_data,
+#endif
+ },
+};
+
+
+static struct i2c_board_info __initdata_or_module n800_i2c_board_info_2[] = {
+ {
+ I2C_BOARD_INFO("tea5761", 0x10),
+ },
+};
+
+static struct i2c_board_info __initdata_or_module n810_i2c_board_info_2[] = {
+ {
+ I2C_BOARD_INFO("lm8323", 0x45),
+ .irq = OMAP_GPIO_IRQ(109),
+ .platform_data = &lm8323_pdata,
+ },
+ {
+ I2C_BOARD_INFO("tsl2563", 0x29),
+ },
+ {
+ I2C_BOARD_INFO("lp5521", 0x32),
+ },
+};
+
+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, n8x0_i2c_board_info_2,
+ ARRAY_SIZE(n8x0_i2c_board_info_2));
+ if (machine_is_nokia_n800())
+ i2c_register_board_info(2, n800_i2c_board_info_2,
+ ARRAY_SIZE(n800_i2c_board_info_2));
+ if (machine_is_nokia_n810())
+ i2c_register_board_info(2, n810_i2c_board_info_2,
+ ARRAY_SIZE(n810_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);
+
+extern const struct tcm825x_platform_data n800_tcm825x_platform_data;
+
+#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 <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <mach/board.h>
+#include <mach/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
+
+MACHINE_START(NOKIA_N810_WIMAX, "Nokia N810 WiMAX")
+ .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-omap2evm.c
+ *
+ * Copyright (C) 2008 Mistral Solutions 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 <linux/io.h>
+#include <linux/input.h>
+#include <linux/i2c/twl4030.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/nand.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/ads7846.h>
+
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/flash.h>
+
+#include <mach/gpio.h>
+#include <mach/board.h>
+#include <mach/common.h>
+#include <mach/mmc.h>
+#include <mach/keypad.h>
+#include <mach/gpmc.h>
+#include <mach/nand.h>
+#include <mach/mcspi.h>
+#include <mach/mux.h>
+
+#include "mmc-twl4030.h"
+
+
+#define GPMC_OFF_CONFIG1_0 0x60
+
+static struct mtd_partition omap2evm_nand_partitions[] = {
+ {
+ .name = "X-Loader",
+ .offset = 0,
+ .size = 1 * (64 * 2048),
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ },
+ {
+ .name = "U-Boot",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 3 * (64 * 2048),
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ },
+ {
+ .name = "U-Boot Environment",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 1 * (64 * 2048),
+ },
+ {
+ .name = "Kernel",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 16 * (64 * 2048), /* 2MB */
+ },
+ {
+ .name = "Ramdisk",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 32 * (64 * 2048), /* 4MB */
+ },
+ {
+ .name = "Filesystem",
+ .offset = MTDPART_OFS_APPEND,
+ .size = MTDPART_SIZ_FULL,
+ }
+};
+
+static struct omap_nand_platform_data omap2evm_nand_data = {
+ .parts = omap2evm_nand_partitions,
+ .nr_parts = ARRAY_SIZE(omap2evm_nand_partitions),
+ .dma_channel = -1, /* disable DMA in OMAP NAND driver */
+};
+
+static struct resource omap2evm_nand_resource = {
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device omap2evm_nand_device = {
+ .name = "omap2-nand",
+ .id = -1,
+ .dev = {
+ .platform_data = &omap2evm_nand_data,
+ },
+ .num_resources = 1,
+ .resource = &omap2evm_nand_resource,
+};
+
+void __init omap2evm_flash_init(void)
+{
+ void __iomem *gpmc_base_add, *gpmc_cs_base_add;
+ unsigned char cs = 0;
+
+ gpmc_base_add = (__force void __iomem *)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
+ * 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 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);
+ break;
+ }
+ cs++;
+ }
+ if (cs >= GPMC_CS_NUM) {
+ printk(KERN_INFO "MTD: Unable to find MTD configuration in "
+ "GPMC - not registering.\n");
+ return;
+ }
+
+ omap2evm_nand_data.cs = cs;
+ omap2evm_nand_data.gpmc_cs_baseaddr = gpmc_cs_base_add;
+ omap2evm_nand_data.gpmc_baseaddr = gpmc_base_add;
+
+ if (platform_device_register(&omap2evm_nand_device) < 0) {
+ printk(KERN_ERR "Unable to register NAND device\n");
+ return;
+ }
+}
+
+static struct resource omap2evm_smc911x_resources[] = {
+ [0] = {
+ .start = OMAP2EVM_ETHR_START,
+ .end = (OMAP2EVM_ETHR_START + OMAP2EVM_ETHR_SIZE - 1),
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = OMAP_GPIO_IRQ(OMAP2EVM_ETHR_GPIO_IRQ),
+ .end = OMAP_GPIO_IRQ(OMAP2EVM_ETHR_GPIO_IRQ),
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device omap2evm_smc911x_device = {
+ .name = "smc911x",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(omap2evm_smc911x_resources),
+ .resource = &omap2evm_smc911x_resources [0],
+};
+
+static inline void __init omap2evm_init_smc911x(void)
+{
+ int gpio = OMAP2EVM_ETHR_GPIO_IRQ;
+ int ret;
+
+ ret = gpio_request(gpio, "smc911x IRQ");
+ if (ret < 0) {
+ printk(KERN_ERR "Failed to request GPIO %d for smc911x IRQ\n",
+ gpio);
+ return;
+ }
+ gpio_direction_input(gpio);
+
+}
+
+static struct platform_device omap2_evm_lcd_device = {
+ .name = "omap2evm_lcd",
+ .id = -1,
+};
+
+static struct omap_lcd_config omap2_evm_lcd_config __initdata = {
+ .ctrl_name = "internal",
+};
+
+static void ads7846_dev_init(void)
+{
+ int gpio = OMAP2_EVM_TS_GPIO;
+ int ret;
+
+ ret = gpio_request(gpio, "ads7846_pen_down");
+ if (ret < 0) {
+ printk(KERN_ERR "Failed to request GPIO %d for ads7846 pen down IRQ\n",
+ gpio);
+ return;
+ }
+
+ gpio_direction_input(gpio);
+
+ /*Setting the MUX */
+ omap_cfg_reg(Y18_2430_MCSPI1_CLK);
+ omap_cfg_reg(AD15_2430_MCSPI1_SIMO);
+ omap_cfg_reg(AE17_2430_MCSPI1_SOMI);
+ omap_cfg_reg(U1_2430_MCSPI1_CS0);
+
+ omap_cfg_reg(AF19_2430_GPIO_85);
+
+}
+
+static int ads7846_get_pendown_state(void)
+{
+ return !gpio_get_value(OMAP2_EVM_TS_GPIO);
+}
+
+struct ads7846_platform_data ads7846_config = {
+ .x_max = 0x0fff,
+ .y_max = 0x0fff,
+ .x_plate_ohms = 180,
+ .pressure_max = 255,
+ .debounce_max = 10,
+ .debounce_tol = 3,
+ .debounce_rep = 1,
+ .get_pendown_state = ads7846_get_pendown_state,
+ .keep_vref_on = 1,
+ .settle_delay_usecs = 150,
+};
+
+static struct omap2_mcspi_device_config ads7846_mcspi_config = {
+ .turbo_mode = 0,
+ .single_channel = 1, /* 0: slave, 1: master */
+};
+
+struct spi_board_info omap2evm_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(OMAP2_EVM_TS_GPIO),
+ .platform_data = &ads7846_config,
+ },
+};
+
+
+static int omap2evm_keymap[] = {
+ KEY(0, 0, KEY_LEFT),
+ KEY(0, 1, KEY_RIGHT),
+ KEY(0, 2, KEY_A),
+ KEY(0, 3, KEY_B),
+ KEY(1, 0, KEY_DOWN),
+ KEY(1, 1, KEY_UP),
+ KEY(1, 2, KEY_E),
+ KEY(1, 3, KEY_F),
+ KEY(2, 0, KEY_ENTER),
+ KEY(2, 1, KEY_I),
+ KEY(2, 2, KEY_J),
+ KEY(2, 3, KEY_K),
+ KEY(3, 0, KEY_M),
+ KEY(3, 1, KEY_N),
+ KEY(3, 2, KEY_O),
+ KEY(3, 3, KEY_P)
+};
+
+static struct twl4030_keypad_data omap2evm_kp_data = {
+ .rows = 4,
+ .cols = 4,
+ .keymap = omap2evm_keymap,
+ .keymapsize = ARRAY_SIZE(omap2evm_keymap),
+ .rep = 1,
+};
+
+static void __init omap2_evm_init_irq(void)
+{
+ omap2_init_common_hw(NULL);
+ omap_init_irq();
+ omap_gpio_init();
+ omap2evm_init_smc911x();
+}
+
+static struct omap_uart_config omap2_evm_uart_config __initdata = {
+ .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
+};
+
+static struct omap_board_config_kernel omap2_evm_config[] __initdata = {
+ { OMAP_TAG_UART, &omap2_evm_uart_config },
+ { OMAP_TAG_LCD, &omap2_evm_lcd_config },
+};
+
+static struct twl4030_gpio_platform_data omap2evm_gpio_data = {
+ .gpio_base = OMAP_MAX_GPIO_LINES,
+ .irq_base = TWL4030_GPIO_IRQ_BASE,
+ .irq_end = TWL4030_GPIO_IRQ_END,
+};
+
+static struct twl4030_usb_data omap2evm_usb_data = {
+ .usb_mode = T2_USB_MODE_ULPI,
+};
+
+static struct twl4030_madc_platform_data omap2evm_madc_data = {
+ .irq_line = 1,
+};
+
+static struct twl4030_platform_data omap2evm_twldata = {
+ .irq_base = TWL4030_IRQ_BASE,
+ .irq_end = TWL4030_IRQ_END,
+
+ /* platform_data for children goes here */
+ .keypad = &omap2evm_kp_data,
+ .madc = &omap2evm_madc_data,
+ .usb = &omap2evm_usb_data,
+ .gpio = &omap2evm_gpio_data,
+};
+
+static struct i2c_board_info __initdata omap2evm_i2c_boardinfo[] = {
+ {
+ I2C_BOARD_INFO("twl4030", 0x48),
+ .flags = I2C_CLIENT_WAKE,
+ .irq = INT_24XX_SYS_NIRQ,
+ .platform_data = &omap2evm_twldata,
+ },
+};
+
+static int __init omap2_evm_i2c_init(void)
+{
+ omap_register_i2c_bus(1, 400, NULL, 0);
+ omap_register_i2c_bus(2, 2600, omap2evm_i2c_boardinfo,
+ ARRAY_SIZE(omap2evm_i2c_boardinfo));
+ return 0;
+}
+
+static struct platform_device *omap2_evm_devices[] __initdata = {
+ &omap2_evm_lcd_device,
+ &omap2evm_smc911x_device,
+};
+
+static struct twl4030_hsmmc_info mmc[] __initdata = {
+ {
+ .mmc = 1,
+ .wires = 4,
+ .gpio_cd = -EINVAL,
+ .gpio_wp = -EINVAL,
+ },
+ {} /* Terminator */
+};
+
+static void __init omap2_evm_init(void)
+{
+ omap2_evm_i2c_init();
+
+ platform_add_devices(omap2_evm_devices, ARRAY_SIZE(omap2_evm_devices));
+ omap_board_config = omap2_evm_config;
+ omap_board_config_size = ARRAY_SIZE(omap2_evm_config);
+ spi_register_board_info(omap2evm_spi_board_info,
+ ARRAY_SIZE(omap2evm_spi_board_info));
+ omap_serial_init();
+ twl4030_mmc_init(mmc);
+ omap2evm_flash_init();
+ ads7846_dev_init();
+}
+
+static void __init omap2_evm_map_io(void)
+{
+ omap2_set_globals_243x();
+ omap2_map_common_io();
+}
+
+MACHINE_START(OMAP2EVM, "OMAP2EVM Board")
+ /* Maintainer: Arun KS <arunks@mistralsolutions.com> */
+ .phys_io = 0x48000000,
+ .io_pg_offst = ((0xd8000000) >> 18) & 0xfffc,
+ .boot_params = 0x80000100,
+ .map_io = omap2_evm_map_io,
+ .init_irq = omap2_evm_init_irq,
+ .init_machine = omap2_evm_init,
+ .timer = &omap_timer,
+MACHINE_END
#include <linux/mtd/partitions.h>
#include <linux/mtd/nand.h>
+#include <linux/regulator/machine.h>
+
#include <mach/hardware.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/flash.h>
#include <mach/board.h>
+#include <mach/usb-musb.h>
+#include <mach/usb-ehci.h>
#include <mach/common.h>
#include <mach/gpmc.h>
#include <mach/nand.h>
#include <mach/mux.h>
+#include "twl4030-generic-scripts.h"
#include "mmc-twl4030.h"
+
#define GPMC_CS0_BASE 0x60
#define GPMC_CS_SIZE 0x30
.resource = &omap3beagle_nand_resource,
};
+#include "sdram-micron-mt46h32m32lf-6.h"
+
static struct omap_uart_config omap3_beagle_uart_config __initdata = {
.enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
};
+static struct twl4030_usb_data beagle_usb_data = {
+ .usb_mode = T2_USB_MODE_ULPI,
+};
+
static struct twl4030_hsmmc_info mmc[] = {
{
.mmc = 1,
unsigned gpio, unsigned ngpio)
{
/* gpio + 0 is "mmc0_cd" (input/IRQ) */
+ omap_cfg_reg(AH8_34XX_GPIO29);
+ mmc[0].gpio_cd = gpio + 0;
+ twl4030_mmc_init(mmc);
/* REVISIT: need ehci-omap hooks for external VBUS
* power switch and overcurrent detect
.setup = beagle_twl_gpio_setup,
};
+/* VMMC1 for MMC1 pins CMD, CLK, DAT0..DAT3 (20 mA, plus card == max 220 mA) */
+static struct regulator_init_data beagle_vmmc1 = {
+ .constraints = {
+ .valid_modes_mask = REGULATOR_MODE_NORMAL
+ | REGULATOR_MODE_STANDBY,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
+ | REGULATOR_CHANGE_MODE
+ | REGULATOR_CHANGE_STATUS,
+ },
+};
+
+/* VSIM for MMC1 pins DAT4..DAT7 (2 mA, plus card == max 50 mA) */
+static struct regulator_init_data beagle_vsim = {
+ .constraints = {
+ .valid_modes_mask = REGULATOR_MODE_NORMAL
+ | REGULATOR_MODE_STANDBY,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
+ | REGULATOR_CHANGE_MODE
+ | REGULATOR_CHANGE_STATUS,
+ },
+};
+
+/* VDAC for DSS driving S-Video (8 mA unloaded, max 65 mA) */
+static struct regulator_init_data beagle_vdac = {
+ .constraints = {
+ .min_uV = 1800000,
+ .max_uV = 1800000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL
+ | REGULATOR_MODE_STANDBY,
+ .valid_ops_mask = REGULATOR_CHANGE_MODE
+ | REGULATOR_CHANGE_STATUS,
+ },
+};
+
static struct twl4030_platform_data beagle_twldata = {
.irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END,
/* platform_data for children goes here */
+ .usb = &beagle_usb_data,
.gpio = &beagle_gpio_data,
+ .power = GENERIC3430_T2SCRIPTS_DATA,
+ .vmmc1 = &beagle_vmmc1,
+ .vsim = &beagle_vsim,
+ .vdac = &beagle_vdac,
};
static struct i2c_board_info __initdata beagle_i2c_boardinfo[] = {
static void __init omap3_beagle_init_irq(void)
{
- omap2_init_common_hw();
+ omap2_init_common_hw(mt46h32m32lf6_sdrc_params);
omap_init_irq();
omap_gpio_init();
}
omap_board_config_size = ARRAY_SIZE(omap3_beagle_config);
omap_serial_init();
- omap_cfg_reg(AH8_34XX_GPIO29);
- mmc[0].gpio_cd = gpio + 0;
- twl4030_mmc_init(mmc);
-
omap_cfg_reg(J25_34XX_GPIO170);
gpio_request(170, "DVI_nPD");
/* REVISIT leave DVI powered down until it's needed ... */
gpio_direction_output(170, true);
+ usb_musb_init();
+ usb_ehci_init();
omap3beagle_flash_init();
}
--- /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 <mach/onenand.h>
+#include <mach/board.h>
+#include <mach/gpmc.h>
+#include <mach/nand.h>
+
+static int omap3evm_onenand_setup(void __iomem *, int freq);
+
+static struct mtd_partition omap3evm_onenand_partitions[] = {
+ {
+ .name = "xloader-onenand",
+ .offset = 0,
+ .size = 4*(64*2048),
+ .mask_flags = MTD_WRITEABLE
+ },
+ {
+ .name = "uboot-onenand",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 15*(64*2048),
+ .mask_flags = MTD_WRITEABLE
+ },
+ {
+ .name = "params-onenand",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 1*(64*2048),
+ },
+ {
+ .name = "linux-onenand",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 40*(64*2048),
+ },
+ {
+ .name = "jffs2-onenand",
+ .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,
+ },
+};
+
+static struct mtd_partition omap3evm_nand_partitions[] = {
+ /* All the partition sizes are listed in terms of NAND block size */
+ {
+ .name = "xloader-nand",
+ .offset = 0,
+ .size = 4*(128 * 1024),
+ .mask_flags = MTD_WRITEABLE
+ },
+ {
+ .name = "uboot-nand",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 14*(128 * 1024),
+ .mask_flags = MTD_WRITEABLE
+ },
+ {
+ .name = "params-nand",
+
+ .offset = MTDPART_OFS_APPEND,
+ .size = 2*(128 * 1024)
+ },
+ {
+ .name = "linux-nand",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 40*(128 * 1024)
+ },
+ {
+ .name = "jffs2-nand",
+ .size = MTDPART_SIZ_FULL,
+ .offset = MTDPART_OFS_APPEND,
+ },
+};
+
+static struct omap_nand_platform_data omap3evm_nand_data = {
+ .parts = omap3evm_nand_partitions,
+ .nr_parts = ARRAY_SIZE(omap3evm_nand_partitions),
+ .nand_setup = NULL,
+ .dma_channel = -1, /* disable DMA in OMAP NAND driver */
+ .dev_ready = NULL,
+};
+
+static struct resource omap3evm_nand_resource = {
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device omap3evm_nand_device = {
+ .name = "omap2-nand",
+ .id = 0,
+ .dev = {
+ .platform_data = &omap3evm_nand_data,
+ },
+ .num_resources = 1,
+ .resource = &omap3evm_nand_resource,
+};
+
+/*
+ * 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, int freq)
+{
+ /* 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, nandcs = GPMC_CS_NUM + 1;
+ u32 gpmc_base_add = OMAP34XX_GPMC_VIRT;
+
+ while (cs < GPMC_CS_NUM) {
+ u32 ret = 0;
+ ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
+
+ /*
+ * 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
+ */
+ if ((ret & 0xC00) == 0x800) {
+ /* Found it!! */
+ if (nandcs > GPMC_CS_NUM)
+ nandcs = cs;
+ } else {
+ ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
+ if ((ret & 0x3F) == (ONENAND_MAP >> 24))
+ onenandcs = cs;
+ }
+ cs++;
+ }
+ if ((nandcs > GPMC_CS_NUM) && (onenandcs > GPMC_CS_NUM)) {
+ printk(KERN_INFO "NAND/OneNAND: Unable to find configuration "
+ " in GPMC\n ");
+ return;
+ }
+
+ if (nandcs < GPMC_CS_NUM) {
+ omap3evm_nand_data.cs = nandcs;
+ omap3evm_nand_data.gpmc_cs_baseaddr = (void *)(gpmc_base_add +
+ GPMC_CS0_BASE + nandcs*GPMC_CS_SIZE);
+ omap3evm_nand_data.gpmc_baseaddr = (void *) (gpmc_base_add);
+
+ if (platform_device_register(&omap3evm_nand_device) < 0) {
+ printk(KERN_ERR "Unable to register NAND device\n");
+ }
+ }
+
+ 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/input.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/ads7846.h>
+#include <linux/i2c/twl4030.h>
+
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <mach/gpio.h>
+#include <mach/keypad.h>
+#include <mach/board.h>
+#include <mach/usb-musb.h>
+#include <mach/usb-ehci.h>
+#include <mach/common.h>
+#include <mach/mcspi.h>
+
+#include "sdram-micron-mt46h32m32lf-6.h"
+#include "twl4030-generic-scripts.h"
+#include "mmc-twl4030.h"
+
+
+static struct resource omap3evm_smc911x_resources[] = {
+ [0] = {
+ .start = OMAP3EVM_ETHR_START,
+ .end = (OMAP3EVM_ETHR_START + OMAP3EVM_ETHR_SIZE - 1),
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = OMAP_GPIO_IRQ(OMAP3EVM_ETHR_GPIO_IRQ),
+ .end = OMAP_GPIO_IRQ(OMAP3EVM_ETHR_GPIO_IRQ),
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device omap3evm_smc911x_device = {
+ .name = "smc911x",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(omap3evm_smc911x_resources),
+ .resource = &omap3evm_smc911x_resources [0],
+};
+
+static inline void __init omap3evm_init_smc911x(void)
+{
+ int eth_cs;
+ struct clk *l3ck;
+ unsigned int rate;
+
+ eth_cs = OMAP3EVM_SMC911X_CS;
+
+ l3ck = clk_get(NULL, "l3_ck");
+ if (IS_ERR(l3ck))
+ rate = 100000000;
+ else
+ rate = clk_get_rate(l3ck);
+
+ if (gpio_request(OMAP3EVM_ETHR_GPIO_IRQ, "SMC911x irq") < 0) {
+ printk(KERN_ERR "Failed to request GPIO%d for smc911x IRQ\n",
+ OMAP3EVM_ETHR_GPIO_IRQ);
+ return;
+ }
+
+ gpio_direction_input(OMAP3EVM_ETHR_GPIO_IRQ);
+}
+
+static struct omap_uart_config omap3_evm_uart_config __initdata = {
+ .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
+};
+
+static struct twl4030_gpio_platform_data omap3evm_gpio_data = {
+ .gpio_base = OMAP_MAX_GPIO_LINES,
+ .irq_base = TWL4030_GPIO_IRQ_BASE,
+ .irq_end = TWL4030_GPIO_IRQ_END,
+};
+
+static struct twl4030_usb_data omap3evm_usb_data = {
+ .usb_mode = T2_USB_MODE_ULPI,
+};
+
+static int omap3evm_keymap[] = {
+ KEY(0, 0, KEY_LEFT),
+ KEY(0, 1, KEY_RIGHT),
+ KEY(0, 2, KEY_A),
+ KEY(0, 3, KEY_B),
+ KEY(1, 0, KEY_DOWN),
+ KEY(1, 1, KEY_UP),
+ KEY(1, 2, KEY_E),
+ KEY(1, 3, KEY_F),
+ KEY(2, 0, KEY_ENTER),
+ KEY(2, 1, KEY_I),
+ KEY(2, 2, KEY_J),
+ KEY(2, 3, KEY_K),
+ KEY(3, 0, KEY_M),
+ KEY(3, 1, KEY_N),
+ KEY(3, 2, KEY_O),
+ KEY(3, 3, KEY_P)
+};
+
+static struct twl4030_keypad_data omap3evm_kp_data = {
+ .rows = 4,
+ .cols = 4,
+ .keymap = omap3evm_keymap,
+ .keymapsize = ARRAY_SIZE(omap3evm_keymap),
+ .rep = 1,
+};
+
+static struct twl4030_madc_platform_data omap3evm_madc_data = {
+ .irq_line = 1,
+};
+
+static struct twl4030_platform_data omap3evm_twldata = {
+ .irq_base = TWL4030_IRQ_BASE,
+ .irq_end = TWL4030_IRQ_END,
+
+ /* platform_data for children goes here */
+ .keypad = &omap3evm_kp_data,
+ .madc = &omap3evm_madc_data,
+ .usb = &omap3evm_usb_data,
+ .power = GENERIC3430_T2SCRIPTS_DATA,
+ .gpio = &omap3evm_gpio_data,
+};
+
+static struct i2c_board_info __initdata omap3evm_i2c_boardinfo[] = {
+ {
+ I2C_BOARD_INFO("twl4030", 0x48),
+ .flags = I2C_CLIENT_WAKE,
+ .irq = INT_34XX_SYS_NIRQ,
+ .platform_data = &omap3evm_twldata,
+ },
+};
+
+static int __init omap3_evm_i2c_init(void)
+{
+ omap_register_i2c_bus(1, 2600, omap3evm_i2c_boardinfo,
+ ARRAY_SIZE(omap3evm_i2c_boardinfo));
+ omap_register_i2c_bus(2, 400, NULL, 0);
+ omap_register_i2c_bus(3, 400, NULL, 0);
+ return 0;
+}
+
+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 void ads7846_dev_init(void)
+{
+ if (gpio_request(OMAP3_EVM_TS_GPIO, "ADS7846 pendown") < 0)
+ printk(KERN_ERR "can't get ads7846 pen down GPIO\n");
+
+ gpio_direction_input(OMAP3_EVM_TS_GPIO);
+
+ 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 !gpio_get_value(OMAP3_EVM_TS_GPIO);
+}
+
+struct ads7846_platform_data ads7846_config = {
+ .x_max = 0x0fff,
+ .y_max = 0x0fff,
+ .x_plate_ohms = 180,
+ .pressure_max = 255,
+ .debounce_max = 10,
+ .debounce_tol = 3,
+ .debounce_rep = 1,
+ .get_pendown_state = ads7846_get_pendown_state,
+ .keep_vref_on = 1,
+ .settle_delay_usecs = 150,
+};
+
+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(mt46h32m32lf6_sdrc_params);
+ omap_init_irq();
+ omap_gpio_init();
+ omap3evm_init_smc911x();
+}
+
+static struct omap_board_config_kernel omap3_evm_config[] __initdata = {
+ { OMAP_TAG_UART, &omap3_evm_uart_config },
+ { OMAP_TAG_LCD, &omap3_evm_lcd_config },
+};
+
+static struct platform_device *omap3_evm_devices[] __initdata = {
+ &omap3_evm_lcd_device,
+ &omap3evm_smc911x_device,
+};
+
+static struct twl4030_hsmmc_info mmc[] __initdata = {
+ {
+ .mmc = 1,
+ .wires = 4,
+ .gpio_cd = -EINVAL,
+ .gpio_wp = -EINVAL,
+ },
+ {} /* Terminator */
+};
+
+static void __init omap3_evm_init(void)
+{
+ omap3_evm_i2c_init();
+
+ 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();
+ twl4030_mmc_init(mmc);
+ usb_musb_init();
+ usb_ehci_init();
+ omap3evm_flash_init();
+ ads7846_dev_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
*
*/
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
#include <linux/init.h>
+#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/spi/ads7846.h>
#include <linux/i2c/twl4030.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
+#include <asm/mach/flash.h>
#include <asm/mach/map.h>
#include <mach/board.h>
#include <mach/common.h>
#include <mach/gpio.h>
+#include <mach/gpmc.h>
#include <mach/hardware.h>
+#include <mach/nand.h>
+#include <mach/usb-ehci.h>
+#include <mach/usb-musb.h>
#include <mach/mcspi.h>
+#include "sdram-micron-mt46h32m32lf-6.h"
#include "mmc-twl4030.h"
+
+#define NAND_BLOCK_SIZE SZ_128K
+#define GPMC_CS0_BASE 0x60
+#define GPMC_CS_SIZE 0x30
+
#define OMAP3_PANDORA_TS_GPIO 94
+static struct mtd_partition omap3pandora_nand_partitions[] = {
+ {
+ .name = "xloader",
+ .offset = 0, /* Offset = 0x00000 */
+ .size = 4 * NAND_BLOCK_SIZE,
+ .mask_flags = MTD_WRITEABLE
+ }, {
+ .name = "uboot",
+ .offset = MTDPART_OFS_APPEND, /* Offset = 0x80000 */
+ .size = 14 * NAND_BLOCK_SIZE,
+ }, {
+ .name = "uboot environment",
+ .offset = MTDPART_OFS_APPEND, /* Offset = 0x240000 */
+ .size = 2 * NAND_BLOCK_SIZE,
+ }, {
+ .name = "linux",
+ .offset = MTDPART_OFS_APPEND, /* Offset = 0x280000 */
+ .size = 32 * NAND_BLOCK_SIZE,
+ }, {
+ .name = "rootfs",
+ .offset = MTDPART_OFS_APPEND, /* Offset = 0x680000 */
+ .size = MTDPART_SIZ_FULL,
+ },
+};
+
+static struct omap_nand_platform_data omap3pandora_nand_data = {
+ .parts = omap3pandora_nand_partitions,
+ .nr_parts = ARRAY_SIZE(omap3pandora_nand_partitions),
+ .dma_channel = -1, /* disable DMA in OMAP NAND driver */
+};
+
+static struct resource omap3pandora_nand_resource[] = {
+ {
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device omap3pandora_nand_device = {
+ .name = "omap2-nand",
+ .id = -1,
+ .dev = {
+ .platform_data = &omap3pandora_nand_data,
+ },
+ .num_resources = ARRAY_SIZE(omap3pandora_nand_resource),
+ .resource = omap3pandora_nand_resource,
+};
+
+static void __init omap3pandora_flash_init(void)
+{
+ u8 cs = 0;
+ u8 nandcs = GPMC_CS_NUM + 1;
+
+ u32 gpmc_base_add = OMAP34XX_GPMC_VIRT;
+
+ /* find out the chip-select on which NAND exists */
+ while (cs < GPMC_CS_NUM) {
+ u32 ret = 0;
+ ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
+
+ if ((ret & 0xC00) == 0x800) {
+ printk(KERN_INFO "Found NAND on CS%d\n", cs);
+ if (nandcs > GPMC_CS_NUM)
+ nandcs = cs;
+ }
+ cs++;
+ }
+
+ if (nandcs > GPMC_CS_NUM) {
+ printk(KERN_INFO "NAND: Unable to find configuration "
+ "in GPMC\n ");
+ return;
+ }
+
+ if (nandcs < GPMC_CS_NUM) {
+ omap3pandora_nand_data.cs = nandcs;
+ omap3pandora_nand_data.gpmc_cs_baseaddr = (void *)
+ (gpmc_base_add + GPMC_CS0_BASE + nandcs * GPMC_CS_SIZE);
+ omap3pandora_nand_data.gpmc_baseaddr = (void *) (gpmc_base_add);
+
+ printk(KERN_INFO "Registering NAND on CS%d\n", nandcs);
+ if (platform_device_register(&omap3pandora_nand_device) < 0)
+ printk(KERN_ERR "Unable to register NAND device\n");
+ }
+}
+
static struct twl4030_hsmmc_info omap3pandora_mmc[] = {
{
.mmc = 1,
static void __init omap3pandora_init_irq(void)
{
- omap2_init_common_hw();
+ omap2_init_common_hw(mt46h32m32lf6_sdrc_params);
omap_init_irq();
omap_gpio_init();
}
omap_serial_init();
spi_register_board_info(omap3pandora_spi_board_info,
ARRAY_SIZE(omap3pandora_spi_board_info));
+ usb_musb_init();
+ usb_ehci_init();
+ omap3pandora_flash_init();
omap3pandora_ads7846_init();
}
#include <mach/gpmc.h>
#include <mach/hardware.h>
#include <mach/nand.h>
+#include <mach/usb-ehci.h>
+#include <mach/usb-musb.h>
+#include "sdram-micron-mt46h32m32lf-6.h"
+#include "twl4030-generic-scripts.h"
#include "mmc-twl4030.h"
#define NAND_BLOCK_SIZE SZ_128K
.irq_end = TWL4030_GPIO_IRQ_END,
};
+static struct twl4030_usb_data overo_usb_data = {
+ .usb_mode = T2_USB_MODE_ULPI,
+};
+
static struct twl4030_platform_data overo_twldata = {
.irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END,
.gpio = &overo_gpio_data,
+ .usb = &overo_usb_data,
+ .power = GENERIC3430_T2SCRIPTS_DATA,
};
static struct i2c_board_info __initdata overo_i2c_boardinfo[] = {
{
- I2C_BOARD_INFO("twl4030", 0x48),
+ I2C_BOARD_INFO("tps65950", 0x48),
.flags = I2C_CLIENT_WAKE,
.irq = INT_34XX_SYS_NIRQ,
.platform_data = &overo_twldata,
static void __init overo_init_irq(void)
{
- omap2_init_common_hw();
+ omap2_init_common_hw(mt46h32m32lf6_sdrc_params);
omap_init_irq();
omap_gpio_init();
}
omap_board_config_size = ARRAY_SIZE(overo_config);
omap_serial_init();
twl4030_mmc_init(mmc);
+ usb_musb_init();
+ usb_ehci_init();
overo_flash_init();
if ((gpio_request(OVERO_GPIO_W2W_NRESET,
#include <mach/clockdomain.h>
#include <mach/sram.h>
#include <mach/cpu.h>
+#include <mach/prcm.h>
+#include <mach/control.h>
#include <asm/div64.h>
-#include "memory.h"
+#include <mach/sdrc.h>
#include "sdrc.h"
#include "clock.h"
#include "prm.h"
#define DPLL_MIN_DIVIDER 1
/* Possible error results from _dpll_test_mult */
-#define DPLL_MULT_UNDERFLOW (1 << 0)
+#define DPLL_MULT_UNDERFLOW -1
/*
* Scale factor to mitigate roundoff errors in DPLL rate rounding.
#define DPLL_ROUNDING_VAL ((DPLL_SCALE_BASE / 2) * \
(DPLL_SCALE_FACTOR / DPLL_SCALE_BASE))
+/* DPLL valid Fint frequency band limits - from 34xx TRM Section 4.7.6.2 */
+#define DPLL_FINT_BAND1_MIN 750000
+#define DPLL_FINT_BAND1_MAX 2100000
+#define DPLL_FINT_BAND2_MIN 7500000
+#define DPLL_FINT_BAND2_MAX 21000000
+
+/* _dpll_test_fint() return codes */
+#define DPLL_FINT_UNDERFLOW -1
+#define DPLL_FINT_INVALID -2
+
+/* Bitmask to isolate the register type of clk.enable_reg */
+#define PRCM_REGTYPE_MASK 0xf0
+/* various CM register type options */
+#define CM_FCLKEN_REGTYPE 0x00
+#define CM_ICLKEN_REGTYPE 0x10
+#define CM_IDLEST_REGTYPE 0x20
+
u8 cpu_mask;
/*-------------------------------------------------------------------------
* OMAP2/3 specific clock functions
*-------------------------------------------------------------------------*/
+/*
+ * _omap2_clk_read_reg - read a clock register
+ * @clk: struct clk *
+ *
+ * Given a struct clk *, returns the value of the clock's register.
+ */
+static u32 _omap2_clk_read_reg(u16 reg_offset, struct clk *clk)
+{
+ if (clk->prcm_mod & CLK_REG_IN_SCM)
+ return omap_ctrl_readl(reg_offset);
+ else if (clk->prcm_mod & CLK_REG_IN_PRM)
+ return prm_read_mod_reg(clk->prcm_mod & PRCM_MOD_ADDR_MASK,
+ reg_offset);
+ else
+ return cm_read_mod_reg(clk->prcm_mod, reg_offset);
+}
+
+/*
+ * _omap2_clk_write_reg - write a clock's register
+ * @v: value to write to the clock's enable_reg
+ * @clk: struct clk *
+ *
+ * Given a register value @v and struct clk * @clk, writes the value of @v to
+ * the clock's enable register. No return value.
+ */
+static void _omap2_clk_write_reg(u32 v, u16 reg_offset, struct clk *clk)
+{
+ if (clk->prcm_mod & CLK_REG_IN_SCM)
+ omap_ctrl_writel(v, reg_offset);
+ else if (clk->prcm_mod & CLK_REG_IN_PRM)
+ prm_write_mod_reg(v, clk->prcm_mod & PRCM_MOD_ADDR_MASK,
+ reg_offset);
+ else
+ cm_write_mod_reg(v, clk->prcm_mod, reg_offset);
+}
+
+/**
+ * _omap2xxx_clk_commit - commit clock parent/rate changes in hardware
+ * @clk: struct clk *
+ *
+ * If @clk has the DELAYED_APP flag set, meaning that parent/rate changes
+ * don't take effect until the VALID_CONFIG bit is written, write the
+ * VALID_CONFIG bit and wait for the write to complete. No return value.
+ */
+static void _omap2xxx_clk_commit(struct clk *clk)
+{
+ if (!cpu_is_omap24xx())
+ return;
+
+ if (!(clk->flags & DELAYED_APP))
+ return;
+
+ prm_write_mod_reg(OMAP24XX_VALID_CONFIG, OMAP24XX_GR_MOD,
+ OMAP24XX_PRCM_CLKCFG_CTRL_OFFSET);
+ /* OCP barrier */
+ prm_read_mod_reg(OMAP24XX_GR_MOD, OMAP24XX_PRCM_CLKCFG_CTRL_OFFSET);
+}
+
+/*
+ * _dpll_test_fint - test whether an Fint value is valid for the DPLL
+ * @clk: DPLL struct clk to test
+ * @n: divider value (N) to test
+ *
+ * Tests whether a particular divider @n will result in a valid DPLL
+ * internal clock frequency Fint. See the 34xx TRM 4.7.6.2 "DPLL Jitter
+ * Correction". Returns 0 if OK, -1 if the enclosing loop can terminate
+ * (assuming that it is counting N upwards), or -2 if the enclosing loop
+ * should skip to the next iteration (again assuming N is increasing).
+ */
+static int _dpll_test_fint(struct clk *clk, u8 n)
+{
+ struct dpll_data *dd;
+ long fint;
+ int ret = 0;
+
+ dd = clk->dpll_data;
+
+ /* DPLL divider must result in a valid jitter correction val */
+ fint = clk->parent->rate / (n + 1);
+ if (fint < DPLL_FINT_BAND1_MIN) {
+
+ pr_debug("rejecting n=%d due to Fint failure, "
+ "lowering max_divider\n", n);
+ dd->max_divider = n;
+ ret = DPLL_FINT_UNDERFLOW;
+
+ } else if (fint > DPLL_FINT_BAND1_MAX &&
+ fint < DPLL_FINT_BAND2_MIN) {
+
+ pr_debug("rejecting n=%d due to Fint failure\n", n);
+ ret = DPLL_FINT_INVALID;
+
+ } else if (fint > DPLL_FINT_BAND2_MAX) {
+
+ pr_debug("rejecting n=%d due to Fint failure, "
+ "boosting min_divider\n", n);
+ dd->min_divider = n;
+ ret = DPLL_FINT_INVALID;
+
+ }
+
+ return ret;
+}
+
/**
* omap2_init_clk_clkdm - look up a clockdomain name, store pointer in clk
* @clk: OMAP clock struct ptr to use
{
struct clockdomain *clkdm;
- if (!clk->clkdm_name)
- return;
-
- clkdm = clkdm_lookup(clk->clkdm_name);
+ 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;
+ clk->name, clk->clkdm.name);
+ clk->clkdm.ptr = clkdm;
} else {
- pr_debug("clock: could not associate clk %s to "
- "clkdm %s\n", clk->name, clk->clkdm_name);
+ pr_err("clock: %s: could not associate to clkdm %s\n",
+ clk->name, clk->clkdm.name);
}
}
if (!clk->clksel)
return;
- r = __raw_readl(clk->clksel_reg) & clk->clksel_mask;
+ r = _omap2_clk_read_reg(clk->clksel_reg, clk);
+ r &= clk->clksel_mask;
r >>= __ffs(clk->clksel_mask);
for (clks = clk->clksel; clks->parent && !found; clks++) {
clk->name, clks->parent->name,
((clk->parent) ?
clk->parent->name : "NULL"));
+ if (clk->parent)
+ omap_clk_del_child(clk->parent,
+ clk);
clk->parent = clks->parent;
+ omap_clk_add_child(clk->parent, clk);
};
found = 1;
}
return;
}
-/* Returns the DPLL rate */
-u32 omap2_get_dpll_rate(struct clk *clk)
+/**
+ * omap2_get_dpll_rate - returns the current DPLL CLKOUT rate
+ * @clk: struct clk * of a DPLL
+ * @parent_rate: rate of the parent of the DPLL clock
+ *
+ * DPLLs can be locked or bypassed - basically, enabled or disabled.
+ * When locked, the DPLL output depends on the M and N values. When
+ * bypassed, on OMAP2xxx, the output rate is either the 32KiHz clock
+ * or sys_clk. Bypass rates on OMAP3 depend on the DPLL: DPLLs 1 and
+ * 2 are bypassed with dpll1_fclk and dpll2_fclk respectively
+ * (generated by DPLL3), while DPLL 3, 4, and 5 bypass rates are sys_clk.
+ * Returns the current DPLL CLKOUT rate (*not* CLKOUTX2) if the DPLL is
+ * locked, or the appropriate bypass rate if the DPLL is bypassed, or 0
+ * if the clock @clk is not a DPLL.
+ */
+u32 omap2_get_dpll_rate(struct clk *clk, unsigned long parent_rate)
{
long long dpll_clk;
- u32 dpll_mult, dpll_div, dpll;
+ u32 dpll_mult, dpll_div, v;
struct dpll_data *dd;
dd = clk->dpll_data;
- /* REVISIT: What do we return on error? */
if (!dd)
return 0;
- dpll = __raw_readl(dd->mult_div1_reg);
- dpll_mult = dpll & dd->mult_mask;
+ /* Return bypass rate if DPLL is bypassed */
+ v = cm_read_mod_reg(clk->prcm_mod, dd->control_reg);
+ v &= dd->enable_mask;
+ v >>= __ffs(dd->enable_mask);
+
+ if (cpu_is_omap24xx()) {
+
+ if (v == OMAP2XXX_EN_DPLL_LPBYPASS ||
+ v == OMAP2XXX_EN_DPLL_FRBYPASS)
+ return parent_rate;
+
+ } else if (cpu_is_omap34xx()) {
+
+ if (v == OMAP3XXX_EN_DPLL_LPBYPASS ||
+ v == OMAP3XXX_EN_DPLL_FRBYPASS)
+ return dd->bypass_clk->rate;
+
+ }
+
+ v = cm_read_mod_reg(clk->prcm_mod, dd->mult_div1_reg);
+ dpll_mult = v & dd->mult_mask;
dpll_mult >>= __ffs(dd->mult_mask);
- dpll_div = dpll & dd->div1_mask;
+ dpll_div = v & dd->div1_mask;
dpll_div >>= __ffs(dd->div1_mask);
- dpll_clk = (long long)clk->parent->rate * dpll_mult;
+ dpll_clk = (long long)parent_rate * dpll_mult;
do_div(dpll_clk, dpll_div + 1);
return dpll_clk;
* Used for clocks that have the same value as the parent clock,
* divided by some factor
*/
-void omap2_fixed_divisor_recalc(struct clk *clk)
+void omap2_fixed_divisor_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage)
{
- WARN_ON(!clk->fixed_div);
+ unsigned long rate;
+
+ WARN_ON(!clk->fixed_div); /* XXX move this to init */
- clk->rate = clk->parent->rate / clk->fixed_div;
+ rate = parent_rate / clk->fixed_div;
- if (clk->flags & RATE_PROPAGATES)
- propagate_rate(clk);
+ if (rate_storage == CURRENT_RATE)
+ clk->rate = rate;
+ else if (rate_storage == TEMP_RATE)
+ clk->temp_rate = rate;
}
/**
* omap2_wait_clock_ready - wait for clock to enable
- * @reg: physical address of clock IDLEST register
+ * @prcm_mod: CM submodule offset from CM_BASE (e.g., "MPU_MOD")
+ * @reg_index: offset of CM register address from prcm_mod
* @mask: value to mask against to determine if the clock is active
* @name: name of the clock (for printk)
*
* Returns 1 if the clock enabled in time, or 0 if it failed to enable
* in roughly MAX_CLOCK_ENABLE_WAIT microseconds.
*/
-int omap2_wait_clock_ready(void __iomem *reg, u32 mask, const char *name)
+int omap2_wait_clock_ready(s16 prcm_mod, u16 reg_index, u32 mask,
+ const char *name)
{
- int i = 0;
- int ena = 0;
+ int i = 0, ena = 0;
/*
* 24xx uses 0 to indicate not ready, and 1 to indicate ready.
* 34xx reverses this, just to keep us on our toes
*/
- if (cpu_mask & (RATE_IN_242X | RATE_IN_243X)) {
+ if (cpu_mask & (RATE_IN_242X | RATE_IN_243X))
ena = mask;
- } else if (cpu_mask & RATE_IN_343X) {
+ else if (cpu_mask & RATE_IN_343X)
ena = 0;
- }
/* Wait for lock */
- while (((__raw_readl(reg) & mask) != ena) &&
+ while (((cm_read_mod_reg(prcm_mod, reg_index) & mask) != ena) &&
(i++ < MAX_CLOCK_ENABLE_WAIT)) {
udelay(1);
}
printk(KERN_ERR "Clock %s didn't enable in %d tries\n",
name, MAX_CLOCK_ENABLE_WAIT);
-
return (i < MAX_CLOCK_ENABLE_WAIT) ? 1 : 0;
};
/*
- * Note: We don't need special code here for INVERT_ENABLE
- * for the time being since INVERT_ENABLE only applies to clocks enabled by
- * CM_CLKEN_PLL
+ * omap2_clk_wait_ready - wait for a OMAP module to come out of target idle
+ * @clk: struct clk * recently enabled to indicate the module to test
+ *
+ * Wait for an OMAP module with a target idle state bit to come out of
+ * idle once both its interface clock and primary functional clock are
+ * both enabled. Any register read or write to the device before it
+ * returns from idle will cause an abort. Not all modules have target
+ * idle state bits (for example, DSS and CAM on OMAP24xx); so we don't
+ * wait for those. No return value.
+ *
+ * We don't need special code here for INVERT_ENABLE for the time
+ * being since INVERT_ENABLE only applies to clocks enabled by
+ * CM_CLKEN_PLL.
+ *
+ * REVISIT: This function is misnamed: it should be something like
+ * "omap2_module_wait_ready", and in the long-term, it does not belong
+ * in the clock framework. It also shouldn't be doing register
+ * arithmetic to determine the companion clock.
*/
static void omap2_clk_wait_ready(struct clk *clk)
{
- void __iomem *reg, *other_reg, *st_reg;
- u32 bit;
+ u16 other_reg, idlest_reg;
+ u32 other_bit;
- /*
- * REVISIT: This code is pretty ugly. It would be nice to generalize
- * it and pull it into struct clk itself somehow.
- */
- reg = clk->enable_reg;
- if ((((u32)reg & 0xff) >= CM_FCLKEN1) &&
- (((u32)reg & 0xff) <= OMAP24XX_CM_FCLKEN2))
- other_reg = (void __iomem *)(((u32)reg & ~0xf0) | 0x10); /* CM_ICLKEN* */
- else if ((((u32)reg & 0xff) >= CM_ICLKEN1) &&
- (((u32)reg & 0xff) <= OMAP24XX_CM_ICLKEN4))
- other_reg = (void __iomem *)(((u32)reg & ~0xf0) | 0x00); /* CM_FCLKEN* */
- else
+ if (!(clk->flags & WAIT_READY))
return;
- /* REVISIT: What are the appropriate exclusions for 34XX? */
- /* No check for DSS or cam clocks */
- if (cpu_is_omap24xx() && ((u32)reg & 0x0f) == 0) { /* CM_{F,I}CLKEN1 */
- if (clk->enable_bit == OMAP24XX_EN_DSS2_SHIFT ||
- clk->enable_bit == OMAP24XX_EN_DSS1_SHIFT ||
- clk->enable_bit == OMAP24XX_EN_CAM_SHIFT)
- return;
- }
+ /* If we are enabling an iclk, also test the fclk; and vice versa */
+ other_bit = 1 << clk->enable_bit;
+ other_reg = clk->enable_reg & ~PRCM_REGTYPE_MASK;
- /* 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(CORE_MOD, 0)) &&
- clk->enable_bit == OMAP3430_EN_SSI_SHIFT)))
- return;
+ if (clk->enable_reg & CM_ICLKEN_REGTYPE)
+ other_reg |= CM_FCLKEN_REGTYPE;
+ else
+ other_reg |= CM_ICLKEN_REGTYPE;
- /* Check if both functional and interface clocks
- * are running. */
- bit = 1 << clk->enable_bit;
- if (!(__raw_readl(other_reg) & bit))
+ /* Ensure functional and interface clocks are running. */
+ if (!(cm_read_mod_reg(clk->prcm_mod, other_reg) & other_bit))
return;
- st_reg = (void __iomem *)(((u32)other_reg & ~0xf0) | 0x20); /* CM_IDLEST* */
- omap2_wait_clock_ready(st_reg, bit, clk->name);
+ idlest_reg = other_reg & ~PRCM_REGTYPE_MASK;
+ idlest_reg |= CM_IDLEST_REGTYPE;
+
+ omap2_wait_clock_ready(clk->prcm_mod, idlest_reg, 1 << clk->idlest_bit,
+ clk->name);
}
/* Enables clock without considering parent dependencies or use count
* REVISIT: Maybe change this to use clk->enable like on omap1?
*/
-int _omap2_clk_enable(struct clk *clk)
+static int _omap2_clk_enable(struct clk *clk)
{
- u32 regval32;
+ u32 v;
if (clk->flags & (ALWAYS_ENABLED | PARENT_CONTROLS_CLOCK))
return 0;
if (clk->enable)
return clk->enable(clk);
- if (unlikely(clk->enable_reg == NULL)) {
- printk(KERN_ERR "clock.c: Enable for %s without enable code\n",
- clk->name);
- return 0; /* REVISIT: -EINVAL */
- }
-
- regval32 = __raw_readl(clk->enable_reg);
+ v = _omap2_clk_read_reg(clk->enable_reg, clk);
if (clk->flags & INVERT_ENABLE)
- regval32 &= ~(1 << clk->enable_bit);
+ v &= ~(1 << clk->enable_bit);
else
- regval32 |= (1 << clk->enable_bit);
- __raw_writel(regval32, clk->enable_reg);
- wmb();
+ v |= (1 << clk->enable_bit);
+ _omap2_clk_write_reg(v, clk->enable_reg, clk);
+ v = _omap2_clk_read_reg(clk->enable_reg, clk); /* OCP barrier */
omap2_clk_wait_ready(clk);
}
/* Disables clock without considering parent dependencies or use count */
-void _omap2_clk_disable(struct clk *clk)
+static void _omap2_clk_disable(struct clk *clk)
{
- u32 regval32;
+ u32 v;
if (clk->flags & (ALWAYS_ENABLED | PARENT_CONTROLS_CLOCK))
return;
return;
}
- if (clk->enable_reg == NULL) {
- /*
- * 'Independent' here refers to a clock which is not
- * controlled by its parent.
- */
- printk(KERN_ERR "clock: clk_disable called on independent "
- "clock %s which has no enable_reg\n", clk->name);
- return;
- }
-
- regval32 = __raw_readl(clk->enable_reg);
+ v = _omap2_clk_read_reg(clk->enable_reg, clk);
if (clk->flags & INVERT_ENABLE)
- regval32 |= (1 << clk->enable_bit);
+ v |= (1 << clk->enable_bit);
else
- regval32 &= ~(1 << clk->enable_bit);
- __raw_writel(regval32, clk->enable_reg);
- wmb();
+ v &= ~(1 << clk->enable_bit);
+ _omap2_clk_write_reg(v, clk->enable_reg, clk);
+ /* No OCP barrier needed here since it is a disable operation */
}
void omap2_clk_disable(struct clk *clk)
{
if (clk->usecount > 0 && !(--clk->usecount)) {
_omap2_clk_disable(clk);
- if (likely((u32)clk->parent))
+ if (clk->parent)
omap2_clk_disable(clk->parent);
- if (clk->clkdm)
- omap2_clkdm_clk_disable(clk->clkdm, clk);
+ omap2_clkdm_clk_disable(clk->clkdm.ptr, clk);
}
}
int omap2_clk_enable(struct clk *clk)
{
- int ret = 0;
+ int ret;
- if (clk->usecount++ == 0) {
- if (likely((u32)clk->parent))
- ret = omap2_clk_enable(clk->parent);
-
- if (unlikely(ret != 0)) {
- clk->usecount--;
- return ret;
- }
+ if (++clk->usecount > 1)
+ return 0;
- if (clk->clkdm)
- omap2_clkdm_clk_enable(clk->clkdm, clk);
+ omap2_clkdm_clk_enable(clk->clkdm.ptr, clk);
- ret = _omap2_clk_enable(clk);
+ if (clk->parent) {
+ int parent_ret;
- if (unlikely(ret != 0)) {
- if (clk->clkdm)
- omap2_clkdm_clk_disable(clk->clkdm, clk);
+ parent_ret = omap2_clk_enable(clk->parent);
- if (clk->parent) {
- omap2_clk_disable(clk->parent);
- clk->usecount--;
- }
+ if (parent_ret != 0) {
+ clk->usecount--;
+ omap2_clkdm_clk_disable(clk->clkdm.ptr, clk);
+ return parent_ret;
}
}
+ ret = _omap2_clk_enable(clk);
+
+ if (ret != 0) {
+ clk->usecount--;
+ omap2_clkdm_clk_disable(clk->clkdm.ptr, clk);
+ if (clk->parent)
+ omap2_clk_disable(clk->parent);
+ }
+
return ret;
}
* Used for clocks that are part of CLKSEL_xyz governed clocks.
* REVISIT: Maybe change to use clk->enable() functions like on omap1?
*/
-void omap2_clksel_recalc(struct clk *clk)
+void omap2_clksel_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage)
{
u32 div = 0;
+ unsigned long rate;
pr_debug("clock: recalc'ing clksel clk %s\n", clk->name);
if (div == 0)
return;
- if (unlikely(clk->rate == clk->parent->rate / div))
- return;
- clk->rate = clk->parent->rate / div;
+ rate = parent_rate / div;
- pr_debug("clock: new clock rate is %ld (div %d)\n", clk->rate, div);
+ if (rate_storage == CURRENT_RATE)
+ clk->rate = rate;
+ else if (rate_storage == TEMP_RATE)
+ clk->temp_rate = rate;
- if (unlikely(clk->flags & RATE_PROPAGATES))
- propagate_rate(clk);
+ pr_debug("clock: new clock rate is %ld (div %d)\n", clk->rate, div);
}
/**
* the element associated with the supplied parent clock address.
* Returns a pointer to the struct clksel on success or NULL on error.
*/
-const struct clksel *omap2_get_clksel_by_parent(struct clk *clk,
- struct clk *src_clk)
+static const struct clksel *omap2_get_clksel_by_parent(struct clk *clk,
+ struct clk *src_clk)
{
const struct clksel *clks;
*
* Finds 'best' divider value in an array based on the source and target
* rates. The divider array must be sorted with smallest divider first.
- * Note that this will not work for clocks which are part of CONFIG_PARTICIPANT,
- * they are only settable as part of virtual_prcm set.
*
* Returns the rounded clock rate or returns 0xffffffff on error.
*/
*new_div = 1;
clks = omap2_get_clksel_by_parent(clk, clk->parent);
- if (clks == NULL)
+ if (!clks)
return ~0;
for (clkr = clks->rates; clkr->div; clkr++) {
* Compatibility wrapper for OMAP clock framework
* Finds best target rate based on the source clock and possible dividers.
* rates. The divider array must be sorted with smallest divider first.
- * Note that this will not work for clocks which are part of CONFIG_PARTICIPANT,
- * they are only settable as part of virtual_prcm set.
*
* Returns the rounded clock rate or returns 0xffffffff on error.
*/
if (clk->round_rate != NULL)
return clk->round_rate(clk, rate);
- if (clk->flags & RATE_FIXED)
- printk(KERN_ERR "clock: generic omap2_clk_round_rate called "
- "on fixed-rate clock %s\n", clk->name);
-
return clk->rate;
}
const struct clksel_rate *clkr;
clks = omap2_get_clksel_by_parent(clk, clk->parent);
- if (clks == NULL)
+ if (!clks)
return 0;
for (clkr = clks->rates; clkr->div; clkr++) {
WARN_ON(div == 0);
clks = omap2_get_clksel_by_parent(clk, clk->parent);
- if (clks == NULL)
+ if (!clks)
return 0;
for (clkr = clks->rates; clkr->div; clkr++) {
return clkr->val;
}
-/**
- * omap2_get_clksel - find clksel register addr & field mask for a clk
- * @clk: struct clk to use
- * @field_mask: ptr to u32 to store the register field mask
- *
- * Returns the address of the clksel register upon success or NULL on error.
- */
-void __iomem *omap2_get_clksel(struct clk *clk, u32 *field_mask)
-{
- if (unlikely((clk->clksel_reg == NULL) || (clk->clksel_mask == NULL)))
- return NULL;
-
- *field_mask = clk->clksel_mask;
-
- return clk->clksel_reg;
-}
-
/**
* omap2_clksel_get_divisor - get current divider applied to parent clock.
* @clk: OMAP struct clk to use.
*/
u32 omap2_clksel_get_divisor(struct clk *clk)
{
- u32 field_mask, field_val;
- void __iomem *div_addr;
+ u32 v;
- div_addr = omap2_get_clksel(clk, &field_mask);
- if (div_addr == NULL)
+ if (!clk->clksel_mask)
return 0;
- field_val = __raw_readl(div_addr) & field_mask;
- field_val >>= __ffs(field_mask);
+ v = _omap2_clk_read_reg(clk->clksel_reg, clk);
+ v &= clk->clksel_mask;
+ v >>= __ffs(clk->clksel_mask);
- return omap2_clksel_to_divisor(clk, field_val);
+ return omap2_clksel_to_divisor(clk, v);
}
int omap2_clksel_set_rate(struct clk *clk, unsigned long rate)
{
- u32 field_mask, field_val, reg_val, validrate, new_div = 0;
- void __iomem *div_addr;
+ u32 v, field_val, validrate, new_div = 0;
- validrate = omap2_clksel_round_rate_div(clk, rate, &new_div);
- if (validrate != rate)
+ if (!clk->clksel_mask)
return -EINVAL;
- div_addr = omap2_get_clksel(clk, &field_mask);
- if (div_addr == NULL)
- return -EINVAL;
+ validrate = omap2_clksel_round_rate_div(clk, rate, &new_div);
+ if (validrate != rate)
+ return -EINVAL;
field_val = omap2_divisor_to_clksel(clk, 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);
- wmb();
+ v = _omap2_clk_read_reg(clk->clksel_reg, clk);
+ v &= ~clk->clksel_mask;
+ v |= field_val << __ffs(clk->clksel_mask);
+ _omap2_clk_write_reg(v, clk->clksel_reg, clk);
+ v = _omap2_clk_read_reg(clk->clksel_reg, clk); /* OCP barrier */
clk->rate = clk->parent->rate / new_div;
- if (clk->flags & DELAYED_APP && cpu_is_omap24xx()) {
- prm_write_mod_reg(OMAP24XX_VALID_CONFIG,
- OMAP24XX_GR_MOD, OMAP24XX_PRCM_CLKCFG_CTRL_OFFSET);
- wmb();
- }
+ _omap2xxx_clk_commit(clk);
return 0;
}
pr_debug("clock: set_rate for clock %s to rate %ld\n", clk->name, rate);
- /* CONFIG_PARTICIPANT clocks are changed only in sets via the
- rate table mechanism, driven by mpu_speed */
- if (clk->flags & CONFIG_PARTICIPANT)
- return -EINVAL;
-
- /* dpll_ck, core_ck, virt_prcm_set; plus all clksel clocks */
if (clk->set_rate != NULL)
ret = clk->set_rate(clk, rate);
- if (unlikely(ret == 0 && (clk->flags & RATE_PROPAGATES)))
- propagate_rate(clk);
-
return ret;
}
/*
* Converts encoded control register address into a full address
- * On error, *src_addr will be returned as 0.
+ * On error, the return value (parent_div) will be 0.
*/
-static u32 omap2_clksel_get_src_field(void __iomem **src_addr,
- struct clk *src_clk, u32 *field_mask,
- struct clk *clk, u32 *parent_div)
+static u32 _omap2_clksel_get_src_field(struct clk *src_clk, struct clk *clk,
+ u32 *field_val)
{
const struct clksel *clks;
const struct clksel_rate *clkr;
- *parent_div = 0;
- *src_addr = NULL;
-
clks = omap2_get_clksel_by_parent(clk, src_clk);
- if (clks == NULL)
+ if (!clks)
return 0;
for (clkr = clks->rates; clkr->div; clkr++) {
/* Should never happen. Add a clksel mask to the struct clk. */
WARN_ON(clk->clksel_mask == 0);
- *field_mask = clk->clksel_mask;
- *src_addr = clk->clksel_reg;
- *parent_div = clkr->div;
+ *field_val = clkr->val;
- return clkr->val;
+ return clkr->div;
}
int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent)
{
- void __iomem *src_addr;
- u32 field_val, field_mask, reg_val, parent_div;
-
- if (unlikely(clk->flags & CONFIG_PARTICIPANT))
- return -EINVAL;
+ u32 field_val, v, parent_div;
if (!clk->clksel)
return -EINVAL;
- field_val = omap2_clksel_get_src_field(&src_addr, new_parent,
- &field_mask, clk, &parent_div);
- if (src_addr == NULL)
+ parent_div = _omap2_clksel_get_src_field(new_parent, clk, &field_val);
+ if (!parent_div)
return -EINVAL;
if (clk->usecount > 0)
_omap2_clk_disable(clk);
/* Set new source value (previous dividers if any in effect) */
- reg_val = __raw_readl(src_addr) & ~field_mask;
- reg_val |= (field_val << __ffs(field_mask));
- __raw_writel(reg_val, src_addr);
- wmb();
-
- if (clk->flags & DELAYED_APP && cpu_is_omap24xx()) {
- __raw_writel(OMAP24XX_VALID_CONFIG, OMAP24XX_PRCM_CLKCFG_CTRL);
- wmb();
- }
+ v = _omap2_clk_read_reg(clk->clksel_reg, clk);
+ v &= ~clk->clksel_mask;
+ v |= field_val << __ffs(clk->clksel_mask);
+ _omap2_clk_write_reg(v, clk->clksel_reg, clk);
+ v = _omap2_clk_read_reg(clk->clksel_reg, clk); /* OCP barrier */
+
+ _omap2xxx_clk_commit(clk);
if (clk->usecount > 0)
_omap2_clk_enable(clk);
pr_debug("clock: set parent of %s to %s (new rate %ld)\n",
clk->name, clk->parent->name, clk->rate);
- if (unlikely(clk->flags & RATE_PROPAGATES))
- propagate_rate(clk);
-
return 0;
}
+struct clk *omap2_clk_get_parent(struct clk *clk)
+{
+ return clk->parent;
+}
+
/* DPLL rate rounding code */
/**
return 0;
}
-static unsigned long _dpll_compute_new_rate(unsigned long parent_rate, unsigned int m, unsigned int n)
+static unsigned long _dpll_compute_new_rate(unsigned long parent_rate,
+ unsigned int m, unsigned int n)
{
unsigned long long num;
unsigned long target_rate,
unsigned long parent_rate)
{
- int flags = 0, carry = 0;
+ int r = 0, carry = 0;
/* Unscale m and round if necessary */
if (*m % DPLL_SCALE_FACTOR >= DPLL_ROUNDING_VAL)
if (*m < DPLL_MIN_MULTIPLIER) {
*m = DPLL_MIN_MULTIPLIER;
*new_rate = 0;
- flags = DPLL_MULT_UNDERFLOW;
+ r = DPLL_MULT_UNDERFLOW;
}
if (*new_rate == 0)
*new_rate = _dpll_compute_new_rate(parent_rate, *m, n);
- return flags;
+ return r;
}
/**
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;
+ struct dpll_data *dd;
if (!clk || !clk->dpll_data)
return ~0;
+ dd = clk->dpll_data;
+
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;
+ scaled_max_m = dd->max_multiplier * DPLL_SCALE_FACTOR;
- clk->dpll_data->last_rounded_rate = 0;
+ dd->last_rounded_rate = 0;
- for (n = clk->dpll_data->max_divider; n >= DPLL_MIN_DIVIDER; n--) {
+ for (n = dd->min_divider; n <= dd->max_divider; n++) {
+
+ /* Is the (input clk, divider) pair valid for the DPLL? */
+ r = _dpll_test_fint(clk, n);
+ if (r == DPLL_FINT_UNDERFLOW)
+ break;
+ else if (r == DPLL_FINT_INVALID)
+ continue;
/* 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
+ * Since we're counting n up, a m overflow means we
+ * can bail out completely (since as n increases in
+ * the next iteration, there's no way that m can
+ * increase beyond the current m)
*/
if (m > scaled_max_m)
- continue;
+ break;
r = _dpll_test_mult(&m, n, &new_rate, target_rate,
clk->parent->rate);
+ /* m can't be set low enough for this n - try with a larger n */
+ if (r == DPLL_MULT_UNDERFLOW)
+ continue;
+
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 >= (int)(abs(e) - dd->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;
+ /* We found good settings -- bail out now */
+ if (min_e <= dd->rate_tolerance)
+ break;
+ }
}
if (min_e < 0) {
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);
+ dd->last_rounded_m = min_e_m;
+ dd->last_rounded_n = min_e_n;
+ dd->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);
+ dd->last_rounded_rate, target_rate);
- return clk->dpll_data->last_rounded_rate;
+ return dd->last_rounded_rate;
}
/*-------------------------------------------------------------------------
v = (clk->flags & INVERT_ENABLE) ? (1 << clk->enable_bit) : 0;
- regval32 = __raw_readl(clk->enable_reg);
+ regval32 = _omap2_clk_read_reg(clk->enable_reg, clk);
if ((regval32 & (1 << clk->enable_bit)) == v)
return;
printk(KERN_INFO "Disabling unused clock \"%s\"\n", clk->name);
- _omap2_clk_disable(clk);
+ if (cpu_is_omap34xx()) {
+ omap2_clk_enable(clk);
+ omap2_clk_disable(clk);
+ } else
+ _omap2_clk_disable(clk);
}
#endif
+
+int omap2_clk_register(struct clk *clk)
+{
+ if (!clk->clkdm.name) {
+ pr_debug("clock: %s: missing clockdomain", clk->name);
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
+ omap2_init_clk_clkdm(clk);
+ return 0;
+}
/* The maximum error between a target DPLL rate and the rounded rate in Hz */
#define DEFAULT_DPLL_RATE_TOLERANCE 50000
+/* CM_CLKSEL2_PLL.CORE_CLK_SRC bits (2XXX) */
+#define CORE_CLK_SRC_32K 0x0
+#define CORE_CLK_SRC_DPLL 0x1
+#define CORE_CLK_SRC_DPLL_X2 0x2
+
+/* OMAP2xxx CM_CLKEN_PLL.EN_DPLL bits - for omap2_get_dpll_rate() */
+#define OMAP2XXX_EN_DPLL_LPBYPASS 0x1
+#define OMAP2XXX_EN_DPLL_FRBYPASS 0x2
+#define OMAP2XXX_EN_DPLL_LOCKED 0x3
+
+/* OMAP3xxx CM_CLKEN_PLL*.EN_*_DPLL bits - for omap2_get_dpll_rate() */
+#define OMAP3XXX_EN_DPLL_LPBYPASS 0x5
+#define OMAP3XXX_EN_DPLL_FRBYPASS 0x6
+#define OMAP3XXX_EN_DPLL_LOCKED 0x7
+
int omap2_clk_init(void);
+int omap2_clk_register(struct clk *clk);
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);
+int omap2_dpll_set_rate_tolerance(struct clk *clk, unsigned int tolerance);
long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate);
+struct clk *omap2_clk_get_parent(struct clk *clk);
#ifdef CONFIG_OMAP_RESET_CLOCKS
void omap2_clk_disable_unused(struct clk *clk);
#define omap2_clk_disable_unused NULL
#endif
-void omap2_clksel_recalc(struct clk *clk);
+void omap2_clksel_recalc(struct clk *clk, unsigned long new_parent_rate,
+ u8 rate_storage);
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 *new_div);
u32 omap2_clksel_to_divisor(struct clk *clk, u32 field_val);
u32 omap2_divisor_to_clksel(struct clk *clk, u32 div);
-void omap2_fixed_divisor_recalc(struct clk *clk);
+void omap2_fixed_divisor_recalc(struct clk *clk, unsigned long new_parent_rate,
+ u8 rate_storage);
long omap2_clksel_round_rate(struct clk *clk, unsigned long target_rate);
int omap2_clksel_set_rate(struct clk *clk, unsigned long rate);
-u32 omap2_get_dpll_rate(struct clk *clk);
-int omap2_wait_clock_ready(void __iomem *reg, u32 cval, const char *name);
+u32 omap2_get_dpll_rate(struct clk *clk, unsigned long parent_rate);
+int omap2_wait_clock_ready(s16 prcm_mod, u16 idlest_reg, u32 cval,
+ const char *name);
void omap2_clk_prepare_for_reboot(void);
extern u8 cpu_mask;
#include <linux/cpufreq.h>
#include <linux/bitops.h>
+#include <mach/common.h>
#include <mach/clock.h>
#include <mach/sram.h>
#include <asm/div64.h>
-#include "memory.h"
+#include <mach/sdrc.h>
#include "clock.h"
#include "clock24xx.h"
#include "prm.h"
* Omap24xx specific clock functions
*-------------------------------------------------------------------------*/
-/* This actually returns the rate of core_ck, not dpll_ck. */
-static u32 omap2_get_dpll_rate_24xx(struct clk *tclk)
+/**
+ * omap2xxx_clk_get_core_rate - return the CORE_CLK rate
+ * @clk: pointer to the combined dpll_ck + core_ck (currently "dpll_ck")
+ * @parent_rate: rate of the parent of the dpll_ck
+ *
+ * Returns the CORE_CLK rate. CORE_CLK can have one of three rate
+ * sources on OMAP2xxx: the DPLL CLKOUT rate, DPLL CLKOUTX2, or 32KHz
+ * (the latter is unusual). This currently should be called with
+ * struct clk *dpll_ck, which is a composite clock of dpll_ck and
+ * core_ck.
+ */
+static u32 omap2xxx_clk_get_core_rate(struct clk *clk,
+ unsigned long parent_rate)
{
- long long dpll_clk;
- u8 amult;
+ long long core_clk;
+ u32 v;
- dpll_clk = omap2_get_dpll_rate(tclk);
+ core_clk = omap2_get_dpll_rate(clk, parent_rate);
- amult = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2);
- amult &= OMAP24XX_CORE_CLK_SRC_MASK;
- dpll_clk *= amult;
+ v = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2);
+ v &= OMAP24XX_CORE_CLK_SRC_MASK;
+
+ if (v == CORE_CLK_SRC_32K)
+ core_clk = 32768;
+ else
+ core_clk *= v;
- return dpll_clk;
+ return core_clk;
}
-static int omap2_enable_osc_ck(struct clk *clk)
+static unsigned long omap2xxx_clk_find_oppset_by_mpurate(unsigned long mpu_speed,
+ struct prcm_config **prcm)
{
- u32 pcc;
+ unsigned long found_speed = 0;
+ struct prcm_config *p;
- pcc = __raw_readl(OMAP24XX_PRCM_CLKSRC_CTRL);
+ p = *prcm;
- __raw_writel(pcc & ~OMAP_AUTOEXTCLKMODE_MASK,
- OMAP24XX_PRCM_CLKSRC_CTRL);
+ for (p = rate_table; p->mpu_speed; p++) {
+ if (!(p->flags & cpu_mask))
+ continue;
- return 0;
+ if (p->xtal_speed != sys_ck.rate)
+ continue;
+
+ if (p->mpu_speed <= mpu_speed) {
+ found_speed = p->mpu_speed;
+ break;
+ }
+ }
+
+ return found_speed;
}
-static void omap2_disable_osc_ck(struct clk *clk)
+static int omap2_enable_osc_ck(struct clk *clk)
{
- u32 pcc;
+ prm_rmw_mod_reg_bits(OMAP_AUTOEXTCLKMODE_MASK, 0,
+ OMAP24XX_GR_MOD, OMAP24XX_PRCM_CLKSRC_CTRL_OFFSET);
- pcc = __raw_readl(OMAP24XX_PRCM_CLKSRC_CTRL);
-
- __raw_writel(pcc | OMAP_AUTOEXTCLKMODE_MASK,
- OMAP24XX_PRCM_CLKSRC_CTRL);
+ return 0;
}
-#ifdef OLD_CK
-/* Recalculate SYST_CLK */
-static void omap2_sys_clk_recalc(struct clk * clk)
+static void omap2_disable_osc_ck(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_mod_reg_bits(OMAP_AUTOEXTCLKMODE_MASK, OMAP_AUTOEXTCLKMODE_MASK,
+ OMAP24XX_GR_MOD, OMAP24XX_PRCM_CLKSRC_CTRL_OFFSET);
}
-#endif /* OLD_CK */
/* Enable an APLL if off */
static int omap2_clk_fixed_enable(struct clk *clk)
else if (clk == &apll54_ck)
cval = OMAP24XX_ST_54M_APLL;
- omap2_wait_clock_ready(OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST), cval,
- clk->name);
+ omap2_wait_clock_ready(PLL_MOD, CM_IDLEST, cval, clk->name);
/*
* REVISIT: Should we return an error code if omap2_wait_clock_ready()
* Uses the current prcm set to tell if a rate is valid.
* You can go slower, but not faster within a given rate set.
*/
-long omap2_dpllcore_round_rate(unsigned long target_rate)
+static long omap2_dpllcore_round_rate(unsigned long target_rate)
{
u32 high, low, core_clk_src;
}
-static void omap2_dpllcore_recalc(struct clk *clk)
+static void omap2_dpllcore_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage)
{
- clk->rate = omap2_get_dpll_rate_24xx(clk);
+ unsigned long rate;
- propagate_rate(clk);
+ rate = omap2xxx_clk_get_core_rate(clk, parent_rate);
+
+ if (rate_storage == CURRENT_RATE)
+ clk->rate = rate;
+ else if (rate_storage == TEMP_RATE)
+ clk->temp_rate = rate;
}
static int omap2_reprogram_dpllcore(struct clk *clk, unsigned long rate)
u32 bypass = 0;
struct prcm_config tmpset;
const struct dpll_data *dd;
- unsigned long flags;
- int ret = -EINVAL;
- local_irq_save(flags);
- cur_rate = omap2_get_dpll_rate_24xx(&dpll_ck);
+ cur_rate = omap2xxx_clk_get_core_rate(&dpll_ck, dpll_ck.parent->rate);
mult = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2);
mult &= OMAP24XX_CORE_CLK_SRC_MASK;
if ((rate == (cur_rate / 2)) && (mult == 2)) {
- omap2_reprogram_sdrc(CORE_CLK_SRC_DPLL, 1);
+ omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL, 1);
} else if ((rate == (cur_rate * 2)) && (mult == 1)) {
- omap2_reprogram_sdrc(CORE_CLK_SRC_DPLL_X2, 1);
+ omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL_X2, 1);
} else if (rate != cur_rate) {
valid_rate = omap2_dpllcore_round_rate(rate);
if (valid_rate != rate)
- goto dpll_exit;
+ return -EINVAL;
if (mult == 1)
low = curr_prcm_set->dpll_speed;
dd = clk->dpll_data;
if (!dd)
- goto dpll_exit;
+ return -EINVAL;
- tmpset.cm_clksel1_pll = __raw_readl(dd->mult_div1_reg);
+ tmpset.cm_clksel1_pll = cm_read_mod_reg(clk->prcm_mod,
+ dd->mult_div1_reg);
tmpset.cm_clksel1_pll &= ~(dd->mult_mask |
dd->div1_mask);
div = ((curr_prcm_set->xtal_speed / 1000000) - 1);
if (rate == curr_prcm_set->xtal_speed) /* If asking for 1-1 */
bypass = 1;
- omap2_reprogram_sdrc(CORE_CLK_SRC_DPLL_X2, 1); /* For init_mem */
+ /* For omap2xxx_sdrc_init_params() */
+ omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL_X2, 1);
/* Force dll lock mode */
omap2_set_prcm(tmpset.cm_clksel1_pll, tmpset.base_sdrc_rfr,
bypass);
/* Errata: ret dll entry state */
- omap2_init_memory_params(omap2_dll_force_needed());
- omap2_reprogram_sdrc(done_rate, 0);
+ omap2xxx_sdrc_init_params(omap2xxx_sdrc_dll_is_unlocked());
+ omap2xxx_sdrc_reprogram(done_rate, 0);
}
- omap2_dpllcore_recalc(&dpll_ck);
- ret = 0;
-dpll_exit:
- local_irq_restore(flags);
- return(ret);
+ return 0;
}
/**
*
* Set virt_prcm_set's rate to the mpu_speed field of the current PRCM set.
*/
-static void omap2_table_mpu_recalc(struct clk *clk)
+static void omap2_table_mpu_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage)
{
- clk->rate = curr_prcm_set->mpu_speed;
+ struct prcm_config *prcm;
+ unsigned long mpurate;
+
+ mpurate = omap2xxx_clk_find_oppset_by_mpurate(parent_rate, &prcm);
+
+ if (rate_storage == CURRENT_RATE)
+ clk->rate = mpurate;
+ else if (rate_storage == TEMP_RATE)
+ clk->temp_rate = mpurate;
}
/*
{
u32 cur_rate, done_rate, bypass = 0, tmp;
struct prcm_config *prcm;
- unsigned long found_speed = 0;
- unsigned long flags;
+ unsigned long flags, found_speed;
if (clk != &virt_prcm_set)
return -EINVAL;
- for (prcm = rate_table; prcm->mpu_speed; prcm++) {
- if (!(prcm->flags & cpu_mask))
- continue;
-
- if (prcm->xtal_speed != sys_ck.rate)
- continue;
-
- if (prcm->mpu_speed <= rate) {
- found_speed = prcm->mpu_speed;
- break;
- }
- }
-
+ found_speed = omap2xxx_clk_find_oppset_by_mpurate(rate, &prcm);
if (!found_speed) {
printk(KERN_INFO "Could not set MPU rate to %luMHz\n",
rate / 1000000);
}
curr_prcm_set = prcm;
- cur_rate = omap2_get_dpll_rate_24xx(&dpll_ck);
+ cur_rate = omap2xxx_clk_get_core_rate(&dpll_ck, dpll_ck.parent->rate);
if (prcm->dpll_speed == cur_rate / 2) {
- omap2_reprogram_sdrc(CORE_CLK_SRC_DPLL, 1);
+ omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL, 1);
} else if (prcm->dpll_speed == cur_rate * 2) {
- omap2_reprogram_sdrc(CORE_CLK_SRC_DPLL_X2, 1);
+ omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL_X2, 1);
} else if (prcm->dpll_speed != cur_rate) {
local_irq_save(flags);
/* Major subsystem dividers */
tmp = cm_read_mod_reg(CORE_MOD, CM_CLKSEL1) & OMAP24XX_CLKSEL_DSS2_MASK;
- cm_write_mod_reg(prcm->cm_clksel1_core | tmp, CORE_MOD, CM_CLKSEL1);
+ cm_write_mod_reg(prcm->cm_clksel1_core | tmp, CORE_MOD,
+ CM_CLKSEL1);
+
if (cpu_is_omap2430())
cm_write_mod_reg(prcm->cm_clksel_mdm,
OMAP2430_MDM_MOD, CM_CLKSEL);
- /* x2 to enter init_mem */
- omap2_reprogram_sdrc(CORE_CLK_SRC_DPLL_X2, 1);
+ /* x2 to enter omap2xxx_sdrc_init_params() */
+ omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL_X2, 1);
omap2_set_prcm(prcm->cm_clksel1_pll, prcm->base_sdrc_rfr,
bypass);
- omap2_init_memory_params(omap2_dll_force_needed());
- omap2_reprogram_sdrc(done_rate, 0);
+ omap2xxx_sdrc_init_params(omap2xxx_sdrc_dll_is_unlocked());
+ omap2xxx_sdrc_reprogram(done_rate, 0);
local_irq_restore(flags);
}
- 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", __func__);
+ 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_register = omap2_clk_register,
.clk_enable = omap2_clk_enable,
.clk_disable = omap2_clk_disable,
.clk_round_rate = omap2_clk_round_rate,
.clk_set_rate = omap2_clk_set_rate,
.clk_set_parent = omap2_clk_set_parent,
+ .clk_get_parent = omap2_clk_get_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)
{
- u32 aplls, sclk = 0;
+ u32 aplls, srate = 0;
aplls = cm_read_mod_reg(PLL_MOD, CM_CLKSEL1);
aplls &= OMAP24XX_APLLS_CLKIN_MASK;
aplls >>= OMAP24XX_APLLS_CLKIN_SHIFT;
if (aplls == APLLS_CLKIN_19_2MHZ)
- sclk = 19200000;
+ srate = 19200000;
else if (aplls == APLLS_CLKIN_13MHZ)
- sclk = 13000000;
+ srate = 13000000;
else if (aplls == APLLS_CLKIN_12MHZ)
- sclk = 12000000;
+ srate = 12000000;
- return sclk;
+ return srate;
}
static u32 omap2_get_sysclkdiv(void)
{
u32 div;
- div = __raw_readl(OMAP24XX_PRCM_CLKSRC_CTRL);
+ div = prm_read_mod_reg(OMAP24XX_GR_MOD,
+ OMAP24XX_PRCM_CLKSRC_CTRL_OFFSET);
div &= OMAP_SYSCLKDIV_MASK;
div >>= OMAP_SYSCLKDIV_SHIFT;
return div;
}
-static void omap2_osc_clk_recalc(struct clk *clk)
+static void omap2_osc_clk_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage)
{
- clk->rate = omap2_get_apll_clkin() * omap2_get_sysclkdiv();
- propagate_rate(clk);
+ unsigned long rate;
+
+ /* XXX osc_ck on 2xxx currently is parentless */
+ rate = omap2_get_apll_clkin() * omap2_get_sysclkdiv();
+
+ if (rate_storage == CURRENT_RATE)
+ clk->rate = rate;
+ else if (rate_storage == TEMP_RATE)
+ clk->temp_rate = rate;
}
-static void omap2_sys_clk_recalc(struct clk *clk)
+static void omap2_sys_clk_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage)
{
- clk->rate = clk->parent->rate / omap2_get_sysclkdiv();
- propagate_rate(clk);
+ unsigned long rate;
+
+ rate = parent_rate / omap2_get_sysclkdiv();
+
+ if (rate_storage == CURRENT_RATE)
+ clk->rate = rate;
+ else if (rate_storage == TEMP_RATE)
+ clk->temp_rate = rate;
}
/*
if (!mpurate)
return -EINVAL;
- if (omap2_select_table_rate(&virt_prcm_set, mpurate))
+ if (clk_set_rate(&virt_prcm_set, mpurate))
printk(KERN_ERR "Could not find matching MPU rate\n");
recalculate_root_clocks();
clk_init(&omap2_clk_functions);
- omap2_osc_clk_recalc(&osc_ck);
- omap2_sys_clk_recalc(&sys_ck);
+ omap2_osc_clk_recalc(&osc_ck, 0, CURRENT_RATE);
+ omap2_sys_clk_recalc(&sys_ck, sys_ck.parent->rate, CURRENT_RATE);
for (clkp = onchip_24xx_clks;
clkp < onchip_24xx_clks + ARRAY_SIZE(onchip_24xx_clks);
}
/* Check the MPU rate set by bootloader */
- clkrate = omap2_get_dpll_rate_24xx(&dpll_ck);
+ clkrate = omap2xxx_clk_get_core_rate(&dpll_ck, dpll_ck.parent->rate);
for (prcm = rate_table; prcm->mpu_speed; prcm++) {
if (!(prcm->flags & cpu_mask))
continue;
#include "cm-regbits-24xx.h"
#include "sdrc.h"
-static void omap2_table_mpu_recalc(struct clk *clk);
+static void omap2_table_mpu_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage);
static int omap2_select_table_rate(struct clk *clk, unsigned long rate);
static long omap2_round_to_table_rate(struct clk *clk, unsigned long rate);
-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_dpllcore_recalc(struct clk *clk);
+static void omap2_sys_clk_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage);
+static void omap2_osc_clk_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage);
+static void omap2_dpllcore_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage);
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);
.name = "func_32k_ck",
.rate = 32000,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
- RATE_FIXED | ALWAYS_ENABLED | RATE_PROPAGATES,
- .clkdm_name = "wkup_clkdm",
- .recalc = &propagate_rate,
+ ALWAYS_ENABLED,
+ .clkdm = { .name = "prm_clkdm" },
};
/* Typical 12/13MHz in standalone mode, will be 26Mhz in chassis mode */
static struct clk osc_ck = { /* (*12, *13, 19.2, *26, 38.4)MHz */
.name = "osc_ck",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
- RATE_PROPAGATES,
- .clkdm_name = "wkup_clkdm",
+ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+ .clkdm = { .name = "prm_clkdm" },
.enable = &omap2_enable_osc_ck,
.disable = &omap2_disable_osc_ck,
.recalc = &omap2_osc_clk_recalc,
.name = "sys_ck", /* ~ ref_clk also */
.parent = &osc_ck,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
- ALWAYS_ENABLED | RATE_PROPAGATES,
- .clkdm_name = "wkup_clkdm",
+ ALWAYS_ENABLED,
+ .clkdm = { .name = "prm_clkdm" },
.recalc = &omap2_sys_clk_recalc,
};
.name = "alt_ck",
.rate = 54000000,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
- RATE_FIXED | ALWAYS_ENABLED | RATE_PROPAGATES,
- .clkdm_name = "wkup_clkdm",
- .recalc = &propagate_rate,
+ ALWAYS_ENABLED,
+ .clkdm = { .name = "prm_clkdm" },
};
/*
*/
static struct dpll_data dpll_dd = {
- .mult_div1_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1),
+ .mult_div1_reg = CM_CLKSEL1,
.mult_mask = OMAP24XX_DPLL_MULT_MASK,
.div1_mask = OMAP24XX_DPLL_DIV_MASK,
+ .control_reg = CM_CLKEN,
+ .enable_mask = OMAP24XX_EN_DPLL_MASK,
.max_multiplier = 1024,
+ .min_divider = 1,
.max_divider = 16,
.rate_tolerance = DEFAULT_DPLL_RATE_TOLERANCE
};
static struct clk dpll_ck = {
.name = "dpll_ck",
.parent = &sys_ck, /* Can be func_32k also */
+ .prcm_mod = PLL_MOD,
.dpll_data = &dpll_dd,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
- RATE_PROPAGATES | ALWAYS_ENABLED,
- .clkdm_name = "wkup_clkdm",
+ ALWAYS_ENABLED,
+ .clkdm = { .name = "prm_clkdm" },
.recalc = &omap2_dpllcore_recalc,
.set_rate = &omap2_reprogram_dpllcore,
};
static struct clk apll96_ck = {
.name = "apll96_ck",
.parent = &sys_ck,
+ .prcm_mod = PLL_MOD,
.rate = 96000000,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
- RATE_FIXED | RATE_PROPAGATES | ENABLE_ON_INIT,
- .clkdm_name = "wkup_clkdm",
- .enable_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKEN),
+ ENABLE_ON_INIT,
+ .clkdm = { .name = "prm_clkdm" },
+ .enable_reg = CM_CLKEN,
.enable_bit = OMAP24XX_EN_96M_PLL_SHIFT,
.enable = &omap2_clk_fixed_enable,
.disable = &omap2_clk_fixed_disable,
- .recalc = &propagate_rate,
};
static struct clk apll54_ck = {
.name = "apll54_ck",
.parent = &sys_ck,
+ .prcm_mod = PLL_MOD,
.rate = 54000000,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
- RATE_FIXED | RATE_PROPAGATES | ENABLE_ON_INIT,
- .clkdm_name = "wkup_clkdm",
- .enable_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKEN),
+ ENABLE_ON_INIT,
+ .clkdm = { .name = "prm_clkdm" },
+ .enable_reg = CM_CLKEN,
.enable_bit = OMAP24XX_EN_54M_PLL_SHIFT,
.enable = &omap2_clk_fixed_enable,
.disable = &omap2_clk_fixed_disable,
- .recalc = &propagate_rate,
};
/*
static struct clk func_54m_ck = {
.name = "func_54m_ck",
.parent = &apll54_ck, /* can also be alt_clk */
+ .prcm_mod = PLL_MOD,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
- RATE_PROPAGATES | PARENT_CONTROLS_CLOCK,
- .clkdm_name = "wkup_clkdm",
+ PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "cm_clkdm" },
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1),
+ .clksel_reg = CM_CLKSEL1,
.clksel_mask = OMAP24XX_54M_SOURCE,
.clksel = func_54m_clksel,
.recalc = &omap2_clksel_recalc,
.name = "core_ck",
.parent = &dpll_ck, /* can also be 32k */
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
- ALWAYS_ENABLED | RATE_PROPAGATES,
- .clkdm_name = "wkup_clkdm",
+ ALWAYS_ENABLED,
+ .clkdm = { .name = "cm_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk func_96m_ck = {
.name = "func_96m_ck",
.parent = &apll96_ck,
+ .prcm_mod = PLL_MOD,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
- RATE_PROPAGATES | PARENT_CONTROLS_CLOCK,
- .clkdm_name = "wkup_clkdm",
+ PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "cm_clkdm" },
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1),
+ .clksel_reg = CM_CLKSEL1,
.clksel_mask = OMAP2430_96M_SOURCE,
.clksel = func_96m_clksel,
.recalc = &omap2_clksel_recalc,
static struct clk func_48m_ck = {
.name = "func_48m_ck",
.parent = &apll96_ck, /* 96M or Alt */
+ .prcm_mod = PLL_MOD,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
- RATE_PROPAGATES | PARENT_CONTROLS_CLOCK,
- .clkdm_name = "wkup_clkdm",
+ PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "cm_clkdm" },
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1),
+ .clksel_reg = CM_CLKSEL1,
.clksel_mask = OMAP24XX_48M_SOURCE,
.clksel = func_48m_clksel,
.recalc = &omap2_clksel_recalc,
.parent = &func_48m_ck,
.fixed_div = 4,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
- RATE_PROPAGATES | PARENT_CONTROLS_CLOCK,
- .clkdm_name = "wkup_clkdm",
+ PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "cm_clkdm" },
.recalc = &omap2_fixed_divisor_recalc,
};
/* Secure timer, only available in secure mode */
static struct clk wdt1_osc_ck = {
- .name = "ck_wdt1_osc",
+ .name = "wdt1_osc_ck",
.parent = &osc_ck,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+ .clkdm = { .name = "prm_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk sys_clkout_src = {
.name = "sys_clkout_src",
.parent = &func_54m_ck,
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
- RATE_PROPAGATES,
- .clkdm_name = "wkup_clkdm",
- .enable_reg = OMAP24XX_PRCM_CLKOUT_CTRL,
+ .prcm_mod = OMAP24XX_GR_MOD,
+ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+ .clkdm = { .name = "prm_clkdm" },
+ .enable_reg = OMAP24XX_PRCM_CLKOUT_CTRL_OFFSET,
.enable_bit = OMAP24XX_CLKOUT_EN_SHIFT,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP24XX_PRCM_CLKOUT_CTRL,
+ .clksel_reg = OMAP24XX_PRCM_CLKOUT_CTRL_OFFSET,
.clksel_mask = OMAP24XX_CLKOUT_SOURCE_MASK,
.clksel = common_clkout_src_clksel,
.recalc = &omap2_clksel_recalc,
static struct clk sys_clkout = {
.name = "sys_clkout",
.parent = &sys_clkout_src,
+ .prcm_mod = OMAP24XX_GR_MOD,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
PARENT_CONTROLS_CLOCK,
- .clkdm_name = "wkup_clkdm",
- .clksel_reg = OMAP24XX_PRCM_CLKOUT_CTRL,
+ .clkdm = { .name = "prm_clkdm" },
+ .clksel_reg = OMAP24XX_PRCM_CLKOUT_CTRL_OFFSET,
.clksel_mask = OMAP24XX_CLKOUT_DIV_MASK,
.clksel = sys_clkout_clksel,
.recalc = &omap2_clksel_recalc,
static struct clk sys_clkout2_src = {
.name = "sys_clkout2_src",
.parent = &func_54m_ck,
- .flags = CLOCK_IN_OMAP242X | RATE_PROPAGATES,
- .clkdm_name = "wkup_clkdm",
- .enable_reg = OMAP24XX_PRCM_CLKOUT_CTRL,
+ .prcm_mod = OMAP24XX_GR_MOD,
+ .flags = CLOCK_IN_OMAP242X,
+ .clkdm = { .name = "cm_clkdm" },
+ .enable_reg = OMAP24XX_PRCM_CLKOUT_CTRL_OFFSET,
.enable_bit = OMAP2420_CLKOUT2_EN_SHIFT,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP24XX_PRCM_CLKOUT_CTRL,
+ .clksel_reg = OMAP24XX_PRCM_CLKOUT_CTRL_OFFSET,
.clksel_mask = OMAP2420_CLKOUT2_SOURCE_MASK,
.clksel = common_clkout_src_clksel,
.recalc = &omap2_clksel_recalc,
static struct clk sys_clkout2 = {
.name = "sys_clkout2",
.parent = &sys_clkout2_src,
+ .prcm_mod = OMAP24XX_GR_MOD,
.flags = CLOCK_IN_OMAP242X | PARENT_CONTROLS_CLOCK,
- .clkdm_name = "wkup_clkdm",
- .clksel_reg = OMAP24XX_PRCM_CLKOUT_CTRL,
+ .clkdm = { .name = "cm_clkdm" },
+ .clksel_reg = OMAP24XX_PRCM_CLKOUT_CTRL_OFFSET,
.clksel_mask = OMAP2420_CLKOUT2_DIV_MASK,
.clksel = sys_clkout2_clksel,
.recalc = &omap2_clksel_recalc,
static struct clk emul_ck = {
.name = "emul_ck",
.parent = &func_54m_ck,
+ .prcm_mod = OMAP24XX_GR_MOD,
.flags = CLOCK_IN_OMAP242X,
- .clkdm_name = "wkup_clkdm",
- .enable_reg = OMAP24XX_PRCM_CLKEMUL_CTRL,
+ .clkdm = { .name = "cm_clkdm" },
+ .enable_reg = OMAP24XX_PRCM_CLKEMUL_CTRL_OFFSET,
.enable_bit = OMAP24XX_EMULATION_EN_SHIFT,
.recalc = &followparent_recalc,
static struct clk mpu_ck = { /* Control cpu */
.name = "mpu_ck",
.parent = &core_ck,
+ .prcm_mod = MPU_MOD,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
- ALWAYS_ENABLED | DELAYED_APP |
- CONFIG_PARTICIPANT | RATE_PROPAGATES,
- .clkdm_name = "mpu_clkdm",
+ ALWAYS_ENABLED | DELAYED_APP,
+ .clkdm = { .name = "mpu_clkdm" },
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(MPU_MOD, CM_CLKSEL),
+ .clksel_reg = CM_CLKSEL,
.clksel_mask = OMAP24XX_CLKSEL_MPU_MASK,
.clksel = mpu_clksel,
.recalc = &omap2_clksel_recalc,
- .round_rate = &omap2_clksel_round_rate,
- .set_rate = &omap2_clksel_set_rate
};
/*
static struct clk dsp_fck = {
.name = "dsp_fck",
.parent = &core_ck,
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | DELAYED_APP |
- CONFIG_PARTICIPANT | RATE_PROPAGATES,
- .clkdm_name = "dsp_clkdm",
- .enable_reg = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_FCLKEN),
+ .prcm_mod = OMAP24XX_DSP_MOD,
+ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | DELAYED_APP,
+ .clkdm = { .name = "dsp_clkdm" },
+ .enable_reg = CM_FCLKEN,
.enable_bit = OMAP24XX_CM_FCLKEN_DSP_EN_DSP_SHIFT,
- .clksel_reg = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_CLKSEL),
+ .clksel_reg = CM_CLKSEL,
.clksel_mask = OMAP24XX_CLKSEL_DSP_MASK,
.clksel = dsp_fck_clksel,
.recalc = &omap2_clksel_recalc,
- .round_rate = &omap2_clksel_round_rate,
- .set_rate = &omap2_clksel_set_rate
};
/* DSP interface clock */
static struct clk dsp_irate_ick = {
.name = "dsp_irate_ick",
.parent = &dsp_fck,
+ .prcm_mod = OMAP24XX_DSP_MOD,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | DELAYED_APP |
- CONFIG_PARTICIPANT | PARENT_CONTROLS_CLOCK,
- .clksel_reg = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_CLKSEL),
+ PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "dsp_clkdm" },
+ .clksel_reg = CM_CLKSEL,
.clksel_mask = OMAP24XX_CLKSEL_DSP_IF_MASK,
.clksel = dsp_irate_ick_clksel,
.recalc = &omap2_clksel_recalc,
- .round_rate = &omap2_clksel_round_rate,
- .set_rate = &omap2_clksel_set_rate
};
/* 2420 only */
static struct clk dsp_ick = {
.name = "dsp_ick", /* apparently ipi and isp */
.parent = &dsp_irate_ick,
- .flags = CLOCK_IN_OMAP242X | DELAYED_APP | CONFIG_PARTICIPANT,
- .enable_reg = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_ICLKEN),
+ .prcm_mod = OMAP24XX_DSP_MOD,
+ .flags = CLOCK_IN_OMAP242X | DELAYED_APP,
+ .clkdm = { .name = "dsp_clkdm" },
+ .enable_reg = CM_ICLKEN,
.enable_bit = OMAP2420_EN_DSP_IPI_SHIFT, /* for ipi */
};
static struct clk iva2_1_ick = {
.name = "iva2_1_ick",
.parent = &dsp_irate_ick,
- .flags = CLOCK_IN_OMAP243X | DELAYED_APP | CONFIG_PARTICIPANT,
- .enable_reg = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_FCLKEN),
+ .prcm_mod = OMAP24XX_DSP_MOD,
+ .flags = CLOCK_IN_OMAP243X | DELAYED_APP,
+ .clkdm = { .name = "dsp_clkdm" },
+ .enable_reg = CM_FCLKEN,
.enable_bit = OMAP24XX_CM_FCLKEN_DSP_EN_DSP_SHIFT,
};
static struct clk iva1_ifck = {
.name = "iva1_ifck",
.parent = &core_ck,
- .flags = CLOCK_IN_OMAP242X | CONFIG_PARTICIPANT |
- RATE_PROPAGATES | DELAYED_APP,
- .clkdm_name = "iva1_clkdm",
- .enable_reg = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_FCLKEN),
+ .prcm_mod = OMAP24XX_DSP_MOD,
+ .flags = CLOCK_IN_OMAP242X | DELAYED_APP,
+ .clkdm = { .name = "iva1_clkdm" },
+ .enable_reg = CM_FCLKEN,
.enable_bit = OMAP2420_EN_IVA_COP_SHIFT,
- .clksel_reg = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_CLKSEL),
+ .clksel_reg = CM_CLKSEL,
.clksel_mask = OMAP2420_CLKSEL_IVA_MASK,
.clksel = dsp_fck_clksel,
.recalc = &omap2_clksel_recalc,
static struct clk iva1_mpu_int_ifck = {
.name = "iva1_mpu_int_ifck",
.parent = &iva1_ifck,
+ .prcm_mod = OMAP24XX_DSP_MOD,
.flags = CLOCK_IN_OMAP242X,
- .clkdm_name = "iva1_clkdm",
- .enable_reg = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_FCLKEN),
+ .clkdm = { .name = "iva1_clkdm" },
+ .enable_reg = CM_FCLKEN,
.enable_bit = OMAP2420_EN_IVA_MPU_SHIFT,
.fixed_div = 2,
.recalc = &omap2_fixed_divisor_recalc,
static struct clk core_l3_ck = { /* Used for ick and fck, interconnect */
.name = "core_l3_ck",
.parent = &core_ck,
+ .prcm_mod = CORE_MOD,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
- ALWAYS_ENABLED | DELAYED_APP |
- CONFIG_PARTICIPANT | RATE_PROPAGATES,
- .clkdm_name = "core_l3_clkdm",
- .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1),
+ ALWAYS_ENABLED | DELAYED_APP,
+ .clkdm = { .name = "core_l3_clkdm" },
+ .clksel_reg = CM_CLKSEL1,
.clksel_mask = OMAP24XX_CLKSEL_L3_MASK,
.clksel = core_l3_clksel,
.recalc = &omap2_clksel_recalc,
- .round_rate = &omap2_clksel_round_rate,
- .set_rate = &omap2_clksel_set_rate
};
/* usb_l4_ick */
static struct clk usb_l4_ick = { /* FS-USB interface clock */
.name = "usb_l4_ick",
.parent = &core_l3_ck,
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
- DELAYED_APP | CONFIG_PARTICIPANT,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY |
+ DELAYED_APP,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_ICLKEN2,
.enable_bit = OMAP24XX_EN_USB_SHIFT,
- .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1),
+ .idlest_bit = OMAP24XX_ST_USB_SHIFT,
+ .clksel_reg = CM_CLKSEL1,
.clksel_mask = OMAP24XX_CLKSEL_USB_MASK,
.clksel = usb_l4_ick_clksel,
.recalc = &omap2_clksel_recalc,
- .round_rate = &omap2_clksel_round_rate,
- .set_rate = &omap2_clksel_set_rate
};
/*
static struct clk l4_ck = { /* used both as an ick and fck */
.name = "l4_ck",
.parent = &core_l3_ck,
+ .prcm_mod = CORE_MOD,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
- ALWAYS_ENABLED | DELAYED_APP | RATE_PROPAGATES,
- .clkdm_name = "core_l4_clkdm",
- .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1),
+ ALWAYS_ENABLED | DELAYED_APP,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .clksel_reg = CM_CLKSEL1,
.clksel_mask = OMAP24XX_CLKSEL_L4_MASK,
.clksel = l4_clksel,
.recalc = &omap2_clksel_recalc,
static struct clk ssi_ssr_sst_fck = {
.name = "ssi_fck",
.parent = &core_ck,
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY |
DELAYED_APP,
- .clkdm_name = "core_l3_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
+ .clkdm = { .name = "core_l3_clkdm" },
+ .enable_reg = OMAP24XX_CM_FCLKEN2,
.enable_bit = OMAP24XX_EN_SSI_SHIFT,
- .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1),
+ .idlest_bit = OMAP24XX_ST_SSI_SHIFT,
+ .clksel_reg = CM_CLKSEL1,
.clksel_mask = OMAP24XX_CLKSEL_SSI_MASK,
.clksel = ssi_ssr_sst_fck_clksel,
.recalc = &omap2_clksel_recalc,
.set_rate = &omap2_clksel_set_rate
};
+/*
+ * Presumably this is the same as SSI_ICLK.
+ * TRM contradicts itself on what clockdomain SSI_ICLK is in
+ */
+static struct clk ssi_l4_ick = {
+ .name = "ssi_l4_ick",
+ .parent = &l4_ck,
+ .prcm_mod = CORE_MOD,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+ .enable_reg = CM_ICLKEN2,
+ .enable_bit = OMAP24XX_EN_SSI_SHIFT,
+ .idlest_bit = OMAP24XX_ST_SSI_SHIFT,
+ .recalc = &followparent_recalc,
+};
+
/*
* GFX clock domain
* divided value of fclk.
*
*/
-/* XXX REVISIT: GFX clock is part of CONFIG_PARTICIPANT, no? doublecheck. */
+/* XXX REVISIT: GFX clock is part of the table rate set also? doublecheck. */
/* This clksel struct is shared between gfx_3d_fck and gfx_2d_fck */
static const struct clksel gfx_fck_clksel[] = {
static struct clk gfx_3d_fck = {
.name = "gfx_3d_fck",
.parent = &core_l3_ck,
+ .prcm_mod = GFX_MOD,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "gfx_clkdm",
- .enable_reg = OMAP_CM_REGADDR(GFX_MOD, CM_FCLKEN),
+ .clkdm = { .name = "gfx_clkdm" },
+ .enable_reg = CM_FCLKEN,
.enable_bit = OMAP24XX_EN_3D_SHIFT,
- .clksel_reg = OMAP_CM_REGADDR(GFX_MOD, CM_CLKSEL),
+ .clksel_reg = CM_CLKSEL,
.clksel_mask = OMAP_CLKSEL_GFX_MASK,
.clksel = gfx_fck_clksel,
.recalc = &omap2_clksel_recalc,
static struct clk gfx_2d_fck = {
.name = "gfx_2d_fck",
.parent = &core_l3_ck,
+ .prcm_mod = GFX_MOD,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "gfx_clkdm",
- .enable_reg = OMAP_CM_REGADDR(GFX_MOD, CM_FCLKEN),
+ .clkdm = { .name = "gfx_clkdm" },
+ .enable_reg = CM_FCLKEN,
.enable_bit = OMAP24XX_EN_2D_SHIFT,
- .clksel_reg = OMAP_CM_REGADDR(GFX_MOD, CM_CLKSEL),
+ .clksel_reg = CM_CLKSEL,
.clksel_mask = OMAP_CLKSEL_GFX_MASK,
.clksel = gfx_fck_clksel,
.recalc = &omap2_clksel_recalc,
static struct clk gfx_ick = {
.name = "gfx_ick", /* From l3 */
.parent = &core_l3_ck,
+ .prcm_mod = GFX_MOD,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "gfx_clkdm",
- .enable_reg = OMAP_CM_REGADDR(GFX_MOD, CM_ICLKEN),
+ .clkdm = { .name = "gfx_clkdm" },
+ .enable_reg = CM_ICLKEN,
.enable_bit = OMAP_EN_GFX_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk mdm_ick = { /* used both as a ick and fck */
.name = "mdm_ick",
.parent = &core_ck,
- .flags = CLOCK_IN_OMAP243X | DELAYED_APP | CONFIG_PARTICIPANT,
- .clkdm_name = "mdm_clkdm",
- .enable_reg = OMAP_CM_REGADDR(OMAP2430_MDM_MOD, CM_ICLKEN),
+ .prcm_mod = OMAP2430_MDM_MOD,
+ .flags = CLOCK_IN_OMAP243X | DELAYED_APP,
+ .clkdm = { .name = "mdm_clkdm" },
+ .enable_reg = CM_ICLKEN,
.enable_bit = OMAP2430_CM_ICLKEN_MDM_EN_MDM_SHIFT,
- .clksel_reg = OMAP_CM_REGADDR(OMAP2430_MDM_MOD, CM_CLKSEL),
+ .clksel_reg = CM_CLKSEL,
.clksel_mask = OMAP2430_CLKSEL_MDM_MASK,
.clksel = mdm_ick_clksel,
.recalc = &omap2_clksel_recalc,
- .round_rate = &omap2_clksel_round_rate,
- .set_rate = &omap2_clksel_set_rate
};
static struct clk mdm_osc_ck = {
.name = "mdm_osc_ck",
.parent = &osc_ck,
+ .prcm_mod = OMAP2430_MDM_MOD,
.flags = CLOCK_IN_OMAP243X,
- .clkdm_name = "mdm_clkdm",
- .enable_reg = OMAP_CM_REGADDR(OMAP2430_MDM_MOD, CM_FCLKEN),
+ .clkdm = { .name = "mdm_clkdm" },
+ .enable_reg = CM_FCLKEN,
.enable_bit = OMAP2430_EN_OSC_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk dss_ick = { /* Enables both L3,L4 ICLK's */
.name = "dss_ick",
.parent = &l4_ck, /* really both l3 and l4 */
+ .prcm_mod = CORE_MOD,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "dss_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .clkdm = { .name = "dss_clkdm" },
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP24XX_EN_DSS1_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk dss1_fck = {
.name = "dss1_fck",
.parent = &core_ck, /* Core or sys */
+ .prcm_mod = CORE_MOD,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
DELAYED_APP,
- .clkdm_name = "dss_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .clkdm = { .name = "dss_clkdm" },
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP24XX_EN_DSS1_SHIFT,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1),
+ .clksel_reg = CM_CLKSEL1,
.clksel_mask = OMAP24XX_CLKSEL_DSS1_MASK,
.clksel = dss1_fck_clksel,
.recalc = &omap2_clksel_recalc,
static struct clk dss2_fck = { /* Alt clk used in power management */
.name = "dss2_fck",
.parent = &sys_ck, /* fixed at sys_ck or 48MHz */
+ .prcm_mod = CORE_MOD,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
DELAYED_APP,
- .clkdm_name = "dss_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .clkdm = { .name = "dss_clkdm" },
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP24XX_EN_DSS2_SHIFT,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1),
+ .clksel_reg = CM_CLKSEL1,
.clksel_mask = OMAP24XX_CLKSEL_DSS2_MASK,
.clksel = dss2_fck_clksel,
.recalc = &followparent_recalc,
static struct clk dss_54m_fck = { /* Alt clk used in power management */
.name = "dss_54m_fck", /* 54m tv clk */
.parent = &func_54m_ck,
+ .prcm_mod = CORE_MOD,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "dss_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .clkdm = { .name = "dss_clkdm" },
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP24XX_EN_TV_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk gpt1_ick = {
.name = "gpt1_ick",
.parent = &l4_ck,
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
+ .prcm_mod = WKUP_MOD,
+ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_ICLKEN,
.enable_bit = OMAP24XX_EN_GPT1_SHIFT,
+ .idlest_bit = OMAP24XX_ST_GPT1_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk gpt1_fck = {
.name = "gpt1_fck",
.parent = &func_32k_ck,
+ .prcm_mod = WKUP_MOD,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_FCLKEN),
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_FCLKEN,
.enable_bit = OMAP24XX_EN_GPT1_SHIFT,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_CLKSEL1),
+ .clksel_reg = CM_CLKSEL1,
.clksel_mask = OMAP24XX_CLKSEL_GPT1_MASK,
.clksel = omap24xx_gpt_clksel,
.recalc = &omap2_clksel_recalc,
static struct clk gpt2_ick = {
.name = "gpt2_ick",
.parent = &l4_ck,
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP24XX_EN_GPT2_SHIFT,
+ .idlest_bit = OMAP24XX_ST_GPT2_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk gpt2_fck = {
.name = "gpt2_fck",
.parent = &func_32k_ck,
+ .prcm_mod = CORE_MOD,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP24XX_EN_GPT2_SHIFT,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
+ .clksel_reg = CM_CLKSEL2,
.clksel_mask = OMAP24XX_CLKSEL_GPT2_MASK,
.clksel = omap24xx_gpt_clksel,
.recalc = &omap2_clksel_recalc,
static struct clk gpt3_ick = {
.name = "gpt3_ick",
.parent = &l4_ck,
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP24XX_EN_GPT3_SHIFT,
+ .idlest_bit = OMAP24XX_ST_GPT3_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk gpt3_fck = {
.name = "gpt3_fck",
.parent = &func_32k_ck,
+ .prcm_mod = CORE_MOD,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP24XX_EN_GPT3_SHIFT,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
+ .clksel_reg = CM_CLKSEL2,
.clksel_mask = OMAP24XX_CLKSEL_GPT3_MASK,
.clksel = omap24xx_gpt_clksel,
.recalc = &omap2_clksel_recalc,
static struct clk gpt4_ick = {
.name = "gpt4_ick",
.parent = &l4_ck,
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP24XX_EN_GPT4_SHIFT,
+ .idlest_bit = OMAP24XX_ST_GPT4_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk gpt4_fck = {
.name = "gpt4_fck",
.parent = &func_32k_ck,
+ .prcm_mod = CORE_MOD,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP24XX_EN_GPT4_SHIFT,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
+ .clksel_reg = CM_CLKSEL2,
.clksel_mask = OMAP24XX_CLKSEL_GPT4_MASK,
.clksel = omap24xx_gpt_clksel,
.recalc = &omap2_clksel_recalc,
static struct clk gpt5_ick = {
.name = "gpt5_ick",
.parent = &l4_ck,
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP24XX_EN_GPT5_SHIFT,
+ .idlest_bit = OMAP24XX_ST_GPT5_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk gpt5_fck = {
.name = "gpt5_fck",
.parent = &func_32k_ck,
+ .prcm_mod = CORE_MOD,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP24XX_EN_GPT5_SHIFT,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
+ .clksel_reg = CM_CLKSEL2,
.clksel_mask = OMAP24XX_CLKSEL_GPT5_MASK,
.clksel = omap24xx_gpt_clksel,
.recalc = &omap2_clksel_recalc,
static struct clk gpt6_ick = {
.name = "gpt6_ick",
.parent = &l4_ck,
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP24XX_EN_GPT6_SHIFT,
+ .idlest_bit = OMAP24XX_ST_GPT6_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk gpt6_fck = {
.name = "gpt6_fck",
.parent = &func_32k_ck,
+ .prcm_mod = CORE_MOD,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP24XX_EN_GPT6_SHIFT,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
+ .clksel_reg = CM_CLKSEL2,
.clksel_mask = OMAP24XX_CLKSEL_GPT6_MASK,
.clksel = omap24xx_gpt_clksel,
.recalc = &omap2_clksel_recalc,
static struct clk gpt7_ick = {
.name = "gpt7_ick",
.parent = &l4_ck,
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP24XX_EN_GPT7_SHIFT,
+ .idlest_bit = OMAP24XX_ST_GPT7_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk gpt7_fck = {
.name = "gpt7_fck",
.parent = &func_32k_ck,
+ .prcm_mod = CORE_MOD,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP24XX_EN_GPT7_SHIFT,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
+ .clksel_reg = CM_CLKSEL2,
.clksel_mask = OMAP24XX_CLKSEL_GPT7_MASK,
.clksel = omap24xx_gpt_clksel,
.recalc = &omap2_clksel_recalc,
static struct clk gpt8_ick = {
.name = "gpt8_ick",
.parent = &l4_ck,
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP24XX_EN_GPT8_SHIFT,
+ .idlest_bit = OMAP24XX_ST_GPT8_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk gpt8_fck = {
.name = "gpt8_fck",
.parent = &func_32k_ck,
+ .prcm_mod = CORE_MOD,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP24XX_EN_GPT8_SHIFT,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
+ .clksel_reg = CM_CLKSEL2,
.clksel_mask = OMAP24XX_CLKSEL_GPT8_MASK,
.clksel = omap24xx_gpt_clksel,
.recalc = &omap2_clksel_recalc,
static struct clk gpt9_ick = {
.name = "gpt9_ick",
.parent = &l4_ck,
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP24XX_EN_GPT9_SHIFT,
+ .idlest_bit = OMAP24XX_ST_GPT9_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk gpt9_fck = {
.name = "gpt9_fck",
.parent = &func_32k_ck,
+ .prcm_mod = CORE_MOD,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP24XX_EN_GPT9_SHIFT,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
+ .clksel_reg = CM_CLKSEL2,
.clksel_mask = OMAP24XX_CLKSEL_GPT9_MASK,
.clksel = omap24xx_gpt_clksel,
.recalc = &omap2_clksel_recalc,
static struct clk gpt10_ick = {
.name = "gpt10_ick",
.parent = &l4_ck,
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP24XX_EN_GPT10_SHIFT,
+ .idlest_bit = OMAP24XX_ST_GPT10_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk gpt10_fck = {
.name = "gpt10_fck",
.parent = &func_32k_ck,
+ .prcm_mod = CORE_MOD,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP24XX_EN_GPT10_SHIFT,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
+ .clksel_reg = CM_CLKSEL2,
.clksel_mask = OMAP24XX_CLKSEL_GPT10_MASK,
.clksel = omap24xx_gpt_clksel,
.recalc = &omap2_clksel_recalc,
static struct clk gpt11_ick = {
.name = "gpt11_ick",
.parent = &l4_ck,
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP24XX_EN_GPT11_SHIFT,
+ .idlest_bit = OMAP24XX_ST_GPT11_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk gpt11_fck = {
.name = "gpt11_fck",
.parent = &func_32k_ck,
+ .prcm_mod = CORE_MOD,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP24XX_EN_GPT11_SHIFT,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
+ .clksel_reg = CM_CLKSEL2,
.clksel_mask = OMAP24XX_CLKSEL_GPT11_MASK,
.clksel = omap24xx_gpt_clksel,
.recalc = &omap2_clksel_recalc,
static struct clk gpt12_ick = {
.name = "gpt12_ick",
.parent = &l4_ck,
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP24XX_EN_GPT12_SHIFT,
+ .idlest_bit = OMAP24XX_ST_GPT12_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk gpt12_fck = {
.name = "gpt12_fck",
.parent = &func_32k_ck,
+ .prcm_mod = CORE_MOD,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP24XX_EN_GPT12_SHIFT,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
+ .clksel_reg = CM_CLKSEL2,
.clksel_mask = OMAP24XX_CLKSEL_GPT12_MASK,
.clksel = omap24xx_gpt_clksel,
.recalc = &omap2_clksel_recalc,
.name = "mcbsp_ick",
.id = 1,
.parent = &l4_ck,
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP24XX_EN_MCBSP1_SHIFT,
+ .idlest_bit = OMAP24XX_ST_MCBSP1_SHIFT,
.recalc = &followparent_recalc,
};
.name = "mcbsp_fck",
.id = 1,
.parent = &func_96m_ck,
+ .prcm_mod = CORE_MOD,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP24XX_EN_MCBSP1_SHIFT,
.recalc = &followparent_recalc,
};
.name = "mcbsp_ick",
.id = 2,
.parent = &l4_ck,
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP24XX_EN_MCBSP2_SHIFT,
+ .idlest_bit = OMAP24XX_ST_MCBSP2_SHIFT,
.recalc = &followparent_recalc,
};
.name = "mcbsp_fck",
.id = 2,
.parent = &func_96m_ck,
+ .prcm_mod = CORE_MOD,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP24XX_EN_MCBSP2_SHIFT,
.recalc = &followparent_recalc,
};
.name = "mcbsp_ick",
.id = 3,
.parent = &l4_ck,
- .flags = CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP243X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_ICLKEN2,
.enable_bit = OMAP2430_EN_MCBSP3_SHIFT,
+ .idlest_bit = OMAP2430_ST_MCBSP3_SHIFT,
.recalc = &followparent_recalc,
};
.name = "mcbsp_fck",
.id = 3,
.parent = &func_96m_ck,
+ .prcm_mod = CORE_MOD,
.flags = CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = OMAP24XX_CM_FCLKEN2,
.enable_bit = OMAP2430_EN_MCBSP3_SHIFT,
.recalc = &followparent_recalc,
};
.name = "mcbsp_ick",
.id = 4,
.parent = &l4_ck,
- .flags = CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP243X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_ICLKEN2,
.enable_bit = OMAP2430_EN_MCBSP4_SHIFT,
+ .idlest_bit = OMAP2430_ST_MCBSP4_SHIFT,
.recalc = &followparent_recalc,
};
.name = "mcbsp_fck",
.id = 4,
.parent = &func_96m_ck,
+ .prcm_mod = CORE_MOD,
.flags = CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = OMAP24XX_CM_FCLKEN2,
.enable_bit = OMAP2430_EN_MCBSP4_SHIFT,
.recalc = &followparent_recalc,
};
.name = "mcbsp_ick",
.id = 5,
.parent = &l4_ck,
- .flags = CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP243X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_ICLKEN2,
.enable_bit = OMAP2430_EN_MCBSP5_SHIFT,
+ .idlest_bit = OMAP2430_ST_MCBSP5_SHIFT,
.recalc = &followparent_recalc,
};
.name = "mcbsp_fck",
.id = 5,
.parent = &func_96m_ck,
+ .prcm_mod = CORE_MOD,
.flags = CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = OMAP24XX_CM_FCLKEN2,
.enable_bit = OMAP2430_EN_MCBSP5_SHIFT,
.recalc = &followparent_recalc,
};
.name = "mcspi_ick",
.id = 1,
.parent = &l4_ck,
- .clkdm_name = "core_l4_clkdm",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP24XX_EN_MCSPI1_SHIFT,
+ .idlest_bit = OMAP24XX_ST_MCSPI1_SHIFT,
.recalc = &followparent_recalc,
};
.name = "mcspi_fck",
.id = 1,
.parent = &func_48m_ck,
+ .prcm_mod = CORE_MOD,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP24XX_EN_MCSPI1_SHIFT,
.recalc = &followparent_recalc,
};
.name = "mcspi_ick",
.id = 2,
.parent = &l4_ck,
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP24XX_EN_MCSPI2_SHIFT,
+ .idlest_bit = OMAP24XX_ST_MCSPI2_SHIFT,
.recalc = &followparent_recalc,
};
.name = "mcspi_fck",
.id = 2,
.parent = &func_48m_ck,
+ .prcm_mod = CORE_MOD,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP24XX_EN_MCSPI2_SHIFT,
.recalc = &followparent_recalc,
};
.name = "mcspi_ick",
.id = 3,
.parent = &l4_ck,
- .flags = CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP243X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_ICLKEN2,
.enable_bit = OMAP2430_EN_MCSPI3_SHIFT,
+ .idlest_bit = OMAP2430_ST_MCSPI3_SHIFT,
.recalc = &followparent_recalc,
};
.name = "mcspi_fck",
.id = 3,
.parent = &func_48m_ck,
+ .prcm_mod = CORE_MOD,
.flags = CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = OMAP24XX_CM_FCLKEN2,
.enable_bit = OMAP2430_EN_MCSPI3_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk uart1_ick = {
.name = "uart1_ick",
.parent = &l4_ck,
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP24XX_EN_UART1_SHIFT,
+ .idlest_bit = OMAP24XX_ST_UART1_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk uart1_fck = {
.name = "uart1_fck",
.parent = &func_48m_ck,
+ .prcm_mod = CORE_MOD,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP24XX_EN_UART1_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk uart2_ick = {
.name = "uart2_ick",
.parent = &l4_ck,
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP24XX_EN_UART2_SHIFT,
+ .idlest_bit = OMAP24XX_ST_UART2_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk uart2_fck = {
.name = "uart2_fck",
.parent = &func_48m_ck,
+ .prcm_mod = CORE_MOD,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP24XX_EN_UART2_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk uart3_ick = {
.name = "uart3_ick",
.parent = &l4_ck,
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_ICLKEN2,
.enable_bit = OMAP24XX_EN_UART3_SHIFT,
+ .idlest_bit = OMAP24XX_ST_UART3_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk uart3_fck = {
.name = "uart3_fck",
.parent = &func_48m_ck,
+ .prcm_mod = CORE_MOD,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = OMAP24XX_CM_FCLKEN2,
.enable_bit = OMAP24XX_EN_UART3_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk gpios_ick = {
.name = "gpios_ick",
.parent = &l4_ck,
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
+ .prcm_mod = WKUP_MOD,
+ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_ICLKEN,
.enable_bit = OMAP24XX_EN_GPIOS_SHIFT,
+ .idlest_bit = OMAP24XX_ST_GPIOS_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk gpios_fck = {
.name = "gpios_fck",
.parent = &func_32k_ck,
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "wkup_clkdm",
- .enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_FCLKEN),
+ .prcm_mod = WKUP_MOD,
+ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+ .clkdm = { .name = "prm_clkdm" },
+ .enable_reg = CM_FCLKEN,
.enable_bit = OMAP24XX_EN_GPIOS_SHIFT,
+ .idlest_bit = OMAP24XX_ST_GPIOS_SHIFT,
.recalc = &followparent_recalc,
};
+/* aka WDT2 - REVISIT: we should split wu_l4_iclk from l4_ck */
static struct clk mpu_wdt_ick = {
.name = "mpu_wdt_ick",
.parent = &l4_ck,
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
+ .prcm_mod = WKUP_MOD,
+ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+ .clkdm = { .name = "prm_clkdm" },
+ .enable_reg = CM_ICLKEN,
.enable_bit = OMAP24XX_EN_MPU_WDT_SHIFT,
+ .idlest_bit = OMAP24XX_ST_MPU_WDT_SHIFT,
.recalc = &followparent_recalc,
};
+/* aka WDT2 */
static struct clk mpu_wdt_fck = {
.name = "mpu_wdt_fck",
.parent = &func_32k_ck,
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "wkup_clkdm",
- .enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_FCLKEN),
+ .prcm_mod = WKUP_MOD,
+ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+ .clkdm = { .name = "prm_clkdm" },
+ .enable_reg = CM_FCLKEN,
.enable_bit = OMAP24XX_EN_MPU_WDT_SHIFT,
+ .idlest_bit = OMAP24XX_ST_MPU_WDT_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk sync_32k_ick = {
.name = "sync_32k_ick",
.parent = &l4_ck,
+ .prcm_mod = WKUP_MOD,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
- ENABLE_ON_INIT,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
+ ENABLE_ON_INIT | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_ICLKEN,
.enable_bit = OMAP24XX_EN_32KSYNC_SHIFT,
+ .idlest_bit = OMAP24XX_ST_32KSYNC_SHIFT,
.recalc = &followparent_recalc,
};
+/* REVISIT: parent is really wu_l4_iclk */
static struct clk wdt1_ick = {
.name = "wdt1_ick",
.parent = &l4_ck,
+ .prcm_mod = WKUP_MOD,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
+ .clkdm = { .name = "prm_clkdm" },
+ .enable_reg = CM_ICLKEN,
.enable_bit = OMAP24XX_EN_WDT1_SHIFT,
+ .idlest_bit = OMAP24XX_ST_WDT1_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk omapctrl_ick = {
.name = "omapctrl_ick",
.parent = &l4_ck,
+ .prcm_mod = WKUP_MOD,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
ENABLE_ON_INIT,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_ICLKEN,
.enable_bit = OMAP24XX_EN_OMAPCTRL_SHIFT,
+ .idlest_bit = OMAP24XX_ST_OMAPCTRL_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk icr_ick = {
.name = "icr_ick",
.parent = &l4_ck,
- .flags = CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
+ .prcm_mod = WKUP_MOD,
+ .flags = CLOCK_IN_OMAP243X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_ICLKEN,
.enable_bit = OMAP2430_EN_ICR_SHIFT,
+ .idlest_bit = OMAP2430_ST_ICR_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk cam_ick = {
.name = "cam_ick",
.parent = &l4_ck,
+ .prcm_mod = CORE_MOD,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP24XX_EN_CAM_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk cam_fck = {
.name = "cam_fck",
.parent = &func_96m_ck,
+ .prcm_mod = CORE_MOD,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l3_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .clkdm = { .name = "core_l3_clkdm" },
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP24XX_EN_CAM_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk mailboxes_ick = {
.name = "mailboxes_ick",
.parent = &l4_ck,
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP24XX_EN_MAILBOXES_SHIFT,
+ .idlest_bit = OMAP24XX_ST_MAILBOXES_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk wdt4_ick = {
.name = "wdt4_ick",
.parent = &l4_ck,
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP24XX_EN_WDT4_SHIFT,
+ .idlest_bit = OMAP24XX_ST_WDT4_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk wdt4_fck = {
.name = "wdt4_fck",
.parent = &func_32k_ck,
+ .prcm_mod = CORE_MOD,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP24XX_EN_WDT4_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk wdt3_ick = {
.name = "wdt3_ick",
.parent = &l4_ck,
- .flags = CLOCK_IN_OMAP242X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP242X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP2420_EN_WDT3_SHIFT,
+ .idlest_bit = OMAP2420_ST_WDT3_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk wdt3_fck = {
.name = "wdt3_fck",
.parent = &func_32k_ck,
- .flags = CLOCK_IN_OMAP242X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP242X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP2420_EN_WDT3_SHIFT,
+ .enable_bit = OMAP2420_ST_WDT3_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk mspro_ick = {
.name = "mspro_ick",
.parent = &l4_ck,
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP24XX_EN_MSPRO_SHIFT,
+ .idlest_bit = OMAP24XX_ST_MSPRO_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk mspro_fck = {
.name = "mspro_fck",
.parent = &func_96m_ck,
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP24XX_EN_MSPRO_SHIFT,
+ .idlest_bit = OMAP24XX_ST_MSPRO_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk mmc_ick = {
.name = "mmc_ick",
.parent = &l4_ck,
- .flags = CLOCK_IN_OMAP242X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP242X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP2420_EN_MMC_SHIFT,
+ .idlest_bit = OMAP2420_ST_MMC_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk mmc_fck = {
.name = "mmc_fck",
.parent = &func_96m_ck,
- .flags = CLOCK_IN_OMAP242X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP242X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP2420_EN_MMC_SHIFT,
+ .idlest_bit = OMAP2420_ST_MMC_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk fac_ick = {
.name = "fac_ick",
.parent = &l4_ck,
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP24XX_EN_FAC_SHIFT,
+ .idlest_bit = OMAP24XX_ST_FAC_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk fac_fck = {
.name = "fac_fck",
.parent = &func_12m_ck,
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP24XX_EN_FAC_SHIFT,
+ .idlest_bit = OMAP24XX_ST_FAC_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk eac_ick = {
.name = "eac_ick",
.parent = &l4_ck,
- .flags = CLOCK_IN_OMAP242X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP242X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP2420_EN_EAC_SHIFT,
+ .idlest_bit = OMAP2420_ST_EAC_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk eac_fck = {
.name = "eac_fck",
.parent = &func_96m_ck,
- .flags = CLOCK_IN_OMAP242X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP242X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP2420_EN_EAC_SHIFT,
+ .idlest_bit = OMAP2420_ST_EAC_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk hdq_ick = {
.name = "hdq_ick",
.parent = &l4_ck,
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP24XX_EN_HDQ_SHIFT,
+ .idlest_bit = OMAP24XX_ST_HDQ_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk hdq_fck = {
.name = "hdq_fck",
.parent = &func_12m_ck,
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP24XX_EN_HDQ_SHIFT,
+ .idlest_bit = OMAP24XX_ST_HDQ_SHIFT,
.recalc = &followparent_recalc,
};
.name = "i2c_ick",
.id = 2,
.parent = &l4_ck,
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP2420_EN_I2C2_SHIFT,
+ .idlest_bit = OMAP2420_ST_I2C2_SHIFT,
.recalc = &followparent_recalc,
};
.name = "i2c_fck",
.id = 2,
.parent = &func_12m_ck,
- .flags = CLOCK_IN_OMAP242X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP242X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP2420_EN_I2C2_SHIFT,
+ .idlest_bit = OMAP2420_ST_I2C2_SHIFT,
.recalc = &followparent_recalc,
};
.name = "i2c_fck",
.id = 2,
.parent = &func_96m_ck,
+ .prcm_mod = CORE_MOD,
.flags = CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = OMAP24XX_CM_FCLKEN2,
.enable_bit = OMAP2430_EN_I2CHS2_SHIFT,
.recalc = &followparent_recalc,
};
.name = "i2c_ick",
.id = 1,
.parent = &l4_ck,
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP2420_EN_I2C1_SHIFT,
+ .idlest_bit = OMAP2420_ST_I2C1_SHIFT,
.recalc = &followparent_recalc,
};
.name = "i2c_fck",
.id = 1,
.parent = &func_12m_ck,
- .flags = CLOCK_IN_OMAP242X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP242X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP2420_EN_I2C1_SHIFT,
+ .idlest_bit = OMAP2420_ST_I2C1_SHIFT,
.recalc = &followparent_recalc,
};
.name = "i2c_fck",
.id = 1,
.parent = &func_96m_ck,
+ .prcm_mod = CORE_MOD,
.flags = CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = OMAP24XX_CM_FCLKEN2,
.enable_bit = OMAP2430_EN_I2CHS1_SHIFT,
.recalc = &followparent_recalc,
};
.parent = &core_l3_ck,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
ENABLE_ON_INIT,
- .clkdm_name = "core_l3_clkdm",
+ .clkdm = { .name = "core_l3_clkdm" },
.recalc = &followparent_recalc,
};
.name = "sdma_fck",
.parent = &core_l3_ck,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l3_clkdm",
+ .clkdm = { .name = "core_l3_clkdm" },
.recalc = &followparent_recalc,
};
.name = "sdma_ick",
.parent = &l4_ck,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l3_clkdm",
+ .clkdm = { .name = "core_l3_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk vlynq_ick = {
.name = "vlynq_ick",
.parent = &core_l3_ck,
- .flags = CLOCK_IN_OMAP242X,
- .clkdm_name = "core_l3_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP242X | WAIT_READY,
+ .clkdm = { .name = "core_l3_clkdm" },
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP2420_EN_VLYNQ_SHIFT,
+ .idlest_bit = OMAP2420_ST_VLYNQ_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk vlynq_fck = {
.name = "vlynq_fck",
.parent = &func_96m_ck,
- .flags = CLOCK_IN_OMAP242X | DELAYED_APP,
- .clkdm_name = "core_l3_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP242X | DELAYED_APP | WAIT_READY,
+ .clkdm = { .name = "core_l3_clkdm" },
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP2420_EN_VLYNQ_SHIFT,
+ .idlest_bit = OMAP2420_ST_VLYNQ_SHIFT,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1),
+ .clksel_reg = CM_CLKSEL1,
.clksel_mask = OMAP2420_CLKSEL_VLYNQ_MASK,
.clksel = vlynq_fck_clksel,
.recalc = &omap2_clksel_recalc,
static struct clk sdrc_ick = {
.name = "sdrc_ick",
.parent = &l4_ck,
- .flags = CLOCK_IN_OMAP243X | ENABLE_ON_INIT,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN3),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP243X | WAIT_READY | ENABLE_ON_INIT,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_ICLKEN3,
.enable_bit = OMAP2430_EN_SDRC_SHIFT,
+ .idlest_bit = OMAP2430_ST_SDRC_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk des_ick = {
.name = "des_ick",
.parent = &l4_ck,
- .flags = CLOCK_IN_OMAP243X | CLOCK_IN_OMAP242X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_ICLKEN4),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP243X | CLOCK_IN_OMAP242X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = OMAP24XX_CM_ICLKEN4,
.enable_bit = OMAP24XX_EN_DES_SHIFT,
+ .idlest_bit = OMAP24XX_ST_DES_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk sha_ick = {
.name = "sha_ick",
.parent = &l4_ck,
- .flags = CLOCK_IN_OMAP243X | CLOCK_IN_OMAP242X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_ICLKEN4),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP243X | CLOCK_IN_OMAP242X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = OMAP24XX_CM_ICLKEN4,
.enable_bit = OMAP24XX_EN_SHA_SHIFT,
+ .idlest_bit = OMAP24XX_ST_SHA_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk rng_ick = {
.name = "rng_ick",
.parent = &l4_ck,
- .flags = CLOCK_IN_OMAP243X | CLOCK_IN_OMAP242X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_ICLKEN4),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP243X | CLOCK_IN_OMAP242X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = OMAP24XX_CM_ICLKEN4,
.enable_bit = OMAP24XX_EN_RNG_SHIFT,
+ .idlest_bit = OMAP24XX_ST_RNG_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk aes_ick = {
.name = "aes_ick",
.parent = &l4_ck,
- .flags = CLOCK_IN_OMAP243X | CLOCK_IN_OMAP242X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_ICLKEN4),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP243X | CLOCK_IN_OMAP242X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = OMAP24XX_CM_ICLKEN4,
.enable_bit = OMAP24XX_EN_AES_SHIFT,
+ .idlest_bit = OMAP24XX_ST_AES_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk pka_ick = {
.name = "pka_ick",
.parent = &l4_ck,
- .flags = CLOCK_IN_OMAP243X | CLOCK_IN_OMAP242X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_ICLKEN4),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP243X | CLOCK_IN_OMAP242X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = OMAP24XX_CM_ICLKEN4,
.enable_bit = OMAP24XX_EN_PKA_SHIFT,
+ .idlest_bit = OMAP24XX_ST_PKA_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk usb_fck = {
.name = "usb_fck",
.parent = &func_48m_ck,
- .flags = CLOCK_IN_OMAP243X | CLOCK_IN_OMAP242X,
- .clkdm_name = "core_l3_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP243X | CLOCK_IN_OMAP242X | WAIT_READY,
+ .clkdm = { .name = "core_l3_clkdm" },
+ .enable_reg = OMAP24XX_CM_FCLKEN2,
.enable_bit = OMAP24XX_EN_USB_SHIFT,
+ .idlest_bit = OMAP24XX_ST_USB_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk usbhs_ick = {
.name = "usbhs_ick",
.parent = &core_l3_ck,
- .flags = CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l3_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP243X | WAIT_READY,
+ .clkdm = { .name = "core_l3_clkdm" },
+ .enable_reg = CM_ICLKEN2,
.enable_bit = OMAP2430_EN_USBHS_SHIFT,
+ .idlest_bit = OMAP2430_ST_USBHS_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk mmchs1_ick = {
.name = "mmchs_ick",
.parent = &l4_ck,
- .flags = CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP243X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_ICLKEN2,
.enable_bit = OMAP2430_EN_MMCHS1_SHIFT,
+ .idlest_bit = OMAP2430_ST_MMCHS1_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk mmchs1_fck = {
.name = "mmchs_fck",
.parent = &func_96m_ck,
+ .prcm_mod = CORE_MOD,
.flags = CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l3_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
+ .clkdm = { .name = "core_l3_clkdm" },
+ .enable_reg = OMAP24XX_CM_FCLKEN2,
.enable_bit = OMAP2430_EN_MMCHS1_SHIFT,
.recalc = &followparent_recalc,
};
.name = "mmchs_ick",
.id = 1,
.parent = &l4_ck,
- .flags = CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP243X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_ICLKEN2,
.enable_bit = OMAP2430_EN_MMCHS2_SHIFT,
+ .idlest_bit = OMAP2430_ST_MMCHS2_SHIFT,
.recalc = &followparent_recalc,
};
.name = "mmchs_fck",
.id = 1,
.parent = &func_96m_ck,
+ .prcm_mod = CORE_MOD,
.flags = CLOCK_IN_OMAP243X,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = OMAP24XX_CM_FCLKEN2,
.enable_bit = OMAP2430_EN_MMCHS2_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk gpio5_ick = {
.name = "gpio5_ick",
.parent = &l4_ck,
- .flags = CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP243X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_ICLKEN2,
.enable_bit = OMAP2430_EN_GPIO5_SHIFT,
+ .idlest_bit = OMAP2430_ST_GPIO5_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk gpio5_fck = {
.name = "gpio5_fck",
.parent = &func_32k_ck,
+ .prcm_mod = CORE_MOD,
.flags = CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = OMAP24XX_CM_FCLKEN2,
.enable_bit = OMAP2430_EN_GPIO5_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk mdm_intc_ick = {
.name = "mdm_intc_ick",
.parent = &l4_ck,
- .flags = CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
+ .prcm_mod = CORE_MOD,
+ .flags = CLOCK_IN_OMAP243X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = CM_ICLKEN2,
.enable_bit = OMAP2430_EN_MDM_INTC_SHIFT,
+ .idlest_bit = OMAP2430_ST_MDM_INTC_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk mmchsdb1_fck = {
.name = "mmchsdb_fck",
.parent = &func_32k_ck,
+ .prcm_mod = CORE_MOD,
.flags = CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = OMAP24XX_CM_FCLKEN2,
.enable_bit = OMAP2430_EN_MMCHSDB1_SHIFT,
.recalc = &followparent_recalc,
};
.name = "mmchsdb_fck",
.id = 1,
.parent = &func_32k_ck,
+ .prcm_mod = CORE_MOD,
.flags = CLOCK_IN_OMAP243X,
- .clkdm_name = "core_l4_clkdm",
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
+ .clkdm = { .name = "core_l4_clkdm" },
+ .enable_reg = OMAP24XX_CM_FCLKEN2,
.enable_bit = OMAP2430_EN_MMCHSDB2_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk virt_prcm_set = {
.name = "virt_prcm_set",
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
- VIRTUAL_CLOCK | ALWAYS_ENABLED | DELAYED_APP,
+ ALWAYS_ENABLED | DELAYED_APP,
+ .clkdm = { .name = "virt_opp_clkdm" },
.parent = &mpu_ck, /* Indexed by mpu speed, no parent */
.recalc = &omap2_table_mpu_recalc, /* sets are keyed on mpu rate */
.set_rate = &omap2_select_table_rate,
&usb_l4_ick,
/* L4 domain clocks */
&l4_ck, /* used as both core_l4 and wu_l4 */
+ &ssi_l4_ick,
/* virtual meta-group clock */
&virt_prcm_set,
/* general l4 interface ck, multi-parent functional clk */
#include <mach/sram.h>
#include <asm/div64.h>
-#include "memory.h"
+#include <mach/sdrc.h>
#include "clock.h"
#include "clock34xx.h"
#include "prm.h"
/**
* omap3_dpll_recalc - recalculate DPLL rate
* @clk: DPLL struct clk
+ * @parent_rate: rate of the DPLL's parent clock
+ * @rate_storage: flag indicating whether current or temporary rate is changing
*
* Recalculate and propagate the DPLL rate.
*/
-static void omap3_dpll_recalc(struct clk *clk)
+static void omap3_dpll_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage)
{
- clk->rate = omap2_get_dpll_rate(clk);
+ unsigned long rate;
- propagate_rate(clk);
+ rate = omap2_get_dpll_rate(clk, parent_rate);
+
+ if (rate_storage == CURRENT_RATE)
+ clk->rate = rate;
+ else if (rate_storage == TEMP_RATE)
+ clk->temp_rate = rate;
}
/* _omap3_dpll_write_clken - write clken_bits arg to a DPLL's enable bits */
dd = clk->dpll_data;
- v = __raw_readl(dd->control_reg);
+ v = cm_read_mod_reg(clk->prcm_mod, dd->control_reg);
v &= ~dd->enable_mask;
v |= clken_bits << __ffs(dd->enable_mask);
- __raw_writel(v, dd->control_reg);
+ cm_write_mod_reg(v, clk->prcm_mod, dd->control_reg);
}
/* _omap3_wait_dpll_status: wait for a DPLL to enter a specific 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;
+ state <<= __ffs(dd->idlest_mask);
- while (((__raw_readl(dd->idlest_reg) & idlest_mask) != state) &&
+ while (((cm_read_mod_reg(clk->prcm_mod, dd->idlest_reg)
+ & dd->idlest_mask) != state) &&
i < MAX_DPLL_WAIT_TRIES) {
i++;
udelay(1);
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 */
/*
ai = omap3_dpll_autoidle_read(clk);
+ omap3_dpll_deny_idle(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;
+ r = _omap3_wait_dpll_status(clk, 1);
+
+ if (ai)
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
+ * _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
static int omap3_noncore_dpll_enable(struct clk *clk)
{
int r;
+ struct dpll_data *dd;
if (clk == &dpll3_ck)
return -EINVAL;
- if (clk->parent->rate == clk_get_rate(clk))
+ dd = clk->dpll_data;
+ if (!dd)
+ return -EINVAL;
+
+ if (clk->rate == dd->bypass_clk->rate)
r = _omap3_noncore_dpll_bypass(clk);
else
r = _omap3_noncore_dpll_lock(clk);
_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 (omap_rev() == 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);
+
+ /* Set jitter correction */
+ v = cm_read_mod_reg(clk->prcm_mod, dd->control_reg);
+ v &= ~dd->freqsel_mask;
+ v |= freqsel << __ffs(dd->freqsel_mask);
+ cm_write_mod_reg(v, clk->prcm_mod, dd->control_reg);
+
+ /* Set DPLL multiplier, divider */
+ v = cm_read_mod_reg(clk->prcm_mod, dd->mult_div1_reg);
+ v &= ~(dd->mult_mask | dd->div1_mask);
+ v |= m << __ffs(dd->mult_mask);
+ v |= (n - 1) << __ffs(dd->div1_mask);
+ cm_write_mod_reg(v, clk->prcm_mod, 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
+ *
+ * Set the DPLL CLKOUT to the target rate. If the DPLL can enter
+ * low-power bypass, and the target rate is the bypass source clock
+ * rate, then configure the DPLL for bypass. Otherwise, round the
+ * target rate if it hasn't been done already, then program and lock
+ * the DPLL. 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;
+ int ret;
+
+ if (!clk || !rate)
+ return -EINVAL;
+
+ dd = clk->dpll_data;
+ if (!dd)
+ return -EINVAL;
+
+ if (rate == omap2_get_dpll_rate(clk, clk->parent->rate))
+ return 0;
+
+ if (dd->bypass_clk->rate == rate &&
+ (clk->dpll_data->modes & (1 << DPLL_LOW_POWER_BYPASS))) {
+
+ pr_debug("clock: %s: set rate: entering bypass.\n", clk->name);
+
+ ret = _omap3_noncore_dpll_bypass(clk);
+ if (!ret)
+ clk->rate = rate;
+
+ } else {
+
+ 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);
+
+ pr_debug("clock: %s: set rate: locking rate to %lu.\n",
+ clk->name, rate);
+
+ ret = omap3_noncore_dpll_program(clk, dd->last_rounded_m,
+ dd->last_rounded_n, freqsel);
+
+ if (!ret)
+ clk->rate = rate;
+
+ }
+
+ return 0;
+}
+
+
+/*
+ * CORE DPLL (DPLL3) rate programming functions
+ *
+ * These call into SRAM code to do the actual CM writes, since the SDRAM
+ * is clocked from DPLL3.
+ */
+
+/**
+ * omap3_core_dpll_m2_set_rate - set CORE DPLL M2 divider
+ * @clk: struct clk * of DPLL to set
+ * @rate: rounded target rate
+ *
+ * Program the DPLL M2 divider with the rounded target rate. Returns
+ * -EINVAL upon error, or 0 upon success.
+ */
+static int omap3_core_dpll_m2_set_rate(struct clk *clk, unsigned long rate)
+{
+ u32 new_div = 0;
+ unsigned long validrate, sdrcrate;
+ struct omap_sdrc_params *sp;
+
+ if (!clk || !rate)
+ return -EINVAL;
+
+ if (clk != &dpll3_m2_ck)
+ return -EINVAL;
+
+ if (rate == clk->rate)
+ return 0;
+
+ validrate = omap2_clksel_round_rate_div(clk, rate, &new_div);
+ if (validrate != rate)
+ return -EINVAL;
+
+ sdrcrate = sdrc_ick.rate;
+ if (rate > clk->rate)
+ sdrcrate <<= ((rate / clk->rate) - 1);
+ else
+ sdrcrate >>= ((clk->rate / rate) - 1);
+
+ sp = omap2_sdrc_get_params(sdrcrate);
+ if (!sp)
+ return -EINVAL;
+
+ pr_info("clock: changing CORE DPLL rate from %lu to %lu\n", clk->rate,
+ validrate);
+ pr_info("clock: SDRC timing params used: %08x %08x %08x\n",
+ sp->rfr_ctrl, sp->actim_ctrla, sp->actim_ctrlb);
+
+ /* REVISIT: SRAM code doesn't support other M2 divisors yet */
+ WARN_ON(new_div != 1 && new_div != 2);
+
+ /* REVISIT: Add SDRC_MR changing to this code also */
+ omap3_configure_core_dpll(sp->rfr_ctrl, sp->actim_ctrla,
+ sp->actim_ctrlb, new_div);
+
+ 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
dd = clk->dpll_data;
- v = __raw_readl(dd->autoidle_reg);
+ v = cm_read_mod_reg(clk->prcm_mod, dd->autoidle_reg);
v &= dd->autoidle_mask;
v >>= __ffs(dd->autoidle_mask);
* by writing 0x5 instead of 0x1. Add some mechanism to
* optionally enter this mode.
*/
- v = __raw_readl(dd->autoidle_reg);
+ v = cm_read_mod_reg(clk->prcm_mod, dd->autoidle_reg);
v &= ~dd->autoidle_mask;
v |= DPLL_AUTOIDLE_LOW_POWER_STOP << __ffs(dd->autoidle_mask);
- __raw_writel(v, dd->autoidle_reg);
+ cm_write_mod_reg(v, clk->prcm_mod, dd->autoidle_reg);
}
/**
dd = clk->dpll_data;
- v = __raw_readl(dd->autoidle_reg);
+ v = cm_read_mod_reg(clk->prcm_mod, dd->autoidle_reg);
v &= ~dd->autoidle_mask;
v |= DPLL_AUTOIDLE_DISABLE << __ffs(dd->autoidle_mask);
- __raw_writel(v, dd->autoidle_reg);
+ cm_write_mod_reg(v, clk->prcm_mod, dd->autoidle_reg);
}
/* Clock control for DPLL outputs */
/**
* omap3_clkoutx2_recalc - recalculate DPLL X2 output virtual clock rate
* @clk: DPLL output struct clk
+ * @parent_rate: rate of the parent clock of @clk
+ * @rate_storage: flag indicating whether current or temporary rate is changing
*
* Using parent clock DPLL data, look up DPLL state. If locked, set our
* rate to the dpll_clk * 2; otherwise, just use dpll_clk.
*/
-static void omap3_clkoutx2_recalc(struct clk *clk)
+static void omap3_clkoutx2_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage)
{
const struct dpll_data *dd;
u32 v;
+ unsigned long rate;
struct clk *pclk;
/* Walk up the parents of clk, looking for a DPLL */
dd = pclk->dpll_data;
- WARN_ON(!dd->control_reg || !dd->enable_mask);
+ WARN_ON(!dd->enable_mask);
- v = __raw_readl(dd->control_reg) & dd->enable_mask;
+ rate = parent_rate;
+
+ v = cm_read_mod_reg(pclk->prcm_mod, dd->control_reg) & dd->enable_mask;
v >>= __ffs(dd->enable_mask);
- if (v != DPLL_LOCKED)
- clk->rate = clk->parent->rate;
- else
- clk->rate = clk->parent->rate * 2;
+ if (v == OMAP3XXX_EN_DPLL_LOCKED)
+ rate *= 2;
- if (clk->flags & RATE_PROPAGATES)
- propagate_rate(clk);
+ if (rate_storage == CURRENT_RATE)
+ clk->rate = rate;
+ else if (rate_storage == TEMP_RATE)
+ clk->temp_rate = rate;
}
/* Common clock code */
#if defined(CONFIG_ARCH_OMAP3)
static struct clk_functions omap2_clk_functions = {
+ .clk_register = omap2_clk_register,
.clk_enable = omap2_clk_enable,
.clk_disable = omap2_clk_disable,
.clk_round_rate = omap2_clk_round_rate,
.clk_set_rate = omap2_clk_set_rate,
.clk_set_parent = omap2_clk_set_parent,
+ .clk_get_parent = omap2_clk_get_parent,
.clk_disable_unused = omap2_clk_disable_unused,
};
/* REVISIT: not yet ready for 343x */
#if 0
- if (omap2_select_table_rate(&virt_prcm_set, mpurate))
+ if (clk_set_rate(&virt_prcm_set, mpurate))
printk(KERN_ERR "Could not find matching MPU rate\n");
#endif
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 */
#include "prm.h"
#include "prm-regbits-34xx.h"
-static void omap3_dpll_recalc(struct clk *clk);
-static void omap3_clkoutx2_recalc(struct clk *clk);
+static void omap3_dpll_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage);
+static void omap3_clkoutx2_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage);
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);
+static int omap3_core_dpll_m2_set_rate(struct clk *clk, unsigned long rate);
/* Maximum DPLL multiplier, divider values for OMAP3 */
#define OMAP3_MAX_DPLL_MULT 2048
* DPLL5 supplies other peripheral clocks (USBHOST, USIM).
*/
+/* Forward declarations for DPLL bypass clocks */
+static struct clk dpll1_fck;
+static struct clk dpll2_fck;
+
/* 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
static struct clk omap_32k_fck = {
.name = "omap_32k_fck",
.rate = 32768,
- .flags = CLOCK_IN_OMAP343X | RATE_FIXED | RATE_PROPAGATES |
- ALWAYS_ENABLED,
- .recalc = &propagate_rate,
+ .flags = CLOCK_IN_OMAP343X | ALWAYS_ENABLED,
+ .clkdm = { .name = "prm_clkdm" },
};
static struct clk secure_32k_fck = {
.name = "secure_32k_fck",
.rate = 32768,
- .flags = CLOCK_IN_OMAP343X | RATE_FIXED | RATE_PROPAGATES |
- ALWAYS_ENABLED,
- .recalc = &propagate_rate,
+ .flags = CLOCK_IN_OMAP343X | ALWAYS_ENABLED,
+ .clkdm = { .name = "prm_clkdm" },
};
/* Virtual source clocks for osc_sys_ck */
static struct clk virt_12m_ck = {
.name = "virt_12m_ck",
.rate = 12000000,
- .flags = CLOCK_IN_OMAP343X | RATE_FIXED | RATE_PROPAGATES |
- ALWAYS_ENABLED,
- .recalc = &propagate_rate,
+ .flags = CLOCK_IN_OMAP343X | ALWAYS_ENABLED,
+ .clkdm = { .name = "prm_clkdm" },
};
static struct clk virt_13m_ck = {
.name = "virt_13m_ck",
.rate = 13000000,
- .flags = CLOCK_IN_OMAP343X | RATE_FIXED | RATE_PROPAGATES |
- ALWAYS_ENABLED,
- .recalc = &propagate_rate,
+ .flags = CLOCK_IN_OMAP343X | ALWAYS_ENABLED,
+ .clkdm = { .name = "prm_clkdm" },
};
static struct clk virt_16_8m_ck = {
.name = "virt_16_8m_ck",
.rate = 16800000,
- .flags = CLOCK_IN_OMAP3430ES2 | RATE_FIXED | RATE_PROPAGATES |
- ALWAYS_ENABLED,
- .recalc = &propagate_rate,
+ .flags = CLOCK_IN_OMAP3430ES2 | ALWAYS_ENABLED,
+ .clkdm = { .name = "prm_clkdm" },
};
static struct clk virt_19_2m_ck = {
.name = "virt_19_2m_ck",
.rate = 19200000,
- .flags = CLOCK_IN_OMAP343X | RATE_FIXED | RATE_PROPAGATES |
- ALWAYS_ENABLED,
- .recalc = &propagate_rate,
+ .flags = CLOCK_IN_OMAP343X | ALWAYS_ENABLED,
+ .clkdm = { .name = "prm_clkdm" },
};
static struct clk virt_26m_ck = {
.name = "virt_26m_ck",
.rate = 26000000,
- .flags = CLOCK_IN_OMAP343X | RATE_FIXED | RATE_PROPAGATES |
- ALWAYS_ENABLED,
- .recalc = &propagate_rate,
+ .flags = CLOCK_IN_OMAP343X | ALWAYS_ENABLED,
+ .clkdm = { .name = "prm_clkdm" },
};
static struct clk virt_38_4m_ck = {
.name = "virt_38_4m_ck",
.rate = 38400000,
- .flags = CLOCK_IN_OMAP343X | RATE_FIXED | RATE_PROPAGATES |
- ALWAYS_ENABLED,
- .recalc = &propagate_rate,
+ .flags = CLOCK_IN_OMAP343X | ALWAYS_ENABLED,
+ .clkdm = { .name = "prm_clkdm" },
};
static const struct clksel_rate osc_sys_12m_rates[] = {
/* 12, 13, 16.8, 19.2, 26, or 38.4 MHz */
static struct clk osc_sys_ck = {
.name = "osc_sys_ck",
+ .prcm_mod = OMAP3430_CCR_MOD | CLK_REG_IN_PRM,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP3430_PRM_CLKSEL,
+ .clksel_reg = OMAP3_PRM_CLKSEL_OFFSET,
.clksel_mask = OMAP3430_SYS_CLKIN_SEL_MASK,
.clksel = osc_sys_clksel,
/* REVISIT: deal with autoextclkmode? */
- .flags = CLOCK_IN_OMAP343X | RATE_FIXED | RATE_PROPAGATES |
- ALWAYS_ENABLED,
+ .flags = CLOCK_IN_OMAP343X | ALWAYS_ENABLED,
+ .clkdm = { .name = "prm_clkdm" },
.recalc = &omap2_clksel_recalc,
};
static struct clk sys_ck = {
.name = "sys_ck",
.parent = &osc_sys_ck,
+ .prcm_mod = OMAP3430_GR_MOD | CLK_REG_IN_PRM,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP3430_PRM_CLKSRC_CTRL,
+ .clksel_reg = OMAP3_PRM_CLKSRC_CTRL_OFFSET,
.clksel_mask = OMAP_SYSCLKDIV_MASK,
.clksel = sys_clksel,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
+ .flags = CLOCK_IN_OMAP343X | ALWAYS_ENABLED,
+ .clkdm = { .name = "prm_clkdm" },
.recalc = &omap2_clksel_recalc,
};
static struct clk sys_altclk = {
.name = "sys_altclk",
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
- .recalc = &propagate_rate,
+ .flags = CLOCK_IN_OMAP343X | ALWAYS_ENABLED,
+ .clkdm = { .name = "cm_clkdm" },
};
-/* Optional external clock input for some McBSPs */
+/*
+ * Optional external clock input for some McBSPs
+ * Apparently this is not really in prm_clkdm, but rather is fed into
+ * both CORE and PER separately.
+ */
static struct clk mcbsp_clks = {
.name = "mcbsp_clks",
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
- .recalc = &propagate_rate,
+ .flags = CLOCK_IN_OMAP343X | ALWAYS_ENABLED,
+ .clkdm = { .name = "prm_clkdm" },
};
/* PRM EXTERNAL CLOCK OUTPUT */
static struct clk sys_clkout1 = {
.name = "sys_clkout1",
.parent = &osc_sys_ck,
- .enable_reg = OMAP3430_PRM_CLKOUT_CTRL,
+ .prcm_mod = OMAP3430_CCR_MOD | CLK_REG_IN_PRM,
+ .enable_reg = OMAP3_PRM_CLKOUT_CTRL_OFFSET,
.enable_bit = OMAP3430_CLKOUT_EN_SHIFT,
.flags = CLOCK_IN_OMAP343X,
+ .clkdm = { .name = "prm_clkdm" },
.recalc = &followparent_recalc,
};
/* CM CLOCKS */
-static const struct clksel_rate dpll_bypass_rates[] = {
- { .div = 1, .val = 0, .flags = RATE_IN_343X | DEFAULT_RATE },
- { .div = 0 }
-};
-
-static const struct clksel_rate dpll_locked_rates[] = {
- { .div = 1, .val = 1, .flags = RATE_IN_343X | DEFAULT_RATE },
- { .div = 0 }
-};
-
static const struct clksel_rate div16_dpll_rates[] = {
{ .div = 1, .val = 1, .flags = RATE_IN_343X | DEFAULT_RATE },
{ .div = 2, .val = 2, .flags = RATE_IN_343X },
/* MPU clock source */
/* Type: DPLL */
static struct dpll_data dpll1_dd = {
- .mult_div1_reg = OMAP_CM_REGADDR(MPU_MOD, OMAP3430_CM_CLKSEL1_PLL),
+ .mult_div1_reg = OMAP3430_CM_CLKSEL1_PLL,
.mult_mask = OMAP3430_MPU_DPLL_MULT_MASK,
.div1_mask = OMAP3430_MPU_DPLL_DIV_MASK,
- .control_reg = OMAP_CM_REGADDR(MPU_MOD, OMAP3430_CM_CLKEN_PLL),
+ .freqsel_mask = OMAP3430_MPU_DPLL_FREQSEL_MASK,
+ .control_reg = 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_reg = 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,
+ .idlest_reg = OMAP3430_CM_IDLEST_PLL,
+ .idlest_mask = OMAP3430_ST_MPU_CLK_MASK,
+ .bypass_clk = &dpll1_fck,
.max_multiplier = OMAP3_MAX_DPLL_MULT,
+ .min_divider = 1,
.max_divider = OMAP3_MAX_DPLL_DIV,
.rate_tolerance = DEFAULT_DPLL_RATE_TOLERANCE
};
static struct clk dpll1_ck = {
.name = "dpll1_ck",
.parent = &sys_ck,
+ .prcm_mod = MPU_MOD,
.dpll_data = &dpll1_dd,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
+ .flags = CLOCK_IN_OMAP343X | ALWAYS_ENABLED | RECALC_ON_ENABLE,
.round_rate = &omap2_dpll_round_rate,
+ .set_rate = &omap3_noncore_dpll_set_rate,
+ .clkdm = { .name = "dpll1_clkdm" },
.recalc = &omap3_dpll_recalc,
};
static struct clk dpll1_x2_ck = {
.name = "dpll1_x2_ck",
.parent = &dpll1_ck,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
- PARENT_CONTROLS_CLOCK,
+ .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "dpll1_clkdm" },
.recalc = &omap3_clkoutx2_recalc,
};
static struct clk dpll1_x2m2_ck = {
.name = "dpll1_x2m2_ck",
.parent = &dpll1_x2_ck,
+ .prcm_mod = MPU_MOD,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(MPU_MOD, OMAP3430_CM_CLKSEL2_PLL),
+ .clksel_reg = OMAP3430_CM_CLKSEL2_PLL,
.clksel_mask = OMAP3430_MPU_DPLL_CLKOUT_DIV_MASK,
.clksel = div16_dpll1_x2m2_clksel,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
- PARENT_CONTROLS_CLOCK,
+ .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "dpll1_clkdm" },
.recalc = &omap2_clksel_recalc,
};
/* Type: DPLL */
static struct dpll_data dpll2_dd = {
- .mult_div1_reg = OMAP_CM_REGADDR(OMAP3430_IVA2_MOD, OMAP3430_CM_CLKSEL1_PLL),
+ .mult_div1_reg = OMAP3430_CM_CLKSEL1_PLL,
.mult_mask = OMAP3430_IVA2_DPLL_MULT_MASK,
.div1_mask = OMAP3430_IVA2_DPLL_DIV_MASK,
- .control_reg = OMAP_CM_REGADDR(OMAP3430_IVA2_MOD, OMAP3430_CM_CLKEN_PLL),
+ .freqsel_mask = OMAP3430_IVA2_DPLL_FREQSEL_MASK,
+ .control_reg = 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_reg = 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,
+ .idlest_reg = OMAP3430_CM_IDLEST_PLL,
+ .idlest_mask = OMAP3430_ST_IVA2_CLK_MASK,
+ .bypass_clk = &dpll2_fck,
.max_multiplier = OMAP3_MAX_DPLL_MULT,
+ .min_divider = 1,
.max_divider = OMAP3_MAX_DPLL_DIV,
.rate_tolerance = DEFAULT_DPLL_RATE_TOLERANCE
};
static struct clk dpll2_ck = {
.name = "dpll2_ck",
.parent = &sys_ck,
+ .prcm_mod = OMAP3430_IVA2_MOD,
.dpll_data = &dpll2_dd,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES,
+ .flags = CLOCK_IN_OMAP343X | RECALC_ON_ENABLE,
.enable = &omap3_noncore_dpll_enable,
.disable = &omap3_noncore_dpll_disable,
.round_rate = &omap2_dpll_round_rate,
+ .set_rate = &omap3_noncore_dpll_set_rate,
+ .clkdm = { .name = "dpll2_clkdm" },
.recalc = &omap3_dpll_recalc,
};
static struct clk dpll2_m2_ck = {
.name = "dpll2_m2_ck",
.parent = &dpll2_ck,
+ .prcm_mod = OMAP3430_IVA2_MOD,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(OMAP3430_IVA2_MOD,
- OMAP3430_CM_CLKSEL2_PLL),
+ .clksel_reg = OMAP3430_CM_CLKSEL2_PLL,
.clksel_mask = OMAP3430_IVA2_DPLL_CLKOUT_DIV_MASK,
.clksel = div16_dpll2_m2x2_clksel,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
- PARENT_CONTROLS_CLOCK,
+ .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "dpll2_clkdm" },
.recalc = &omap2_clksel_recalc,
};
* 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_div1_reg = CM_CLKSEL1,
.mult_mask = OMAP3430_CORE_DPLL_MULT_MASK,
.div1_mask = OMAP3430_CORE_DPLL_DIV_MASK,
- .control_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKEN),
+ .freqsel_mask = OMAP3430_CORE_DPLL_FREQSEL_MASK,
+ .control_reg = 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_reg = CM_AUTOIDLE,
.autoidle_mask = OMAP3430_AUTO_CORE_DPLL_MASK,
+ .idlest_reg = CM_IDLEST,
+ .idlest_mask = OMAP3430_ST_CORE_CLK_MASK,
+ .bypass_clk = &sys_ck,
.max_multiplier = OMAP3_MAX_DPLL_MULT,
+ .min_divider = 1,
.max_divider = OMAP3_MAX_DPLL_DIV,
.rate_tolerance = DEFAULT_DPLL_RATE_TOLERANCE
};
static struct clk dpll3_ck = {
.name = "dpll3_ck",
.parent = &sys_ck,
+ .prcm_mod = PLL_MOD,
.dpll_data = &dpll3_dd,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
+ .flags = CLOCK_IN_OMAP343X | ALWAYS_ENABLED | RECALC_ON_ENABLE,
.round_rate = &omap2_dpll_round_rate,
+ .clkdm = { .name = "dpll3_clkdm" },
.recalc = &omap3_dpll_recalc,
};
static struct clk dpll3_x2_ck = {
.name = "dpll3_x2_ck",
.parent = &dpll3_ck,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
- PARENT_CONTROLS_CLOCK,
+ .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "dpll3_clkdm" },
.recalc = &omap3_clkoutx2_recalc,
};
{ .parent = NULL }
};
-/*
- * DPLL3 output M2
- * REVISIT: This DPLL output divider must be changed in SRAM, so until
- * that code is ready, this should remain a 'read-only' clksel clock.
- */
+/* DPLL3 output M2 - primary control point for CORE speed */
static struct clk dpll3_m2_ck = {
.name = "dpll3_m2_ck",
.parent = &dpll3_ck,
+ .prcm_mod = PLL_MOD,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1),
+ .clksel_reg = CM_CLKSEL1,
.clksel_mask = OMAP3430_CORE_DPLL_CLKOUT_DIV_MASK,
.clksel = div31_dpll3m2_clksel,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
- PARENT_CONTROLS_CLOCK,
+ .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "dpll3_clkdm" },
+ .round_rate = &omap2_clksel_round_rate,
+ .set_rate = &omap3_core_dpll_m2_set_rate,
.recalc = &omap2_clksel_recalc,
};
-static const struct clksel core_ck_clksel[] = {
- { .parent = &sys_ck, .rates = dpll_bypass_rates },
- { .parent = &dpll3_m2_ck, .rates = dpll_locked_rates },
- { .parent = NULL }
-};
-
static struct clk core_ck = {
.name = "core_ck",
- .init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST),
- .clksel_mask = OMAP3430_ST_CORE_CLK_MASK,
- .clksel = core_ck_clksel,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
- PARENT_CONTROLS_CLOCK,
- .recalc = &omap2_clksel_recalc,
-};
-
-static const struct clksel dpll3_m2x2_ck_clksel[] = {
- { .parent = &sys_ck, .rates = dpll_bypass_rates },
- { .parent = &dpll3_x2_ck, .rates = dpll_locked_rates },
- { .parent = NULL }
+ .parent = &dpll3_m2_ck,
+ .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "cm_clkdm" },
+ .recalc = &followparent_recalc,
};
static struct clk dpll3_m2x2_ck = {
.name = "dpll3_m2x2_ck",
- .init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST),
- .clksel_mask = OMAP3430_ST_CORE_CLK_MASK,
- .clksel = dpll3_m2x2_ck_clksel,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
- PARENT_CONTROLS_CLOCK,
- .recalc = &omap2_clksel_recalc,
+ .parent = &dpll3_x2_ck,
+ .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "dpll3_clkdm" },
+ .recalc = &followparent_recalc,
};
/* The PWRDN bit is apparently only available on 3430ES2 and above */
static struct clk dpll3_m3_ck = {
.name = "dpll3_m3_ck",
.parent = &dpll3_ck,
+ .prcm_mod = OMAP3430_EMU_MOD,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(OMAP3430_EMU_MOD, CM_CLKSEL1),
+ .clksel_reg = CM_CLKSEL1,
.clksel_mask = OMAP3430_DIV_DPLL3_MASK,
.clksel = div16_dpll3_clksel,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
- PARENT_CONTROLS_CLOCK,
+ .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "dpll3_clkdm" },
.recalc = &omap2_clksel_recalc,
};
static struct clk dpll3_m3x2_ck = {
.name = "dpll3_m3x2_ck",
.parent = &dpll3_m3_ck,
- .enable_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKEN),
+ .prcm_mod = PLL_MOD,
+ .enable_reg = CM_CLKEN,
.enable_bit = OMAP3430_PWRDN_EMU_CORE_SHIFT,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES | INVERT_ENABLE,
+ .flags = CLOCK_IN_OMAP343X | INVERT_ENABLE,
+ .clkdm = { .name = "dpll3_clkdm" },
.recalc = &omap3_clkoutx2_recalc,
};
-static const struct clksel emu_core_alwon_ck_clksel[] = {
- { .parent = &sys_ck, .rates = dpll_bypass_rates },
- { .parent = &dpll3_m3x2_ck, .rates = dpll_locked_rates },
- { .parent = NULL }
-};
-
static struct clk emu_core_alwon_ck = {
.name = "emu_core_alwon_ck",
.parent = &dpll3_m3x2_ck,
- .init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST),
- .clksel_mask = OMAP3430_ST_CORE_CLK_MASK,
- .clksel = emu_core_alwon_ck_clksel,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
- PARENT_CONTROLS_CLOCK,
- .recalc = &omap2_clksel_recalc,
+ .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "dpll3_clkdm" },
+ .recalc = &followparent_recalc,
};
/* DPLL4 */
/* Supplies 96MHz, 54Mhz TV DAC, DSS fclk, CAM sensor clock, emul trace clk */
/* Type: DPLL */
static struct dpll_data dpll4_dd = {
- .mult_div1_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL2),
+ .mult_div1_reg = CM_CLKSEL2,
.mult_mask = OMAP3430_PERIPH_DPLL_MULT_MASK,
.div1_mask = OMAP3430_PERIPH_DPLL_DIV_MASK,
- .control_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKEN),
+ .freqsel_mask = OMAP3430_PERIPH_DPLL_FREQSEL_MASK,
+ .control_reg = 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_reg = 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,
+ .idlest_reg = CM_IDLEST,
+ .idlest_mask = OMAP3430_ST_PERIPH_CLK_MASK,
+ .bypass_clk = &sys_ck,
.max_multiplier = OMAP3_MAX_DPLL_MULT,
+ .min_divider = 1,
.max_divider = OMAP3_MAX_DPLL_DIV,
.rate_tolerance = DEFAULT_DPLL_RATE_TOLERANCE
};
static struct clk dpll4_ck = {
.name = "dpll4_ck",
.parent = &sys_ck,
+ .prcm_mod = PLL_MOD,
.dpll_data = &dpll4_dd,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES,
+ .flags = CLOCK_IN_OMAP343X | RECALC_ON_ENABLE,
.enable = &omap3_noncore_dpll_enable,
.disable = &omap3_noncore_dpll_disable,
.round_rate = &omap2_dpll_round_rate,
+ .set_rate = &omap3_noncore_dpll_set_rate,
+ .clkdm = { .name = "dpll4_clkdm" },
.recalc = &omap3_dpll_recalc,
};
static struct clk dpll4_x2_ck = {
.name = "dpll4_x2_ck",
.parent = &dpll4_ck,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
- PARENT_CONTROLS_CLOCK,
+ .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "dpll4_clkdm" },
.recalc = &omap3_clkoutx2_recalc,
};
static struct clk dpll4_m2_ck = {
.name = "dpll4_m2_ck",
.parent = &dpll4_ck,
+ .prcm_mod = PLL_MOD,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(PLL_MOD, OMAP3430_CM_CLKSEL3),
+ .clksel_reg = OMAP3430_CM_CLKSEL3,
.clksel_mask = OMAP3430_DIV_96M_MASK,
.clksel = div16_dpll4_clksel,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
- PARENT_CONTROLS_CLOCK,
+ .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "dpll4_clkdm" },
.recalc = &omap2_clksel_recalc,
};
static struct clk dpll4_m2x2_ck = {
.name = "dpll4_m2x2_ck",
.parent = &dpll4_m2_ck,
- .enable_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKEN),
+ .prcm_mod = PLL_MOD,
+ .enable_reg = CM_CLKEN,
.enable_bit = OMAP3430_PWRDN_96M_SHIFT,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES | INVERT_ENABLE,
+ .flags = CLOCK_IN_OMAP343X | INVERT_ENABLE,
+ .clkdm = { .name = "dpll4_clkdm" },
.recalc = &omap3_clkoutx2_recalc,
};
-static const struct clksel omap_96m_alwon_fck_clksel[] = {
- { .parent = &sys_ck, .rates = dpll_bypass_rates },
- { .parent = &dpll4_m2x2_ck, .rates = dpll_locked_rates },
- { .parent = NULL }
-};
-
+/*
+ * DPLL4 generates DPLL4_M2X2_CLK which is then routed into the PRM as
+ * PRM_96M_ALWON_(F)CLK. Two clocks then emerge from the PRM:
+ * 96M_ALWON_FCLK (called "omap_96m_alwon_fck" below) and
+ * CM_96K_(F)CLK.
+ */
static struct clk omap_96m_alwon_fck = {
.name = "omap_96m_alwon_fck",
.parent = &dpll4_m2x2_ck,
- .init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST),
- .clksel_mask = OMAP3430_ST_PERIPH_CLK_MASK,
- .clksel = omap_96m_alwon_fck_clksel,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
- PARENT_CONTROLS_CLOCK,
- .recalc = &omap2_clksel_recalc,
+ .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "prm_clkdm" },
+ .recalc = &followparent_recalc,
};
-static struct clk omap_96m_fck = {
- .name = "omap_96m_fck",
+static struct clk cm_96m_fck = {
+ .name = "cm_96m_fck",
.parent = &omap_96m_alwon_fck,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
- PARENT_CONTROLS_CLOCK,
+ .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "cm_clkdm" },
.recalc = &followparent_recalc,
};
-static const struct clksel cm_96m_fck_clksel[] = {
- { .parent = &sys_ck, .rates = dpll_bypass_rates },
- { .parent = &dpll4_m2x2_ck, .rates = dpll_locked_rates },
+static const struct clksel_rate omap_96m_dpll_rates[] = {
+ { .div = 1, .val = 0, .flags = RATE_IN_343X | DEFAULT_RATE },
+ { .div = 0 }
+};
+
+static const struct clksel_rate omap_96m_sys_rates[] = {
+ { .div = 1, .val = 1, .flags = RATE_IN_343X | DEFAULT_RATE },
+ { .div = 0 }
+};
+
+static const struct clksel omap_96m_fck_clksel[] = {
+ { .parent = &cm_96m_fck, .rates = omap_96m_dpll_rates },
+ { .parent = &sys_ck, .rates = omap_96m_sys_rates },
{ .parent = NULL }
};
-static struct clk cm_96m_fck = {
- .name = "cm_96m_fck",
- .parent = &dpll4_m2x2_ck,
+static struct clk omap_96m_fck = {
+ .name = "omap_96m_fck",
+ .parent = &sys_ck,
+ .prcm_mod = PLL_MOD,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST),
- .clksel_mask = OMAP3430_ST_PERIPH_CLK_MASK,
- .clksel = cm_96m_fck_clksel,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
- PARENT_CONTROLS_CLOCK,
+ .clksel_reg = CM_CLKSEL1,
+ .clksel_mask = OMAP3430_SOURCE_96M_MASK,
+ .clksel = omap_96m_fck_clksel,
+ .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "cm_clkdm" },
.recalc = &omap2_clksel_recalc,
};
static struct clk dpll4_m3_ck = {
.name = "dpll4_m3_ck",
.parent = &dpll4_ck,
+ .prcm_mod = OMAP3430_DSS_MOD,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(OMAP3430_DSS_MOD, CM_CLKSEL),
+ .clksel_reg = CM_CLKSEL,
.clksel_mask = OMAP3430_CLKSEL_TV_MASK,
.clksel = div16_dpll4_clksel,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
- PARENT_CONTROLS_CLOCK,
+ .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "dpll4_clkdm" },
.recalc = &omap2_clksel_recalc,
};
static struct clk dpll4_m3x2_ck = {
.name = "dpll4_m3x2_ck",
.parent = &dpll4_m3_ck,
+ .prcm_mod = PLL_MOD,
.init = &omap2_init_clksel_parent,
- .enable_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKEN),
+ .enable_reg = CM_CLKEN,
.enable_bit = OMAP3430_PWRDN_TV_SHIFT,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES | INVERT_ENABLE,
+ .flags = CLOCK_IN_OMAP343X | INVERT_ENABLE,
+ .clkdm = { .name = "dpll4_clkdm" },
.recalc = &omap3_clkoutx2_recalc,
};
-static const struct clksel virt_omap_54m_fck_clksel[] = {
- { .parent = &sys_ck, .rates = dpll_bypass_rates },
- { .parent = &dpll4_m3x2_ck, .rates = dpll_locked_rates },
- { .parent = NULL }
-};
-
-static struct clk virt_omap_54m_fck = {
- .name = "virt_omap_54m_fck",
- .parent = &dpll4_m3x2_ck,
- .init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST),
- .clksel_mask = OMAP3430_ST_PERIPH_CLK_MASK,
- .clksel = virt_omap_54m_fck_clksel,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
- PARENT_CONTROLS_CLOCK,
- .recalc = &omap2_clksel_recalc,
-};
-
static const struct clksel_rate omap_54m_d4m3x2_rates[] = {
{ .div = 1, .val = 0, .flags = RATE_IN_343X | DEFAULT_RATE },
{ .div = 0 }
};
static const struct clksel omap_54m_clksel[] = {
- { .parent = &virt_omap_54m_fck, .rates = omap_54m_d4m3x2_rates },
+ { .parent = &dpll4_m3x2_ck, .rates = omap_54m_d4m3x2_rates },
{ .parent = &sys_altclk, .rates = omap_54m_alt_rates },
{ .parent = NULL }
};
static struct clk omap_54m_fck = {
.name = "omap_54m_fck",
+ .prcm_mod = PLL_MOD,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1),
- .clksel_mask = OMAP3430_SOURCE_54M,
+ .clksel_reg = CM_CLKSEL1,
+ .clksel_mask = OMAP3430_SOURCE_54M_MASK,
.clksel = omap_54m_clksel,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
- PARENT_CONTROLS_CLOCK,
+ .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "cm_clkdm" },
.recalc = &omap2_clksel_recalc,
};
-static const struct clksel_rate omap_48m_96md2_rates[] = {
+static const struct clksel_rate omap_48m_cm96m_rates[] = {
{ .div = 2, .val = 0, .flags = RATE_IN_343X | DEFAULT_RATE },
{ .div = 0 }
};
};
static const struct clksel omap_48m_clksel[] = {
- { .parent = &cm_96m_fck, .rates = omap_48m_96md2_rates },
+ { .parent = &cm_96m_fck, .rates = omap_48m_cm96m_rates },
{ .parent = &sys_altclk, .rates = omap_48m_alt_rates },
{ .parent = NULL }
};
static struct clk omap_48m_fck = {
.name = "omap_48m_fck",
+ .prcm_mod = PLL_MOD,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1),
- .clksel_mask = OMAP3430_SOURCE_48M,
+ .clksel_reg = CM_CLKSEL1,
+ .clksel_mask = OMAP3430_SOURCE_48M_MASK,
.clksel = omap_48m_clksel,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
- PARENT_CONTROLS_CLOCK,
+ .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "cm_clkdm" },
.recalc = &omap2_clksel_recalc,
};
.name = "omap_12m_fck",
.parent = &omap_48m_fck,
.fixed_div = 4,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
- PARENT_CONTROLS_CLOCK,
+ .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "cm_clkdm" },
.recalc = &omap2_fixed_divisor_recalc,
};
static struct clk dpll4_m4_ck = {
.name = "dpll4_m4_ck",
.parent = &dpll4_ck,
+ .prcm_mod = OMAP3430_DSS_MOD,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(OMAP3430_DSS_MOD, CM_CLKSEL),
+ .clksel_reg = CM_CLKSEL,
.clksel_mask = OMAP3430_CLKSEL_DSS1_MASK,
.clksel = div16_dpll4_clksel,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
- PARENT_CONTROLS_CLOCK,
+ .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "dpll4_clkdm" },
.recalc = &omap2_clksel_recalc,
+ .set_rate = &omap2_clksel_set_rate,
+ .round_rate = &omap2_clksel_round_rate,
};
/* The PWRDN bit is apparently only available on 3430ES2 and above */
static struct clk dpll4_m4x2_ck = {
.name = "dpll4_m4x2_ck",
.parent = &dpll4_m4_ck,
- .enable_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKEN),
- .enable_bit = OMAP3430_PWRDN_CAM_SHIFT,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES | INVERT_ENABLE,
+ .prcm_mod = PLL_MOD,
+ .enable_reg = CM_CLKEN,
+ .enable_bit = OMAP3430_PWRDN_DSS1_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | INVERT_ENABLE,
+ .clkdm = { .name = "dpll4_clkdm" },
.recalc = &omap3_clkoutx2_recalc,
};
static struct clk dpll4_m5_ck = {
.name = "dpll4_m5_ck",
.parent = &dpll4_ck,
+ .prcm_mod = OMAP3430_CAM_MOD,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(OMAP3430_CAM_MOD, CM_CLKSEL),
+ .clksel_reg = CM_CLKSEL,
.clksel_mask = OMAP3430_CLKSEL_CAM_MASK,
.clksel = div16_dpll4_clksel,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
- PARENT_CONTROLS_CLOCK,
+ .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "dpll4_clkdm" },
.recalc = &omap2_clksel_recalc,
};
static struct clk dpll4_m5x2_ck = {
.name = "dpll4_m5x2_ck",
.parent = &dpll4_m5_ck,
- .enable_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKEN),
+ .prcm_mod = PLL_MOD,
+ .enable_reg = CM_CLKEN,
.enable_bit = OMAP3430_PWRDN_CAM_SHIFT,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES | INVERT_ENABLE,
+ .flags = CLOCK_IN_OMAP343X | INVERT_ENABLE,
+ .clkdm = { .name = "dpll4_clkdm" },
.recalc = &omap3_clkoutx2_recalc,
};
static struct clk dpll4_m6_ck = {
.name = "dpll4_m6_ck",
.parent = &dpll4_ck,
+ .prcm_mod = OMAP3430_EMU_MOD,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(OMAP3430_EMU_MOD, CM_CLKSEL1),
+ .clksel_reg = CM_CLKSEL1,
.clksel_mask = OMAP3430_DIV_DPLL4_MASK,
.clksel = div16_dpll4_clksel,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
- PARENT_CONTROLS_CLOCK,
+ .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "dpll4_clkdm" },
.recalc = &omap2_clksel_recalc,
};
static struct clk dpll4_m6x2_ck = {
.name = "dpll4_m6x2_ck",
.parent = &dpll4_m6_ck,
+ .prcm_mod = PLL_MOD,
.init = &omap2_init_clksel_parent,
- .enable_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKEN),
+ .enable_reg = CM_CLKEN,
.enable_bit = OMAP3430_PWRDN_EMU_PERIPH_SHIFT,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES | INVERT_ENABLE,
+ .flags = CLOCK_IN_OMAP343X | INVERT_ENABLE,
+ .clkdm = { .name = "dpll4_clkdm" },
.recalc = &omap3_clkoutx2_recalc,
};
static struct clk emu_per_alwon_ck = {
.name = "emu_per_alwon_ck",
.parent = &dpll4_m6x2_ck,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
- PARENT_CONTROLS_CLOCK,
+ .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "dpll4_clkdm" },
.recalc = &followparent_recalc,
};
/* Type: DPLL */
/* 3430ES2 only */
static struct dpll_data dpll5_dd = {
- .mult_div1_reg = OMAP_CM_REGADDR(PLL_MOD, OMAP3430ES2_CM_CLKSEL4),
+ .mult_div1_reg = OMAP3430ES2_CM_CLKSEL4,
.mult_mask = OMAP3430ES2_PERIPH2_DPLL_MULT_MASK,
.div1_mask = OMAP3430ES2_PERIPH2_DPLL_DIV_MASK,
- .control_reg = OMAP_CM_REGADDR(PLL_MOD, OMAP3430ES2_CM_CLKEN2),
+ .freqsel_mask = OMAP3430ES2_PERIPH2_DPLL_FREQSEL_MASK,
+ .control_reg = 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_reg = 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,
+ .idlest_reg = CM_IDLEST2,
+ .idlest_mask = OMAP3430ES2_ST_PERIPH2_CLK_MASK,
+ .bypass_clk = &sys_ck,
.max_multiplier = OMAP3_MAX_DPLL_MULT,
+ .min_divider = 1,
.max_divider = OMAP3_MAX_DPLL_DIV,
.rate_tolerance = DEFAULT_DPLL_RATE_TOLERANCE
};
static struct clk dpll5_ck = {
.name = "dpll5_ck",
.parent = &sys_ck,
+ .prcm_mod = PLL_MOD,
.dpll_data = &dpll5_dd,
- .flags = CLOCK_IN_OMAP3430ES2 | RATE_PROPAGATES,
+ .flags = CLOCK_IN_OMAP3430ES2 | RECALC_ON_ENABLE,
.enable = &omap3_noncore_dpll_enable,
.disable = &omap3_noncore_dpll_disable,
.round_rate = &omap2_dpll_round_rate,
+ .set_rate = &omap3_noncore_dpll_set_rate,
+ .clkdm = { .name = "dpll5_clkdm" },
.recalc = &omap3_dpll_recalc,
};
static struct clk dpll5_m2_ck = {
.name = "dpll5_m2_ck",
.parent = &dpll5_ck,
+ .prcm_mod = PLL_MOD,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(PLL_MOD, OMAP3430ES2_CM_CLKSEL5),
+ .clksel_reg = OMAP3430ES2_CM_CLKSEL5,
.clksel_mask = OMAP3430ES2_DIV_120M_MASK,
.clksel = div16_dpll5_clksel,
- .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 = &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,
- .flags = CLOCK_IN_OMAP3430ES2 | RATE_PROPAGATES |
- PARENT_CONTROLS_CLOCK,
+ .flags = CLOCK_IN_OMAP3430ES2 | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "dpll5_clkdm" },
.recalc = &omap2_clksel_recalc,
};
};
static const struct clksel clkout2_src_clksel[] = {
- { .parent = &core_ck, .rates = clkout2_src_core_rates },
- { .parent = &sys_ck, .rates = clkout2_src_sys_rates },
- { .parent = &omap_96m_alwon_fck, .rates = clkout2_src_96m_rates },
- { .parent = &omap_54m_fck, .rates = clkout2_src_54m_rates },
+ { .parent = &core_ck, .rates = clkout2_src_core_rates },
+ { .parent = &sys_ck, .rates = clkout2_src_sys_rates },
+ { .parent = &cm_96m_fck, .rates = clkout2_src_96m_rates },
+ { .parent = &omap_54m_fck, .rates = clkout2_src_54m_rates },
{ .parent = NULL }
};
static struct clk clkout2_src_ck = {
.name = "clkout2_src_ck",
+ .prcm_mod = OMAP3430_CCR_MOD,
.init = &omap2_init_clksel_parent,
- .enable_reg = OMAP3430_CM_CLKOUT_CTRL,
+ .enable_reg = OMAP3430_CM_CLKOUT_CTRL_OFFSET,
.enable_bit = OMAP3430_CLKOUT2_EN_SHIFT,
- .clksel_reg = OMAP3430_CM_CLKOUT_CTRL,
+ .clksel_reg = OMAP3430_CM_CLKOUT_CTRL_OFFSET,
.clksel_mask = OMAP3430_CLKOUT2SOURCE_MASK,
.clksel = clkout2_src_clksel,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES,
+ .flags = CLOCK_IN_OMAP343X,
+ .clkdm = { .name = "cm_clkdm" },
.recalc = &omap2_clksel_recalc,
};
static struct clk sys_clkout2 = {
.name = "sys_clkout2",
+ .prcm_mod = OMAP3430_CCR_MOD,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP3430_CM_CLKOUT_CTRL,
+ .clksel_reg = OMAP3430_CM_CLKOUT_CTRL_OFFSET,
.clksel_mask = OMAP3430_CLKOUT2_DIV_MASK,
.clksel = sys_clkout2_clksel,
.flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "cm_clkdm" },
.recalc = &omap2_clksel_recalc,
};
static struct clk corex2_fck = {
.name = "corex2_fck",
.parent = &dpll3_m2x2_ck,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
- PARENT_CONTROLS_CLOCK,
+ .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "cm_clkdm" },
.recalc = &followparent_recalc,
};
/* DPLL power domain clock controls */
-static const struct clksel div2_core_clksel[] = {
- { .parent = &core_ck, .rates = div2_rates },
+static const struct clksel_rate div4_rates[] = {
+ { .div = 1, .val = 1, .flags = RATE_IN_343X | DEFAULT_RATE },
+ { .div = 2, .val = 2, .flags = RATE_IN_343X },
+ { .div = 4, .val = 4, .flags = RATE_IN_343X },
+ { .div = 0 }
+};
+
+static const struct clksel div4_core_clksel[] = {
+ { .parent = &core_ck, .rates = div4_rates },
{ .parent = NULL }
};
-/*
- * REVISIT: Are these in DPLL power domain or CM power domain? docs
- * may be inconsistent here?
- */
static struct clk dpll1_fck = {
.name = "dpll1_fck",
.parent = &core_ck,
+ .prcm_mod = MPU_MOD,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(MPU_MOD, OMAP3430_CM_CLKSEL1_PLL),
+ .clksel_reg = OMAP3430_CM_CLKSEL1_PLL,
.clksel_mask = OMAP3430_MPU_CLK_SRC_MASK,
- .clksel = div2_core_clksel,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
- PARENT_CONTROLS_CLOCK,
+ .clksel = div4_core_clksel,
+ .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "cm_clkdm" },
.recalc = &omap2_clksel_recalc,
};
-/*
- * MPU clksel:
- * If DPLL1 is locked, mpu_ck derives from DPLL1; otherwise, mpu_ck
- * derives from the high-frequency bypass clock originating from DPLL3,
- * called 'dpll1_fck'
- */
-static const struct clksel mpu_clksel[] = {
- { .parent = &dpll1_fck, .rates = dpll_bypass_rates },
- { .parent = &dpll1_x2m2_ck, .rates = dpll_locked_rates },
- { .parent = NULL }
-};
-
static struct clk mpu_ck = {
.name = "mpu_ck",
.parent = &dpll1_x2m2_ck,
- .init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(MPU_MOD, OMAP3430_CM_IDLEST_PLL),
- .clksel_mask = OMAP3430_ST_MPU_CLK_MASK,
- .clksel = mpu_clksel,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
- PARENT_CONTROLS_CLOCK,
- .clkdm_name = "mpu_clkdm",
- .recalc = &omap2_clksel_recalc,
+ .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "mpu_clkdm" },
+ .recalc = &followparent_recalc,
};
/* arm_fck is divided by two when DPLL1 locked; otherwise, passthrough mpu_ck */
static struct clk arm_fck = {
.name = "arm_fck",
.parent = &mpu_ck,
+ .prcm_mod = MPU_MOD,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(MPU_MOD, OMAP3430_CM_IDLEST_PLL),
+ .clksel_reg = OMAP3430_CM_IDLEST_PLL,
.clksel_mask = OMAP3430_ST_MPU_CLK_MASK,
.clksel = arm_fck_clksel,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
- PARENT_CONTROLS_CLOCK,
+ .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "mpu_clkdm" },
.recalc = &omap2_clksel_recalc,
};
static struct clk emu_mpu_alwon_ck = {
.name = "emu_mpu_alwon_ck",
.parent = &mpu_ck,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
- PARENT_CONTROLS_CLOCK,
+ .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "mpu_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk dpll2_fck = {
.name = "dpll2_fck",
.parent = &core_ck,
+ .prcm_mod = OMAP3430_IVA2_MOD,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(OMAP3430_IVA2_MOD, OMAP3430_CM_CLKSEL1_PLL),
+ .clksel_reg = OMAP3430_CM_CLKSEL1_PLL,
.clksel_mask = OMAP3430_IVA2_CLK_SRC_MASK,
- .clksel = div2_core_clksel,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
- PARENT_CONTROLS_CLOCK,
+ .clksel = div4_core_clksel,
+ .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "cm_clkdm" },
.recalc = &omap2_clksel_recalc,
};
-/*
- * IVA2 clksel:
- * If DPLL2 is locked, iva2_ck derives from DPLL2; otherwise, iva2_ck
- * derives from the high-frequency bypass clock originating from DPLL3,
- * called 'dpll2_fck'
- */
-
-static const struct clksel iva2_clksel[] = {
- { .parent = &dpll2_fck, .rates = dpll_bypass_rates },
- { .parent = &dpll2_m2_ck, .rates = dpll_locked_rates },
- { .parent = NULL }
-};
-
static struct clk iva2_ck = {
.name = "iva2_ck",
.parent = &dpll2_m2_ck,
+ .prcm_mod = OMAP3430_IVA2_MOD,
.init = &omap2_init_clksel_parent,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_IVA2_MOD, CM_FCLKEN),
+ .enable_reg = 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,
- .clkdm_name = "iva2_clkdm",
- .recalc = &omap2_clksel_recalc,
+ .flags = CLOCK_IN_OMAP343X,
+ .clkdm = { .name = "iva2_clkdm" },
+ .recalc = &followparent_recalc,
};
/* Common interface clocks */
+static const struct clksel div2_core_clksel[] = {
+ { .parent = &core_ck, .rates = div2_rates },
+ { .parent = NULL }
+};
+
static struct clk l3_ick = {
.name = "l3_ick",
.parent = &core_ck,
+ .prcm_mod = CORE_MOD,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL),
+ .clksel_reg = CM_CLKSEL,
.clksel_mask = OMAP3430_CLKSEL_L3_MASK,
.clksel = div2_core_clksel,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
- PARENT_CONTROLS_CLOCK,
- .clkdm_name = "core_l3_clkdm",
+ .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "core_l3_clkdm" },
.recalc = &omap2_clksel_recalc,
};
static struct clk l4_ick = {
.name = "l4_ick",
.parent = &l3_ick,
+ .prcm_mod = CORE_MOD,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL),
+ .clksel_reg = CM_CLKSEL,
.clksel_mask = OMAP3430_CLKSEL_L4_MASK,
.clksel = div2_l3_clksel,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
- PARENT_CONTROLS_CLOCK,
- .clkdm_name = "core_l4_clkdm",
+ .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &omap2_clksel_recalc,
};
static struct clk rm_ick = {
.name = "rm_ick",
.parent = &l4_ick,
+ .prcm_mod = WKUP_MOD,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_CLKSEL),
+ .clksel_reg = CM_CLKSEL,
.clksel_mask = OMAP3430_CLKSEL_RM_MASK,
.clksel = div2_l4_clksel,
.flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "cm_clkdm" },
.recalc = &omap2_clksel_recalc,
};
static struct clk gfx_l3_ck = {
.name = "gfx_l3_ck",
.parent = &l3_ick,
+ .prcm_mod = GFX_MOD,
.init = &omap2_init_clksel_parent,
- .enable_reg = OMAP_CM_REGADDR(GFX_MOD, CM_ICLKEN),
+ .enable_reg = CM_ICLKEN,
.enable_bit = OMAP_EN_GFX_SHIFT,
.flags = CLOCK_IN_OMAP3430ES1,
+ .clkdm = { .name = "gfx_3430es1_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk gfx_l3_fck = {
.name = "gfx_l3_fck",
.parent = &gfx_l3_ck,
+ .prcm_mod = GFX_MOD,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(GFX_MOD, CM_CLKSEL),
+ .clksel_reg = CM_CLKSEL,
.clksel_mask = OMAP_CLKSEL_GFX_MASK,
.clksel = gfx_l3_clksel,
- .flags = CLOCK_IN_OMAP3430ES1 | RATE_PROPAGATES |
- PARENT_CONTROLS_CLOCK,
- .clkdm_name = "gfx_3430es1_clkdm",
+ .flags = CLOCK_IN_OMAP3430ES1 | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "gfx_3430es1_clkdm" },
.recalc = &omap2_clksel_recalc,
};
.name = "gfx_l3_ick",
.parent = &gfx_l3_ck,
.flags = CLOCK_IN_OMAP3430ES1 | PARENT_CONTROLS_CLOCK,
- .clkdm_name = "gfx_3430es1_clkdm",
+ .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),
+ .prcm_mod = GFX_MOD,
+ .enable_reg = CM_FCLKEN,
.enable_bit = OMAP3430ES1_EN_2D_SHIFT,
.flags = CLOCK_IN_OMAP3430ES1,
- .clkdm_name = "gfx_3430es1_clkdm",
+ .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),
+ .prcm_mod = GFX_MOD,
+ .enable_reg = CM_FCLKEN,
.enable_bit = OMAP3430ES1_EN_3D_SHIFT,
.flags = CLOCK_IN_OMAP3430ES1,
- .clkdm_name = "gfx_3430es1_clkdm",
+ .clkdm = { .name = "gfx_3430es1_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk sgx_fck = {
.name = "sgx_fck",
.init = &omap2_init_clksel_parent,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430ES2_SGX_MOD, CM_FCLKEN),
- .enable_bit = OMAP3430ES2_EN_SGX_SHIFT,
- .clksel_reg = OMAP_CM_REGADDR(OMAP3430ES2_SGX_MOD, CM_CLKSEL),
+ .prcm_mod = OMAP3430ES2_SGX_MOD,
+ .enable_reg = CM_FCLKEN,
+ .enable_bit = OMAP3430ES2_CM_FCLKEN_SGX_EN_SGX_SHIFT,
+ .clksel_reg = CM_CLKSEL,
.clksel_mask = OMAP3430ES2_CLKSEL_SGX_MASK,
.clksel = sgx_clksel,
.flags = CLOCK_IN_OMAP3430ES2,
- .clkdm_name = "sgx_clkdm",
+ .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,
+ .prcm_mod = OMAP3430ES2_SGX_MOD,
+ .enable_reg = CM_ICLKEN,
+ .enable_bit = OMAP3430ES2_CM_ICLKEN_SGX_EN_SGX_SHIFT,
.flags = CLOCK_IN_OMAP3430ES2,
- .clkdm_name = "sgx_clkdm",
+ .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),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP3430ES1_EN_D2D_SHIFT,
.flags = CLOCK_IN_OMAP3430ES1,
- .clkdm_name = "d2d_clkdm",
+ .clkdm = { .name = "d2d_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk gpt10_fck = {
.name = "gpt10_fck",
.parent = &sys_ck,
+ .prcm_mod = CORE_MOD,
.init = &omap2_init_clksel_parent,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP3430_EN_GPT10_SHIFT,
- .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL),
+ .idlest_bit = OMAP3430_ST_GPT10_SHIFT,
+ .clksel_reg = CM_CLKSEL,
.clksel_mask = OMAP3430_CLKSEL_GPT10_MASK,
.clksel = omap343x_gpt_clksel,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "core_l4_clkdm",
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &omap2_clksel_recalc,
};
static struct clk gpt11_fck = {
.name = "gpt11_fck",
.parent = &sys_ck,
+ .prcm_mod = CORE_MOD,
.init = &omap2_init_clksel_parent,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP3430_EN_GPT11_SHIFT,
- .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL),
+ .idlest_bit = OMAP3430_ST_GPT11_SHIFT,
+ .clksel_reg = CM_CLKSEL,
.clksel_mask = OMAP3430_CLKSEL_GPT11_MASK,
.clksel = omap343x_gpt_clksel,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "core_l4_clkdm",
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &omap2_clksel_recalc,
};
static struct clk cpefuse_fck = {
.name = "cpefuse_fck",
.parent = &sys_ck,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, OMAP3430ES2_CM_FCLKEN3),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = OMAP3430ES2_CM_FCLKEN3,
.enable_bit = OMAP3430ES2_EN_CPEFUSE_SHIFT,
- .flags = CLOCK_IN_OMAP3430ES2,
+ .idlest_bit = OMAP3430ES2_ST_CPEFUSE_SHIFT,
+ .flags = CLOCK_IN_OMAP3430ES2 | WAIT_READY,
+ .clkdm = { .name = "cm_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk ts_fck = {
.name = "ts_fck",
.parent = &omap_32k_fck,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, OMAP3430ES2_CM_FCLKEN3),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = OMAP3430ES2_CM_FCLKEN3,
.enable_bit = OMAP3430ES2_EN_TS_SHIFT,
.flags = CLOCK_IN_OMAP3430ES2,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk usbtll_fck = {
.name = "usbtll_fck",
- .parent = &omap_120m_fck,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, OMAP3430ES2_CM_FCLKEN3),
+ .parent = &dpll5_m2_ck,
+ .prcm_mod = CORE_MOD,
+ .enable_reg = OMAP3430ES2_CM_FCLKEN3,
.enable_bit = OMAP3430ES2_EN_USBTLL_SHIFT,
- .flags = CLOCK_IN_OMAP3430ES2,
+ .idlest_bit = OMAP3430ES2_ST_USBTLL_SHIFT,
+ .flags = CLOCK_IN_OMAP3430ES2 | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk core_96m_fck = {
.name = "core_96m_fck",
.parent = &omap_96m_fck,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
- PARENT_CONTROLS_CLOCK,
- .clkdm_name = "core_l4_clkdm",
+ .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
.name = "mmchs_fck",
.id = 2,
.parent = &core_96m_fck,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP3430ES2_EN_MMC3_SHIFT,
- .flags = CLOCK_IN_OMAP3430ES2,
- .clkdm_name = "core_l4_clkdm",
+ .idlest_bit = OMAP3430ES2_ST_MMC3_SHIFT,
+ .flags = CLOCK_IN_OMAP3430ES2 | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
.name = "mmchs_fck",
.id = 1,
.parent = &core_96m_fck,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP3430_EN_MMC2_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "core_l4_clkdm",
+ .idlest_bit = OMAP3430_ST_MMC2_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk mspro_fck = {
.name = "mspro_fck",
.parent = &core_96m_fck,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP3430_EN_MSPRO_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "core_l4_clkdm",
+ .idlest_bit = OMAP3430_ST_MSPRO_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk mmchs1_fck = {
.name = "mmchs_fck",
.parent = &core_96m_fck,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP3430_EN_MMC1_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "core_l4_clkdm",
+ .idlest_bit = OMAP3430_ST_MMC1_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
.name = "i2c_fck",
.id = 3,
.parent = &core_96m_fck,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP3430_EN_I2C3_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "core_l4_clkdm",
+ .idlest_bit = OMAP3430_ST_I2C3_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
.name = "i2c_fck",
.id = 2,
.parent = &core_96m_fck,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP3430_EN_I2C2_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "core_l4_clkdm",
+ .idlest_bit = OMAP3430_ST_I2C2_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
.name = "i2c_fck",
.id = 1,
.parent = &core_96m_fck,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP3430_EN_I2C1_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "core_l4_clkdm",
+ .idlest_bit = OMAP3430_ST_I2C1_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
{ .parent = NULL }
};
-static struct clk mcbsp5_fck = {
- .name = "mcbsp_fck",
+static struct clk mcbsp5_src_fck = {
+ .name = "mcbsp_src_fck",
.id = 5,
+ .prcm_mod = CLK_REG_IN_SCM,
.init = &omap2_init_clksel_parent,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
- .enable_bit = OMAP3430_EN_MCBSP5_SHIFT,
- .clksel_reg = OMAP343X_CTRL_REGADDR(OMAP343X_CONTROL_DEVCONF1),
+ .clksel_reg = OMAP343X_CONTROL_DEVCONF1,
.clksel_mask = OMAP2_MCBSP5_CLKS_MASK,
.clksel = mcbsp_15_clksel,
.flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "core_l4_clkdm",
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &omap2_clksel_recalc,
};
-static struct clk mcbsp1_fck = {
+static struct clk mcbsp5_fck = {
.name = "mcbsp_fck",
+ .id = 5,
+ .parent = &mcbsp5_src_fck,
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_FCLKEN1,
+ .enable_bit = OMAP3430_EN_MCBSP5_SHIFT,
+ .idlest_bit = OMAP3430_ST_MCBSP5_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .recalc = &followparent_recalc,
+};
+
+static struct clk mcbsp1_src_fck = {
+ .name = "mcbsp_src_fck",
.id = 1,
+ .prcm_mod = CLK_REG_IN_SCM,
.init = &omap2_init_clksel_parent,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
- .enable_bit = OMAP3430_EN_MCBSP1_SHIFT,
- .clksel_reg = OMAP343X_CTRL_REGADDR(OMAP2_CONTROL_DEVCONF0),
+ .clksel_reg = OMAP2_CONTROL_DEVCONF0,
.clksel_mask = OMAP2_MCBSP1_CLKS_MASK,
.clksel = mcbsp_15_clksel,
.flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "core_l4_clkdm",
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &omap2_clksel_recalc,
};
+static struct clk mcbsp1_fck = {
+ .name = "mcbsp_fck",
+ .id = 1,
+ .parent = &mcbsp1_src_fck,
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_FCLKEN1,
+ .enable_bit = OMAP3430_EN_MCBSP1_SHIFT,
+ .idlest_bit = OMAP3430_ST_MCBSP1_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .recalc = &followparent_recalc,
+};
+
/* CORE_48M_FCK-derived clocks */
static struct clk core_48m_fck = {
.name = "core_48m_fck",
.parent = &omap_48m_fck,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
- PARENT_CONTROLS_CLOCK,
- .clkdm_name = "core_l4_clkdm",
+ .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
.name = "mcspi_fck",
.id = 4,
.parent = &core_48m_fck,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP3430_EN_MCSPI4_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
+ .idlest_bit = OMAP3430_ST_MCSPI4_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
.name = "mcspi_fck",
.id = 3,
.parent = &core_48m_fck,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP3430_EN_MCSPI3_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
+ .idlest_bit = OMAP3430_ST_MCSPI3_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
.name = "mcspi_fck",
.id = 2,
.parent = &core_48m_fck,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP3430_EN_MCSPI2_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
+ .idlest_bit = OMAP3430_ST_MCSPI2_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
.name = "mcspi_fck",
.id = 1,
.parent = &core_48m_fck,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP3430_EN_MCSPI1_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
+ .idlest_bit = OMAP3430_ST_MCSPI1_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk uart2_fck = {
.name = "uart2_fck",
.parent = &core_48m_fck,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP3430_EN_UART2_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
+ .idlest_bit = OMAP3430_ST_UART2_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk uart1_fck = {
.name = "uart1_fck",
.parent = &core_48m_fck,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP3430_EN_UART1_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
+ .idlest_bit = OMAP3430_ST_UART1_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
+/* XXX doublecheck: is this idle or standby? */
static struct clk fshostusb_fck = {
.name = "fshostusb_fck",
.parent = &core_48m_fck,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP3430ES1_EN_FSHOSTUSB_SHIFT,
- .flags = CLOCK_IN_OMAP3430ES1,
+ .idlest_bit = OMAP3430ES1_ST_FSHOSTUSB_SHIFT,
+ .flags = CLOCK_IN_OMAP3430ES1 | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk core_12m_fck = {
.name = "core_12m_fck",
.parent = &omap_12m_fck,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
- PARENT_CONTROLS_CLOCK,
- .clkdm_name = "core_l4_clkdm",
+ .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk hdq_fck = {
.name = "hdq_fck",
.parent = &core_12m_fck,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP3430_EN_HDQ_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
+ .idlest_bit = OMAP3430_ST_HDQ_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
{ .parent = NULL }
};
-static struct clk ssi_ssr_fck = {
+static struct clk ssi_ssr_fck_3430es1 = {
.name = "ssi_ssr_fck",
.init = &omap2_init_clksel_parent,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_FCLKEN1,
.enable_bit = OMAP3430_EN_SSI_SHIFT,
- .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL),
+ .clksel_reg = CM_CLKSEL,
.clksel_mask = OMAP3430_CLKSEL_SSI_MASK,
.clksel = ssi_ssr_clksel,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES,
- .clkdm_name = "core_l4_clkdm",
+ .flags = CLOCK_IN_OMAP3430ES1,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .recalc = &omap2_clksel_recalc,
+};
+
+static struct clk ssi_ssr_fck_3430es2 = {
+ .name = "ssi_ssr_fck",
+ .init = &omap2_init_clksel_parent,
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_FCLKEN1,
+ .enable_bit = OMAP3430_EN_SSI_SHIFT,
+ .idlest_bit = OMAP3430ES2_ST_SSI_IDLE_SHIFT,
+ .clksel_reg = CM_CLKSEL,
+ .clksel_mask = OMAP3430_CLKSEL_SSI_MASK,
+ .clksel = ssi_ssr_clksel,
+ .flags = CLOCK_IN_OMAP3430ES2 | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &omap2_clksel_recalc,
};
-static struct clk ssi_sst_fck = {
+/* It's unfortunate that we need to duplicate this clock. */
+static struct clk ssi_sst_fck_3430es1 = {
.name = "ssi_sst_fck",
- .parent = &ssi_ssr_fck,
+ .parent = &ssi_ssr_fck_3430es1,
.fixed_div = 2,
- .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .flags = CLOCK_IN_OMAP3430ES1 | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .recalc = &omap2_fixed_divisor_recalc,
+};
+
+static struct clk ssi_sst_fck_3430es2 = {
+ .name = "ssi_sst_fck",
+ .parent = &ssi_ssr_fck_3430es2,
+ .fixed_div = 2,
+ .flags = CLOCK_IN_OMAP3430ES2 | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &omap2_fixed_divisor_recalc,
};
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",
+ .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "core_l3_clkdm" },
.recalc = &followparent_recalc,
};
-static struct clk hsotgusb_ick = {
+static struct clk hsotgusb_ick_3430es1 = {
.name = "hsotgusb_ick",
.parent = &core_l3_ick,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP3430_EN_HSOTGUSB_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "core_l3_clkdm",
+ .flags = CLOCK_IN_OMAP3430ES1,
+ .clkdm = { .name = "core_l3_clkdm" },
+ .recalc = &followparent_recalc,
+};
+
+static struct clk hsotgusb_ick_3430es2 = {
+ .name = "hsotgusb_ick",
+ .parent = &core_l3_ick,
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_ICLKEN1,
+ .enable_bit = OMAP3430_EN_HSOTGUSB_SHIFT,
+ .idlest_bit = OMAP3430ES2_ST_HSOTGUSB_IDLE_SHIFT,
+ .flags = CLOCK_IN_OMAP3430ES2 | WAIT_READY,
+ .clkdm = { .name = "core_l3_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk sdrc_ick = {
.name = "sdrc_ick",
.parent = &core_l3_ick,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP3430_EN_SDRC_SHIFT,
- .flags = CLOCK_IN_OMAP343X | ENABLE_ON_INIT,
- .clkdm_name = "core_l3_clkdm",
+ .idlest_bit = OMAP3430_ST_SDRC_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | ENABLE_ON_INIT | WAIT_READY,
+ .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",
+ .clkdm = { .name = "core_l3_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk security_l3_ick = {
.name = "security_l3_ick",
.parent = &l3_ick,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
- PARENT_CONTROLS_CLOCK,
+ .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "core_l3_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk pka_ick = {
.name = "pka_ick",
.parent = &security_l3_ick,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_ICLKEN2,
.enable_bit = OMAP3430_EN_PKA_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
+ .idlest_bit = OMAP3430_ST_PKA_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .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",
+ .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk usbtll_ick = {
.name = "usbtll_ick",
.parent = &core_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN3),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_ICLKEN3,
.enable_bit = OMAP3430ES2_EN_USBTLL_SHIFT,
- .flags = CLOCK_IN_OMAP3430ES2,
- .clkdm_name = "core_l4_clkdm",
+ .idlest_bit = OMAP3430ES2_ST_USBTLL_SHIFT,
+ .flags = CLOCK_IN_OMAP3430ES2 | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
.name = "mmchs_ick",
.id = 2,
.parent = &core_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP3430ES2_EN_MMC3_SHIFT,
- .flags = CLOCK_IN_OMAP3430ES2,
- .clkdm_name = "core_l4_clkdm",
+ .idlest_bit = OMAP3430ES2_ST_MMC3_SHIFT,
+ .flags = CLOCK_IN_OMAP3430ES2 | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk icr_ick = {
.name = "icr_ick",
.parent = &core_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP3430_EN_ICR_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "core_l4_clkdm",
+ .idlest_bit = OMAP3430_ST_ICR_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk aes2_ick = {
.name = "aes2_ick",
.parent = &core_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP3430_EN_AES2_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "core_l4_clkdm",
+ .idlest_bit = OMAP3430_ST_AES2_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk sha12_ick = {
.name = "sha12_ick",
.parent = &core_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP3430_EN_SHA12_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "core_l4_clkdm",
+ .idlest_bit = OMAP3430_ST_SHA12_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk des2_ick = {
.name = "des2_ick",
.parent = &core_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP3430_EN_DES2_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "core_l4_clkdm",
+ .idlest_bit = OMAP3430_ST_DES2_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
.name = "mmchs_ick",
.id = 1,
.parent = &core_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP3430_EN_MMC2_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "core_l4_clkdm",
+ .idlest_bit = OMAP3430_ST_MMC2_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk mmchs1_ick = {
.name = "mmchs_ick",
.parent = &core_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP3430_EN_MMC1_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "core_l4_clkdm",
+ .idlest_bit = OMAP3430_ST_MMC1_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk mspro_ick = {
.name = "mspro_ick",
.parent = &core_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP3430_EN_MSPRO_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "core_l4_clkdm",
+ .idlest_bit = OMAP3430_ST_MSPRO_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk hdq_ick = {
.name = "hdq_ick",
.parent = &core_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP3430_EN_HDQ_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "core_l4_clkdm",
+ .idlest_bit = OMAP3430_ST_HDQ_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
.name = "mcspi_ick",
.id = 4,
.parent = &core_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP3430_EN_MCSPI4_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "core_l4_clkdm",
+ .idlest_bit = OMAP3430_ST_MCSPI4_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
.name = "mcspi_ick",
.id = 3,
.parent = &core_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP3430_EN_MCSPI3_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "core_l4_clkdm",
+ .idlest_bit = OMAP3430_ST_MCSPI3_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
.name = "mcspi_ick",
.id = 2,
.parent = &core_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP3430_EN_MCSPI2_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "core_l4_clkdm",
+ .idlest_bit = OMAP3430_ST_MCSPI2_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
.name = "mcspi_ick",
.id = 1,
.parent = &core_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP3430_EN_MCSPI1_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "core_l4_clkdm",
+ .idlest_bit = OMAP3430_ST_MCSPI1_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
.name = "i2c_ick",
.id = 3,
.parent = &core_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP3430_EN_I2C3_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "core_l4_clkdm",
+ .idlest_bit = OMAP3430_ST_I2C3_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
.name = "i2c_ick",
.id = 2,
.parent = &core_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP3430_EN_I2C2_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "core_l4_clkdm",
+ .idlest_bit = OMAP3430_ST_I2C2_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
.name = "i2c_ick",
.id = 1,
.parent = &core_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP3430_EN_I2C1_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "core_l4_clkdm",
+ .idlest_bit = OMAP3430_ST_I2C1_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk uart2_ick = {
.name = "uart2_ick",
.parent = &core_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP3430_EN_UART2_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "core_l4_clkdm",
+ .idlest_bit = OMAP3430_ST_UART2_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk uart1_ick = {
.name = "uart1_ick",
.parent = &core_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP3430_EN_UART1_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "core_l4_clkdm",
+ .idlest_bit = OMAP3430_ST_UART1_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk gpt11_ick = {
.name = "gpt11_ick",
.parent = &core_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP3430_EN_GPT11_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "core_l4_clkdm",
+ .idlest_bit = OMAP3430_ST_GPT11_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk gpt10_ick = {
.name = "gpt10_ick",
.parent = &core_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP3430_EN_GPT10_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "core_l4_clkdm",
+ .idlest_bit = OMAP3430_ST_GPT10_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
.name = "mcbsp_ick",
.id = 5,
.parent = &core_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP3430_EN_MCBSP5_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "core_l4_clkdm",
+ .idlest_bit = OMAP3430_ST_MCBSP5_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
.name = "mcbsp_ick",
.id = 1,
.parent = &core_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP3430_EN_MCBSP1_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "core_l4_clkdm",
+ .idlest_bit = OMAP3430_ST_MCBSP1_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk fac_ick = {
.name = "fac_ick",
.parent = &core_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP3430ES1_EN_FAC_SHIFT,
- .flags = CLOCK_IN_OMAP3430ES1,
- .clkdm_name = "core_l4_clkdm",
+ .idlest_bit = OMAP3430ES1_ST_FAC_SHIFT,
+ .flags = CLOCK_IN_OMAP3430ES1 | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk mailboxes_ick = {
.name = "mailboxes_ick",
.parent = &core_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP3430_EN_MAILBOXES_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "core_l4_clkdm",
+ .idlest_bit = OMAP3430_ST_MAILBOXES_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk omapctrl_ick = {
.name = "omapctrl_ick",
.parent = &core_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP3430_EN_OMAPCTRL_SHIFT,
- .flags = CLOCK_IN_OMAP343X | ENABLE_ON_INIT,
+ .idlest_bit = OMAP3430_ST_OMAPCTRL_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | ENABLE_ON_INIT | WAIT_READY,
+ .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 |
- PARENT_CONTROLS_CLOCK,
- .clkdm_name = "core_l4_clkdm",
+ .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
-static struct clk ssi_ick = {
+static struct clk ssi_ick_3430es1 = {
.name = "ssi_ick",
.parent = &ssi_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP3430_EN_SSI_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "core_l4_clkdm",
+ .flags = CLOCK_IN_OMAP3430ES1,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
-/* REVISIT: Technically the TRM claims that this is CORE_CLK based,
- * but l4_ick makes more sense to me */
+static struct clk ssi_ick_3430es2 = {
+ .name = "ssi_ick",
+ .parent = &ssi_l4_ick,
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_ICLKEN1,
+ .enable_bit = OMAP3430_EN_SSI_SHIFT,
+ .idlest_bit = OMAP3430ES2_ST_SSI_IDLE_SHIFT,
+ .flags = CLOCK_IN_OMAP3430ES2 | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
+ .recalc = &followparent_recalc,
+};
+/*
+ * REVISIT: Technically the TRM claims that this is CORE_CLK based,
+ * but l4_ick makes more sense to me
+ */
static const struct clksel usb_l4_clksel[] = {
{ .parent = &l4_ick, .rates = div2_rates },
{ .parent = NULL },
static struct clk usb_l4_ick = {
.name = "usb_l4_ick",
.parent = &l4_ick,
+ .prcm_mod = CORE_MOD,
.init = &omap2_init_clksel_parent,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+ .enable_reg = CM_ICLKEN1,
.enable_bit = OMAP3430ES1_EN_FSHOSTUSB_SHIFT,
- .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL),
+ .idlest_bit = OMAP3430ES1_ST_FSHOSTUSB_SHIFT,
+ .clksel_reg = CM_CLKSEL,
.clksel_mask = OMAP3430ES1_CLKSEL_FSHOSTUSB_MASK,
.clksel = usb_l4_clksel,
- .flags = CLOCK_IN_OMAP3430ES1,
+ .flags = CLOCK_IN_OMAP3430ES1 | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &omap2_clksel_recalc,
};
static struct clk security_l4_ick2 = {
.name = "security_l4_ick2",
.parent = &l4_ick,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
- PARENT_CONTROLS_CLOCK,
+ .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk aes1_ick = {
.name = "aes1_ick",
.parent = &security_l4_ick2,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_ICLKEN2,
.enable_bit = OMAP3430_EN_AES1_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
+ .idlest_bit = OMAP3430_ST_AES1_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk rng_ick = {
.name = "rng_ick",
.parent = &security_l4_ick2,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_ICLKEN2,
.enable_bit = OMAP3430_EN_RNG_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
+ .idlest_bit = OMAP3430_ST_RNG_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk sha11_ick = {
.name = "sha11_ick",
.parent = &security_l4_ick2,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_ICLKEN2,
.enable_bit = OMAP3430_EN_SHA11_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
+ .idlest_bit = OMAP3430_ST_SHA11_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk des1_ick = {
.name = "des1_ick",
.parent = &security_l4_ick2,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
+ .prcm_mod = CORE_MOD,
+ .enable_reg = CM_ICLKEN2,
.enable_bit = OMAP3430_EN_DES1_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
+ .idlest_bit = OMAP3430_ST_DES1_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .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 = &dpll4_m4x2_ck, .rates = dpll_locked_rates },
- { .parent = NULL }
+static struct clk dss1_alwon_fck_3430es1 = {
+ .name = "dss1_alwon_fck",
+ .parent = &dpll4_m4x2_ck,
+ .prcm_mod = OMAP3430_DSS_MOD,
+ .enable_reg = CM_FCLKEN,
+ .enable_bit = OMAP3430_EN_DSS1_SHIFT,
+ .flags = CLOCK_IN_OMAP3430ES1,
+ .clkdm = { .name = "dss_clkdm" },
+ .recalc = &followparent_recalc,
};
-static struct clk dss1_alwon_fck = {
+static struct clk dss1_alwon_fck_3430es2 = {
.name = "dss1_alwon_fck",
.parent = &dpll4_m4x2_ck,
.init = &omap2_init_clksel_parent,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_DSS_MOD, CM_FCLKEN),
+ .prcm_mod = OMAP3430_DSS_MOD,
+ .enable_reg = CM_FCLKEN,
.enable_bit = OMAP3430_EN_DSS1_SHIFT,
- .clksel_reg = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST),
- .clksel_mask = OMAP3430_ST_PERIPH_CLK_MASK,
- .clksel = dss1_alwon_fck_clksel,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "dss_clkdm",
- .recalc = &omap2_clksel_recalc,
+ .idlest_bit = OMAP3430ES2_ST_DSS_IDLE_SHIFT,
+ .flags = CLOCK_IN_OMAP3430ES2 | WAIT_READY,
+ .clkdm = { .name = "dss_clkdm" },
+ .recalc = &followparent_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),
+ .prcm_mod = OMAP3430_DSS_MOD,
+ .enable_reg = CM_FCLKEN,
.enable_bit = OMAP3430_EN_TV_SHIFT,
.flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "dss_clkdm",
+ .clkdm = { .name = "dss_clkdm" }, /* XXX: in cm_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),
+ .prcm_mod = OMAP3430_DSS_MOD,
+ .enable_reg = CM_FCLKEN,
.enable_bit = OMAP3430_EN_TV_SHIFT,
.flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "dss_clkdm",
+ .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),
+ .prcm_mod = OMAP3430_DSS_MOD,
+ .enable_reg = CM_FCLKEN,
.enable_bit = OMAP3430_EN_DSS2_SHIFT,
.flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "dss_clkdm",
+ .clkdm = { .name = "dss_clkdm" },
.recalc = &followparent_recalc,
};
-static struct clk dss_ick = {
+static struct clk dss_ick_3430es1 = {
/* 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),
+ .prcm_mod = OMAP3430_DSS_MOD,
+ .enable_reg = CM_ICLKEN,
.enable_bit = OMAP3430_CM_ICLKEN_DSS_EN_DSS_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "dss_clkdm",
+ .flags = CLOCK_IN_OMAP3430ES1,
+ .clkdm = { .name = "dss_clkdm" },
.recalc = &followparent_recalc,
};
-/* CAM */
-
-static const struct clksel cam_mclk_clksel[] = {
- { .parent = &sys_ck, .rates = dpll_bypass_rates },
- { .parent = &dpll4_m5x2_ck, .rates = dpll_locked_rates },
- { .parent = NULL }
+static struct clk dss_ick_3430es2 = {
+ /* Handles both L3 and L4 clocks */
+ .name = "dss_ick",
+ .parent = &l4_ick,
+ .prcm_mod = OMAP3430_DSS_MOD,
+ .enable_reg = CM_ICLKEN,
+ .enable_bit = OMAP3430_CM_ICLKEN_DSS_EN_DSS_SHIFT,
+ .idlest_bit = OMAP3430ES2_ST_DSS_IDLE_SHIFT,
+ .flags = CLOCK_IN_OMAP3430ES2 | WAIT_READY,
+ .clkdm = { .name = "dss_clkdm" },
+ .recalc = &followparent_recalc,
};
+/* CAM */
+
static struct clk cam_mclk = {
.name = "cam_mclk",
.parent = &dpll4_m5x2_ck,
- .init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST),
- .clksel_mask = OMAP3430_ST_PERIPH_CLK_MASK,
- .clksel = cam_mclk_clksel,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_CAM_MOD, CM_FCLKEN),
+ .prcm_mod = OMAP3430_CAM_MOD,
+ .enable_reg = CM_FCLKEN,
.enable_bit = OMAP3430_EN_CAM_SHIFT,
.flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "cam_clkdm",
- .recalc = &omap2_clksel_recalc,
+ .clkdm = { .name = "cam_clkdm" },
+ .recalc = &followparent_recalc,
};
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),
+ .prcm_mod = OMAP3430_CAM_MOD,
+ .enable_reg = CM_ICLKEN,
.enable_bit = OMAP3430_EN_CAM_SHIFT,
.flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "cam_clkdm",
+ .clkdm = { .name = "cam_clkdm" },
+ .recalc = &followparent_recalc,
+};
+
+static struct clk csi2_96m_fck = {
+ .name = "csi2_96m_fck",
+ .parent = &core_96m_fck,
+ .prcm_mod = OMAP3430_CAM_MOD,
+ .enable_reg = CM_FCLKEN,
+ .enable_bit = OMAP3430_EN_CSI2_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),
+ .parent = &dpll5_m2_ck,
+ .prcm_mod = OMAP3430ES2_USBHOST_MOD,
+ .enable_reg = CM_FCLKEN,
.enable_bit = OMAP3430ES2_EN_USBHOST2_SHIFT,
.flags = CLOCK_IN_OMAP3430ES2,
- .clkdm_name = "usbhost_clkdm",
+ .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),
+ .prcm_mod = OMAP3430ES2_USBHOST_MOD,
+ .enable_reg = CM_FCLKEN,
.enable_bit = OMAP3430ES2_EN_USBHOST1_SHIFT,
- .flags = CLOCK_IN_OMAP3430ES2,
- .clkdm_name = "usbhost_clkdm",
+ .idlest_bit = OMAP3430ES2_ST_USBHOST_IDLE_SHIFT,
+ .flags = CLOCK_IN_OMAP3430ES2 | WAIT_READY,
+ .clkdm = { .name = "usbhost_clkdm" },
.recalc = &followparent_recalc,
};
/* 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),
+ .prcm_mod = OMAP3430ES2_USBHOST_MOD,
+ .enable_reg = 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",
+ .idlest_bit = OMAP3430ES2_ST_USBHOST_IDLE_SHIFT,
+ .flags = CLOCK_IN_OMAP3430ES2 | WAIT_READY,
+ .clkdm = { .name = "usbhost_clkdm" },
.recalc = &followparent_recalc,
};
static const struct clksel usim_clksel[] = {
{ .parent = &omap_96m_fck, .rates = usim_96m_rates },
- { .parent = &omap_120m_fck, .rates = usim_120m_rates },
+ { .parent = &dpll5_m2_ck, .rates = usim_120m_rates },
{ .parent = &sys_ck, .rates = div2_rates },
{ .parent = NULL },
};
/* 3430ES2 only */
static struct clk usim_fck = {
.name = "usim_fck",
+ .prcm_mod = WKUP_MOD,
.init = &omap2_init_clksel_parent,
- .enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_FCLKEN),
+ .enable_reg = CM_FCLKEN,
.enable_bit = OMAP3430ES2_EN_USIMOCP_SHIFT,
- .clksel_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_CLKSEL),
+ .idlest_bit = OMAP3430ES2_ST_USIMOCP_SHIFT,
+ .clksel_reg = CM_CLKSEL,
.clksel_mask = OMAP3430ES2_CLKSEL_USIMOCP_MASK,
.clksel = usim_clksel,
- .flags = CLOCK_IN_OMAP3430ES2,
+ .flags = CLOCK_IN_OMAP3430ES2 | WAIT_READY,
+ .clkdm = { .name = "prm_clkdm" },
.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",
+ .prcm_mod = WKUP_MOD,
.init = &omap2_init_clksel_parent,
- .enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_FCLKEN),
+ .enable_reg = CM_FCLKEN,
.enable_bit = OMAP3430_EN_GPT1_SHIFT,
- .clksel_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_CLKSEL),
+ .idlest_bit = OMAP3430_ST_GPT1_SHIFT,
+ .clksel_reg = CM_CLKSEL,
.clksel_mask = OMAP3430_CLKSEL_GPT1_MASK,
.clksel = omap343x_gpt_clksel,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "wkup_clkdm",
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "prm_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",
+ .flags = CLOCK_IN_OMAP343X | ALWAYS_ENABLED,
+ .clkdm = { .name = "prm_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk gpio1_dbck = {
.name = "gpio1_dbck",
.parent = &wkup_32k_fck,
- .enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_FCLKEN),
+ .prcm_mod = WKUP_MOD,
+ .enable_reg = CM_FCLKEN,
.enable_bit = OMAP3430_EN_GPIO1_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "wkup_clkdm",
+ .idlest_bit = OMAP3430_ST_GPIO1_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "prm_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk wdt2_fck = {
.name = "wdt2_fck",
.parent = &wkup_32k_fck,
- .enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_FCLKEN),
+ .prcm_mod = WKUP_MOD,
+ .enable_reg = CM_FCLKEN,
.enable_bit = OMAP3430_EN_WDT2_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "wkup_clkdm",
+ .idlest_bit = OMAP3430_ST_WDT2_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "prm_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk wkup_l4_ick = {
.name = "wkup_l4_ick",
.parent = &sys_ck,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
- .clkdm_name = "wkup_clkdm",
+ .flags = CLOCK_IN_OMAP343X | ALWAYS_ENABLED,
+ .clkdm = { .name = "prm_clkdm" },
.recalc = &followparent_recalc,
};
-/* 3430ES2 only */
-/* Never specifically named in the TRM, so we have to infer a likely name */
static struct clk usim_ick = {
.name = "usim_ick",
.parent = &wkup_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
+ .prcm_mod = WKUP_MOD,
+ .enable_reg = CM_ICLKEN,
.enable_bit = OMAP3430ES2_EN_USIMOCP_SHIFT,
- .flags = CLOCK_IN_OMAP3430ES2,
- .clkdm_name = "wkup_clkdm",
+ .idlest_bit = OMAP3430ES2_ST_USIMOCP_SHIFT,
+ .flags = CLOCK_IN_OMAP3430ES2 | WAIT_READY,
+ .clkdm = { .name = "prm_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk wdt2_ick = {
.name = "wdt2_ick",
.parent = &wkup_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
+ .prcm_mod = WKUP_MOD,
+ .enable_reg = CM_ICLKEN,
.enable_bit = OMAP3430_EN_WDT2_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "wkup_clkdm",
+ .idlest_bit = OMAP3430_ST_WDT2_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "prm_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk wdt1_ick = {
.name = "wdt1_ick",
.parent = &wkup_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
+ .prcm_mod = WKUP_MOD,
+ .enable_reg = CM_ICLKEN,
.enable_bit = OMAP3430_EN_WDT1_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "wkup_clkdm",
+ .idlest_bit = OMAP3430_ST_WDT1_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "prm_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk gpio1_ick = {
.name = "gpio1_ick",
.parent = &wkup_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
+ .prcm_mod = WKUP_MOD,
+ .enable_reg = CM_ICLKEN,
.enable_bit = OMAP3430_EN_GPIO1_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "wkup_clkdm",
+ .idlest_bit = OMAP3430_ST_GPIO1_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "prm_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk omap_32ksync_ick = {
.name = "omap_32ksync_ick",
.parent = &wkup_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
+ .prcm_mod = WKUP_MOD,
+ .enable_reg = CM_ICLKEN,
.enable_bit = OMAP3430_EN_32KSYNC_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "wkup_clkdm",
+ .idlest_bit = OMAP3430_ST_32KSYNC_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "prm_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),
+ .prcm_mod = WKUP_MOD,
+ .enable_reg = CM_ICLKEN,
.enable_bit = OMAP3430_EN_GPT12_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "wkup_clkdm",
+ .idlest_bit = OMAP3430_ST_GPT12_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "prm_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk gpt1_ick = {
.name = "gpt1_ick",
.parent = &wkup_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
+ .prcm_mod = WKUP_MOD,
+ .enable_reg = CM_ICLKEN,
.enable_bit = OMAP3430_EN_GPT1_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "wkup_clkdm",
+ .idlest_bit = OMAP3430_ST_GPT1_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "prm_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",
+ .flags = CLOCK_IN_OMAP343X | 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",
+ .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "per_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk uart3_fck = {
.name = "uart3_fck",
.parent = &per_48m_fck,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
+ .prcm_mod = OMAP3430_PER_MOD,
+ .enable_reg = CM_FCLKEN,
.enable_bit = OMAP3430_EN_UART3_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "per_clkdm",
+ .idlest_bit = OMAP3430_ST_UART3_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "per_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk gpt2_fck = {
.name = "gpt2_fck",
+ .prcm_mod = OMAP3430_PER_MOD,
.init = &omap2_init_clksel_parent,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
+ .enable_reg = CM_FCLKEN,
.enable_bit = OMAP3430_EN_GPT2_SHIFT,
- .clksel_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_CLKSEL),
+ .idlest_bit = OMAP3430_ST_GPT2_SHIFT,
+ .clksel_reg = CM_CLKSEL,
.clksel_mask = OMAP3430_CLKSEL_GPT2_MASK,
.clksel = omap343x_gpt_clksel,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "per_clkdm",
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "per_clkdm" },
.recalc = &omap2_clksel_recalc,
};
static struct clk gpt3_fck = {
.name = "gpt3_fck",
+ .prcm_mod = OMAP3430_PER_MOD,
.init = &omap2_init_clksel_parent,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
+ .enable_reg = CM_FCLKEN,
.enable_bit = OMAP3430_EN_GPT3_SHIFT,
- .clksel_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_CLKSEL),
+ .idlest_bit = OMAP3430_ST_GPT3_SHIFT,
+ .clksel_reg = CM_CLKSEL,
.clksel_mask = OMAP3430_CLKSEL_GPT3_MASK,
.clksel = omap343x_gpt_clksel,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "per_clkdm",
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "per_clkdm" },
.recalc = &omap2_clksel_recalc,
};
static struct clk gpt4_fck = {
.name = "gpt4_fck",
+ .prcm_mod = OMAP3430_PER_MOD,
.init = &omap2_init_clksel_parent,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
+ .enable_reg = CM_FCLKEN,
.enable_bit = OMAP3430_EN_GPT4_SHIFT,
- .clksel_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_CLKSEL),
+ .idlest_bit = OMAP3430_ST_GPT4_SHIFT,
+ .clksel_reg = CM_CLKSEL,
.clksel_mask = OMAP3430_CLKSEL_GPT4_MASK,
.clksel = omap343x_gpt_clksel,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "per_clkdm",
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "per_clkdm" },
.recalc = &omap2_clksel_recalc,
};
static struct clk gpt5_fck = {
.name = "gpt5_fck",
+ .prcm_mod = OMAP3430_PER_MOD,
.init = &omap2_init_clksel_parent,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
+ .enable_reg = CM_FCLKEN,
.enable_bit = OMAP3430_EN_GPT5_SHIFT,
- .clksel_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_CLKSEL),
+ .idlest_bit = OMAP3430_ST_GPT5_SHIFT,
+ .clksel_reg = CM_CLKSEL,
.clksel_mask = OMAP3430_CLKSEL_GPT5_MASK,
.clksel = omap343x_gpt_clksel,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "per_clkdm",
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "per_clkdm" },
.recalc = &omap2_clksel_recalc,
};
static struct clk gpt6_fck = {
.name = "gpt6_fck",
+ .prcm_mod = OMAP3430_PER_MOD,
.init = &omap2_init_clksel_parent,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
+ .enable_reg = CM_FCLKEN,
.enable_bit = OMAP3430_EN_GPT6_SHIFT,
- .clksel_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_CLKSEL),
+ .idlest_bit = OMAP3430_ST_GPT6_SHIFT,
+ .clksel_reg = CM_CLKSEL,
.clksel_mask = OMAP3430_CLKSEL_GPT6_MASK,
.clksel = omap343x_gpt_clksel,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "per_clkdm",
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "per_clkdm" },
.recalc = &omap2_clksel_recalc,
};
static struct clk gpt7_fck = {
.name = "gpt7_fck",
+ .prcm_mod = OMAP3430_PER_MOD,
.init = &omap2_init_clksel_parent,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
+ .enable_reg = CM_FCLKEN,
.enable_bit = OMAP3430_EN_GPT7_SHIFT,
- .clksel_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_CLKSEL),
+ .idlest_bit = OMAP3430_ST_GPT7_SHIFT,
+ .clksel_reg = CM_CLKSEL,
.clksel_mask = OMAP3430_CLKSEL_GPT7_MASK,
.clksel = omap343x_gpt_clksel,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "per_clkdm",
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "per_clkdm" },
.recalc = &omap2_clksel_recalc,
};
static struct clk gpt8_fck = {
.name = "gpt8_fck",
+ .prcm_mod = OMAP3430_PER_MOD,
.init = &omap2_init_clksel_parent,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
+ .enable_reg = CM_FCLKEN,
.enable_bit = OMAP3430_EN_GPT8_SHIFT,
- .clksel_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_CLKSEL),
+ .idlest_bit = OMAP3430_ST_GPT8_SHIFT,
+ .clksel_reg = CM_CLKSEL,
.clksel_mask = OMAP3430_CLKSEL_GPT8_MASK,
.clksel = omap343x_gpt_clksel,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "per_clkdm",
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "per_clkdm" },
.recalc = &omap2_clksel_recalc,
};
static struct clk gpt9_fck = {
.name = "gpt9_fck",
+ .prcm_mod = OMAP3430_PER_MOD,
.init = &omap2_init_clksel_parent,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
+ .enable_reg = CM_FCLKEN,
.enable_bit = OMAP3430_EN_GPT9_SHIFT,
- .clksel_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_CLKSEL),
+ .idlest_bit = OMAP3430_ST_GPT9_SHIFT,
+ .clksel_reg = CM_CLKSEL,
.clksel_mask = OMAP3430_CLKSEL_GPT9_MASK,
.clksel = omap343x_gpt_clksel,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "per_clkdm",
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .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,
+ .clkdm = { .name = "per_clkdm" },
+ .flags = CLOCK_IN_OMAP343X | ALWAYS_ENABLED,
.recalc = &followparent_recalc,
};
static struct clk gpio6_dbck = {
.name = "gpio6_dbck",
.parent = &per_32k_alwon_fck,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
+ .prcm_mod = OMAP3430_PER_MOD,
+ .enable_reg = CM_FCLKEN,
.enable_bit = OMAP3430_EN_GPIO6_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "per_clkdm",
+ .idlest_bit = OMAP3430_ST_GPIO6_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "per_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk gpio5_dbck = {
.name = "gpio5_dbck",
.parent = &per_32k_alwon_fck,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
+ .prcm_mod = OMAP3430_PER_MOD,
+ .enable_reg = CM_FCLKEN,
.enable_bit = OMAP3430_EN_GPIO5_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "per_clkdm",
+ .idlest_bit = OMAP3430_ST_GPIO5_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "per_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk gpio4_dbck = {
.name = "gpio4_dbck",
.parent = &per_32k_alwon_fck,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
+ .prcm_mod = OMAP3430_PER_MOD,
+ .enable_reg = CM_FCLKEN,
.enable_bit = OMAP3430_EN_GPIO4_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "per_clkdm",
+ .idlest_bit = OMAP3430_ST_GPIO4_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "per_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk gpio3_dbck = {
.name = "gpio3_dbck",
.parent = &per_32k_alwon_fck,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
+ .prcm_mod = OMAP3430_PER_MOD,
+ .enable_reg = CM_FCLKEN,
.enable_bit = OMAP3430_EN_GPIO3_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "per_clkdm",
+ .idlest_bit = OMAP3430_ST_GPIO3_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "per_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk gpio2_dbck = {
.name = "gpio2_dbck",
.parent = &per_32k_alwon_fck,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
+ .prcm_mod = OMAP3430_PER_MOD,
+ .enable_reg = CM_FCLKEN,
.enable_bit = OMAP3430_EN_GPIO2_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "per_clkdm",
+ .idlest_bit = OMAP3430_ST_GPIO2_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "per_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk wdt3_fck = {
.name = "wdt3_fck",
.parent = &per_32k_alwon_fck,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
+ .prcm_mod = OMAP3430_PER_MOD,
+ .enable_reg = CM_FCLKEN,
.enable_bit = OMAP3430_EN_WDT3_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "per_clkdm",
+ .idlest_bit = OMAP3430_ST_WDT3_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "per_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk per_l4_ick = {
.name = "per_l4_ick",
.parent = &l4_ick,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
- PARENT_CONTROLS_CLOCK,
- .clkdm_name = "per_clkdm",
+ .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "per_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk gpio6_ick = {
.name = "gpio6_ick",
.parent = &per_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
+ .prcm_mod = OMAP3430_PER_MOD,
+ .enable_reg = CM_ICLKEN,
.enable_bit = OMAP3430_EN_GPIO6_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "per_clkdm",
+ .idlest_bit = OMAP3430_ST_GPIO6_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "per_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk gpio5_ick = {
.name = "gpio5_ick",
.parent = &per_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
+ .prcm_mod = OMAP3430_PER_MOD,
+ .enable_reg = CM_ICLKEN,
.enable_bit = OMAP3430_EN_GPIO5_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "per_clkdm",
+ .idlest_bit = OMAP3430_ST_GPIO5_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "per_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk gpio4_ick = {
.name = "gpio4_ick",
.parent = &per_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
+ .prcm_mod = OMAP3430_PER_MOD,
+ .enable_reg = CM_ICLKEN,
.enable_bit = OMAP3430_EN_GPIO4_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "per_clkdm",
+ .idlest_bit = OMAP3430_ST_GPIO4_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "per_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk gpio3_ick = {
.name = "gpio3_ick",
.parent = &per_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
+ .prcm_mod = OMAP3430_PER_MOD,
+ .enable_reg = CM_ICLKEN,
.enable_bit = OMAP3430_EN_GPIO3_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "per_clkdm",
+ .idlest_bit = OMAP3430_ST_GPIO3_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "per_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk gpio2_ick = {
.name = "gpio2_ick",
.parent = &per_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
+ .prcm_mod = OMAP3430_PER_MOD,
+ .enable_reg = CM_ICLKEN,
.enable_bit = OMAP3430_EN_GPIO2_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "per_clkdm",
+ .idlest_bit = OMAP3430_ST_GPIO2_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "per_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk wdt3_ick = {
.name = "wdt3_ick",
.parent = &per_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
+ .prcm_mod = OMAP3430_PER_MOD,
+ .enable_reg = CM_ICLKEN,
.enable_bit = OMAP3430_EN_WDT3_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "per_clkdm",
+ .idlest_bit = OMAP3430_ST_WDT3_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "per_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk uart3_ick = {
.name = "uart3_ick",
.parent = &per_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
+ .prcm_mod = OMAP3430_PER_MOD,
+ .enable_reg = CM_ICLKEN,
.enable_bit = OMAP3430_EN_UART3_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "per_clkdm",
+ .idlest_bit = OMAP3430_ST_UART3_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "per_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk gpt9_ick = {
.name = "gpt9_ick",
.parent = &per_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
+ .prcm_mod = OMAP3430_PER_MOD,
+ .enable_reg = CM_ICLKEN,
.enable_bit = OMAP3430_EN_GPT9_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "per_clkdm",
+ .idlest_bit = OMAP3430_ST_GPT9_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "per_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk gpt8_ick = {
.name = "gpt8_ick",
.parent = &per_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
+ .prcm_mod = OMAP3430_PER_MOD,
+ .enable_reg = CM_ICLKEN,
.enable_bit = OMAP3430_EN_GPT8_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "per_clkdm",
+ .idlest_bit = OMAP3430_ST_GPT8_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "per_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk gpt7_ick = {
.name = "gpt7_ick",
.parent = &per_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
+ .prcm_mod = OMAP3430_PER_MOD,
+ .enable_reg = CM_ICLKEN,
.enable_bit = OMAP3430_EN_GPT7_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "per_clkdm",
+ .idlest_bit = OMAP3430_ST_GPT7_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "per_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk gpt6_ick = {
.name = "gpt6_ick",
.parent = &per_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
+ .prcm_mod = OMAP3430_PER_MOD,
+ .enable_reg = CM_ICLKEN,
.enable_bit = OMAP3430_EN_GPT6_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "per_clkdm",
+ .idlest_bit = OMAP3430_ST_GPT6_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "per_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk gpt5_ick = {
.name = "gpt5_ick",
.parent = &per_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
+ .prcm_mod = OMAP3430_PER_MOD,
+ .enable_reg = CM_ICLKEN,
.enable_bit = OMAP3430_EN_GPT5_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "per_clkdm",
+ .idlest_bit = OMAP3430_ST_GPT5_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "per_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk gpt4_ick = {
.name = "gpt4_ick",
.parent = &per_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
+ .prcm_mod = OMAP3430_PER_MOD,
+ .enable_reg = CM_ICLKEN,
.enable_bit = OMAP3430_EN_GPT4_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "per_clkdm",
+ .idlest_bit = OMAP3430_ST_GPT4_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "per_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk gpt3_ick = {
.name = "gpt3_ick",
.parent = &per_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
+ .prcm_mod = OMAP3430_PER_MOD,
+ .enable_reg = CM_ICLKEN,
.enable_bit = OMAP3430_EN_GPT3_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "per_clkdm",
+ .idlest_bit = OMAP3430_ST_GPT3_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "per_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk gpt2_ick = {
.name = "gpt2_ick",
.parent = &per_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
+ .prcm_mod = OMAP3430_PER_MOD,
+ .enable_reg = CM_ICLKEN,
.enable_bit = OMAP3430_EN_GPT2_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "per_clkdm",
+ .idlest_bit = OMAP3430_ST_GPT2_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "per_clkdm" },
.recalc = &followparent_recalc,
};
.name = "mcbsp_ick",
.id = 2,
.parent = &per_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
+ .prcm_mod = OMAP3430_PER_MOD,
+ .enable_reg = CM_ICLKEN,
.enable_bit = OMAP3430_EN_MCBSP2_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "per_clkdm",
+ .idlest_bit = OMAP3430_ST_MCBSP2_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "per_clkdm" },
.recalc = &followparent_recalc,
};
.name = "mcbsp_ick",
.id = 3,
.parent = &per_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
+ .prcm_mod = OMAP3430_PER_MOD,
+ .enable_reg = CM_ICLKEN,
.enable_bit = OMAP3430_EN_MCBSP3_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "per_clkdm",
+ .idlest_bit = OMAP3430_ST_MCBSP3_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "per_clkdm" },
.recalc = &followparent_recalc,
};
.name = "mcbsp_ick",
.id = 4,
.parent = &per_l4_ick,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
+ .prcm_mod = OMAP3430_PER_MOD,
+ .enable_reg = CM_ICLKEN,
.enable_bit = OMAP3430_EN_MCBSP4_SHIFT,
- .flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "per_clkdm",
+ .idlest_bit = OMAP3430_ST_MCBSP4_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .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 = &core_96m_fck, .rates = common_mcbsp_96m_rates },
+ { .parent = &mcbsp_clks, .rates = common_mcbsp_mcbsp_rates },
{ .parent = NULL }
};
-static struct clk mcbsp2_fck = {
- .name = "mcbsp_fck",
+static struct clk mcbsp2_src_fck = {
+ .name = "mcbsp_src_fck",
.id = 2,
+ .prcm_mod = CLK_REG_IN_SCM,
.init = &omap2_init_clksel_parent,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
- .enable_bit = OMAP3430_EN_MCBSP2_SHIFT,
- .clksel_reg = OMAP343X_CTRL_REGADDR(OMAP2_CONTROL_DEVCONF0),
+ .clksel_reg = OMAP2_CONTROL_DEVCONF0,
.clksel_mask = OMAP2_MCBSP2_CLKS_MASK,
.clksel = mcbsp_234_clksel,
.flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "per_clkdm",
+ .clkdm = { .name = "per_clkdm" },
.recalc = &omap2_clksel_recalc,
};
-static struct clk mcbsp3_fck = {
+static struct clk mcbsp2_fck = {
.name = "mcbsp_fck",
+ .id = 2,
+ .parent = &mcbsp2_src_fck,
+ .prcm_mod = OMAP3430_PER_MOD,
+ .enable_reg = CM_FCLKEN,
+ .enable_bit = OMAP3430_EN_MCBSP2_SHIFT,
+ .idlest_bit = OMAP3430_ST_MCBSP2_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "per_clkdm" },
+ .recalc = &omap2_clksel_recalc,
+};
+
+static struct clk mcbsp3_src_fck = {
+ .name = "mcbsp_src_fck",
.id = 3,
+ .prcm_mod = CLK_REG_IN_SCM,
.init = &omap2_init_clksel_parent,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
- .enable_bit = OMAP3430_EN_MCBSP3_SHIFT,
- .clksel_reg = OMAP343X_CTRL_REGADDR(OMAP343X_CONTROL_DEVCONF1),
+ .clksel_reg = OMAP343X_CONTROL_DEVCONF1,
.clksel_mask = OMAP2_MCBSP3_CLKS_MASK,
.clksel = mcbsp_234_clksel,
.flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "per_clkdm",
+ .clkdm = { .name = "per_clkdm" },
.recalc = &omap2_clksel_recalc,
};
-static struct clk mcbsp4_fck = {
+static struct clk mcbsp3_fck = {
.name = "mcbsp_fck",
+ .id = 3,
+ .parent = &mcbsp3_src_fck,
+ .prcm_mod = OMAP3430_PER_MOD,
+ .enable_reg = CM_FCLKEN,
+ .enable_bit = OMAP3430_EN_MCBSP3_SHIFT,
+ .idlest_bit = OMAP3430_ST_MCBSP3_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "per_clkdm" },
+ .recalc = &omap2_clksel_recalc,
+};
+
+static struct clk mcbsp4_src_fck = {
+ .name = "mcbsp_src_fck",
.id = 4,
+ .prcm_mod = CLK_REG_IN_SCM,
.init = &omap2_init_clksel_parent,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
- .enable_bit = OMAP3430_EN_MCBSP4_SHIFT,
- .clksel_reg = OMAP343X_CTRL_REGADDR(OMAP343X_CONTROL_DEVCONF1),
+ .clksel_reg = OMAP343X_CONTROL_DEVCONF1,
.clksel_mask = OMAP2_MCBSP4_CLKS_MASK,
.clksel = mcbsp_234_clksel,
.flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "per_clkdm",
+ .clkdm = { .name = "per_clkdm" },
+ .recalc = &omap2_clksel_recalc,
+};
+
+static struct clk mcbsp4_fck = {
+ .name = "mcbsp_fck",
+ .id = 4,
+ .parent = &mcbsp4_src_fck,
+ .prcm_mod = OMAP3430_PER_MOD,
+ .enable_reg = CM_FCLKEN,
+ .enable_bit = OMAP3430_EN_MCBSP4_SHIFT,
+ .idlest_bit = OMAP3430_ST_MCBSP4_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "per_clkdm" },
.recalc = &omap2_clksel_recalc,
};
*/
static struct clk emu_src_ck = {
.name = "emu_src_ck",
+ .prcm_mod = OMAP3430_EMU_MOD,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(OMAP3430_EMU_MOD, CM_CLKSEL1),
+ .clksel_reg = CM_CLKSEL1,
.clksel_mask = OMAP3430_MUX_CTRL_MASK,
.clksel = emu_src_clksel,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
- .clkdm_name = "emu_clkdm",
+ .flags = CLOCK_IN_OMAP343X | ALWAYS_ENABLED,
+ .clkdm = { .name = "emu_clkdm" },
.recalc = &omap2_clksel_recalc,
};
static struct clk pclk_fck = {
.name = "pclk_fck",
+ .prcm_mod = OMAP3430_EMU_MOD,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(OMAP3430_EMU_MOD, CM_CLKSEL1),
+ .clksel_reg = CM_CLKSEL1,
.clksel_mask = OMAP3430_CLKSEL_PCLK_MASK,
.clksel = pclk_emu_clksel,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
- .clkdm_name = "emu_clkdm",
+ .flags = CLOCK_IN_OMAP343X | ALWAYS_ENABLED,
+ .clkdm = { .name = "emu_clkdm" },
.recalc = &omap2_clksel_recalc,
};
static struct clk pclkx2_fck = {
.name = "pclkx2_fck",
+ .prcm_mod = OMAP3430_EMU_MOD,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(OMAP3430_EMU_MOD, CM_CLKSEL1),
+ .clksel_reg = CM_CLKSEL1,
.clksel_mask = OMAP3430_CLKSEL_PCLKX2_MASK,
.clksel = pclkx2_emu_clksel,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
- .clkdm_name = "emu_clkdm",
+ .flags = CLOCK_IN_OMAP343X | ALWAYS_ENABLED,
+ .clkdm = { .name = "emu_clkdm" },
.recalc = &omap2_clksel_recalc,
};
static struct clk atclk_fck = {
.name = "atclk_fck",
+ .prcm_mod = OMAP3430_EMU_MOD,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(OMAP3430_EMU_MOD, CM_CLKSEL1),
+ .clksel_reg = CM_CLKSEL1,
.clksel_mask = OMAP3430_CLKSEL_ATCLK_MASK,
.clksel = atclk_emu_clksel,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
- .clkdm_name = "emu_clkdm",
+ .flags = CLOCK_IN_OMAP343X | ALWAYS_ENABLED,
+ .clkdm = { .name = "emu_clkdm" },
.recalc = &omap2_clksel_recalc,
};
static struct clk traceclk_src_fck = {
.name = "traceclk_src_fck",
+ .prcm_mod = OMAP3430_EMU_MOD,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(OMAP3430_EMU_MOD, CM_CLKSEL1),
+ .clksel_reg = CM_CLKSEL1,
.clksel_mask = OMAP3430_TRACE_MUX_CTRL_MASK,
.clksel = emu_src_clksel,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
- .clkdm_name = "emu_clkdm",
+ .flags = CLOCK_IN_OMAP343X | ALWAYS_ENABLED,
+ .clkdm = { .name = "emu_clkdm" },
.recalc = &omap2_clksel_recalc,
};
static struct clk traceclk_fck = {
.name = "traceclk_fck",
+ .prcm_mod = OMAP3430_EMU_MOD,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP_CM_REGADDR(OMAP3430_EMU_MOD, CM_CLKSEL1),
+ .clksel_reg = CM_CLKSEL1,
.clksel_mask = OMAP3430_CLKSEL_TRACECLK_MASK,
.clksel = traceclk_clksel,
.flags = CLOCK_IN_OMAP343X | ALWAYS_ENABLED,
- .clkdm_name = "emu_clkdm",
+ .clkdm = { .name = "emu_clkdm" },
.recalc = &omap2_clksel_recalc,
};
static struct clk sr1_fck = {
.name = "sr1_fck",
.parent = &sys_ck,
- .enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_FCLKEN),
+ .prcm_mod = WKUP_MOD,
+ .enable_reg = CM_FCLKEN,
.enable_bit = OMAP3430_EN_SR1_SHIFT,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES,
+ .idlest_bit = OMAP3430_ST_SR1_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "prm_clkdm" },
.recalc = &followparent_recalc,
};
static struct clk sr2_fck = {
.name = "sr2_fck",
.parent = &sys_ck,
- .enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_FCLKEN),
+ .prcm_mod = WKUP_MOD,
+ .enable_reg = CM_FCLKEN,
.enable_bit = OMAP3430_EN_SR2_SHIFT,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES,
+ .idlest_bit = OMAP3430_ST_SR2_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | WAIT_READY,
+ .clkdm = { .name = "prm_clkdm" },
.recalc = &followparent_recalc,
};
.name = "sr_l4_ick",
.parent = &l4_ick,
.flags = CLOCK_IN_OMAP343X,
- .clkdm_name = "core_l4_clkdm",
+ .clkdm = { .name = "core_l4_clkdm" },
.recalc = &followparent_recalc,
};
/* SECURE_32K_FCK clocks */
-/* XXX This clock no longer exists in 3430 TRM rev F */
+/* XXX Make sure idlest_bit/wait_ready with no enable_bit works */
static struct clk gpt12_fck = {
.name = "gpt12_fck",
.parent = &secure_32k_fck,
- .flags = CLOCK_IN_OMAP343X | ALWAYS_ENABLED,
+ .idlest_bit = OMAP3430_ST_GPT12_SHIFT,
+ .flags = CLOCK_IN_OMAP343X | ALWAYS_ENABLED | WAIT_READY,
+ .clkdm = { .name = "prm_clkdm" },
.recalc = &followparent_recalc,
};
.name = "wdt1_fck",
.parent = &secure_32k_fck,
.flags = CLOCK_IN_OMAP343X | ALWAYS_ENABLED,
+ .clkdm = { .name = "prm_clkdm" },
.recalc = &followparent_recalc,
};
&omap_96m_alwon_fck,
&omap_96m_fck,
&cm_96m_fck,
- &virt_omap_54m_fck,
&omap_54m_fck,
&omap_48m_fck,
&omap_12m_fck,
&emu_per_alwon_ck,
&dpll5_ck,
&dpll5_m2_ck,
- &omap_120m_fck,
&clkout2_src_ck,
&sys_clkout2,
&corex2_fck,
&i2c3_fck,
&i2c2_fck,
&i2c1_fck,
+ &mcbsp5_src_fck,
&mcbsp5_fck,
+ &mcbsp1_src_fck,
&mcbsp1_fck,
&core_48m_fck,
&mcspi4_fck,
&fshostusb_fck,
&core_12m_fck,
&hdq_fck,
- &ssi_ssr_fck,
- &ssi_sst_fck,
+ &ssi_ssr_fck_3430es1,
+ &ssi_ssr_fck_3430es2,
+ &ssi_sst_fck_3430es1,
+ &ssi_sst_fck_3430es2,
&core_l3_ick,
- &hsotgusb_ick,
+ &hsotgusb_ick_3430es1,
+ &hsotgusb_ick_3430es2,
&sdrc_ick,
&gpmc_fck,
&security_l3_ick,
&mailboxes_ick,
&omapctrl_ick,
&ssi_l4_ick,
- &ssi_ick,
+ &ssi_ick_3430es1,
+ &ssi_ick_3430es2,
&usb_l4_ick,
&security_l4_ick2,
&aes1_ick,
&rng_ick,
&sha11_ick,
&des1_ick,
- &dss1_alwon_fck,
+ &dss1_alwon_fck_3430es1,
+ &dss1_alwon_fck_3430es2,
&dss_tv_fck,
&dss_96m_fck,
&dss2_alwon_fck,
- &dss_ick,
+ &dss_ick_3430es1,
+ &dss_ick_3430es2,
&cam_mclk,
&cam_ick,
+ &csi2_96m_fck,
&usbhost_120m_fck,
&usbhost_48m_fck,
&usbhost_ick,
- &usbhost_sar_fck,
&usim_fck,
&gpt1_fck,
&wkup_32k_fck,
&mcbsp2_ick,
&mcbsp3_ick,
&mcbsp4_ick,
+ &mcbsp2_src_fck,
&mcbsp2_fck,
+ &mcbsp3_src_fck,
&mcbsp3_fck,
+ &mcbsp4_src_fck,
&mcbsp4_fck,
&emu_src_ck,
&pclk_fck,
if (!omap_chip_is(autodep->omap_chip))
return;
- pwrdm = pwrdm_lookup(autodep->pwrdm_name);
+ pwrdm = pwrdm_lookup(autodep->pwrdm.name);
if (!pwrdm) {
pr_debug("clockdomain: _autodep_lookup: powerdomain %s "
- "does not exist\n", autodep->pwrdm_name);
+ "does not exist\n", autodep->pwrdm.name);
WARN_ON(1);
return;
}
- autodep->pwrdm = pwrdm;
+ autodep->pwrdm.ptr = pwrdm;
return;
}
{
struct clkdm_pwrdm_autodep *autodep;
- for (autodep = autodeps; autodep->pwrdm_name; autodep++) {
- if (!autodep->pwrdm)
+ for (autodep = autodeps; autodep->pwrdm.ptr; autodep++) {
+ if (!omap_chip_is(autodep->omap_chip))
continue;
pr_debug("clockdomain: adding %s sleepdep/wkdep for "
- "pwrdm %s\n", autodep->pwrdm_name,
- clkdm->pwrdm->name);
+ "pwrdm %s\n", autodep->pwrdm.ptr->name,
+ clkdm->pwrdm.ptr->name);
- pwrdm_add_sleepdep(clkdm->pwrdm, autodep->pwrdm);
- pwrdm_add_wkdep(clkdm->pwrdm, autodep->pwrdm);
+ pwrdm_add_sleepdep(clkdm->pwrdm.ptr, autodep->pwrdm.ptr);
+ pwrdm_add_wkdep(clkdm->pwrdm.ptr, autodep->pwrdm.ptr);
}
}
{
struct clkdm_pwrdm_autodep *autodep;
- for (autodep = autodeps; autodep->pwrdm_name; autodep++) {
- if (!autodep->pwrdm)
+ for (autodep = autodeps; autodep->pwrdm.ptr; autodep++) {
+ if (!omap_chip_is(autodep->omap_chip))
continue;
pr_debug("clockdomain: removing %s sleepdep/wkdep for "
- "pwrdm %s\n", autodep->pwrdm_name,
- clkdm->pwrdm->name);
+ "pwrdm %s\n", autodep->pwrdm.ptr->name,
+ clkdm->pwrdm.ptr->name);
- pwrdm_del_sleepdep(clkdm->pwrdm, autodep->pwrdm);
- pwrdm_del_wkdep(clkdm->pwrdm, autodep->pwrdm);
+ pwrdm_del_sleepdep(clkdm->pwrdm.ptr, autodep->pwrdm.ptr);
+ pwrdm_del_wkdep(clkdm->pwrdm.ptr, autodep->pwrdm.ptr);
}
}
autodeps = init_autodeps;
if (autodeps)
- for (autodep = autodeps; autodep->pwrdm_name; autodep++)
+ for (autodep = autodeps; autodep->pwrdm.ptr; autodep++)
_autodep_lookup(autodep);
}
if (!omap_chip_is(clkdm->omap_chip))
return -EINVAL;
- pwrdm = pwrdm_lookup(clkdm->pwrdm_name);
+ 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);
+ "does not exist\n", clkdm->name, clkdm->pwrdm.name);
return -EINVAL;
}
- clkdm->pwrdm = pwrdm;
+ clkdm->pwrdm.ptr = pwrdm;
mutex_lock(&clkdm_mutex);
/* Verify that the clockdomain is not already registered */
if (!clkdm)
return -EINVAL;
- pwrdm_del_clkdm(clkdm->pwrdm, clkdm);
+ pwrdm_del_clkdm(clkdm->pwrdm.ptr, clkdm);
mutex_lock(&clkdm_mutex);
list_del(&clkdm->node);
if (!clkdm)
return NULL;
- return clkdm->pwrdm;
+ return clkdm->pwrdm.ptr;
}
if (!clkdm)
return -EINVAL;
- v = cm_read_mod_reg(clkdm->pwrdm->prcm_offs, CM_CLKSTCTRL);
+ v = cm_read_mod_reg(clkdm->pwrdm.ptr->prcm_offs, CM_CLKSTCTRL);
v &= clkdm->clktrctrl_mask;
v >>= __ffs(clkdm->clktrctrl_mask);
if (cpu_is_omap24xx()) {
cm_set_mod_reg_bits(OMAP24XX_FORCESTATE,
- clkdm->pwrdm->prcm_offs, PM_PWSTCTRL);
+ clkdm->pwrdm.ptr->prcm_offs, PM_PWSTCTRL);
} else if (cpu_is_omap34xx()) {
__ffs(clkdm->clktrctrl_mask));
cm_rmw_mod_reg_bits(clkdm->clktrctrl_mask, v,
- clkdm->pwrdm->prcm_offs, CM_CLKSTCTRL);
+ clkdm->pwrdm.ptr->prcm_offs, CM_CLKSTCTRL);
} else {
BUG();
if (cpu_is_omap24xx()) {
cm_clear_mod_reg_bits(OMAP24XX_FORCESTATE,
- clkdm->pwrdm->prcm_offs, PM_PWSTCTRL);
+ clkdm->pwrdm.ptr->prcm_offs, PM_PWSTCTRL);
} else if (cpu_is_omap34xx()) {
__ffs(clkdm->clktrctrl_mask));
cm_rmw_mod_reg_bits(clkdm->clktrctrl_mask, v,
- clkdm->pwrdm->prcm_offs, CM_CLKSTCTRL);
+ clkdm->pwrdm.ptr->prcm_offs, CM_CLKSTCTRL);
} else {
BUG();
cm_rmw_mod_reg_bits(clkdm->clktrctrl_mask,
v << __ffs(clkdm->clktrctrl_mask),
- clkdm->pwrdm->prcm_offs,
+ clkdm->pwrdm.ptr->prcm_offs,
CM_CLKSTCTRL);
}
cm_rmw_mod_reg_bits(clkdm->clktrctrl_mask,
v << __ffs(clkdm->clktrctrl_mask),
- clkdm->pwrdm->prcm_offs, CM_CLKSTCTRL);
+ clkdm->pwrdm.ptr->prcm_offs, CM_CLKSTCTRL);
if (atomic_read(&clkdm->usecount) > 0)
_clkdm_del_autodeps(clkdm);
else
omap2_clkdm_wakeup(clkdm);
+ pwrdm_wait_transition(clkdm->pwrdm.ptr);
+
return 0;
}
/*
* OMAP2/3-common clockdomains
+ *
+ * Even though the 2420 has a single PRCM module from the
+ * interconnect's perspective, internally it does appear to have
+ * separate PRM and CM clockdomains. The usual test case is
+ * sys_clkout/sys_clkout2.
*/
-/* 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",
+static struct clockdomain prm_clkdm = {
+ .name = "prm_clkdm",
+ .pwrdm = { .name = "wkup_pwrdm" },
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX | CHIP_IS_OMAP3430),
+};
+
+static struct clockdomain cm_clkdm = {
+ .name = "cm_clkdm",
+ .pwrdm = { .name = "core_pwrdm" },
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX | CHIP_IS_OMAP3430),
};
+/*
+ * virt_opp_clkdm is intended solely for use with virtual OPP clocks,
+ * e.g., virt_prcm_set, until OPP handling is rationalized.
+ */
+static struct clockdomain virt_opp_clkdm = {
+ .name = "virt_opp_clkdm",
+ .pwrdm = { .name = "wkup_pwrdm" },
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX),
+};
+
/*
* 2420-only clockdomains
*/
static struct clockdomain mpu_2420_clkdm = {
.name = "mpu_clkdm",
- .pwrdm_name = "mpu_pwrdm",
+ .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",
+ .pwrdm = { .name = "dsp_pwrdm" },
.flags = CLKDM_CAN_HWSUP_SWSUP,
.clktrctrl_mask = OMAP2420_AUTOSTATE_IVA_MASK,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420),
static struct clockdomain mpu_2430_clkdm = {
.name = "mpu_clkdm",
- .pwrdm_name = "mpu_pwrdm",
+ .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",
+ .pwrdm = { .name = "mdm_pwrdm" },
.flags = CLKDM_CAN_HWSUP_SWSUP,
.clktrctrl_mask = OMAP2430_AUTOSTATE_MDM_MASK,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430),
static struct clockdomain dsp_clkdm = {
.name = "dsp_clkdm",
- .pwrdm_name = "dsp_pwrdm",
+ .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",
+ .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",
+ .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",
+ .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",
+ .pwrdm = { .name = "core_pwrdm" },
.flags = CLKDM_CAN_HWSUP,
.clktrctrl_mask = OMAP24XX_AUTOSTATE_DSS_MASK,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX),
static struct clockdomain mpu_34xx_clkdm = {
.name = "mpu_clkdm",
- .pwrdm_name = "mpu_pwrdm",
+ .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",
+ .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",
+ .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",
+ .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",
+ .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",
+ .pwrdm = { .name = "core_pwrdm" },
.flags = CLKDM_CAN_HWSUP,
.clktrctrl_mask = OMAP3430ES1_CLKTRCTRL_D2D_MASK,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
static struct clockdomain core_l3_34xx_clkdm = {
.name = "core_l3_clkdm",
- .pwrdm_name = "core_pwrdm",
+ .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",
+ .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",
+ .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",
+ .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",
+ .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",
+ .pwrdm = { .name = "per_pwrdm" },
.flags = CLKDM_CAN_HWSUP_SWSUP,
.clktrctrl_mask = OMAP3430_CLKTRCTRL_PER_MASK,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
};
+/*
+ * Disable hw supervised mode for emu_clkdm, because emu_pwrdm is
+ * switched of even if sdti is in use
+ */
static struct clockdomain emu_clkdm = {
.name = "emu_clkdm",
- .pwrdm_name = "emu_pwrdm",
- .flags = CLKDM_CAN_ENABLE_AUTO | CLKDM_CAN_SWSUP,
+ .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),
};
+static struct clockdomain dpll1_clkdm = {
+ .name = "dpll1_clkdm",
+ .pwrdm = { .name = "dpll1_pwrdm" },
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct clockdomain dpll2_clkdm = {
+ .name = "dpll2_clkdm",
+ .pwrdm = { .name = "dpll2_pwrdm" },
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct clockdomain dpll3_clkdm = {
+ .name = "dpll3_clkdm",
+ .pwrdm = { .name = "dpll3_pwrdm" },
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct clockdomain dpll4_clkdm = {
+ .name = "dpll4_clkdm",
+ .pwrdm = { .name = "dpll4_pwrdm" },
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct clockdomain dpll5_clkdm = {
+ .name = "dpll5_clkdm",
+ .pwrdm = { .name = "dpll5_pwrdm" },
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES2),
+};
+
#endif /* CONFIG_ARCH_OMAP34XX */
/*
static struct clkdm_pwrdm_autodep clkdm_pwrdm_autodeps[] = {
{
- .pwrdm_name = "mpu_pwrdm",
+ .pwrdm = { .name = "mpu_pwrdm" },
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
},
{
- .pwrdm_name = "iva2_pwrdm",
+ .pwrdm = { .name = "iva2_pwrdm" },
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
},
- { NULL }
+ {
+ .pwrdm = { .name = NULL },
+ }
};
/*
static struct clockdomain *clockdomains_omap[] = {
- &wkup_clkdm,
+ &cm_clkdm,
+ &prm_clkdm,
+ &virt_opp_clkdm,
#ifdef CONFIG_ARCH_OMAP2420
&mpu_2420_clkdm,
&usbhost_clkdm,
&per_clkdm,
&emu_clkdm,
+ &dpll1_clkdm,
+ &dpll2_clkdm,
+ &dpll3_clkdm,
+ &dpll4_clkdm,
+ &dpll5_clkdm,
#endif
NULL,
#define OMAP24XX_EN_DES (1 << 0)
/* CM_IDLEST1_CORE specific bits */
-#define OMAP24XX_ST_MAILBOXES (1 << 30)
-#define OMAP24XX_ST_WDT4 (1 << 29)
-#define OMAP2420_ST_WDT3 (1 << 28)
-#define OMAP24XX_ST_MSPRO (1 << 27)
-#define OMAP24XX_ST_FAC (1 << 25)
-#define OMAP2420_ST_EAC (1 << 24)
-#define OMAP24XX_ST_HDQ (1 << 23)
-#define OMAP24XX_ST_I2C2 (1 << 20)
-#define OMAP24XX_ST_I2C1 (1 << 19)
-#define OMAP24XX_ST_MCBSP2 (1 << 16)
-#define OMAP24XX_ST_MCBSP1 (1 << 15)
-#define OMAP24XX_ST_DSS (1 << 0)
+#define OMAP24XX_ST_MAILBOXES_SHIFT 30
+#define OMAP24XX_ST_MAILBOXES_MASK (1 << 30)
+#define OMAP24XX_ST_WDT4_SHIFT 29
+#define OMAP24XX_ST_WDT4_MASK (1 << 29)
+#define OMAP2420_ST_WDT3_SHIFT 28
+#define OMAP2420_ST_WDT3_MASK (1 << 28)
+#define OMAP24XX_ST_MSPRO_SHIFT 27
+#define OMAP24XX_ST_MSPRO_MASK (1 << 27)
+#define OMAP24XX_ST_FAC_SHIFT 25
+#define OMAP24XX_ST_FAC_MASK (1 << 25)
+#define OMAP2420_ST_EAC_SHIFT 24
+#define OMAP2420_ST_EAC_MASK (1 << 24)
+#define OMAP24XX_ST_HDQ_SHIFT 23
+#define OMAP24XX_ST_HDQ_MASK (1 << 23)
+#define OMAP2420_ST_I2C2_SHIFT 20
+#define OMAP2420_ST_I2C2_MASK (1 << 20)
+#define OMAP2420_ST_I2C1_SHIFT 19
+#define OMAP2420_ST_I2C1_MASK (1 << 19)
+#define OMAP24XX_ST_MCBSP2_SHIFT 16
+#define OMAP24XX_ST_MCBSP2_MASK (1 << 16)
+#define OMAP24XX_ST_MCBSP1_SHIFT 15
+#define OMAP24XX_ST_MCBSP1_MASK (1 << 15)
+#define OMAP24XX_ST_DSS_SHIFT 0
+#define OMAP24XX_ST_DSS_MASK (1 << 0)
/* CM_IDLEST2_CORE */
-#define OMAP2430_ST_MCBSP5 (1 << 5)
-#define OMAP2430_ST_MCBSP4 (1 << 4)
-#define OMAP2430_ST_MCBSP3 (1 << 3)
-#define OMAP24XX_ST_SSI (1 << 1)
+#define OMAP2430_ST_MCBSP5_SHIFT 5
+#define OMAP2430_ST_MCBSP5_MASK (1 << 5)
+#define OMAP2430_ST_MCBSP4_SHIFT 4
+#define OMAP2430_ST_MCBSP4_MASK (1 << 4)
+#define OMAP2430_ST_MCBSP3_SHIFT 3
+#define OMAP2430_ST_MCBSP3_MASK (1 << 3)
+#define OMAP24XX_ST_SSI_SHIFT 1
+#define OMAP24XX_ST_SSI_MASK (1 << 1)
/* CM_IDLEST3_CORE */
/* 2430 only */
-#define OMAP2430_ST_SDRC (1 << 2)
+#define OMAP2430_ST_SDRC_SHIFT 2
+#define OMAP2430_ST_SDRC_MASK (1 << 2)
/* CM_IDLEST4_CORE */
-#define OMAP24XX_ST_PKA (1 << 4)
-#define OMAP24XX_ST_AES (1 << 3)
-#define OMAP24XX_ST_RNG (1 << 2)
-#define OMAP24XX_ST_SHA (1 << 1)
-#define OMAP24XX_ST_DES (1 << 0)
+#define OMAP24XX_ST_PKA_SHIFT 4
+#define OMAP24XX_ST_PKA_MASK (1 << 4)
+#define OMAP24XX_ST_AES_SHIFT 3
+#define OMAP24XX_ST_AES_MASK (1 << 3)
+#define OMAP24XX_ST_RNG_SHIFT 2
+#define OMAP24XX_ST_RNG_MASK (1 << 2)
+#define OMAP24XX_ST_SHA_SHIFT 1
+#define OMAP24XX_ST_SHA_MASK (1 << 1)
+#define OMAP24XX_ST_DES_SHIFT 0
+#define OMAP24XX_ST_DES_MASK (1 << 0)
/* CM_AUTOIDLE1_CORE */
#define OMAP24XX_AUTO_CAM (1 << 31)
#define OMAP24XX_EN_32KSYNC (1 << 1)
/* CM_IDLEST_WKUP specific bits */
-#define OMAP2430_ST_ICR (1 << 6)
-#define OMAP24XX_ST_OMAPCTRL (1 << 5)
-#define OMAP24XX_ST_WDT1 (1 << 4)
-#define OMAP24XX_ST_MPU_WDT (1 << 3)
-#define OMAP24XX_ST_32KSYNC (1 << 1)
+#define OMAP2430_ST_ICR_SHIFT 6
+#define OMAP2430_ST_ICR_MASK (1 << 6)
+#define OMAP24XX_ST_OMAPCTRL_SHIFT 5
+#define OMAP24XX_ST_OMAPCTRL_MASK (1 << 5)
+#define OMAP24XX_ST_WDT1_SHIFT 4
+#define OMAP24XX_ST_WDT1_MASK (1 << 4)
+#define OMAP24XX_ST_MPU_WDT_SHIFT 3
+#define OMAP24XX_ST_MPU_WDT_MASK (1 << 3)
+#define OMAP24XX_ST_32KSYNC_SHIFT 1
+#define OMAP24XX_ST_32KSYNC_MASK (1 << 1)
/* CM_AUTOIDLE_WKUP */
#define OMAP24XX_AUTO_OMAPCTRL (1 << 5)
#define OMAP3430ES2_EN_CPEFUSE_MASK (1 << 0)
/* CM_IDLEST1_CORE specific bits */
-#define OMAP3430_ST_ICR (1 << 29)
-#define OMAP3430_ST_AES2 (1 << 28)
-#define OMAP3430_ST_SHA12 (1 << 27)
-#define OMAP3430_ST_DES2 (1 << 26)
-#define OMAP3430_ST_MSPRO (1 << 23)
-#define OMAP3430_ST_HDQ (1 << 22)
-#define OMAP3430ES1_ST_FAC (1 << 8)
-#define OMAP3430ES1_ST_MAILBOXES (1 << 7)
-#define OMAP3430_ST_OMAPCTRL (1 << 6)
-#define OMAP3430_ST_SDMA (1 << 2)
-#define OMAP3430_ST_SDRC (1 << 1)
-#define OMAP3430_ST_SSI (1 << 0)
+#define OMAP3430ES2_ST_MMC3_SHIFT 30
+#define OMAP3430ES2_ST_MMC3_MASK (1 << 30)
+#define OMAP3430_ST_ICR_SHIFT 29
+#define OMAP3430_ST_ICR_MASK (1 << 29)
+#define OMAP3430_ST_AES2_SHIFT 28
+#define OMAP3430_ST_AES2_MASK (1 << 28)
+#define OMAP3430_ST_SHA12_SHIFT 27
+#define OMAP3430_ST_SHA12_MASK (1 << 27)
+#define OMAP3430_ST_DES2_SHIFT 26
+#define OMAP3430_ST_DES2_MASK (1 << 26)
+#define OMAP3430_ST_MSPRO_SHIFT 23
+#define OMAP3430_ST_MSPRO_MASK (1 << 23)
+#define OMAP3430_ST_HDQ_SHIFT 22
+#define OMAP3430_ST_HDQ_MASK (1 << 22)
+#define OMAP3430ES1_ST_FAC_SHIFT 8
+#define OMAP3430ES1_ST_FAC_MASK (1 << 8)
+#define OMAP3430ES2_ST_SSI_IDLE_SHIFT 8
+#define OMAP3430ES2_ST_SSI_IDLE_MASK (1 << 8)
+#define OMAP3430_ST_MAILBOXES_SHIFT 7
+#define OMAP3430_ST_MAILBOXES_MASK (1 << 7)
+#define OMAP3430_ST_OMAPCTRL_SHIFT 6
+#define OMAP3430_ST_OMAPCTRL_MASK (1 << 6)
+#define OMAP3430_ST_SDMA_SHIFT 2
+#define OMAP3430_ST_SDMA_MASK (1 << 2)
+#define OMAP3430_ST_SDRC_SHIFT 1
+#define OMAP3430_ST_SDRC_MASK (1 << 1)
+#define OMAP3430_ST_SSI_STDBY_SHIFT 0
+#define OMAP3430_ST_SSI_STDBY_MASK (1 << 0)
/* CM_IDLEST2_CORE */
-#define OMAP3430_ST_PKA (1 << 4)
-#define OMAP3430_ST_AES1 (1 << 3)
-#define OMAP3430_ST_RNG (1 << 2)
-#define OMAP3430_ST_SHA11 (1 << 1)
-#define OMAP3430_ST_DES1 (1 << 0)
+#define OMAP3430_ST_PKA_SHIFT 4
+#define OMAP3430_ST_PKA_MASK (1 << 4)
+#define OMAP3430_ST_AES1_SHIFT 3
+#define OMAP3430_ST_AES1_MASK (1 << 3)
+#define OMAP3430_ST_RNG_SHIFT 2
+#define OMAP3430_ST_RNG_MASK (1 << 2)
+#define OMAP3430_ST_SHA11_SHIFT 1
+#define OMAP3430_ST_SHA11_MASK (1 << 1)
+#define OMAP3430_ST_DES1_SHIFT 0
+#define OMAP3430_ST_DES1_MASK (1 << 0)
/* CM_IDLEST3_CORE */
#define OMAP3430ES2_ST_USBTLL_SHIFT 2
#define OMAP3430ES2_ST_USBTLL_MASK (1 << 2)
+#define OMAP3430ES2_ST_CPEFUSE_SHIFT 0
+#define OMAP3430ES2_ST_CPEFUSE_MASK (1 << 0)
/* CM_AUTOIDLE1_CORE */
+#define OMAP3430ES2_AUTO_MMC3 (1 << 30)
+#define OMAP3430ES2_AUTO_MMC3_SHIFT 30
+#define OMAP3430ES2_AUTO_ICR (1 << 29)
+#define OMAP3430ES2_AUTO_ICR_SHIFT 29
#define OMAP3430_AUTO_AES2 (1 << 28)
#define OMAP3430_AUTO_AES2_SHIFT 28
#define OMAP3430_AUTO_SHA12 (1 << 27)
#define OMAP3430_AUTO_DES1_SHIFT 0
/* CM_AUTOIDLE3_CORE */
+#define OMAP3430ES2_AUTO_USBHOST (1 << 0)
+#define OMAP3430ES2_AUTO_USBHOST_SHIFT 0
+#define OMAP3430ES2_AUTO_USBTLL (1 << 2)
#define OMAP3430ES2_AUTO_USBTLL_SHIFT 2
#define OMAP3430ES2_AUTO_USBTLL_MASK (1 << 2)
#define OMAP3430ES1_CLKACTIVITY_GFX_MASK (1 << 0)
/* CM_FCLKEN_SGX */
-#define OMAP3430ES2_EN_SGX_SHIFT 1
-#define OMAP3430ES2_EN_SGX_MASK (1 << 1)
+#define OMAP3430ES2_CM_FCLKEN_SGX_EN_SGX_SHIFT 1
+#define OMAP3430ES2_CM_FCLKEN_SGX_EN_SGX_MASK (1 << 1)
+
+/* CM_ICLKEN_SGX */
+#define OMAP3430ES2_CM_ICLKEN_SGX_EN_SGX_SHIFT 0
+#define OMAP3430ES2_CM_ICLKEN_SGX_EN_SGX_MASK (1 << 0)
/* CM_CLKSEL_SGX */
#define OMAP3430ES2_CLKSEL_SGX_SHIFT 0
/* CM_FCLKEN_WKUP specific bits */
#define OMAP3430ES2_EN_USIMOCP_SHIFT 9
+#define OMAP3430ES2_EN_USIMOCP_MASK (1 << 9)
/* CM_ICLKEN_WKUP specific bits */
#define OMAP3430_EN_WDT1 (1 << 4)
#define OMAP3430_EN_32KSYNC_SHIFT 2
/* CM_IDLEST_WKUP specific bits */
-#define OMAP3430_ST_WDT2 (1 << 5)
-#define OMAP3430_ST_WDT1 (1 << 4)
-#define OMAP3430_ST_32KSYNC (1 << 2)
+#define OMAP3430ES2_ST_USIMOCP_SHIFT 9
+#define OMAP3430ES2_ST_USIMOCP_MASK (1 << 9)
+#define OMAP3430_ST_WDT2_SHIFT 5
+#define OMAP3430_ST_WDT2_MASK (1 << 5)
+#define OMAP3430_ST_WDT1_SHIFT 4
+#define OMAP3430_ST_WDT1_MASK (1 << 4)
+#define OMAP3430_ST_32KSYNC_SHIFT 2
+#define OMAP3430_ST_32KSYNC_MASK (1 << 2)
/* CM_AUTOIDLE_WKUP */
+#define OMAP3430ES2_AUTO_USIMOCP (1 << 9)
+#define OMAP3430ES2_AUTO_USIMOCP_SHIFT 9
#define OMAP3430_AUTO_WDT2 (1 << 5)
#define OMAP3430_AUTO_WDT2_SHIFT 5
#define OMAP3430_AUTO_WDT1 (1 << 4)
#define OMAP3430_ST_CORE_CLK_MASK (1 << 0)
/* CM_IDLEST2_CKGEN */
+#define OMAP3430ES2_ST_USIM_CLK_SHIFT 2
+#define OMAP3430ES2_ST_USIM_CLK_MASK (1 << 2)
#define OMAP3430ES2_ST_120M_CLK_SHIFT 1
#define OMAP3430ES2_ST_120M_CLK_MASK (1 << 1)
#define OMAP3430ES2_ST_PERIPH2_CLK_SHIFT 0
#define OMAP3430_CORE_DPLL_MULT_MASK (0x7ff << 16)
#define OMAP3430_CORE_DPLL_DIV_SHIFT 8
#define OMAP3430_CORE_DPLL_DIV_MASK (0x7f << 8)
-#define OMAP3430_SOURCE_54M (1 << 5)
-#define OMAP3430_SOURCE_48M (1 << 3)
+#define OMAP3430_SOURCE_96M_SHIFT 6
+#define OMAP3430_SOURCE_96M_MASK (1 << 6)
+#define OMAP3430_SOURCE_54M_SHIFT 5
+#define OMAP3430_SOURCE_54M_MASK (1 << 5)
+#define OMAP3430_SOURCE_48M_SHIFT 3
+#define OMAP3430_SOURCE_48M_MASK (1 << 3)
/* CM_CLKSEL2_PLL */
#define OMAP3430_PERIPH_DPLL_MULT_SHIFT 8
#define OMAP3430_CM_ICLKEN_DSS_EN_DSS_SHIFT 0
/* CM_IDLEST_DSS */
-#define OMAP3430_ST_DSS (1 << 0)
+#define OMAP3430ES2_ST_DSS_IDLE_SHIFT 1
+#define OMAP3430ES2_ST_DSS_IDLE_MASK (1 << 1)
+#define OMAP3430ES2_ST_DSS_STDBY_SHIFT 0
+#define OMAP3430ES2_ST_DSS_STDBY_MASK (1 << 0)
+#define OMAP3430ES1_ST_DSS_SHIFT 0
+#define OMAP3430ES1_ST_DSS_MASK (1 << 0)
/* CM_AUTOIDLE_DSS */
#define OMAP3430_AUTO_DSS (1 << 0)
#define OMAP3430_CLKACTIVITY_DSS_MASK (1 << 0)
/* CM_FCLKEN_CAM specific bits */
+#define OMAP3430_EN_CSI2 (1 << 1)
+#define OMAP3430_EN_CSI2_SHIFT 1
/* CM_ICLKEN_CAM specific bits */
/* CM_ICLKEN_PER specific bits */
/* CM_IDLEST_PER */
-#define OMAP3430_ST_WDT3 (1 << 12)
-#define OMAP3430_ST_MCBSP4 (1 << 2)
-#define OMAP3430_ST_MCBSP3 (1 << 1)
-#define OMAP3430_ST_MCBSP2 (1 << 0)
+#define OMAP3430_ST_WDT3_SHIFT 12
+#define OMAP3430_ST_WDT3_MASK (1 << 12)
+#define OMAP3430_ST_MCBSP4_SHIFT 2
+#define OMAP3430_ST_MCBSP4_MASK (1 << 2)
+#define OMAP3430_ST_MCBSP3_SHIFT 1
+#define OMAP3430_ST_MCBSP3_MASK (1 << 1)
+#define OMAP3430_ST_MCBSP2_SHIFT 0
+#define OMAP3430_ST_MCBSP2_MASK (1 << 0)
/* CM_AUTOIDLE_PER */
#define OMAP3430_AUTO_GPIO6 (1 << 17)
#define OMAP3430ES2_EN_USBHOST_MASK (1 << 0)
/* CM_IDLEST_USBHOST */
+#define OMAP3430ES2_ST_USBHOST_IDLE_SHIFT 1
+#define OMAP3430ES2_ST_USBHOST_IDLE_MASK (1 << 1)
+#define OMAP3430ES2_ST_USBHOST_STDBY_SHIFT 0
+#define OMAP3430ES2_ST_USBHOST_STDBY_MASK (1 << 0)
/* CM_AUTOIDLE_USBHOST */
#define OMAP3430ES2_AUTO_USBHOST_SHIFT 0
#include "prcm-common.h"
-#ifndef __ASSEMBLER__
-#define OMAP_CM_REGADDR(module, reg) \
- IO_ADDRESS(OMAP2_CM_BASE + (module) + (reg))
-#else
#define OMAP2420_CM_REGADDR(module, reg) \
IO_ADDRESS(OMAP2420_CM_BASE + (module) + (reg))
#define OMAP2430_CM_REGADDR(module, reg) \
IO_ADDRESS(OMAP2430_CM_BASE + (module) + (reg))
#define OMAP34XX_CM_REGADDR(module, reg) \
IO_ADDRESS(OMAP3430_CM_BASE + (module) + (reg))
-#endif
/*
* Architecture-specific global CM registers
- * Use cm_{read,write}_reg() with these registers.
+ * Use __raw_{read,write}l() with these registers.
* These registers appear once per CM module.
*/
-#define OMAP3430_CM_REVISION OMAP_CM_REGADDR(OCP_MOD, 0x0000)
-#define OMAP3430_CM_SYSCONFIG OMAP_CM_REGADDR(OCP_MOD, 0x0010)
-#define OMAP3430_CM_POLCTRL OMAP_CM_REGADDR(OCP_MOD, 0x009c)
+#define OMAP3430_CM_REVISION OMAP34XX_CM_REGADDR(OCP_MOD, 0x0000)
+#define OMAP3430_CM_SYSCONFIG OMAP34XX_CM_REGADDR(OCP_MOD, 0x0010)
+#define OMAP3430_CM_POLCTRL OMAP34XX_CM_REGADDR(OCP_MOD, 0x009c)
-#define OMAP3430_CM_CLKOUT_CTRL OMAP_CM_REGADDR(OMAP3430_CCR_MOD, 0x0070)
+#define OMAP3430_CM_CLKOUT_CTRL_OFFSET 0x0070
/*
* Module specific CM registers from CM_BASE + domain offset
#define CM_CLKSEL2 0x0044
#define CM_CLKSTCTRL 0x0048
-
/* Architecture-specific registers */
#define OMAP24XX_CM_FCLKEN2 0x0004
#include <mach/eac.h>
#include <mach/mmc.h>
-#if defined(CONFIG_OMAP_DSP) || defined(CONFIG_OMAP_DSP_MODULE)
-#define OMAP2_MBOX_BASE IO_ADDRESS(OMAP24XX_MAILBOX_BASE)
+#if defined(CONFIG_VIDEO_OMAP2) || defined(CONFIG_VIDEO_OMAP2_MODULE)
-static struct resource mbox_resources[] = {
+static struct resource cam_resources[] = {
{
- .start = OMAP2_MBOX_BASE,
- .end = OMAP2_MBOX_BASE + 0x11f,
+ .start = OMAP24XX_CAMERA_BASE,
+ .end = OMAP24XX_CAMERA_BASE + 0xfff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = INT_24XX_CAM_IRQ,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static struct platform_device omap_cam_device = {
+ .name = "omap24xxcam",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(cam_resources),
+ .resource = cam_resources,
+};
+
+static inline void omap_init_camera(void)
+{
+ platform_device_register(&omap_cam_device);
+}
+
+#elif defined(CONFIG_VIDEO_OMAP3) || defined(CONFIG_VIDEO_OMAP3_MODULE)
+
+static struct resource cam_resources[] = {
+ {
+ .start = OMAP34XX_CAMERA_BASE,
+ .end = OMAP34XX_CAMERA_BASE + 0x1B70,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = INT_34XX_CAM_IRQ,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static struct platform_device omap_cam_device = {
+ .name = "omap34xxcam",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(cam_resources),
+ .resource = cam_resources,
+};
+
+static inline void omap_init_camera(void)
+{
+ platform_device_register(&omap_cam_device);
+}
+#else
+static inline void omap_init_camera(void)
+{
+}
+#endif
+
+#if defined(CONFIG_OMAP_MBOX_FWK) || defined(CONFIG_OMAP_MBOX_FWK_MODULE)
+
+#define MBOX_REG_SIZE 0x120
+
+static struct resource omap2_mbox_resources[] = {
+ {
+ .start = OMAP24XX_MAILBOX_BASE,
+ .end = OMAP24XX_MAILBOX_BASE + MBOX_REG_SIZE - 1,
.flags = IORESOURCE_MEM,
},
{
},
};
+static struct resource omap3_mbox_resources[] = {
+ {
+ .start = OMAP34XX_MAILBOX_BASE,
+ .end = OMAP34XX_MAILBOX_BASE + MBOX_REG_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = INT_24XX_MAIL_U0_MPU,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
static struct platform_device mbox_device = {
- .name = "mailbox",
+ .name = "omap2-mailbox",
.id = -1,
- .num_resources = ARRAY_SIZE(mbox_resources),
- .resource = mbox_resources,
};
static inline void omap_init_mbox(void)
{
+ if (cpu_is_omap2420()) {
+ mbox_device.num_resources = ARRAY_SIZE(omap2_mbox_resources);
+ mbox_device.resource = omap2_mbox_resources;
+ } else if (cpu_is_omap3430()) {
+ mbox_device.num_resources = ARRAY_SIZE(omap3_mbox_resources);
+ mbox_device.resource = omap3_mbox_resources;
+ } else {
+ return;
+ }
platform_device_register(&mbox_device);
}
#else
static inline void omap_init_mbox(void) { }
-#endif
+#endif /* CONFIG_OMAP_MBOX_FWK */
#if defined(CONFIG_OMAP_STI)
platform_device_register(&omap2_mcspi1);
platform_device_register(&omap2_mcspi2);
#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3)
- platform_device_register(&omap2_mcspi3);
+ if (cpu_is_omap2430() || cpu_is_omap343x())
+ platform_device_register(&omap2_mcspi3);
#endif
#ifdef CONFIG_ARCH_OMAP3
- platform_device_register(&omap2_mcspi4);
+ if (cpu_is_omap343x())
+ platform_device_register(&omap2_mcspi4);
#endif
}
#ifdef CONFIG_SND_OMAP24XX_EAC
-#define OMAP2_EAC_BASE 0x48090000
+#define OMAP2_EAC_BASE (L4_24XX_BASE + 0x90000)
static struct resource omap2_eac_resources[] = {
{
.start = OMAP2_EAC_BASE,
- .end = OMAP2_EAC_BASE + 0x109,
+ .end = OMAP2_EAC_BASE + 0xfff,
.flags = IORESOURCE_MEM,
},
};
* in alphabetical order so they're easier to sort through.
*/
omap_hsmmc_reset();
+ omap_init_camera();
omap_init_mbox();
omap_init_mcspi();
omap_hdq_init();
}
EXPORT_SYMBOL(omap_chip_is);
+int omap_type(void)
+{
+ u32 val = 0;
+
+ if (cpu_is_omap24xx()) {
+ val = omap_ctrl_readl(OMAP24XX_CONTROL_STATUS);
+ } else if (cpu_is_omap34xx()) {
+ val = omap_ctrl_readl(OMAP343X_CONTROL_STATUS);
+ } else {
+ pr_err("Cannot detect omap type!\n");
+ goto out;
+ }
+
+ val &= OMAP2_DEVICETYPE_MASK;
+ val >>= 8;
+
+out:
+ return val;
+}
+EXPORT_SYMBOL(omap_type);
+
+
/*----------------------------------------------------------------------------*/
#define OMAP_TAP_IDCODE 0x0204
#include <asm/tlb.h>
#include <asm/mach/map.h>
-
#include <mach/mux.h>
#include <mach/omapfb.h>
#include <mach/sram.h>
-
-#include "memory.h"
+#include <mach/sdrc.h>
+#include <mach/gpmc.h>
#include "clock.h"
omapfb_reserve_sdram();
}
-void __init omap2_init_common_hw(void)
+void __init omap2_init_common_hw(struct omap_sdrc_params *sp)
{
omap2_mux_init();
pwrdm_init(powerdomains_omap);
clkdm_init(clockdomains_omap, clkdm_pwrdm_autodeps);
omap2_clk_init();
- omap2_init_memory();
+ omap2_sdrc_init(sp);
gpmc_init();
}
intc_bank_write_reg(1 << irq, &irq_banks[0], INTC_MIR_CLEAR0 + offset);
}
+static void omap_disable_irq(unsigned int irq)
+{
+ omap_mask_irq(irq);
+}
+
static void omap_mask_ack_irq(unsigned int irq)
{
omap_mask_irq(irq);
.ack = omap_mask_ack_irq,
.mask = omap_mask_irq,
.unmask = omap_unmask_irq,
+ .disable = omap_disable_irq,
};
static void __init omap_irq_bank_init_one(struct omap_irq_bank *bank)
intc_bank_write_reg(1 << 0, bank, INTC_SYSCONFIG);
}
+int omap_irq_pending(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(irq_banks); i++) {
+ struct omap_irq_bank *bank = irq_banks + i;
+ int irq;
+
+ for (irq = 0; irq < bank->nr_irqs; irq += IRQ_BITS_PER_REG) {
+ int offset = irq & (~(IRQ_BITS_PER_REG - 1));
+
+ if (intc_bank_read_reg(bank, (INTC_PENDING_IRQ0 +
+ offset)))
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
void __init omap_init_irq(void)
{
unsigned long nr_of_irqs = 0;
/*
- * Mailbox reservation modules for OMAP2
+ * Mailbox reservation modules for OMAP2/3
*
- * Copyright (C) 2006 Nokia Corporation
+ * Copyright (C) 2006-2008 Nokia Corporation
* Written by: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
- * and Paul Mundt <paul.mundt@nokia.com>
+ * and Paul Mundt
*
* 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
#include <mach/mailbox.h>
#include <mach/irqs.h>
-#define MAILBOX_REVISION 0x00
-#define MAILBOX_SYSCONFIG 0x10
-#define MAILBOX_SYSSTATUS 0x14
-#define MAILBOX_MESSAGE_0 0x40
-#define MAILBOX_MESSAGE_1 0x44
-#define MAILBOX_MESSAGE_2 0x48
-#define MAILBOX_MESSAGE_3 0x4c
-#define MAILBOX_MESSAGE_4 0x50
-#define MAILBOX_MESSAGE_5 0x54
-#define MAILBOX_FIFOSTATUS_0 0x80
-#define MAILBOX_FIFOSTATUS_1 0x84
-#define MAILBOX_FIFOSTATUS_2 0x88
-#define MAILBOX_FIFOSTATUS_3 0x8c
-#define MAILBOX_FIFOSTATUS_4 0x90
-#define MAILBOX_FIFOSTATUS_5 0x94
-#define MAILBOX_MSGSTATUS_0 0xc0
-#define MAILBOX_MSGSTATUS_1 0xc4
-#define MAILBOX_MSGSTATUS_2 0xc8
-#define MAILBOX_MSGSTATUS_3 0xcc
-#define MAILBOX_MSGSTATUS_4 0xd0
-#define MAILBOX_MSGSTATUS_5 0xd4
-#define MAILBOX_IRQSTATUS_0 0x100
-#define MAILBOX_IRQENABLE_0 0x104
-#define MAILBOX_IRQSTATUS_1 0x108
-#define MAILBOX_IRQENABLE_1 0x10c
-#define MAILBOX_IRQSTATUS_2 0x110
-#define MAILBOX_IRQENABLE_2 0x114
-#define MAILBOX_IRQSTATUS_3 0x118
-#define MAILBOX_IRQENABLE_3 0x11c
-
-static unsigned long mbox_base;
-
-#define MAILBOX_IRQ_NOTFULL(n) (1 << (2 * (n) + 1))
-#define MAILBOX_IRQ_NEWMSG(n) (1 << (2 * (n)))
+#define DRV_NAME "omap2-mailbox"
+
+#define MAILBOX_REVISION 0x000
+#define MAILBOX_SYSCONFIG 0x010
+#define MAILBOX_SYSSTATUS 0x014
+#define MAILBOX_MESSAGE(m) (0x040 + 4 * (m))
+#define MAILBOX_FIFOSTATUS(m) (0x080 + 4 * (m))
+#define MAILBOX_MSGSTATUS(m) (0x0c0 + 4 * (m))
+#define MAILBOX_IRQSTATUS(u) (0x100 + 8 * (u))
+#define MAILBOX_IRQENABLE(u) (0x108 + 8 * (u))
+
+#define MAILBOX_IRQ_NEWMSG(u) (1 << (2 * (u)))
+#define MAILBOX_IRQ_NOTFULL(u) (1 << (2 * (u) + 1))
+
+#define MBOX_REG_SIZE 0x120
+
+static void __iomem *mbox_base;
struct omap_mbox2_fifo {
unsigned long msg;
unsigned long irqstatus;
u32 newmsg_bit;
u32 notfull_bit;
+ char ctx[MBOX_REG_SIZE];
};
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)
+static inline unsigned int mbox_read_reg(size_t ofs)
{
- return __raw_readl(mbox_base + reg);
+ return __raw_readl(mbox_base + ofs);
}
-static inline void mbox_write_reg(unsigned int val, unsigned int reg)
+static inline void mbox_write_reg(u32 val, size_t ofs)
{
- __raw_writel(val, mbox_base + reg);
+ __raw_writel(val, mbox_base + ofs);
}
/* Mailbox H/W preparations */
}
clk_enable(mbox_ick_handle);
+ l = mbox_read_reg(MAILBOX_REVISION);
+ pr_info("omap mailbox rev %d.%d\n", (l & 0xf0) >> 4, (l & 0x0f));
+
/* set smart-idle & autoidle */
l = mbox_read_reg(MAILBOX_SYSCONFIG);
l |= 0x00000011;
return (enable & status & bit);
}
+static void omap2_mbox_save_ctx(struct omap_mbox *mbox)
+{
+ int i;
+ struct omap_mbox2_priv *p = mbox->priv;
+
+ for (i = 0; i < MBOX_REG_SIZE; i += sizeof(u32)) {
+ u32 val;
+
+ val = mbox_read_reg(i);
+ *(u32 *)(p->ctx + i) = val;
+
+ dev_dbg(mbox->dev, "%s\t[%02d] %08x\n", __func__, i, val);
+ }
+}
+
+static void omap2_mbox_restore_ctx(struct omap_mbox *mbox)
+{
+ int i;
+ struct omap_mbox2_priv *p = mbox->priv;
+
+ for (i = 0; i < MBOX_REG_SIZE; i += sizeof(u32)) {
+ u32 val;
+
+ val = *(u32 *)(p->ctx + i);
+ mbox_write_reg(val, i);
+
+ dev_dbg(mbox->dev, "%s\t[%02d] %08x\n", __func__, i, val);
+ }
+}
+
static struct omap_mbox_ops omap2_mbox_ops = {
.type = OMAP_MBOX_TYPE2,
.startup = omap2_mbox_startup,
.disable_irq = omap2_mbox_disable_irq,
.ack_irq = omap2_mbox_ack_irq,
.is_irq = omap2_mbox_is_irq,
+ .save_ctx = omap2_mbox_save_ctx,
+ .restore_ctx = omap2_mbox_restore_ctx,
};
/*
/* DSP */
static struct omap_mbox2_priv omap2_mbox_dsp_priv = {
.tx_fifo = {
- .msg = MAILBOX_MESSAGE_0,
- .fifo_stat = MAILBOX_FIFOSTATUS_0,
+ .msg = MAILBOX_MESSAGE(0),
+ .fifo_stat = MAILBOX_FIFOSTATUS(0),
},
.rx_fifo = {
- .msg = MAILBOX_MESSAGE_1,
- .msg_stat = MAILBOX_MSGSTATUS_1,
+ .msg = MAILBOX_MESSAGE(1),
+ .msg_stat = MAILBOX_MSGSTATUS(1),
},
- .irqenable = MAILBOX_IRQENABLE_0,
- .irqstatus = MAILBOX_IRQSTATUS_0,
+ .irqenable = MAILBOX_IRQENABLE(0),
+ .irqstatus = MAILBOX_IRQSTATUS(0),
.notfull_bit = MAILBOX_IRQ_NOTFULL(0),
.newmsg_bit = MAILBOX_IRQ_NEWMSG(1),
};
};
EXPORT_SYMBOL(mbox_dsp_info);
-/* IVA */
+#if defined(CONFIG_ARCH_OMAP2420) /* IVA */
static struct omap_mbox2_priv omap2_mbox_iva_priv = {
.tx_fifo = {
- .msg = MAILBOX_MESSAGE_2,
- .fifo_stat = MAILBOX_FIFOSTATUS_2,
+ .msg = MAILBOX_MESSAGE(2),
+ .fifo_stat = MAILBOX_FIFOSTATUS(2),
},
.rx_fifo = {
- .msg = MAILBOX_MESSAGE_3,
- .msg_stat = MAILBOX_MSGSTATUS_3,
+ .msg = MAILBOX_MESSAGE(3),
+ .msg_stat = MAILBOX_MSGSTATUS(3),
},
- .irqenable = MAILBOX_IRQENABLE_3,
- .irqstatus = MAILBOX_IRQSTATUS_3,
+ .irqenable = MAILBOX_IRQENABLE(3),
+ .irqstatus = MAILBOX_IRQSTATUS(3),
.notfull_bit = MAILBOX_IRQ_NOTFULL(2),
.newmsg_bit = MAILBOX_IRQ_NEWMSG(3),
};
.ops = &omap2_mbox_ops,
.priv = &omap2_mbox_iva_priv,
};
+#endif
-static int __init omap2_mbox_probe(struct platform_device *pdev)
+static int __devinit omap2_mbox_probe(struct platform_device *pdev)
{
struct resource *res;
- int ret = 0;
-
- if (pdev->num_resources != 3) {
- dev_err(&pdev->dev, "invalid number of resources: %d\n",
- pdev->num_resources);
- return -ENODEV;
- }
+ int ret;
/* MBOX base */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
dev_err(&pdev->dev, "invalid mem resource\n");
return -ENODEV;
}
- mbox_base = res->start;
+ mbox_base = ioremap(res->start, res->end - res->start);
+ if (!mbox_base)
+ return -ENOMEM;
- /* DSP IRQ */
+ /* DSP or IVA2 IRQ */
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (unlikely(!res)) {
dev_err(&pdev->dev, "invalid irq resource\n");
- return -ENODEV;
+ ret = -ENODEV;
+ goto err_dsp;
}
mbox_dsp_info.irq = res->start;
- ret = omap_mbox_register(&mbox_dsp_info);
-
- /* IVA IRQ */
- res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
- if (unlikely(!res)) {
- dev_err(&pdev->dev, "invalid irq resource\n");
- return -ENODEV;
+ ret = omap_mbox_register(&pdev->dev, &mbox_dsp_info);
+ if (ret)
+ goto err_dsp;
+
+#if defined(CONFIG_ARCH_OMAP2420) /* IVA */
+ if (cpu_is_omap2420()) {
+ /* IVA IRQ */
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
+ if (unlikely(!res)) {
+ dev_err(&pdev->dev, "invalid irq resource\n");
+ ret = -ENODEV;
+ goto err_iva1;
+ }
+ mbox_iva_info.irq = res->start;
+ ret = omap_mbox_register(&pdev->dev, &mbox_iva_info);
+ if (ret)
+ goto err_iva1;
}
- mbox_iva_info.irq = res->start;
-
- ret = omap_mbox_register(&mbox_iva_info);
+#endif
+ return 0;
+err_iva1:
+ omap_mbox_unregister(&mbox_dsp_info);
+err_dsp:
+ iounmap(mbox_base);
return ret;
}
-static int omap2_mbox_remove(struct platform_device *pdev)
+static int __devexit omap2_mbox_remove(struct platform_device *pdev)
{
+#if defined(CONFIG_ARCH_OMAP2420)
+ omap_mbox_unregister(&mbox_iva_info);
+#endif
omap_mbox_unregister(&mbox_dsp_info);
+ iounmap(mbox_base);
return 0;
}
static struct platform_driver omap2_mbox_driver = {
.probe = omap2_mbox_probe,
- .remove = omap2_mbox_remove,
+ .remove = __devexit_p(omap2_mbox_remove),
.driver = {
- .name = "mailbox",
+ .name = DRV_NAME,
},
};
module_init(omap2_mbox_init);
module_exit(omap2_mbox_exit);
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("omap mailbox: omap2/3 architecture specific functions");
+MODULE_AUTHOR("Hiroshi DOYU <Hiroshi.DOYU@nokia.com>, Paul Mundt");
+MODULE_ALIAS("platform:"DRV_NAME);
#include <linux/io.h>
#include <linux/platform_device.h>
+#include <mach/irqs.h>
#include <mach/dma.h>
#include <mach/irqs.h>
#include <mach/mux.h>
.clk = {
.name = "mcbsp_clk",
.id = 1,
+ .clkdm = { .name = "virt_opp_clkdm" },
.enable = omap_mcbsp_clk_enable,
.disable = omap_mcbsp_clk_disable,
},
.clk = {
.name = "mcbsp_clk",
.id = 2,
+ .clkdm = { .name = "virt_opp_clkdm" },
.enable = omap_mcbsp_clk_enable,
.disable = omap_mcbsp_clk_disable,
},
.clk = {
.name = "mcbsp_clk",
.id = 3,
+ .clkdm = { .name = "virt_opp_clkdm" },
.enable = omap_mcbsp_clk_enable,
.disable = omap_mcbsp_clk_disable,
},
.clk = {
.name = "mcbsp_clk",
.id = 4,
+ .clkdm = { .name = "virt_opp_clkdm" },
.enable = omap_mcbsp_clk_enable,
.disable = omap_mcbsp_clk_disable,
},
.clk = {
.name = "mcbsp_clk",
.id = 5,
+ .clkdm = { .name = "virt_opp_clkdm" },
.enable = omap_mcbsp_clk_enable,
.disable = omap_mcbsp_clk_disable,
},
+++ /dev/null
-/*
- * linux/arch/arm/mach-omap2/memory.h
- *
- * Interface for memory timing related functions for OMAP24XX
- *
- * Copyright (C) 2005 Texas Instruments Inc.
- * Richard Woodruff <r-woodruff2@ti.com>
- *
- * Copyright (C) 2005 Nokia Corporation
- * Tony Lindgren <tony@atomide.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef ARCH_ARM_MACH_OMAP2_MEMORY_H
-#define ARCH_ARM_MACH_OMAP2_MEMORY_H
-
-/* Memory timings */
-#define M_DDR 1
-#define M_LOCK_CTRL (1 << 2)
-#define M_UNLOCK 0
-#define M_LOCK 1
-
-struct memory_timings {
- u32 m_type; /* ddr = 1, sdr = 0 */
- u32 dll_mode; /* use lock mode = 1, unlock mode = 0 */
- u32 slow_dll_ctrl; /* unlock mode, dll value for slow speed */
- u32 fast_dll_ctrl; /* unlock mode, dll value for fast speed */
- u32 base_cs; /* base chip select to use for calculations */
-};
-
-extern void omap2_init_memory_params(u32 force_lock_to_unlock_mode);
-extern u32 omap2_memory_get_slow_dll_ctrl(void);
-extern u32 omap2_memory_get_fast_dll_ctrl(void);
-extern u32 omap2_memory_get_type(void);
-u32 omap2_dll_force_needed(void);
-u32 omap2_reprogram_sdrc(u32 level, u32 force);
-void __init omap2_init_memory(void);
-void __init gpmc_init(void);
-
-#endif
--- /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 <linux/io.h>
+#include "mmu.h"
+#include <mach/mmu.h>
+#include <asm/tlbflush.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 <linux/io.h>
+#include <mach/mmu.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((void __iomem *)(mmu->base + reg));
+}
+
+static inline void omap_mmu_write_reg(struct omap_mmu *mmu,
+ unsigned long val, unsigned long reg)
+{
+ __raw_writel(val, (void __iomem *)(mmu->base + reg));
+}
+
+#endif /* __MACH_OMAP2_MMU_H */
OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_INPUT)
MUX_CFG_34XX("J25_34XX_GPIO170", 0x1c6,
OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_INPUT)
+MUX_CFG_34XX("AF26_34XX_GPIO0", 0x1e0,
+ OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("AF22_34XX_GPIO9", 0xa18,
+ OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("AF6_34XX_GPIO140_UP", 0x16c,
+ OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_INPUT_PULLUP)
+MUX_CFG_34XX("AE6_34XX_GPIO141", 0x16e,
+ OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("AF5_34XX_GPIO142", 0x170,
+ OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("AE5_34XX_GPIO143", 0x172,
+ OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_OUTPUT)
+
};
#define OMAP34XX_PINS_SZ ARRAY_SIZE(omap34xx_pins)
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap2/pm_debug.c
+ *
+ * OMAP Power Management debug routines
+ *
+ * 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>
+ * Jouni Hogander
+ *
+ * Based on pm.c for omap2
+ *
+ * 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/timer.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+
+#include <mach/clock.h>
+#include <mach/board.h>
+
+#include "prm.h"
+#include "cm.h"
+#include "pm.h"
+
+#ifdef CONFIG_PM_DEBUG
+int omap2_pm_debug = 0;
+
+#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)))
+
+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_MOD_REG(OCP_MOD, OMAP2_PRM_IRQENABLE_MPU_OFFSET);
+ 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);
+ if (cpu_is_omap24xx()) {
+ DUMP_CM_MOD_REG(CORE_MOD, OMAP24XX_CM_FCLKEN2);
+ DUMP_PRM_MOD_REG(OMAP24XX_GR_MOD,
+ OMAP24XX_PRCM_CLKEMUL_CTRL_OFFSET);
+ DUMP_PRM_MOD_REG(OMAP24XX_GR_MOD,
+ OMAP24XX_PRCM_CLKSRC_CTRL_OFFSET);
+ }
+ 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_CM_MOD_REG(PLL_MOD, CM_AUTOIDLE);
+ DUMP_PRM_MOD_REG(CORE_MOD, PM_PWSTST);
+#endif
+#if 0
+ /* DSP */
+ if (cpu_is_omap24xx()) {
+ 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);
+ if (cpu_is_omap24xx())
+ DUMP_PRM_MOD_REG(CORE_MOD, OMAP24XX_PM_WKST2);
+ DUMP_PRM_MOD_REG(WKUP_MOD, PM_WKST);
+ DUMP_PRM_MOD_REG(OCP_MOD, OMAP2_PRM_IRQSTATUS_MPU_OFFSET);
+#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);
+}
+
+#endif
/*
* linux/arch/arm/mach-omap2/pm.c
*
- * OMAP2 Power Management Routines
- *
- * Copyright (C) 2006 Nokia Corporation
- * Tony Lindgren <tony@atomide.com>
+ * OMAP Power Management Common Routines
*
* 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>
+ * Jouni Hogander
*
* Based on pm.c for omap1
*
*/
#include <linux/suspend.h>
-#include <linux/sched.h>
-#include <linux/proc_fs.h>
-#include <linux/interrupt.h>
-#include <linux/sysfs.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-
-#include <asm/irq.h>
-#include <asm/atomic.h>
+#include <linux/time.h>
+
+#include <mach/cpu.h>
#include <asm/mach/time.h>
-#include <asm/mach/irq.h>
+#include <asm/atomic.h>
-#include <mach/irqs.h>
-#include <mach/clock.h>
-#include <mach/sram.h>
#include <mach/pm.h>
+#include "pm.h"
-static struct clk *vclk;
-static void (*omap2_sram_idle)(void);
-static void (*omap2_sram_suspend)(int dllctrl, int cpu_rev);
-static void (*saved_idle)(void);
+unsigned short enable_dyn_sleep;
+unsigned short clocks_off_while_idle;
+atomic_t sleep_block = ATOMIC_INIT(0);
-extern void __init pmdomain_init(void);
-extern void pmdomain_set_autoidle(void);
+static ssize_t idle_show(struct kobject *, struct kobj_attribute *, char *);
+static ssize_t idle_store(struct kobject *k, struct kobj_attribute *,
+ const char *buf, size_t n);
-static unsigned int omap24xx_sleep_save[OMAP24XX_SLEEP_SAVE_SIZE];
+static struct kobj_attribute sleep_while_idle_attr =
+ __ATTR(sleep_while_idle, 0644, idle_show, idle_store);
-void omap2_pm_idle(void)
-{
- local_irq_disable();
- local_fiq_disable();
- if (need_resched()) {
- local_fiq_enable();
- local_irq_enable();
- return;
- }
-
- omap2_sram_idle();
- local_fiq_enable();
- local_irq_enable();
-}
+static struct kobj_attribute clocks_off_while_idle_attr =
+ __ATTR(clocks_off_while_idle, 0644, idle_show, idle_store);
-static int omap2_pm_prepare(void)
+static ssize_t idle_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
{
- /* We cannot sleep in idle until we have resumed */
- saved_idle = pm_idle;
- pm_idle = NULL;
- return 0;
+ if (attr == &sleep_while_idle_attr)
+ return sprintf(buf, "%hu\n", enable_dyn_sleep);
+ else if (attr == &clocks_off_while_idle_attr)
+ return sprintf(buf, "%hu\n", clocks_off_while_idle);
+ else
+ return -EINVAL;
}
-static int omap2_pm_suspend(void)
+static ssize_t idle_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t n)
{
- return 0;
-}
+ unsigned short value;
-static int omap2_pm_enter(suspend_state_t state)
-{
- int ret = 0;
-
- switch (state)
- {
- case PM_SUSPEND_STANDBY:
- case PM_SUSPEND_MEM:
- ret = omap2_pm_suspend();
- break;
- default:
- ret = -EINVAL;
+ if (sscanf(buf, "%hu", &value) != 1 ||
+ (value != 0 && value != 1)) {
+ printk(KERN_ERR "idle_store: Invalid value\n");
+ return -EINVAL;
}
- return ret;
+ if (attr == &sleep_while_idle_attr)
+ enable_dyn_sleep = value;
+ else if (attr == &clocks_off_while_idle_attr)
+ clocks_off_while_idle = value;
+ else
+ return -EINVAL;
+
+ return n;
}
-static void omap2_pm_finish(void)
+void omap2_block_sleep(void)
{
- pm_idle = saved_idle;
+ atomic_inc(&sleep_block);
}
-static struct platform_suspend_ops omap_pm_ops = {
- .prepare = omap2_pm_prepare,
- .enter = omap2_pm_enter,
- .finish = omap2_pm_finish,
- .valid = suspend_valid_only_mem,
-};
+void omap2_allow_sleep(void)
+{
+ int i;
+
+ i = atomic_dec_return(&sleep_block);
+ BUG_ON(i < 0);
+}
-int __init omap2_pm_init(void)
+static int __init omap_pm_init(void)
{
- return 0;
+ int error = -1;
+
+ if (cpu_is_omap24xx())
+ error = omap2_pm_init();
+ if (cpu_is_omap34xx())
+ error = omap3_pm_init();
+ if (error) {
+ printk(KERN_ERR "omap2|3_pm_init failed: %d\n", error);
+ return error;
+ }
+
+ /* disabled till drivers are fixed */
+ enable_dyn_sleep = 0;
+ error = sysfs_create_file(power_kobj, &sleep_while_idle_attr.attr);
+ if (error)
+ printk(KERN_ERR "sysfs_create_file failed: %d\n", error);
+ error = sysfs_create_file(power_kobj,
+ &clocks_off_while_idle_attr.attr);
+ if (error)
+ printk(KERN_ERR "sysfs_create_file failed: %d\n", error);
+
+ return error;
}
-__initcall(omap2_pm_init);
+late_initcall(omap_pm_init);
--- /dev/null
+#ifndef __ARCH_ARM_MACH_OMAP2_PM_H
+#define __ARCH_ARM_MACH_OMAP2_PM_H
+/*
+ * linux/arch/arm/mach-omap2/pm.h
+ *
+ * OMAP Power Management Routines
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Jouni Hogander
+ *
+ * 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.
+ */
+
+extern int omap2_pm_init(void);
+extern int omap3_pm_init(void);
+
+extern unsigned short enable_dyn_sleep;
+extern unsigned short clocks_off_while_idle;
+extern atomic_t sleep_block;
+
+extern void omap2_block_sleep(void);
+extern void omap2_allow_sleep(void);
+
+
+#ifdef CONFIG_PM_DEBUG
+extern void omap2_pm_dump(int mode, int resume, unsigned int us);
+extern int omap2_pm_debug;
+#else
+#define omap2_pm_dump(mode, resume, us) do {} while (0);
+#define omap2_pm_debug 0
+#endif /* CONFIG_PM_DEBUG */
+#endif
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap2/pm.c
+ *
+ * OMAP2 Power Management Routines
+ *
+ * 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
+ *
+ * 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/suspend.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/interrupt.h>
+#include <linux/sysfs.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/time.h>
+
+#include <asm/mach/time.h>
+#include <asm/mach/irq.h>
+#include <asm/mach-types.h>
+
+#include <mach/irqs.h>
+#include <mach/clock.h>
+#include <mach/sram.h>
+#include <mach/control.h>
+#include <mach/gpio.h>
+#include <mach/pm.h>
+#include <mach/mux.h>
+#include <mach/dma.h>
+#include <mach/board.h>
+
+#include "prm.h"
+#include "prm-regbits-24xx.h"
+#include "cm.h"
+#include "cm-regbits-24xx.h"
+#include "sdrc.h"
+#include "pm.h"
+
+#include <mach/powerdomain.h>
+#include <mach/clockdomain.h>
+
+static void (*omap2_sram_idle)(void);
+static void (*omap2_sram_suspend)(u32 dllctrl, void __iomem *sdrc_dlla_ctrl,
+ void __iomem *sdrc_power);
+static void (*saved_idle)(void);
+
+static struct powerdomain *mpu_pwrdm;
+static struct powerdomain *core_pwrdm;
+
+static struct clockdomain *dsp_clkdm;
+static struct clockdomain *gfx_clkdm;
+
+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);
+
+ /* Ignore UART clocks. These are handled by UART core (serial.c) */
+ f1 &= ~(OMAP24XX_EN_UART1 | OMAP24XX_EN_UART2);
+ f2 &= ~OMAP24XX_EN_UART3;
+
+ if (f1 | f2)
+ return 1;
+ return 0;
+}
+
+static void omap2_enter_full_retention(void)
+{
+ u32 l;
+ struct timespec ts_preidle, ts_postidle, ts_idle;
+
+ /* 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);
+
+ /*
+ * Set MPU powerdomain's next power state to RETENTION;
+ * preserve logic state during retention
+ */
+ pwrdm_set_logic_retst(mpu_pwrdm, PWRDM_POWER_RET);
+ pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET);
+
+ /* 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);
+ getnstimeofday(&ts_preidle);
+ }
+
+ /* One last check for pending IRQs to avoid extra latency due
+ * to sleeping unnecessarily. */
+ if (omap_irq_pending())
+ goto no_sleep;
+
+ omap_uart_prepare_idle(0);
+ omap_uart_prepare_idle(1);
+ omap_uart_prepare_idle(2);
+
+ /* Jump to SRAM suspend code */
+ omap2_sram_suspend(sdrc_read_reg(SDRC_DLLA_CTRL),
+ OMAP_SDRC_REGADDR(SDRC_DLLA_CTRL),
+ OMAP_SDRC_REGADDR(SDRC_POWER));
+no_sleep:
+ omap_uart_resume_idle(2);
+ omap_uart_resume_idle(1);
+ omap_uart_resume_idle(0);
+
+ if (omap2_pm_debug) {
+ unsigned long long tmp;
+
+ getnstimeofday(&ts_postidle);
+ ts_idle = timespec_sub(ts_postidle, ts_preidle);
+ tmp = timespec_to_ns(&ts_idle) * NSEC_PER_USEC;
+ omap2_pm_dump(0, 1, tmp);
+ }
+ 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 = prm_read_mod_reg(OCP_MOD, OMAP2_PRM_IRQSTATUS_MPU_OFFSET);
+ if (l & 0x01)
+ prm_write_mod_reg(0x01, OCP_MOD,
+ OMAP2_PRM_IRQSTATUS_MPU_OFFSET);
+ if (l & 0x20)
+ prm_write_mod_reg(0x20, OCP_MOD,
+ OMAP2_PRM_IRQSTATUS_MPU_OFFSET);
+
+ /* Mask future PRCM-to-MPU interrupts */
+ prm_write_mod_reg(0x0, OCP_MOD, OMAP2_PRM_IRQSTATUS_MPU_OFFSET);
+}
+
+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)
+{
+ int only_idle = 0;
+ struct timespec ts_preidle, ts_postidle, ts_idle;
+
+ /* 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);
+ getnstimeofday(&ts_preidle);
+ }
+
+ omap2_sram_idle();
+
+ if (omap2_pm_debug) {
+ unsigned long long tmp;
+
+ getnstimeofday(&ts_postidle);
+ ts_idle = timespec_sub(ts_postidle, ts_preidle);
+ tmp = timespec_to_ns(&ts_idle) * NSEC_PER_USEC;
+ omap2_pm_dump(only_idle ? 2 : 1, 1, tmp);
+ }
+}
+
+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 (osc_ck->usecount > 1)
+ return 0;
+ if (omap_dma_running())
+ return 0;
+
+ return 1;
+}
+
+/*
+ * Note that you can use clock_event_device->min_delta_ns if you want to
+ * avoid reprogramming timer too often when using CONFIG_NO_HZ.
+ */
+static void omap2_pm_idle(void)
+{
+ local_irq_disable();
+ local_fiq_disable();
+
+ if (!omap2_can_sleep()) {
+ if (!atomic_read(&sleep_block) && omap_irq_pending())
+ goto out;
+ omap2_enter_mpu_retention();
+ goto out;
+ }
+
+ if (omap_irq_pending())
+ goto out;
+
+ omap2_enter_full_retention();
+
+out:
+ local_fiq_enable();
+ local_irq_enable();
+}
+
+static int omap2_pm_prepare(void)
+{
+ /* 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);
+
+ omap_uart_prepare_suspend();
+ omap2_enter_full_retention();
+
+ omap_writel(mir1, 0x480fe0a4);
+ prm_write_mod_reg(wken_wkup, WKUP_MOD, PM_WKEN);
+
+ return 0;
+}
+
+static int omap2_pm_enter(suspend_state_t state)
+{
+ int ret = 0;
+
+ switch (state) {
+ case PM_SUSPEND_STANDBY:
+ case PM_SUSPEND_MEM:
+ ret = omap2_pm_suspend();
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static void omap2_pm_finish(void)
+{
+ pm_idle = saved_idle;
+}
+
+static struct platform_suspend_ops omap_pm_ops = {
+ .prepare = omap2_pm_prepare,
+ .enter = omap2_pm_enter,
+ .finish = omap2_pm_finish,
+ .valid = suspend_valid_only_mem,
+};
+
+static int _pm_clkdm_enable_hwsup(struct clockdomain *clkdm)
+{
+ omap2_clkdm_allow_idle(clkdm);
+ return 0;
+}
+
+static void __init prcm_setup_regs(void)
+{
+ int i, num_mem_banks;
+ struct powerdomain *pwrdm;
+
+ /* Enable autoidle */
+ prm_write_mod_reg(OMAP24XX_AUTOIDLE, OCP_MOD,
+ OMAP24XX_PRM_SYSCONFIG_OFFSET);
+
+ /* 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);
+
+ /*
+ * Set CORE powerdomain memory banks to retain their contents
+ * during RETENTION
+ */
+ num_mem_banks = pwrdm_get_mem_bank_count(core_pwrdm);
+ for (i = 0; i < num_mem_banks; i++)
+ pwrdm_set_mem_retst(core_pwrdm, i, PWRDM_POWER_RET);
+
+ /* Set CORE powerdomain's next power state to RETENTION */
+ pwrdm_set_next_pwrst(core_pwrdm, PWRDM_POWER_RET);
+
+ /*
+ * Set MPU powerdomain's next power state to RETENTION;
+ * preserve logic state during retention
+ */
+ pwrdm_set_logic_retst(mpu_pwrdm, PWRDM_POWER_RET);
+ pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET);
+
+ /* Force-power down DSP, GFX powerdomains */
+
+ pwrdm = clkdm_get_pwrdm(dsp_clkdm);
+ pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF);
+ omap2_clkdm_sleep(dsp_clkdm);
+
+ pwrdm = clkdm_get_pwrdm(gfx_clkdm);
+ pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF);
+ omap2_clkdm_sleep(gfx_clkdm);
+
+ /* Enable clockdomain hardware-supervised control for all clkdms */
+ clkdm_for_each(_pm_clkdm_enable_hwsup);
+
+ /* 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 */
+ prm_write_mod_reg(15 << OMAP_SETUP_TIME_SHIFT, OMAP24XX_GR_MOD,
+ OMAP24XX_PRCM_CLKSSETUP_OFFSET);
+
+ /* Configure automatic voltage transition */
+ prm_write_mod_reg(2 << OMAP_SETUP_TIME_SHIFT, OMAP24XX_GR_MOD,
+ OMAP24XX_PRCM_VOLTSETUP_OFFSET);
+ prm_write_mod_reg(OMAP24XX_AUTO_EXTVOLT |
+ (0x1 << OMAP24XX_SETOFF_LEVEL_SHIFT) |
+ OMAP24XX_MEMRETCTRL |
+ (0x1 << OMAP24XX_SETRET_LEVEL_SHIFT) |
+ (0x0 << OMAP24XX_VOLT_LEVEL_SHIFT),
+ OMAP24XX_GR_MOD, OMAP24XX_PRCM_VOLTCTRL_OFFSET);
+
+ /* 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;
+
+ printk(KERN_INFO "Power Management for OMAP2 initializing\n");
+ l = prm_read_mod_reg(OCP_MOD, OMAP24XX_PRM_REVISION_OFFSET);
+ printk(KERN_INFO "PRCM revision %d.%d\n", (l >> 4) & 0x0f, l & 0x0f);
+
+ /* Look up important powerdomains, clockdomains */
+
+ mpu_pwrdm = pwrdm_lookup("mpu_pwrdm");
+ if (!mpu_pwrdm)
+ pr_err("PM: mpu_pwrdm not found\n");
+
+ core_pwrdm = pwrdm_lookup("core_pwrdm");
+ if (!core_pwrdm)
+ pr_err("PM: core_pwrdm not found\n");
+
+ dsp_clkdm = clkdm_lookup("dsp_clkdm");
+ if (!dsp_clkdm)
+ pr_err("PM: mpu_clkdm not found\n");
+
+ gfx_clkdm = clkdm_lookup("gfx_clkdm");
+ if (!gfx_clkdm)
+ pr_err("PM: gfx_clkdm not found\n");
+
+
+ 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();
+
+ /* 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.
+ */
+ if (cpu_is_omap24xx()) {
+ 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);
+ }
+
+ suspend_set_ops(&omap_pm_ops);
+ pm_idle = omap2_pm_idle;
+
+ return 0;
+}
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap2/pm34xx.c
+ *
+ * OMAP3 Power Management Routines
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation
+ * Tony Lindgren <tony@atomide.com>
+ * Jouni Hogander
+ *
+ * Copyright (C) 2005 Texas Instruments, Inc.
+ * Richard Woodruff <r-woodruff2@ti.com>
+ *
+ * Based on pm.c for omap1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/pm.h>
+#include <linux/suspend.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/err.h>
+
+#include <mach/gpio.h>
+#include <mach/sram.h>
+#include <mach/pm.h>
+#include <mach/clockdomain.h>
+#include <mach/powerdomain.h>
+#include <mach/serial.h>
+#include <mach/control.h>
+
+#include "cm.h"
+#include "cm-regbits-34xx.h"
+#include "prm-regbits-34xx.h"
+
+#include "prm.h"
+#include "pm.h"
+#include "smartreflex.h"
+
+struct power_state {
+ struct powerdomain *pwrdm;
+ u32 next_state;
+ u32 saved_state;
+ struct list_head node;
+};
+
+static LIST_HEAD(pwrst_list);
+
+static void (*_omap_sram_idle)(u32 *addr, int save_state);
+
+static void (*saved_idle)(void);
+
+static struct powerdomain *mpu_pwrdm;
+
+/* PRCM Interrupt Handler for wakeups */
+static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id)
+{
+ u32 wkst, irqstatus_mpu;
+ u32 fclk, iclk;
+
+ /* WKUP */
+ wkst = prm_read_mod_reg(WKUP_MOD, PM_WKST);
+ if (wkst) {
+ iclk = cm_read_mod_reg(WKUP_MOD, CM_ICLKEN);
+ fclk = cm_read_mod_reg(WKUP_MOD, CM_FCLKEN);
+ cm_set_mod_reg_bits(wkst, WKUP_MOD, CM_ICLKEN);
+ cm_set_mod_reg_bits(wkst, WKUP_MOD, CM_FCLKEN);
+ prm_write_mod_reg(wkst, WKUP_MOD, PM_WKST);
+ while (prm_read_mod_reg(WKUP_MOD, PM_WKST));
+ cm_write_mod_reg(iclk, WKUP_MOD, CM_ICLKEN);
+ cm_write_mod_reg(fclk, WKUP_MOD, CM_FCLKEN);
+ }
+
+ /* CORE */
+ wkst = prm_read_mod_reg(CORE_MOD, PM_WKST1);
+ if (wkst) {
+ iclk = cm_read_mod_reg(CORE_MOD, CM_ICLKEN1);
+ fclk = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
+ cm_set_mod_reg_bits(wkst, CORE_MOD, CM_ICLKEN1);
+ cm_set_mod_reg_bits(wkst, CORE_MOD, CM_FCLKEN1);
+ prm_write_mod_reg(wkst, CORE_MOD, PM_WKST1);
+ while (prm_read_mod_reg(CORE_MOD, PM_WKST1));
+ cm_write_mod_reg(iclk, CORE_MOD, CM_ICLKEN1);
+ cm_write_mod_reg(fclk, CORE_MOD, CM_FCLKEN1);
+ }
+ wkst = prm_read_mod_reg(CORE_MOD, OMAP3430ES2_PM_WKST3);
+ if (wkst) {
+ iclk = cm_read_mod_reg(CORE_MOD, CM_ICLKEN3);
+ fclk = cm_read_mod_reg(CORE_MOD, OMAP3430ES2_CM_FCLKEN3);
+ cm_set_mod_reg_bits(wkst, CORE_MOD, CM_ICLKEN3);
+ cm_set_mod_reg_bits(wkst, CORE_MOD, OMAP3430ES2_CM_FCLKEN3);
+ prm_write_mod_reg(wkst, CORE_MOD, OMAP3430ES2_PM_WKST3);
+ while (prm_read_mod_reg(CORE_MOD, OMAP3430ES2_PM_WKST3));
+ cm_write_mod_reg(iclk, CORE_MOD, CM_ICLKEN3);
+ cm_write_mod_reg(fclk, CORE_MOD, OMAP3430ES2_CM_FCLKEN3);
+ }
+
+ /* PER */
+ wkst = prm_read_mod_reg(OMAP3430_PER_MOD, PM_WKST);
+ if (wkst) {
+ iclk = cm_read_mod_reg(OMAP3430_PER_MOD, CM_ICLKEN);
+ fclk = cm_read_mod_reg(OMAP3430_PER_MOD, CM_FCLKEN);
+ cm_set_mod_reg_bits(wkst, OMAP3430_PER_MOD, CM_ICLKEN);
+ cm_set_mod_reg_bits(wkst, OMAP3430_PER_MOD, CM_FCLKEN);
+ prm_write_mod_reg(wkst, OMAP3430_PER_MOD, PM_WKST);
+ while (prm_read_mod_reg(OMAP3430_PER_MOD, PM_WKST));
+ cm_write_mod_reg(iclk, OMAP3430_PER_MOD, CM_ICLKEN);
+ cm_write_mod_reg(fclk, OMAP3430_PER_MOD, CM_FCLKEN);
+ }
+
+ if (omap_rev() > OMAP3430_REV_ES1_0) {
+ /* USBHOST */
+ wkst = prm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, PM_WKST);
+ if (wkst) {
+ iclk = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
+ CM_ICLKEN);
+ fclk = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
+ CM_FCLKEN);
+ cm_set_mod_reg_bits(wkst, OMAP3430ES2_USBHOST_MOD,
+ CM_ICLKEN);
+ cm_set_mod_reg_bits(wkst, OMAP3430ES2_USBHOST_MOD,
+ CM_FCLKEN);
+ prm_write_mod_reg(wkst, OMAP3430ES2_USBHOST_MOD,
+ PM_WKST);
+ while (prm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
+ PM_WKST));
+ cm_write_mod_reg(iclk, OMAP3430ES2_USBHOST_MOD,
+ CM_ICLKEN);
+ cm_write_mod_reg(fclk, OMAP3430ES2_USBHOST_MOD,
+ CM_FCLKEN);
+ }
+ }
+
+ irqstatus_mpu = prm_read_mod_reg(OCP_MOD,
+ OMAP2_PRM_IRQSTATUS_MPU_OFFSET);
+ prm_write_mod_reg(irqstatus_mpu, OCP_MOD,
+ OMAP2_PRM_IRQSTATUS_MPU_OFFSET);
+
+ while (prm_read_mod_reg(OCP_MOD, OMAP2_PRM_IRQSTATUS_MPU_OFFSET));
+
+ return IRQ_HANDLED;
+}
+
+static void omap_sram_idle(void)
+{
+ /* Variable to tell what needs to be saved and restored
+ * in omap_sram_idle*/
+ /* save_state = 0 => Nothing to save and restored */
+ /* save_state = 1 => Only L1 and logic lost */
+ /* save_state = 2 => Only L2 lost */
+ /* save_state = 3 => L1, L2 and logic lost */
+ int save_state = 0, mpu_next_state;
+
+ if (!_omap_sram_idle)
+ return;
+
+ mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm);
+ switch (mpu_next_state) {
+ case PWRDM_POWER_RET:
+ /* No need to save context */
+ save_state = 0;
+ break;
+ default:
+ /* Invalid state */
+ printk(KERN_ERR "Invalid mpu state in sram_idle\n");
+ return;
+ }
+ /* Disable smartreflex before entering WFI */
+ disable_smartreflex(SR1);
+ disable_smartreflex(SR2);
+
+ omap2_gpio_prepare_for_retention();
+ omap_uart_prepare_idle(0);
+ omap_uart_prepare_idle(1);
+ omap_uart_prepare_idle(2);
+
+ _omap_sram_idle(NULL, save_state);
+
+ omap_uart_resume_idle(2);
+ omap_uart_resume_idle(1);
+ omap_uart_resume_idle(0);
+ omap2_gpio_resume_after_retention();
+
+ /* Enable smartreflex after WFI */
+ enable_smartreflex(SR1);
+ enable_smartreflex(SR2);
+}
+
+/*
+ * Check if functional clocks are enabled before entering
+ * sleep. This function could be behind CONFIG_PM_DEBUG
+ * when all drivers are configuring their sysconfig registers
+ * properly and using their clocks properly.
+ */
+static int omap3_fclks_active(void)
+{
+ u32 fck_core1 = 0, fck_core3 = 0, fck_sgx = 0, fck_dss = 0,
+ fck_cam = 0, fck_per = 0, fck_usbhost = 0;
+
+ fck_core1 = cm_read_mod_reg(CORE_MOD,
+ CM_FCLKEN1);
+ if (omap_rev() > OMAP3430_REV_ES1_0) {
+ fck_core3 = cm_read_mod_reg(CORE_MOD,
+ OMAP3430ES2_CM_FCLKEN3);
+ fck_sgx = cm_read_mod_reg(OMAP3430ES2_SGX_MOD,
+ CM_FCLKEN);
+ fck_usbhost = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
+ CM_FCLKEN);
+ } else
+ fck_sgx = cm_read_mod_reg(GFX_MOD,
+ OMAP3430ES2_CM_FCLKEN3);
+ fck_dss = cm_read_mod_reg(OMAP3430_DSS_MOD,
+ CM_FCLKEN);
+ fck_cam = cm_read_mod_reg(OMAP3430_CAM_MOD,
+ CM_FCLKEN);
+ fck_per = cm_read_mod_reg(OMAP3430_PER_MOD,
+ CM_FCLKEN);
+
+ /* Ignore UART clocks. These are handled by UART core (serial.c) */
+ fck_core1 &= ~(OMAP3430_EN_UART1 | OMAP3430_EN_UART2);
+ fck_per &= ~OMAP3430_EN_UART3;
+
+ if (fck_core1 | fck_core3 | fck_sgx | fck_dss |
+ fck_cam | fck_per | fck_usbhost)
+ return 1;
+ return 0;
+}
+
+static int omap3_can_sleep(void)
+{
+ if (!enable_dyn_sleep)
+ return 0;
+ if (!omap_uart_can_sleep())
+ return 0;
+ if (omap3_fclks_active())
+ return 0;
+ if (atomic_read(&sleep_block) > 0)
+ return 0;
+ return 1;
+}
+
+/* This sets pwrdm state (other than mpu & core. Currently only ON &
+ * RET are supported. Function is assuming that clkdm doesn't have
+ * hw_sup mode enabled. */
+static int set_pwrdm_state(struct powerdomain *pwrdm, u32 state)
+{
+ u32 cur_state;
+ int sleep_switch = 0;
+ int ret = 0;
+
+ if (pwrdm == NULL || IS_ERR(pwrdm))
+ return -EINVAL;
+
+ while (!(pwrdm->pwrsts & (1 << state))) {
+ if (state == PWRDM_POWER_OFF)
+ return ret;
+ state--;
+ }
+
+ cur_state = pwrdm_read_next_pwrst(pwrdm);
+ if (cur_state == state)
+ return ret;
+
+ if (pwrdm_read_pwrst(pwrdm) < PWRDM_POWER_ON) {
+ omap2_clkdm_wakeup(pwrdm->pwrdm_clkdms[0]);
+ sleep_switch = 1;
+ pwrdm_wait_transition(pwrdm);
+ }
+
+ ret = pwrdm_set_next_pwrst(pwrdm, state);
+ if (ret) {
+ printk(KERN_ERR "Unable to set state of powerdomain: %s\n",
+ pwrdm->name);
+ goto err;
+ }
+
+ if (sleep_switch) {
+ omap2_clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]);
+ pwrdm_wait_transition(pwrdm);
+ }
+
+err:
+ return ret;
+}
+
+static void omap3_pm_idle(void)
+{
+ local_irq_disable();
+ local_fiq_disable();
+
+ if (!omap3_can_sleep())
+ goto out;
+
+ if (omap_irq_pending())
+ goto out;
+
+ omap_sram_idle();
+
+out:
+ local_fiq_enable();
+ local_irq_enable();
+}
+
+static int omap3_pm_prepare(void)
+{
+ saved_idle = pm_idle;
+ pm_idle = NULL;
+ return 0;
+}
+
+static int omap3_pm_suspend(void)
+{
+ struct power_state *pwrst;
+ int state, ret = 0;
+
+ /* Read current next_pwrsts */
+ list_for_each_entry(pwrst, &pwrst_list, node)
+ pwrst->saved_state = pwrdm_read_next_pwrst(pwrst->pwrdm);
+ /* Set ones wanted by suspend */
+ list_for_each_entry(pwrst, &pwrst_list, node) {
+ if (set_pwrdm_state(pwrst->pwrdm, pwrst->next_state))
+ goto restore;
+ if (pwrdm_clear_all_prev_pwrst(pwrst->pwrdm))
+ goto restore;
+ }
+
+ omap_uart_prepare_suspend();
+ omap_sram_idle();
+
+restore:
+ /* Restore next_pwrsts */
+ list_for_each_entry(pwrst, &pwrst_list, node) {
+ set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state);
+ state = pwrdm_read_prev_pwrst(pwrst->pwrdm);
+ if (state > pwrst->next_state) {
+ printk(KERN_INFO "Powerdomain (%s) didn't enter "
+ "target state %d\n",
+ pwrst->pwrdm->name, pwrst->next_state);
+ ret = -1;
+ }
+ }
+ if (ret)
+ printk(KERN_ERR "Could not enter target state in pm_suspend\n");
+ else
+ printk(KERN_INFO "Successfully put all powerdomains "
+ "to target state\n");
+
+ return ret;
+}
+
+static int omap3_pm_enter(suspend_state_t state)
+{
+ int ret = 0;
+
+ switch (state) {
+ case PM_SUSPEND_STANDBY:
+ case PM_SUSPEND_MEM:
+ ret = omap3_pm_suspend();
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static void omap3_pm_finish(void)
+{
+ pm_idle = saved_idle;
+}
+
+static struct platform_suspend_ops omap_pm_ops = {
+ .prepare = omap3_pm_prepare,
+ .enter = omap3_pm_enter,
+ .finish = omap3_pm_finish,
+ .valid = suspend_valid_only_mem,
+};
+
+
+/**
+ * omap3_iva_idle(): ensure IVA is in idle so it can be put into
+ * retention
+ *
+ * In cases where IVA2 is activated by bootcode, it may prevent
+ * full-chip retention or off-mode because it is not idle. This
+ * function forces the IVA2 into idle state so it can go
+ * into retention/off and thus allow full-chip retention/off.
+ *
+ **/
+static void __init omap3_iva_idle(void)
+{
+ /* ensure IVA2 clock is disabled */
+ cm_write_mod_reg(0, OMAP3430_IVA2_MOD, CM_FCLKEN);
+
+ /* Reset IVA2 */
+ prm_write_mod_reg(OMAP3430_RST1_IVA2 |
+ OMAP3430_RST2_IVA2 |
+ OMAP3430_RST3_IVA2,
+ OMAP3430_IVA2_MOD, RM_RSTCTRL);
+
+ /* Enable IVA2 clock */
+ cm_write_mod_reg(OMAP3430_CM_FCLKEN_IVA2_EN_IVA2,
+ OMAP3430_IVA2_MOD, CM_FCLKEN);
+
+ /* Set IVA2 boot mode to 'idle' */
+ omap_ctrl_writel(OMAP3_IVA2_BOOTMOD_IDLE,
+ OMAP343X_CONTROL_IVA2_BOOTMOD);
+
+ /* Un-reset IVA2 */
+ prm_write_mod_reg(0, OMAP3430_IVA2_MOD, RM_RSTCTRL);
+
+ /* Disable IVA2 clock */
+ cm_write_mod_reg(0, OMAP3430_IVA2_MOD, CM_FCLKEN);
+
+ /* Reset IVA2 */
+ prm_write_mod_reg(OMAP3430_RST1_IVA2 |
+ OMAP3430_RST2_IVA2 |
+ OMAP3430_RST3_IVA2,
+ OMAP3430_IVA2_MOD, RM_RSTCTRL);
+}
+
+static void __init prcm_setup_regs(void)
+{
+ /* reset modem */
+ prm_write_mod_reg(OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RSTPWRON |
+ OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RST,
+ CORE_MOD, RM_RSTCTRL);
+ prm_write_mod_reg(0, CORE_MOD, RM_RSTCTRL);
+
+ /* XXX Reset all wkdeps. This should be done when initializing
+ * powerdomains */
+ prm_write_mod_reg(0, OMAP3430_IVA2_MOD, PM_WKDEP);
+ prm_write_mod_reg(0, MPU_MOD, PM_WKDEP);
+ prm_write_mod_reg(0, OMAP3430_DSS_MOD, PM_WKDEP);
+ prm_write_mod_reg(0, OMAP3430_NEON_MOD, PM_WKDEP);
+ prm_write_mod_reg(0, OMAP3430_CAM_MOD, PM_WKDEP);
+ prm_write_mod_reg(0, OMAP3430_PER_MOD, PM_WKDEP);
+ if (omap_rev() > OMAP3430_REV_ES1_0) {
+ prm_write_mod_reg(0, OMAP3430ES2_SGX_MOD, PM_WKDEP);
+ prm_write_mod_reg(0, OMAP3430ES2_USBHOST_MOD, PM_WKDEP);
+ } else
+ prm_write_mod_reg(0, GFX_MOD, PM_WKDEP);
+
+ /*
+ * Enable interface clock autoidle for all modules.
+ * Note that in the long run this should be done by clockfw
+ */
+ cm_write_mod_reg(
+ OMAP3430ES2_AUTO_MMC3 |
+ OMAP3430ES2_AUTO_ICR |
+ OMAP3430_AUTO_AES2 |
+ OMAP3430_AUTO_SHA12 |
+ OMAP3430_AUTO_DES2 |
+ OMAP3430_AUTO_MMC2 |
+ OMAP3430_AUTO_MMC1 |
+ OMAP3430_AUTO_MSPRO |
+ OMAP3430_AUTO_HDQ |
+ OMAP3430_AUTO_MCSPI4 |
+ OMAP3430_AUTO_MCSPI3 |
+ OMAP3430_AUTO_MCSPI2 |
+ OMAP3430_AUTO_MCSPI1 |
+ OMAP3430_AUTO_I2C3 |
+ OMAP3430_AUTO_I2C2 |
+ OMAP3430_AUTO_I2C1 |
+ OMAP3430_AUTO_UART2 |
+ OMAP3430_AUTO_UART1 |
+ OMAP3430_AUTO_GPT11 |
+ OMAP3430_AUTO_GPT10 |
+ OMAP3430_AUTO_MCBSP5 |
+ OMAP3430_AUTO_MCBSP1 |
+ OMAP3430ES1_AUTO_FAC | /* This is es1 only */
+ OMAP3430_AUTO_MAILBOXES |
+ OMAP3430_AUTO_OMAPCTRL |
+ OMAP3430ES1_AUTO_FSHOSTUSB |
+ OMAP3430_AUTO_HSOTGUSB |
+ OMAP3430ES1_AUTO_D2D | /* This is es1 only */
+ OMAP3430_AUTO_SSI,
+ CORE_MOD, CM_AUTOIDLE1);
+
+ cm_write_mod_reg(
+ OMAP3430_AUTO_PKA |
+ OMAP3430_AUTO_AES1 |
+ OMAP3430_AUTO_RNG |
+ OMAP3430_AUTO_SHA11 |
+ OMAP3430_AUTO_DES1,
+ CORE_MOD, CM_AUTOIDLE2);
+
+ if (omap_rev() > OMAP3430_REV_ES1_0) {
+ cm_write_mod_reg(
+ OMAP3430ES2_AUTO_USBTLL,
+ CORE_MOD, CM_AUTOIDLE3);
+ }
+
+ cm_write_mod_reg(
+ OMAP3430_AUTO_WDT2 |
+ OMAP3430_AUTO_WDT1 |
+ OMAP3430_AUTO_GPIO1 |
+ OMAP3430_AUTO_32KSYNC |
+ OMAP3430_AUTO_GPT12 |
+ OMAP3430_AUTO_GPT1 ,
+ WKUP_MOD, CM_AUTOIDLE);
+
+ cm_write_mod_reg(
+ OMAP3430_AUTO_DSS,
+ OMAP3430_DSS_MOD,
+ CM_AUTOIDLE);
+
+ cm_write_mod_reg(
+ OMAP3430_AUTO_CAM,
+ OMAP3430_CAM_MOD,
+ CM_AUTOIDLE);
+
+ cm_write_mod_reg(
+ OMAP3430_AUTO_GPIO6 |
+ OMAP3430_AUTO_GPIO5 |
+ OMAP3430_AUTO_GPIO4 |
+ OMAP3430_AUTO_GPIO3 |
+ OMAP3430_AUTO_GPIO2 |
+ OMAP3430_AUTO_WDT3 |
+ OMAP3430_AUTO_UART3 |
+ OMAP3430_AUTO_GPT9 |
+ OMAP3430_AUTO_GPT8 |
+ OMAP3430_AUTO_GPT7 |
+ OMAP3430_AUTO_GPT6 |
+ OMAP3430_AUTO_GPT5 |
+ OMAP3430_AUTO_GPT4 |
+ OMAP3430_AUTO_GPT3 |
+ OMAP3430_AUTO_GPT2 |
+ OMAP3430_AUTO_MCBSP4 |
+ OMAP3430_AUTO_MCBSP3 |
+ OMAP3430_AUTO_MCBSP2,
+ OMAP3430_PER_MOD,
+ CM_AUTOIDLE);
+
+ if (omap_rev() > OMAP3430_REV_ES1_0) {
+ cm_write_mod_reg(
+ OMAP3430ES2_AUTO_USBHOST,
+ OMAP3430ES2_USBHOST_MOD,
+ CM_AUTOIDLE);
+ }
+
+ /*
+ * Set all plls to autoidle. This is needed until autoidle is
+ * enabled by clockfw
+ */
+ cm_write_mod_reg(1 << OMAP3430_AUTO_IVA2_DPLL_SHIFT,
+ OMAP3430_IVA2_MOD, CM_AUTOIDLE2);
+ cm_write_mod_reg(1 << OMAP3430_AUTO_MPU_DPLL_SHIFT,
+ MPU_MOD,
+ CM_AUTOIDLE2);
+ cm_write_mod_reg((1 << OMAP3430_AUTO_PERIPH_DPLL_SHIFT) |
+ (1 << OMAP3430_AUTO_CORE_DPLL_SHIFT),
+ PLL_MOD,
+ CM_AUTOIDLE);
+ cm_write_mod_reg(1 << OMAP3430ES2_AUTO_PERIPH2_DPLL_SHIFT,
+ PLL_MOD,
+ CM_AUTOIDLE2);
+
+ /*
+ * Enable control of expternal oscillator through
+ * sys_clkreq. In the long run clock framework should
+ * take care of this.
+ */
+ prm_rmw_mod_reg_bits(OMAP_AUTOEXTCLKMODE_MASK,
+ 1 << OMAP_AUTOEXTCLKMODE_SHIFT,
+ OMAP3430_GR_MOD,
+ OMAP3_PRM_CLKSRC_CTRL_OFFSET);
+
+ /* setup wakup source */
+ prm_write_mod_reg(OMAP3430_EN_IO | OMAP3430_EN_GPIO1 |
+ OMAP3430_EN_GPT1 | OMAP3430_EN_GPT12,
+ WKUP_MOD, PM_WKEN);
+ /* No need to write EN_IO, that is always enabled */
+ prm_write_mod_reg(OMAP3430_EN_GPIO1 | OMAP3430_EN_GPT1 |
+ OMAP3430_EN_GPT12,
+ WKUP_MOD, OMAP3430_PM_MPUGRPSEL);
+ /* For some reason IO doesn't generate wakeup event even if
+ * it is selected to mpu wakeup goup */
+ prm_write_mod_reg(OMAP3430_IO_EN | OMAP3430_WKUP_EN,
+ OCP_MOD, OMAP2_PRM_IRQENABLE_MPU_OFFSET);
+
+ omap3_iva_idle();
+}
+
+static int __init pwrdms_setup(struct powerdomain *pwrdm)
+{
+ struct power_state *pwrst;
+
+ if (!pwrdm->pwrsts)
+ return 0;
+
+ pwrst = kmalloc(sizeof(struct power_state), GFP_KERNEL);
+ if (!pwrst)
+ return -ENOMEM;
+ pwrst->pwrdm = pwrdm;
+ pwrst->next_state = PWRDM_POWER_RET;
+ list_add(&pwrst->node, &pwrst_list);
+
+ if (pwrdm_has_hdwr_sar(pwrdm))
+ pwrdm_enable_hdwr_sar(pwrdm);
+
+ return set_pwrdm_state(pwrst->pwrdm, pwrst->next_state);
+}
+
+/*
+ * Enable hw supervised mode for all clockdomains if it's
+ * supported. Initiate sleep transition for other clockdomains, if
+ * they are not used
+ */
+static int __init clkdms_setup(struct clockdomain *clkdm)
+{
+ if (clkdm->flags & CLKDM_CAN_ENABLE_AUTO)
+ omap2_clkdm_allow_idle(clkdm);
+ else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP &&
+ atomic_read(&clkdm->usecount) == 0)
+ omap2_clkdm_sleep(clkdm);
+ return 0;
+}
+
+int __init omap3_pm_init(void)
+{
+ struct power_state *pwrst, *tmp;
+ int ret;
+
+ printk(KERN_ERR "Power Management for TI OMAP3.\n");
+
+ /* XXX prcm_setup_regs needs to be before enabling hw
+ * supervised mode for powerdomains */
+ prcm_setup_regs();
+
+ ret = request_irq(INT_34XX_PRCM_MPU_IRQ,
+ (irq_handler_t)prcm_interrupt_handler,
+ IRQF_DISABLED, "prcm", NULL);
+ if (ret) {
+ printk(KERN_ERR "request_irq failed to register for 0x%x\n",
+ INT_34XX_PRCM_MPU_IRQ);
+ goto err1;
+ }
+
+ ret = pwrdm_for_each(pwrdms_setup);
+ if (ret) {
+ printk(KERN_ERR "Failed to setup powerdomains\n");
+ goto err2;
+ }
+
+ (void) clkdm_for_each(clkdms_setup);
+
+ mpu_pwrdm = pwrdm_lookup("mpu_pwrdm");
+ if (mpu_pwrdm == NULL) {
+ printk(KERN_ERR "Failed to get mpu_pwrdm\n");
+ goto err2;
+ }
+
+ _omap_sram_idle = omap_sram_push(omap34xx_cpu_suspend,
+ omap34xx_cpu_suspend_sz);
+
+ suspend_set_ops(&omap_pm_ops);
+
+ pm_idle = omap3_pm_idle;
+
+err1:
+ return ret;
+err2:
+ free_irq(INT_34XX_PRCM_MPU_IRQ, NULL);
+ list_for_each_entry_safe(pwrst, tmp, &pwrst_list, node) {
+ list_del(&pwrst->node);
+ kfree(pwrst);
+ }
+ return ret;
+}
+
+static void __init configure_vc(void)
+{
+ prm_write_mod_reg((R_SRI2C_SLAVE_ADDR << OMAP3430_SMPS_SA1_SHIFT) |
+ (R_SRI2C_SLAVE_ADDR << OMAP3430_SMPS_SA0_SHIFT),
+ OMAP3430_GR_MOD, OMAP3_PRM_VC_SMPS_SA_OFFSET);
+ prm_write_mod_reg((R_VDD2_SR_CONTROL << OMAP3430_VOLRA1_SHIFT) |
+ (R_VDD1_SR_CONTROL << OMAP3430_VOLRA0_SHIFT),
+ OMAP3430_GR_MOD, OMAP3_PRM_VC_SMPS_VOL_RA_OFFSET);
+
+ prm_write_mod_reg((OMAP3430_VC_CMD_VAL0_ON <<
+ OMAP3430_VC_CMD_ON_SHIFT) |
+ (OMAP3430_VC_CMD_VAL0_ONLP << OMAP3430_VC_CMD_ONLP_SHIFT) |
+ (OMAP3430_VC_CMD_VAL0_RET << OMAP3430_VC_CMD_RET_SHIFT) |
+ (OMAP3430_VC_CMD_VAL0_OFF << OMAP3430_VC_CMD_OFF_SHIFT),
+ OMAP3430_GR_MOD, OMAP3_PRM_VC_CMD_VAL_0_OFFSET);
+
+ prm_write_mod_reg((OMAP3430_VC_CMD_VAL1_ON <<
+ OMAP3430_VC_CMD_ON_SHIFT) |
+ (OMAP3430_VC_CMD_VAL1_ONLP << OMAP3430_VC_CMD_ONLP_SHIFT) |
+ (OMAP3430_VC_CMD_VAL1_RET << OMAP3430_VC_CMD_RET_SHIFT) |
+ (OMAP3430_VC_CMD_VAL1_OFF << OMAP3430_VC_CMD_OFF_SHIFT),
+ OMAP3430_GR_MOD, OMAP3_PRM_VC_CMD_VAL_1_OFFSET);
+
+ prm_write_mod_reg(OMAP3430_CMD1 | OMAP3430_RAV1,
+ OMAP3430_GR_MOD,
+ OMAP3_PRM_VC_CH_CONF_OFFSET);
+
+ prm_write_mod_reg(OMAP3430_MCODE_SHIFT | OMAP3430_HSEN | OMAP3430_SREN,
+ OMAP3430_GR_MOD,
+ OMAP3_PRM_VC_I2C_CFG_OFFSET);
+
+ /* Setup voltctrl and other setup times */
+ prm_write_mod_reg(OMAP3430_AUTO_RET, OMAP3430_GR_MOD,
+ OMAP3_PRM_VOLTCTRL_OFFSET);
+
+ prm_write_mod_reg(OMAP3430_CLKSETUP_DURATION, OMAP3430_GR_MOD,
+ OMAP3_PRM_CLKSETUP_OFFSET);
+ prm_write_mod_reg((OMAP3430_VOLTSETUP_TIME2 <<
+ OMAP3430_SETUP_TIME2_SHIFT) |
+ (OMAP3430_VOLTSETUP_TIME1 <<
+ OMAP3430_SETUP_TIME1_SHIFT),
+ OMAP3430_GR_MOD, OMAP3_PRM_VOLTSETUP1_OFFSET);
+
+ prm_write_mod_reg(OMAP3430_VOLTOFFSET_DURATION, OMAP3430_GR_MOD,
+ OMAP3_PRM_VOLTOFFSET_OFFSET);
+ prm_write_mod_reg(OMAP3430_VOLTSETUP2_DURATION, OMAP3430_GR_MOD,
+ OMAP3_PRM_VOLTSETUP2_OFFSET);
+}
+
+static int __init omap3_pm_early_init(void)
+{
+ prm_clear_mod_reg_bits(OMAP3430_OFFMODE_POL, OMAP3430_GR_MOD,
+ OMAP3_PRM_POLCTRL_OFFSET);
+
+ configure_vc();
+
+ return 0;
+}
+
+arch_initcall(omap3_pm_early_init);
&iva2_pwrdm,
&mpu_34xx_pwrdm,
&neon_pwrdm,
- &core_34xx_pwrdm,
+ &core_34xx_es1_pwrdm,
+ &core_34xx_es2_pwrdm,
&cam_pwrdm,
&dss_pwrdm,
&per_pwrdm,
&emu_pwrdm,
&sgx_pwrdm,
&usbhost_pwrdm,
+ &dpll1_pwrdm,
+ &dpll2_pwrdm,
+ &dpll3_pwrdm,
+ &dpll4_pwrdm,
+ &dpll5_pwrdm,
#endif
NULL
};
/* No wkdeps or sleepdeps for 34xx core apparently */
-static struct powerdomain core_34xx_pwrdm = {
+static struct powerdomain core_34xx_es1_pwrdm = {
.name = "core_pwrdm",
.prcm_offs = CORE_MOD,
- .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES1),
+ .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 */
+ },
+};
+
+/* No wkdeps or sleepdeps for 34xx core apparently */
+static struct powerdomain core_34xx_es2_pwrdm = {
+ .name = "core_pwrdm",
+ .prcm_offs = CORE_MOD,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES2),
.pwrsts = PWRSTS_OFF_RET_ON,
.dep_bit = OMAP3430_EN_CORE_SHIFT,
+ .flags = PWRDM_HAS_HDWR_SAR, /* for USBTLL only */
.banks = 2,
.pwrsts_mem_ret = {
[0] = PWRSTS_OFF_RET, /* MEM1RETSTATE */
},
};
+/*
+ * Although the 34XX TRM Rev K Table 4-371 notes that retention is a
+ * possible SGX powerstate, the SGX device itself does not support
+ * retention.
+ */
static struct powerdomain sgx_pwrdm = {
.name = "sgx_pwrdm",
.prcm_offs = OMAP3430ES2_SGX_MOD,
.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 = PWRSTS_OFF_ON,
.pwrsts_logic_ret = PWRDM_POWER_RET,
.banks = 1,
.pwrsts_mem_ret = {
.sleepdep_srcs = dss_per_usbhost_sleepdeps,
.pwrsts = PWRSTS_OFF_RET_ON,
.pwrsts_logic_ret = PWRDM_POWER_RET,
+ .flags = PWRDM_HAS_HDWR_SAR, /* for USBHOST ctrlr only */
.banks = 1,
.pwrsts_mem_ret = {
[0] = PWRDM_POWER_RET, /* MEMRETSTATE */
},
};
+static struct powerdomain dpll1_pwrdm = {
+ .name = "dpll1_pwrdm",
+ .prcm_offs = MPU_MOD,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct powerdomain dpll2_pwrdm = {
+ .name = "dpll2_pwrdm",
+ .prcm_offs = OMAP3430_IVA2_MOD,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct powerdomain dpll3_pwrdm = {
+ .name = "dpll3_pwrdm",
+ .prcm_offs = PLL_MOD,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct powerdomain dpll4_pwrdm = {
+ .name = "dpll4_pwrdm",
+ .prcm_offs = PLL_MOD,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct powerdomain dpll5_pwrdm = {
+ .name = "dpll5_pwrdm",
+ .prcm_offs = PLL_MOD,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES2),
+};
+
+
#endif /* CONFIG_ARCH_OMAP34XX */
#define OMAP2430_EN_USBHS (1 << 6)
/* CM_IDLEST1_CORE, PM_WKST1_CORE shared bits */
-#define OMAP2420_ST_MMC (1 << 26)
-#define OMAP24XX_ST_UART2 (1 << 22)
-#define OMAP24XX_ST_UART1 (1 << 21)
-#define OMAP24XX_ST_MCSPI2 (1 << 18)
-#define OMAP24XX_ST_MCSPI1 (1 << 17)
-#define OMAP24XX_ST_GPT12 (1 << 14)
-#define OMAP24XX_ST_GPT11 (1 << 13)
-#define OMAP24XX_ST_GPT10 (1 << 12)
-#define OMAP24XX_ST_GPT9 (1 << 11)
-#define OMAP24XX_ST_GPT8 (1 << 10)
-#define OMAP24XX_ST_GPT7 (1 << 9)
-#define OMAP24XX_ST_GPT6 (1 << 8)
-#define OMAP24XX_ST_GPT5 (1 << 7)
-#define OMAP24XX_ST_GPT4 (1 << 6)
-#define OMAP24XX_ST_GPT3 (1 << 5)
-#define OMAP24XX_ST_GPT2 (1 << 4)
-#define OMAP2420_ST_VLYNQ (1 << 3)
+#define OMAP2420_ST_MMC_SHIFT 26
+#define OMAP2420_ST_MMC_MASK (1 << 26)
+#define OMAP24XX_ST_UART2_SHIFT 22
+#define OMAP24XX_ST_UART2_MASK (1 << 22)
+#define OMAP24XX_ST_UART1_SHIFT 21
+#define OMAP24XX_ST_UART1_MASK (1 << 21)
+#define OMAP24XX_ST_MCSPI2_SHIFT 18
+#define OMAP24XX_ST_MCSPI2_MASK (1 << 18)
+#define OMAP24XX_ST_MCSPI1_SHIFT 17
+#define OMAP24XX_ST_MCSPI1_MASK (1 << 17)
+#define OMAP24XX_ST_GPT12_SHIFT 14
+#define OMAP24XX_ST_GPT12_MASK (1 << 14)
+#define OMAP24XX_ST_GPT11_SHIFT 13
+#define OMAP24XX_ST_GPT11_MASK (1 << 13)
+#define OMAP24XX_ST_GPT10_SHIFT 12
+#define OMAP24XX_ST_GPT10_MASK (1 << 12)
+#define OMAP24XX_ST_GPT9_SHIFT 11
+#define OMAP24XX_ST_GPT9_MASK (1 << 11)
+#define OMAP24XX_ST_GPT8_SHIFT 10
+#define OMAP24XX_ST_GPT8_MASK (1 << 10)
+#define OMAP24XX_ST_GPT7_SHIFT 9
+#define OMAP24XX_ST_GPT7_MASK (1 << 9)
+#define OMAP24XX_ST_GPT6_SHIFT 8
+#define OMAP24XX_ST_GPT6_MASK (1 << 8)
+#define OMAP24XX_ST_GPT5_SHIFT 7
+#define OMAP24XX_ST_GPT5_MASK (1 << 7)
+#define OMAP24XX_ST_GPT4_SHIFT 6
+#define OMAP24XX_ST_GPT4_MASK (1 << 6)
+#define OMAP24XX_ST_GPT3_SHIFT 5
+#define OMAP24XX_ST_GPT3_MASK (1 << 5)
+#define OMAP24XX_ST_GPT2_SHIFT 4
+#define OMAP24XX_ST_GPT2_MASK (1 << 4)
+#define OMAP2420_ST_VLYNQ_SHIFT 3
+#define OMAP2420_ST_VLYNQ_MASK (1 << 3)
/* CM_IDLEST2_CORE, PM_WKST2_CORE shared bits */
-#define OMAP2430_ST_MDM_INTC (1 << 11)
-#define OMAP2430_ST_GPIO5 (1 << 10)
-#define OMAP2430_ST_MCSPI3 (1 << 9)
-#define OMAP2430_ST_MMCHS2 (1 << 8)
-#define OMAP2430_ST_MMCHS1 (1 << 7)
-#define OMAP2430_ST_USBHS (1 << 6)
-#define OMAP24XX_ST_UART3 (1 << 2)
-#define OMAP24XX_ST_USB (1 << 0)
+#define OMAP2430_ST_MDM_INTC_SHIFT 11
+#define OMAP2430_ST_MDM_INTC_MASK (1 << 11)
+#define OMAP2430_ST_GPIO5_SHIFT 10
+#define OMAP2430_ST_GPIO5_MASK (1 << 10)
+#define OMAP2430_ST_MCSPI3_SHIFT 9
+#define OMAP2430_ST_MCSPI3_MASK (1 << 9)
+#define OMAP2430_ST_MMCHS2_SHIFT 8
+#define OMAP2430_ST_MMCHS2_MASK (1 << 8)
+#define OMAP2430_ST_MMCHS1_SHIFT 7
+#define OMAP2430_ST_MMCHS1_MASK (1 << 7)
+#define OMAP2430_ST_USBHS_SHIFT 6
+#define OMAP2430_ST_USBHS_MASK (1 << 6)
+#define OMAP24XX_ST_UART3_SHIFT 2
+#define OMAP24XX_ST_UART3_MASK (1 << 2)
+#define OMAP24XX_ST_USB_SHIFT 0
+#define OMAP24XX_ST_USB_MASK (1 << 0)
/* CM_FCLKEN_WKUP, CM_ICLKEN_WKUP, PM_WKEN_WKUP shared bits */
#define OMAP24XX_EN_GPIOS_SHIFT 2
#define OMAP24XX_EN_GPT1 (1 << 0)
/* PM_WKST_WKUP, CM_IDLEST_WKUP shared bits */
-#define OMAP24XX_ST_GPIOS (1 << 2)
-#define OMAP24XX_ST_GPT1 (1 << 0)
+#define OMAP24XX_ST_GPIOS_SHIFT (1 << 2)
+#define OMAP24XX_ST_GPIOS_MASK 2
+#define OMAP24XX_ST_GPT1_SHIFT (1 << 0)
+#define OMAP24XX_ST_GPT1_MASK 0
/* CM_IDLEST_MDM and PM_WKST_MDM shared bits */
-#define OMAP2430_ST_MDM (1 << 0)
+#define OMAP2430_ST_MDM_SHIFT (1 << 0)
/* 3430 register bits shared between CM & PRM registers */
#define OMAP3430_EN_HSOTGUSB_SHIFT 4
/* PM_WKST1_CORE, CM_IDLEST1_CORE shared bits */
-#define OMAP3430_ST_MMC2 (1 << 25)
-#define OMAP3430_ST_MMC1 (1 << 24)
-#define OMAP3430_ST_MCSPI4 (1 << 21)
-#define OMAP3430_ST_MCSPI3 (1 << 20)
-#define OMAP3430_ST_MCSPI2 (1 << 19)
-#define OMAP3430_ST_MCSPI1 (1 << 18)
-#define OMAP3430_ST_I2C3 (1 << 17)
-#define OMAP3430_ST_I2C2 (1 << 16)
-#define OMAP3430_ST_I2C1 (1 << 15)
-#define OMAP3430_ST_UART2 (1 << 14)
-#define OMAP3430_ST_UART1 (1 << 13)
-#define OMAP3430_ST_GPT11 (1 << 12)
-#define OMAP3430_ST_GPT10 (1 << 11)
-#define OMAP3430_ST_MCBSP5 (1 << 10)
-#define OMAP3430_ST_MCBSP1 (1 << 9)
-#define OMAP3430_ST_FSHOSTUSB (1 << 5)
-#define OMAP3430_ST_HSOTGUSB (1 << 4)
-#define OMAP3430_ST_D2D (1 << 3)
+#define OMAP3430_ST_MMC2_SHIFT 25
+#define OMAP3430_ST_MMC2_MASK (1 << 25)
+#define OMAP3430_ST_MMC1_SHIFT 24
+#define OMAP3430_ST_MMC1_MASK (1 << 24)
+#define OMAP3430_ST_MCSPI4_SHIFT 21
+#define OMAP3430_ST_MCSPI4_MASK (1 << 21)
+#define OMAP3430_ST_MCSPI3_SHIFT 20
+#define OMAP3430_ST_MCSPI3_MASK (1 << 20)
+#define OMAP3430_ST_MCSPI2_SHIFT 19
+#define OMAP3430_ST_MCSPI2_MASK (1 << 19)
+#define OMAP3430_ST_MCSPI1_SHIFT 18
+#define OMAP3430_ST_MCSPI1_MASK (1 << 18)
+#define OMAP3430_ST_I2C3_SHIFT 17
+#define OMAP3430_ST_I2C3_MASK (1 << 17)
+#define OMAP3430_ST_I2C2_SHIFT 16
+#define OMAP3430_ST_I2C2_MASK (1 << 16)
+#define OMAP3430_ST_I2C1_SHIFT 15
+#define OMAP3430_ST_I2C1_MASK (1 << 15)
+#define OMAP3430_ST_UART2_SHIFT 14
+#define OMAP3430_ST_UART2_MASK (1 << 14)
+#define OMAP3430_ST_UART1_SHIFT 13
+#define OMAP3430_ST_UART1_MASK (1 << 13)
+#define OMAP3430_ST_GPT11_SHIFT 12
+#define OMAP3430_ST_GPT11_MASK (1 << 12)
+#define OMAP3430_ST_GPT10_SHIFT 11
+#define OMAP3430_ST_GPT10_MASK (1 << 11)
+#define OMAP3430_ST_MCBSP5_SHIFT 10
+#define OMAP3430_ST_MCBSP5_MASK (1 << 10)
+#define OMAP3430_ST_MCBSP1_SHIFT 9
+#define OMAP3430_ST_MCBSP1_MASK (1 << 9)
+#define OMAP3430ES1_ST_FSHOSTUSB_SHIFT 5
+#define OMAP3430ES1_ST_FSHOSTUSB_MASK (1 << 5)
+#define OMAP3430ES1_ST_HSOTGUSB_SHIFT 4
+#define OMAP3430ES1_ST_HSOTGUSB_MASK (1 << 4)
+#define OMAP3430ES2_ST_HSOTGUSB_IDLE_SHIFT 5
+#define OMAP3430ES2_ST_HSOTGUSB_IDLE_MASK (1 << 5)
+#define OMAP3430ES2_ST_HSOTGUSB_STDBY_SHIFT 4
+#define OMAP3430ES2_ST_HSOTGUSB_STDBY_MASK (1 << 4)
+#define OMAP3430_ST_D2D_SHIFT 3
+#define OMAP3430_ST_D2D_MASK (1 << 3)
/* CM_FCLKEN_WKUP, CM_ICLKEN_WKUP, PM_WKEN_WKUP shared bits */
#define OMAP3430_EN_GPIO1 (1 << 3)
#define OMAP3430_EN_GPIO1_SHIFT 3
+#define OMAP3430_EN_GPT12 (1 << 1)
+#define OMAP3430_EN_GPT12_SHIFT 1
#define OMAP3430_EN_GPT1 (1 << 0)
#define OMAP3430_EN_GPT1_SHIFT 0
#define OMAP3430_EN_GPT12_SHIFT 1
/* CM_IDLEST_WKUP, PM_WKST_WKUP shared bits */
-#define OMAP3430_ST_SR2 (1 << 7)
-#define OMAP3430_ST_SR1 (1 << 6)
-#define OMAP3430_ST_GPIO1 (1 << 3)
-#define OMAP3430_ST_GPT12 (1 << 1)
-#define OMAP3430_ST_GPT1 (1 << 0)
+#define OMAP3430_ST_SR2_SHIFT 7
+#define OMAP3430_ST_SR2_MASK (1 << 7)
+#define OMAP3430_ST_SR1_SHIFT 6
+#define OMAP3430_ST_SR1_MASK (1 << 6)
+#define OMAP3430_ST_GPIO1_SHIFT 3
+#define OMAP3430_ST_GPIO1_MASK (1 << 3)
+#define OMAP3430_ST_GPT12_SHIFT 1
+#define OMAP3430_ST_GPT12_MASK (1 << 1)
+#define OMAP3430_ST_GPT1_SHIFT 0
+#define OMAP3430_ST_GPT1_MASK (1 << 0)
/*
* CM_SLEEPDEP_GFX, CM_SLEEPDEP_DSS, CM_SLEEPDEP_CAM,
#define OMAP3430_EN_MCBSP2_SHIFT 0
/* CM_IDLEST_PER, PM_WKST_PER shared bits */
-#define OMAP3430_ST_GPIO6 (1 << 17)
-#define OMAP3430_ST_GPIO5 (1 << 16)
-#define OMAP3430_ST_GPIO4 (1 << 15)
-#define OMAP3430_ST_GPIO3 (1 << 14)
-#define OMAP3430_ST_GPIO2 (1 << 13)
-#define OMAP3430_ST_UART3 (1 << 11)
-#define OMAP3430_ST_GPT9 (1 << 10)
-#define OMAP3430_ST_GPT8 (1 << 9)
-#define OMAP3430_ST_GPT7 (1 << 8)
-#define OMAP3430_ST_GPT6 (1 << 7)
-#define OMAP3430_ST_GPT5 (1 << 6)
-#define OMAP3430_ST_GPT4 (1 << 5)
-#define OMAP3430_ST_GPT3 (1 << 4)
-#define OMAP3430_ST_GPT2 (1 << 3)
+#define OMAP3430_ST_GPIO6_SHIFT 17
+#define OMAP3430_ST_GPIO6_MASK (1 << 17)
+#define OMAP3430_ST_GPIO5_SHIFT 16
+#define OMAP3430_ST_GPIO5_MASK (1 << 16)
+#define OMAP3430_ST_GPIO4_SHIFT 15
+#define OMAP3430_ST_GPIO4_MASK (1 << 15)
+#define OMAP3430_ST_GPIO3_SHIFT 14
+#define OMAP3430_ST_GPIO3_MASK (1 << 14)
+#define OMAP3430_ST_GPIO2_SHIFT 13
+#define OMAP3430_ST_GPIO2_MASK (1 << 13)
+#define OMAP3430_ST_UART3_SHIFT 11
+#define OMAP3430_ST_UART3_MASK (1 << 11)
+#define OMAP3430_ST_GPT9_SHIFT 10
+#define OMAP3430_ST_GPT9_MASK (1 << 10)
+#define OMAP3430_ST_GPT8_SHIFT 9
+#define OMAP3430_ST_GPT8_MASK (1 << 9)
+#define OMAP3430_ST_GPT7_SHIFT 8
+#define OMAP3430_ST_GPT7_MASK (1 << 8)
+#define OMAP3430_ST_GPT6_SHIFT 7
+#define OMAP3430_ST_GPT6_MASK (1 << 7)
+#define OMAP3430_ST_GPT5_SHIFT 6
+#define OMAP3430_ST_GPT5_MASK (1 << 6)
+#define OMAP3430_ST_GPT4_SHIFT 5
+#define OMAP3430_ST_GPT4_MASK (1 << 5)
+#define OMAP3430_ST_GPT3_SHIFT 4
+#define OMAP3430_ST_GPT3_MASK (1 << 4)
+#define OMAP3430_ST_GPT2_SHIFT 3
+#define OMAP3430_ST_GPT2_MASK (1 << 3)
/* CM_SLEEPDEP_PER, PM_WKDEP_IVA2, PM_WKDEP_MPU, PM_WKDEP_PER shared bits */
#define OMAP3430_EN_CORE_SHIFT 0
/* PM_WKEN_WKUP specific bits */
#define OMAP3430_EN_IO (1 << 8)
+#define OMAP3430_EN_GPIO1 (1 << 3)
/* PM_MPUGRPSEL_WKUP specific bits */
/* PM_PWSTST_EMU specific bits */
/* PRM_VC_SMPS_SA */
-#define OMAP3430_PRM_VC_SMPS_SA_SA1_SHIFT 16
-#define OMAP3430_PRM_VC_SMPS_SA_SA1_MASK (0x7f << 16)
-#define OMAP3430_PRM_VC_SMPS_SA_SA0_SHIFT 0
-#define OMAP3430_PRM_VC_SMPS_SA_SA0_MASK (0x7f << 0)
+#define OMAP3430_SMPS_SA1_SHIFT 16
+#define OMAP3430_SMPS_SA1_MASK (0x7f << 16)
+#define OMAP3430_SMPS_SA0_SHIFT 0
+#define OMAP3430_SMPS_SA0_MASK (0x7f << 0)
/* PRM_VC_SMPS_VOL_RA */
#define OMAP3430_VOLRA1_SHIFT 16
#define OMAP3430_CMDRA0_SHIFT 0
#define OMAP3430_CMDRA0_MASK (0xff << 0)
+/* PRM_VC_CMD_VAL */
+#define OMAP3430_VC_CMD_ON_SHIFT 24
+#define OMAP3430_VC_CMD_ON_MASK (0xFF << 24)
+#define OMAP3430_VC_CMD_ONLP_SHIFT 16
+#define OMAP3430_VC_CMD_ONLP_MASK (0xFF << 16)
+#define OMAP3430_VC_CMD_RET_SHIFT 8
+#define OMAP3430_VC_CMD_RET_MASK (0xFF << 8)
+#define OMAP3430_VC_CMD_OFF_SHIFT 0
+#define OMAP3430_VC_CMD_OFF_MASK (0xFF << 0)
+
/* PRM_VC_CMD_VAL_0 specific bits */
+#define OMAP3430_VC_CMD_VAL0_ON (0x3 << 4)
+#define OMAP3430_VC_CMD_VAL0_ONLP (0x3 << 3)
+#define OMAP3430_VC_CMD_VAL0_RET (0x3 << 3)
+#define OMAP3430_VC_CMD_VAL0_OFF (0x3 << 4)
/* PRM_VC_CMD_VAL_1 specific bits */
+#define OMAP3430_VC_CMD_VAL1_ON (0xB << 2)
+#define OMAP3430_VC_CMD_VAL1_ONLP (0x3 << 3)
+#define OMAP3430_VC_CMD_VAL1_RET (0x3 << 3)
+#define OMAP3430_VC_CMD_VAL1_OFF (0xB << 2)
/* PRM_VC_CH_CONF */
#define OMAP3430_CMD1 (1 << 20)
#define OMAP3430_AUTO_RET (1 << 1)
#define OMAP3430_AUTO_SLEEP (1 << 0)
+/* Constants to define setup durations */
+#define OMAP3430_CLKSETUP_DURATION 0xff
+#define OMAP3430_VOLTSETUP_TIME2 0xfff
+#define OMAP3430_VOLTSETUP_TIME1 0xfff
+#define OMAP3430_VOLTOFFSET_DURATION 0xff
+#define OMAP3430_VOLTSETUP2_DURATION 0xff
+
/* PRM_SRAM_PCHARGE */
#define OMAP3430_PCHARGE_TIME_SHIFT 0
#define OMAP3430_PCHARGE_TIME_MASK (0xff << 0)
/*
* 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
*
#include "prcm-common.h"
-#ifndef __ASSEMBLER__
-#define OMAP_PRM_REGADDR(module, reg) \
- IO_ADDRESS(OMAP2_PRM_BASE + (module) + (reg))
-#else
#define OMAP2420_PRM_REGADDR(module, reg) \
IO_ADDRESS(OMAP2420_PRM_BASE + (module) + (reg))
#define OMAP2430_PRM_REGADDR(module, reg) \
IO_ADDRESS(OMAP2430_PRM_BASE + (module) + (reg))
#define OMAP34XX_PRM_REGADDR(module, reg) \
IO_ADDRESS(OMAP3430_PRM_BASE + (module) + (reg))
-#endif
/*
* Architecture-specific global PRM registers
- * Use __raw_{read,write}l() with these registers.
+ * Use prm_{read,write}_mod_reg() 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
*
*/
-/* Global 24xx registers in GR_MOD (Same as OCP_MOD for 24xx) */
+/* Common registers for 24xx and 34xx in OCP_MOD */
+#define OMAP2_PRM_IRQSTATUS_MPU_OFFSET 0x0018
+#define OMAP2_PRM_IRQENABLE_MPU_OFFSET 0x001c
+
+/* 24xx register offsets in OCP_MOD */
+#define OMAP24XX_PRM_REVISION_OFFSET 0x0000
+#define OMAP24XX_PRM_SYSCONFIG_OFFSET 0x0010
+
+/* 34xx register offsets in OCP_MOD */
+#define OMAP3430_PRM_REVISION_OFFSET 0x0004
+#define OMAP3430_PRM_SYSCONFIG_OFFSET 0x0014
+
+/* 24xx register offsets in OMAP24XX_GR_MOD (Same as OCP_MOD for 24xx) */
#define OMAP24XX_PRCM_VOLTCTRL_OFFSET 0x0050
+#define OMAP24XX_PRCM_VOLTST_OFFSET 0x0054
+#define OMAP24XX_PRCM_CLKSRC_CTRL_OFFSET 0x0060
+#define OMAP24XX_PRCM_CLKOUT_CTRL_OFFSET 0x0070
+#define OMAP24XX_PRCM_CLKEMUL_CTRL_OFFSET 0x0078
#define OMAP24XX_PRCM_CLKCFG_CTRL_OFFSET 0x0080
-
-/* 242x GR_MOD registers, use these only for assembly code */
-#define OMAP242X_PRCM_VOLTCTRL OMAP2420_PRM_REGADDR(OMAP24XX_GR_MOD, \
- OMAP24XX_PRCM_VOLTCTRL_OFFSET)
-#define OMAP242X_PRCM_CLKCFG_CTRL OMAP2420_PRM_REGADDR(OMAP24XX_GR_MOD, \
- OMAP24XX_PRCM_CLKCFG_CTRL_OFFSET)
-
-/* 243x GR_MOD registers, use these only for assembly code */
-#define OMAP243X_PRCM_VOLTCTRL OMAP2430_PRM_REGADDR(OMAP24XX_GR_MOD, \
- OMAP24XX_PRCM_VOLTCTRL_OFFSET)
-#define OMAP243X_PRCM_CLKCFG_CTRL OMAP2430_PRM_REGADDR(OMAP24XX_GR_MOD, \
- OMAP24XX_PRCM_CLKCFG_CTRL_OFFSET)
-
-/* These will disappear */
-#define OMAP24XX_PRCM_REVISION OMAP_PRM_REGADDR(OCP_MOD, 0x0000)
-#define OMAP24XX_PRCM_SYSCONFIG OMAP_PRM_REGADDR(OCP_MOD, 0x0010)
-
-#define OMAP24XX_PRCM_IRQSTATUS_MPU OMAP_PRM_REGADDR(OCP_MOD, 0x0018)
-#define OMAP24XX_PRCM_IRQENABLE_MPU OMAP_PRM_REGADDR(OCP_MOD, 0x001c)
-
-#define OMAP24XX_PRCM_VOLTST OMAP_PRM_REGADDR(OCP_MOD, 0x0054)
-#define OMAP24XX_PRCM_CLKSRC_CTRL OMAP_PRM_REGADDR(OCP_MOD, 0x0060)
-#define OMAP24XX_PRCM_CLKOUT_CTRL OMAP_PRM_REGADDR(OCP_MOD, 0x0070)
-#define OMAP24XX_PRCM_CLKEMUL_CTRL OMAP_PRM_REGADDR(OCP_MOD, 0x0078)
-#define OMAP24XX_PRCM_CLKCFG_CTRL OMAP_PRM_REGADDR(OCP_MOD, 0x0080)
-#define OMAP24XX_PRCM_CLKCFG_STATUS OMAP_PRM_REGADDR(OCP_MOD, 0x0084)
-#define OMAP24XX_PRCM_VOLTSETUP OMAP_PRM_REGADDR(OCP_MOD, 0x0090)
-#define OMAP24XX_PRCM_CLKSSETUP OMAP_PRM_REGADDR(OCP_MOD, 0x0094)
-#define OMAP24XX_PRCM_POLCTRL OMAP_PRM_REGADDR(OCP_MOD, 0x0098)
-
-#define OMAP3430_PRM_REVISION OMAP_PRM_REGADDR(OCP_MOD, 0x0004)
-#define OMAP3430_PRM_SYSCONFIG OMAP_PRM_REGADDR(OCP_MOD, 0x0014)
-
-#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_VC_CMD_VAL_0 OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x002c)
-#define OMAP3430_PRM_VC_CMD_VAL_1 OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0030)
-#define OMAP3430_PRM_VC_CH_CONF OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0034)
-#define OMAP3430_PRM_VC_I2C_CFG OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0038)
-#define OMAP3430_PRM_VC_BYPASS_VAL OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x003c)
-#define OMAP3430_PRM_RSTCTRL OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0050)
-#define OMAP3430_PRM_RSTTIME OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0054)
-#define OMAP3430_PRM_RSTST OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0058)
-#define OMAP3430_PRM_VOLTCTRL OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0060)
-#define OMAP3430_PRM_SRAM_PCHARGE OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0064)
-#define OMAP3430_PRM_CLKSRC_CTRL OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0070)
-#define OMAP3430_PRM_VOLTSETUP1 OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0090)
-#define OMAP3430_PRM_VOLTOFFSET OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0094)
-#define OMAP3430_PRM_CLKSETUP OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0098)
-#define OMAP3430_PRM_POLCTRL OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x009c)
-#define OMAP3430_PRM_VOLTSETUP2 OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00a0)
-#define OMAP3430_PRM_VP1_CONFIG OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00b0)
-#define OMAP3430_PRM_VP1_VSTEPMIN OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00b4)
-#define OMAP3430_PRM_VP1_VSTEPMAX OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00b8)
-#define OMAP3430_PRM_VP1_VLIMITTO OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00bc)
-#define OMAP3430_PRM_VP1_VOLTAGE OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00c0)
-#define OMAP3430_PRM_VP1_STATUS OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00c4)
-#define OMAP3430_PRM_VP2_CONFIG OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00d0)
-#define OMAP3430_PRM_VP2_VSTEPMIN OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00d4)
-#define OMAP3430_PRM_VP2_VSTEPMAX OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00d8)
-#define OMAP3430_PRM_VP2_VLIMITTO OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00dc)
-#define OMAP3430_PRM_VP2_VOLTAGE OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00e0)
-#define OMAP3430_PRM_VP2_STATUS OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00e4)
-
-#define OMAP3430_PRM_CLKSEL OMAP_PRM_REGADDR(OMAP3430_CCR_MOD, 0x0040)
-#define OMAP3430_PRM_CLKOUT_CTRL OMAP_PRM_REGADDR(OMAP3430_CCR_MOD, 0x0070)
+#define OMAP24XX_PRCM_CLKCFG_STATUS_OFFSET 0x0084
+#define OMAP24XX_PRCM_VOLTSETUP_OFFSET 0x0090
+#define OMAP24XX_PRCM_CLKSSETUP_OFFSET 0x0094
+#define OMAP24XX_PRCM_POLCTRL_OFFSET 0x0098
+
+/* 34xx register offsets in GR_MOD */
+#define OMAP3_PRM_VC_SMPS_SA_OFFSET 0x0020
+#define OMAP3_PRM_VC_SMPS_VOL_RA_OFFSET 0x0024
+#define OMAP3_PRM_VC_SMPS_CMD_RA_OFFSET 0x0028
+#define OMAP3_PRM_VC_CMD_VAL_0_OFFSET 0x002c
+#define OMAP3_PRM_VC_CMD_VAL_1_OFFSET 0x0030
+#define OMAP3_PRM_VC_CH_CONF_OFFSET 0x0034
+#define OMAP3_PRM_VC_I2C_CFG_OFFSET 0x0038
+#define OMAP3_PRM_VC_BYPASS_VAL_OFFSET 0x003c
+#define OMAP3_PRM_RSTCTRL_OFFSET 0x0050
+#define OMAP3_PRM_RSTTIME_OFFSET 0x0054
+#define OMAP3_PRM_RSTST_OFFSET 0x0058
+#define OMAP3_PRM_VOLTCTRL_OFFSET 0x0060
+#define OMAP3_PRM_SRAM_PCHARGE_OFFSET 0x0064
+#define OMAP3_PRM_CLKSRC_CTRL_OFFSET 0x0070
+#define OMAP3_PRM_VOLTSETUP1_OFFSET 0x0090
+#define OMAP3_PRM_VOLTOFFSET_OFFSET 0x0094
+#define OMAP3_PRM_CLKSETUP_OFFSET 0x0098
+#define OMAP3_PRM_POLCTRL_OFFSET 0x009c
+#define OMAP3_PRM_VOLTSETUP2_OFFSET 0x00a0
+#define OMAP3_PRM_VP1_CONFIG_OFFSET 0x00b0
+#define OMAP3_PRM_VP1_VSTEPMIN_OFFSET 0x00b4
+#define OMAP3_PRM_VP1_VSTEPMAX_OFFSET 0x00b8
+#define OMAP3_PRM_VP1_VLIMITTO_OFFSET 0x00bc
+#define OMAP3_PRM_VP1_VOLTAGE_OFFSET 0x00c0
+#define OMAP3_PRM_VP1_STATUS_OFFSET 0x00c4
+#define OMAP3_PRM_VP2_CONFIG_OFFSET 0x00d0
+#define OMAP3_PRM_VP2_VSTEPMIN_OFFSET 0x00d4
+#define OMAP3_PRM_VP2_VSTEPMAX_OFFSET 0x00d8
+#define OMAP3_PRM_VP2_VLIMITTO_OFFSET 0x00dc
+#define OMAP3_PRM_VP2_VOLTAGE_OFFSET 0x00e0
+#define OMAP3_PRM_VP2_STATUS_OFFSET 0x00e4
+
+/* 34xx register offsets in CCR_MOD */
+#define OMAP3_PRM_CLKSEL_OFFSET 0x0040
+#define OMAP3_PRM_CLKOUT_CTRL_OFFSET 0x0070
/*
* Module specific PRM registers from PRM_BASE + domain offset
#define PM_PWSTCTRL 0x00e0
#define PM_PWSTST 0x00e4
+/* Omap2 specific registers */
+#define OMAP24XX_PM_WKEN2 0x00a4
+#define OMAP24XX_PM_WKST2 0x00b4
+
+#define OMAP24XX_PRCM_IRQSTATUS_DSP 0x00f0 /* IVA mod */
+#define OMAP24XX_PRCM_IRQENABLE_DSP 0x00f4 /* IVA mod */
+#define OMAP24XX_PRCM_IRQSTATUS_IVA 0x00f8
+#define OMAP24XX_PRCM_IRQENABLE_IVA 0x00fc
+
+/* Omap3 specific registers */
+#define OMAP3430ES2_PM_WKEN3 0x00f0
+#define OMAP3430ES2_PM_WKST3 0x00b8
+
#define OMAP3430_PM_MPUGRPSEL 0x00a4
#define OMAP3430_PM_MPUGRPSEL1 OMAP3430_PM_MPUGRPSEL
#define OMAP3430_PRM_IRQSTATUS_IVA2 0x00f8
#define OMAP3430_PRM_IRQENABLE_IVA2 0x00fc
-
-/* Architecture-specific registers */
-
-#define OMAP24XX_PM_WKEN2 0x00a4
-#define OMAP24XX_PM_WKST2 0x00b4
-
-#define OMAP24XX_PRCM_IRQSTATUS_DSP 0x00f0 /* IVA mod */
-#define OMAP24XX_PRCM_IRQENABLE_DSP 0x00f4 /* IVA mod */
-#define OMAP24XX_PRCM_IRQSTATUS_IVA 0x00f8
-#define OMAP24XX_PRCM_IRQENABLE_IVA 0x00fc
-
#ifndef __ASSEMBLER__
/* Power/reset management domain register get/set */
#define OMAP_RSTTIME1_SHIFT 0
#define OMAP_RSTTIME1_MASK (0xff << 0)
-
/* PRM_RSTCTRL */
/* Named RM_RSTCTRL_WKUP on the 24xx */
/* 2420 calls RST_DPLL3 'RST_DPLL' */
--- /dev/null
+/*
+ * SDRC register values for the Micron MT46H32M32LF-6
+ *
+ * Copyright (C) 2008 Texas Instruments, Inc.
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * 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 ARCH_ARM_MACH_OMAP2_SDRAM_MICRON_MT46H32M32LF
+#define ARCH_ARM_MACH_OMAP2_SDRAM_MICRON_MT46H32M32LF
+
+#include <mach/sdrc.h>
+
+/* Micron MT46H32M32LF-6 */
+/* XXX Using ARE = 0x1 (no autorefresh burst) -- can this be changed? */
+static struct omap_sdrc_params mt46h32m32lf6_sdrc_params[] = {
+ [0] = {
+ .rate = 165941176,
+ .actim_ctrla = 0x9a9db4c6,
+ .actim_ctrlb = 0x00011217,
+ .rfr_ctrl = 0x0004dc01,
+ .mr = 0x00000032,
+ },
+ [1] = {
+ .rate = 133333333,
+ .actim_ctrla = 0x7a19b485,
+ .actim_ctrlb = 0x00011213,
+ .rfr_ctrl = 0x0003de01,
+ .mr = 0x00000032,
+ },
+ [2] = {
+ .rate = 82970588,
+ .actim_ctrla = 0x51512283,
+ .actim_ctrlb = 0x0001120c,
+ .rfr_ctrl = 0x00025501,
+ .mr = 0x00000032,
+ },
+ [3] = {
+ .rate = 66666666,
+ .actim_ctrla = 0x410d2243,
+ .actim_ctrlb = 0x0001120a,
+ .rfr_ctrl = 0x0001d601,
+ .mr = 0x00000032,
+ },
+ [4] = {
+ .rate = 0
+ },
+};
+
+#endif
--- /dev/null
+/*
+ * SDRC register values for the Qimonda HYB18M512160AF-6
+ *
+ * Copyright (C) 2008 Texas Instruments, Inc.
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * 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 ARCH_ARM_MACH_OMAP2_SDRAM_QIMONDA_HYB18M512160AF6
+#define ARCH_ARM_MACH_OMAP2_SDRAM_QIMONDA_HYB18M512160AF6
+
+#include <mach/sdrc.h>
+
+/* Qimonda HYB18M512160AF-6 */
+/* XXX Using ARE = 0x1 (no autorefresh burst) -- can this be changed? */
+static struct omap_sdrc_params hyb18m512160af6_sdrc_params[] = {
+ [0] = {
+ .rate = 165941176,
+ .actim_ctrla = 0x629db4c6,
+ .actim_ctrlb = 0x00012214,
+ .rfr_ctrl = 0x0004dc01,
+ .mr = 0x00000032,
+ },
+ [1] = {
+ .rate = 133333333,
+ .actim_ctrla = 0x5219b485,
+ .actim_ctrlb = 0x00012210,
+ .rfr_ctrl = 0x0003de01,
+ .mr = 0x00000032,
+ },
+ [2] = {
+ .rate = 82970588,
+ .actim_ctrla = 0x31512283,
+ .actim_ctrlb = 0x0001220a,
+ .rfr_ctrl = 0x00025501,
+ .mr = 0x00000022,
+ },
+ [3] = {
+ .rate = 66666666,
+ .actim_ctrla = 0x290d2243,
+ .actim_ctrlb = 0x00012208,
+ .rfr_ctrl = 0x0001d601,
+ .mr = 0x00000022,
+ },
+ [4] = {
+ .rate = 0
+ },
+};
+
+#endif
--- /dev/null
+/*
+ * SMS/SDRC (SDRAM controller) common code for OMAP2/3
+ *
+ * Copyright (C) 2005, 2008 Texas Instruments Inc.
+ * Copyright (C) 2005, 2008 Nokia Corporation
+ *
+ * Tony Lindgren <tony@atomide.com>
+ * Paul Walmsley
+ * Richard Woodruff <r-woodruff2@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#undef DEBUG
+
+#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/io.h>
+
+#include <mach/common.h>
+#include <mach/clock.h>
+#include <mach/sram.h>
+
+#include "prm.h"
+
+#include <mach/sdrc.h>
+#include "sdrc.h"
+
+static struct omap_sdrc_params *sdrc_init_params;
+
+void __iomem *omap2_sdrc_base;
+void __iomem *omap2_sms_base;
+
+
+/**
+ * omap2_sdrc_get_params - return SDRC register values for a given clock rate
+ * @r: SDRC clock rate (in Hz)
+ *
+ * Return pre-calculated values for the SDRC_ACTIM_CTRLA,
+ * SDRC_ACTIM_CTRLB, SDRC_RFR_CTRL, and SDRC_MR registers, for a given
+ * SDRC clock rate 'r'. These parameters control various timing
+ * delays in the SDRAM controller that are expressed in terms of the
+ * number of SDRC clock cycles to wait; hence the clock rate
+ * dependency. Note that sdrc_init_params must be sorted rate
+ * descending. Also assumes that both chip-selects use the same
+ * timing parameters. Returns a struct omap_sdrc_params * upon
+ * success, or NULL upon failure.
+ */
+struct omap_sdrc_params *omap2_sdrc_get_params(unsigned long r)
+{
+ struct omap_sdrc_params *sp;
+
+ sp = sdrc_init_params;
+
+ while (sp->rate && sp->rate != r)
+ sp++;
+
+ if (!sp->rate)
+ return NULL;
+
+ return sp;
+}
+
+
+void __init omap2_set_globals_sdrc(struct omap_globals *omap2_globals)
+{
+ omap2_sdrc_base = omap2_globals->sdrc;
+ omap2_sms_base = omap2_globals->sms;
+}
+
+/* turn on smart idle modes for SDRAM scheduler and controller */
+void __init omap2_sdrc_init(struct omap_sdrc_params *sp)
+{
+ u32 l;
+
+ l = sms_read_reg(SMS_SYSCONFIG);
+ l &= ~(0x3 << 3);
+ l |= (0x2 << 3);
+ sms_write_reg(l, SMS_SYSCONFIG);
+
+ l = sdrc_read_reg(SDRC_SYSCONFIG);
+ l &= ~(0x3 << 3);
+ l |= (0x2 << 3);
+ sdrc_write_reg(l, SDRC_SYSCONFIG);
+
+ sdrc_init_params = sp;
+}
/*
* linux/arch/arm/mach-omap2/memory.c
*
- * Memory timing related functions for OMAP24XX
+ * Memory timing related functions for OMAP2xxx
*
- * Copyright (C) 2005 Texas Instruments Inc.
- * Richard Woodruff <r-woodruff2@ti.com>
+ * Copyright (C) 2005, 2008 Texas Instruments Inc.
+ * Copyright (C) 2005, 2008 Nokia Corporation
*
- * Copyright (C) 2005 Nokia Corporation
* Tony Lindgren <tony@atomide.com>
+ * Paul Walmsley
+ * Richard Woodruff <r-woodruff2@ti.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
#include <mach/clock.h>
#include <mach/sram.h>
+#include "clock.h"
+
#include "prm.h"
-#include "memory.h"
+#include <mach/sdrc.h>
#include "sdrc.h"
-void __iomem *omap2_sdrc_base;
-void __iomem *omap2_sms_base;
+/* Memory timing, DLL mode flags */
+#define M_DDR 1
+#define M_LOCK_CTRL (1 << 2)
+#define M_UNLOCK 0
+#define M_LOCK 1
+
static struct memory_timings mem_timings;
static u32 curr_perf_level = CORE_CLK_SRC_DPLL_X2;
-u32 omap2_memory_get_slow_dll_ctrl(void)
+static u32 omap2xxx_sdrc_get_slow_dll_ctrl(void)
{
return mem_timings.slow_dll_ctrl;
}
-u32 omap2_memory_get_fast_dll_ctrl(void)
+static u32 omap2xxx_sdrc_get_fast_dll_ctrl(void)
{
return mem_timings.fast_dll_ctrl;
}
-u32 omap2_memory_get_type(void)
+static u32 omap2xxx_sdrc_get_type(void)
{
return mem_timings.m_type;
}
* Check the DLL lock state, and return tue if running in unlock mode.
* This is needed to compensate for the shifted DLL value in unlock mode.
*/
-u32 omap2_dll_force_needed(void)
+u32 omap2xxx_sdrc_dll_is_unlocked(void)
{
/* dlla and dllb are a set */
u32 dll_state = sdrc_read_reg(SDRC_DLLA_CTRL);
* 'level' is the value to store to CM_CLKSEL2_PLL.CORE_CLK_SRC.
* Practical values are CORE_CLK_SRC_DPLL (for CORE_CLK = DPLL_CLK) or
* CORE_CLK_SRC_DPLL_X2 (for CORE_CLK = * DPLL_CLK * 2)
+ *
+ * Used by the clock framework during CORE DPLL changes
*/
-u32 omap2_reprogram_sdrc(u32 level, u32 force)
+u32 omap2xxx_sdrc_reprogram(u32 level, u32 force)
{
u32 dll_ctrl, m_type;
u32 prev = curr_perf_level;
if ((curr_perf_level == level) && !force)
return prev;
- if (level == CORE_CLK_SRC_DPLL) {
- dll_ctrl = omap2_memory_get_slow_dll_ctrl();
- } else if (level == CORE_CLK_SRC_DPLL_X2) {
- dll_ctrl = omap2_memory_get_fast_dll_ctrl();
- } else {
+ if (level == CORE_CLK_SRC_DPLL)
+ dll_ctrl = omap2xxx_sdrc_get_slow_dll_ctrl();
+ else if (level == CORE_CLK_SRC_DPLL_X2)
+ dll_ctrl = omap2xxx_sdrc_get_fast_dll_ctrl();
+ else
return prev;
- }
- m_type = omap2_memory_get_type();
+ m_type = omap2xxx_sdrc_get_type();
local_irq_save(flags);
- __raw_writel(0xffff, OMAP24XX_PRCM_VOLTSETUP);
+ prm_write_mod_reg(0xffff, OMAP24XX_GR_MOD,
+ OMAP24XX_PRCM_VOLTSETUP_OFFSET);
omap2_sram_reprogram_sdrc(level, dll_ctrl, m_type);
curr_perf_level = level;
local_irq_restore(flags);
return prev;
}
-#if !defined(CONFIG_ARCH_OMAP2)
-void omap2_sram_ddr_init(u32 *slow_dll_ctrl, u32 fast_dll_ctrl,
- u32 base_cs, u32 force_unlock)
-{
-}
-void omap2_sram_reprogram_sdrc(u32 perf_level, u32 dll_val,
- u32 mem_type)
-{
-}
-#endif
-
-void omap2_init_memory_params(u32 force_lock_to_unlock_mode)
+/* Used by the clock framework during CORE DPLL changes */
+void omap2xxx_sdrc_init_params(u32 force_lock_to_unlock_mode)
{
unsigned long dll_cnt;
u32 fast_dll = 0;
- mem_timings.m_type = !((sdrc_read_reg(SDRC_MR_0) & 0x3) == 0x1); /* DDR = 1, SDR = 0 */
+ /* DDR = 1, SDR = 0 */
+ mem_timings.m_type = !((sdrc_read_reg(SDRC_MR_0) & 0x3) == 0x1);
/* 2422 es2.05 and beyond has a single SIP DDR instead of 2 like others.
* In the case of 2422, its ok to use CS1 instead of CS0.
/* 90 degree phase for anything below 133Mhz + disable DLL filter */
mem_timings.slow_dll_ctrl |= ((1 << 1) | (3 << 8));
}
-
-void __init omap2_set_globals_memory(struct omap_globals *omap2_globals)
-{
- omap2_sdrc_base = omap2_globals->sdrc;
- omap2_sms_base = omap2_globals->sms;
-}
-
-/* turn on smart idle modes for SDRAM scheduler and controller */
-void __init omap2_init_memory(void)
-{
- u32 l;
-
- if (!cpu_is_omap2420())
- return;
-
- l = sms_read_reg(SMS_SYSCONFIG);
- l &= ~(0x3 << 3);
- l |= (0x2 << 3);
- sms_write_reg(l, SMS_SYSCONFIG);
-
- l = sdrc_read_reg(SDRC_SYSCONFIG);
- l &= ~(0x3 << 3);
- l |= (0x2 << 3);
- sdrc_write_reg(l, SDRC_SYSCONFIG);
-}
* Copyright (C) 2005-2008 Nokia Corporation
* Author: Paul Mundt <paul.mundt@nokia.com>
*
+ * Major rework for PM support by Kevin Hilman
+ *
* Based off of arch/arm/mach-omap/omap1/serial.c
*
* This file is subject to the terms and conditions of the GNU General Public
#include <mach/common.h>
#include <mach/board.h>
+#include <mach/clock.h>
+#include <mach/control.h>
+
+#include "prm.h"
+#include "pm.h"
+#include "prm-regbits-34xx.h"
+
+#define DEFAULT_TIMEOUT (5 * HZ)
+
+struct omap_uart_state {
+ int num;
+ int can_sleep;
+ struct timer_list timer;
+ u32 timeout;
+
+ void __iomem *wk_st;
+ void __iomem *wk_en;
+ u32 wk_mask;
+ u32 padconf;
-static struct clk *uart_ick[OMAP_MAX_NR_PORTS];
-static struct clk *uart_fck[OMAP_MAX_NR_PORTS];
+ struct clk *ick;
+ struct clk *fck;
+ int clocked;
+
+ struct plat_serial8250_port *p;
+ struct list_head node;
+
+#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM)
+ int context_valid;
+
+ /* Registers to be saved/restored for OFF-mode */
+ u16 dll;
+ u16 dlh;
+ u16 ier;
+ u16 sysc;
+ u16 scr;
+ u16 wer;
+#endif
+};
+
+static struct omap_uart_state omap_uart[OMAP_MAX_NR_PORTS];
+static LIST_HEAD(uart_list);
static struct plat_serial8250_port serial_platform_data[] = {
{
* properly. Note that the TX watermark initialization may not be needed
* once the 8250.c watermark handling code is merged.
*/
-static inline void __init omap_serial_reset(struct plat_serial8250_port *p)
+static inline void __init omap_uart_reset(struct omap_uart_state *uart)
{
+ struct plat_serial8250_port *p = uart->p;
+
serial_write_reg(p, UART_OMAP_MDR1, 0x07);
serial_write_reg(p, UART_OMAP_SCR, 0x08);
serial_write_reg(p, UART_OMAP_MDR1, 0x00);
serial_write_reg(p, UART_OMAP_SYSC, (0x02 << 3) | (1 << 2) | (1 << 0));
}
-void omap_serial_enable_clocks(int enable)
+static inline void omap_uart_enable_clocks(struct omap_uart_state *uart)
{
- int i;
- for (i = 0; i < OMAP_MAX_NR_PORTS; i++) {
- if (uart_ick[i] && uart_fck[i]) {
- if (enable) {
- clk_enable(uart_ick[i]);
- clk_enable(uart_fck[i]);
- } else {
- clk_disable(uart_ick[i]);
- clk_disable(uart_fck[i]);
+ if (uart->clocked)
+ return;
+
+ clk_enable(uart->ick);
+ clk_enable(uart->fck);
+ uart->clocked = 1;
+}
+
+#ifdef CONFIG_PM
+#ifdef CONFIG_ARCH_OMAP3
+
+static int enable_off_mode; /* to be removed by full off-mode patches */
+
+static void omap_uart_save_context(struct omap_uart_state *uart)
+{
+ u16 lcr = 0;
+ struct plat_serial8250_port *p = uart->p;
+
+ if (!enable_off_mode)
+ return;
+
+ lcr = serial_read_reg(p, UART_LCR);
+ serial_write_reg(p, UART_LCR, 0xBF);
+ uart->dll = serial_read_reg(p, UART_DLL);
+ uart->dlh = serial_read_reg(p, UART_DLM);
+ serial_write_reg(p, UART_LCR, lcr);
+ uart->ier = serial_read_reg(p, UART_IER);
+ uart->sysc = serial_read_reg(p, UART_OMAP_SYSC);
+ uart->scr = serial_read_reg(p, UART_OMAP_SCR);
+ uart->wer = serial_read_reg(p, UART_OMAP_WER);
+
+ uart->context_valid = 1;
+}
+
+static void omap_uart_restore_context(struct omap_uart_state *uart)
+{
+ u16 efr = 0;
+ struct plat_serial8250_port *p = uart->p;
+
+ if (!enable_off_mode)
+ return;
+
+ if (!uart->context_valid)
+ return;
+
+ uart->context_valid = 0;
+
+ serial_write_reg(p, UART_OMAP_MDR1, 0x7);
+ serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */
+ efr = serial_read_reg(p, UART_EFR);
+ serial_write_reg(p, UART_EFR, UART_EFR_ECB);
+ serial_write_reg(p, UART_LCR, 0x0); /* Operational mode */
+ serial_write_reg(p, UART_IER, 0x0);
+ serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */
+ serial_write_reg(p, UART_DLL, uart->dll);
+ serial_write_reg(p, UART_DLM, uart->dlh);
+ serial_write_reg(p, UART_LCR, 0x0); /* Operational mode */
+ serial_write_reg(p, UART_IER, uart->ier);
+ serial_write_reg(p, UART_FCR, 0xA1);
+ serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */
+ serial_write_reg(p, UART_EFR, efr);
+ serial_write_reg(p, UART_LCR, UART_LCR_WLEN8);
+ serial_write_reg(p, UART_OMAP_SCR, uart->scr);
+ serial_write_reg(p, UART_OMAP_WER, uart->wer);
+ serial_write_reg(p, UART_OMAP_SYSC, uart->sysc);
+ serial_write_reg(p, UART_OMAP_MDR1, 0x00); /* UART 16x mode */
+}
+#else
+static inline void omap_uart_save_context(struct omap_uart_state *uart) {}
+static inline void omap_uart_restore_context(struct omap_uart_state *uart) {}
+#endif /* CONFIG_ARCH_OMAP3 */
+
+static void omap_uart_smart_idle_enable(struct omap_uart_state *uart,
+ int enable)
+{
+ struct plat_serial8250_port *p = uart->p;
+ u16 sysc;
+
+ sysc = serial_read_reg(p, UART_OMAP_SYSC) & 0x7;
+ if (enable)
+ sysc |= 0x2 << 3;
+ else
+ sysc |= 0x1 << 3;
+
+ serial_write_reg(p, UART_OMAP_SYSC, sysc);
+}
+
+static inline void omap_uart_restore(struct omap_uart_state *uart)
+{
+ omap_uart_enable_clocks(uart);
+ omap_uart_restore_context(uart);
+}
+
+static inline void omap_uart_disable_clocks(struct omap_uart_state *uart)
+{
+ if (!uart->clocked)
+ return;
+
+ omap_uart_save_context(uart);
+ uart->clocked = 0;
+ clk_disable(uart->ick);
+ clk_disable(uart->fck);
+}
+
+static void omap_uart_block_sleep(struct omap_uart_state *uart)
+{
+ omap_uart_restore(uart);
+
+ omap_uart_smart_idle_enable(uart, 0);
+ uart->can_sleep = 0;
+ mod_timer(&uart->timer, jiffies + uart->timeout);
+}
+
+static void omap_uart_allow_sleep(struct omap_uart_state *uart)
+{
+ if (!uart->clocked)
+ return;
+
+ omap_uart_smart_idle_enable(uart, 1);
+ uart->can_sleep = 1;
+ del_timer(&uart->timer);
+}
+
+static void omap_uart_idle_timer(unsigned long data)
+{
+ struct omap_uart_state *uart = (struct omap_uart_state *)data;
+
+ omap_uart_allow_sleep(uart);
+}
+
+void omap_uart_prepare_idle(int num)
+{
+ struct omap_uart_state *uart;
+
+ list_for_each_entry(uart, &uart_list, node) {
+ if (!clocks_off_while_idle)
+ continue;
+
+ if (num == uart->num && uart->can_sleep) {
+ omap_uart_disable_clocks(uart);
+ return;
+ }
+ }
+}
+
+void omap_uart_resume_idle(int num)
+{
+ struct omap_uart_state *uart;
+
+ list_for_each_entry(uart, &uart_list, node) {
+ if (num == uart->num) {
+ omap_uart_restore(uart);
+
+ /* Check for IO pad wakeup */
+ if (cpu_is_omap34xx() && uart->padconf) {
+ u16 p = omap_ctrl_readw(uart->padconf);
+
+ if (p & OMAP3_PADCONF_WAKEUPEVENT0)
+ omap_uart_block_sleep(uart);
}
+
+ /* Check for normal UART wakeup */
+ if (__raw_readl(uart->wk_st) & uart->wk_mask)
+ omap_uart_block_sleep(uart);
+
+ return;
+ }
+ }
+}
+
+void omap_uart_prepare_suspend(void)
+{
+ struct omap_uart_state *uart;
+
+ list_for_each_entry(uart, &uart_list, node) {
+ omap_uart_allow_sleep(uart);
+ }
+}
+
+int omap_uart_can_sleep(void)
+{
+ struct omap_uart_state *uart;
+ int can_sleep = 1;
+
+ list_for_each_entry(uart, &uart_list, node) {
+ if (!uart->clocked)
+ continue;
+
+ if (!uart->can_sleep) {
+ can_sleep = 0;
+ continue;
+ }
+
+ /* This UART can now safely sleep. */
+ omap_uart_allow_sleep(uart);
+ }
+
+ return can_sleep;
+}
+
+/**
+ * omap_uart_interrupt()
+ *
+ * This handler is used only to detect that *any* UART interrupt has
+ * occurred. It does _nothing_ to handle the interrupt. Rather,
+ * any UART interrupt will trigger the inactivity timer so the
+ * UART will not idle or sleep for its timeout period.
+ *
+ **/
+static irqreturn_t omap_uart_interrupt(int irq, void *dev_id)
+{
+ struct omap_uart_state *uart = dev_id;
+
+ omap_uart_block_sleep(uart);
+
+ return IRQ_NONE;
+}
+
+static u32 sleep_timeout = DEFAULT_TIMEOUT;
+
+static void omap_uart_idle_init(struct omap_uart_state *uart)
+{
+ u32 v;
+ struct plat_serial8250_port *p = uart->p;
+ int ret;
+
+ uart->can_sleep = 0;
+ uart->timeout = sleep_timeout;
+ setup_timer(&uart->timer, omap_uart_idle_timer,
+ (unsigned long) uart);
+ mod_timer(&uart->timer, jiffies + uart->timeout);
+ omap_uart_smart_idle_enable(uart, 0);
+
+ if (cpu_is_omap34xx()) {
+ u32 mod = (uart->num == 2) ? OMAP3430_PER_MOD : CORE_MOD;
+ u32 wk_mask = 0;
+ u32 padconf = 0;
+
+ uart->wk_en = OMAP34XX_PRM_REGADDR(mod, PM_WKEN1);
+ uart->wk_st = OMAP34XX_PRM_REGADDR(mod, PM_WKST1);
+ switch (uart->num) {
+ case 0:
+ wk_mask = OMAP3430_ST_UART1_MASK;
+ padconf = 0x182;
+ break;
+ case 1:
+ wk_mask = OMAP3430_ST_UART2_MASK;
+ padconf = 0x17a;
+ break;
+ case 2:
+ wk_mask = OMAP3430_ST_UART3_MASK;
+ padconf = 0x19e;
+ break;
+ }
+ uart->wk_mask = wk_mask;
+ uart->padconf = padconf;
+ } else if (cpu_is_omap24xx()) {
+ u32 wk_mask = 0;
+
+ if (cpu_is_omap2430()) {
+ uart->wk_en = OMAP2430_PRM_REGADDR(CORE_MOD, PM_WKEN1);
+ uart->wk_st = OMAP2430_PRM_REGADDR(CORE_MOD, PM_WKST1);
+ } else if (cpu_is_omap2420()) {
+ uart->wk_en = OMAP2420_PRM_REGADDR(CORE_MOD, PM_WKEN1);
+ uart->wk_st = OMAP2420_PRM_REGADDR(CORE_MOD, PM_WKST1);
}
+ switch (uart->num) {
+ case 0:
+ wk_mask = OMAP24XX_ST_UART1_MASK;
+ break;
+ case 1:
+ wk_mask = OMAP24XX_ST_UART2_MASK;
+ break;
+ case 2:
+ wk_mask = OMAP24XX_ST_UART3_MASK;
+ break;
+ }
+ uart->wk_mask = wk_mask;
+ } else {
+ uart->wk_en = 0;
+ uart->wk_st = 0;
+ uart->wk_mask = 0;
+ uart->padconf = 0;
+ }
+
+ /* Set wake-enable bit */
+ if (uart->wk_en && uart->wk_mask) {
+ v = __raw_readl(uart->wk_en);
+ v |= uart->wk_mask;
+ __raw_writel(v, uart->wk_en);
+ }
+
+ /* Ensure IOPAD wake-enables are set */
+ if (cpu_is_omap34xx() && uart->padconf) {
+ u16 v;
+
+ v = omap_ctrl_readw(uart->padconf);
+ v |= OMAP3_PADCONF_WAKEUPENABLE0;
+ omap_ctrl_writew(v, uart->padconf);
}
+
+ p->flags |= UPF_SHARE_IRQ;
+ ret = request_irq(p->irq, omap_uart_interrupt, IRQF_SHARED,
+ "serial idle", (void *)uart);
+ WARN_ON(ret);
}
+static ssize_t sleep_timeout_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%u\n", sleep_timeout / HZ);
+}
+
+static ssize_t sleep_timeout_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t n)
+{
+ struct omap_uart_state *uart;
+ unsigned int value;
+
+ if (sscanf(buf, "%u", &value) != 1) {
+ printk(KERN_ERR "sleep_timeout_store: Invalid value\n");
+ return -EINVAL;
+ }
+ sleep_timeout = value * HZ;
+ list_for_each_entry(uart, &uart_list, node)
+ uart->timeout = sleep_timeout;
+ return n;
+}
+
+static struct kobj_attribute sleep_timeout_attr =
+ __ATTR(sleep_timeout, 0644, sleep_timeout_show, sleep_timeout_store);
+
+#else
+static inline void omap_uart_idle_init(struct omap_uart_state *uart) {}
+#endif /* CONFIG_PM */
+
void __init omap_serial_init(void)
{
int i;
for (i = 0; i < OMAP_MAX_NR_PORTS; i++) {
struct plat_serial8250_port *p = serial_platform_data + i;
+ struct omap_uart_state *uart = &omap_uart[i];
if (!(info->enabled_uarts & (1 << i))) {
p->membase = NULL;
}
sprintf(name, "uart%d_ick", i+1);
- uart_ick[i] = clk_get(NULL, name);
- if (IS_ERR(uart_ick[i])) {
+ uart->ick = clk_get(NULL, name);
+ if (IS_ERR(uart->ick)) {
printk(KERN_ERR "Could not get uart%d_ick\n", i+1);
- uart_ick[i] = NULL;
- } else
- clk_enable(uart_ick[i]);
+ uart->ick = NULL;
+ }
sprintf(name, "uart%d_fck", i+1);
- uart_fck[i] = clk_get(NULL, name);
- if (IS_ERR(uart_fck[i])) {
+ uart->fck = clk_get(NULL, name);
+ if (IS_ERR(uart->fck)) {
printk(KERN_ERR "Could not get uart%d_fck\n", i+1);
- uart_fck[i] = NULL;
- } else
- clk_enable(uart_fck[i]);
+ uart->fck = NULL;
+ }
+
+ if (!uart->ick || !uart->fck)
+ continue;
+
+ uart->num = i;
+ p->private_data = uart;
+ uart->p = p;
+ list_add(&uart->node, &uart_list);
- omap_serial_reset(p);
+ omap_uart_enable_clocks(uart);
+ omap_uart_reset(uart);
+ omap_uart_idle_init(uart);
}
}
static int __init omap_init(void)
{
- return platform_device_register(&serial_device);
+ int ret;
+
+ ret = platform_device_register(&serial_device);
+
+#ifdef CONFIG_PM
+ if (!ret)
+ ret = sysfs_create_file(&serial_device.dev.kobj,
+ &sleep_timeout_attr.attr);
+#endif
+ return ret;
}
arch_initcall(omap_init);
orr r4, r4, #0x40 @ enable self refresh on idle req
mov r5, #0x2000 @ set delay (DPLL relock + DLL relock)
str r4, [r2] @ make it so
- mov r2, #0
nop
- mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt
+ mcr p15, 0, r3, c7, c0, 4 @ wait for interrupt
nop
loop:
subs r5, r5, #0x1 @ awake, wait just a bit
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap2/sleep.S
+ *
+ * (C) Copyright 2007
+ * Texas Instruments
+ * Karthik Dasu <karthik-dp@ti.com>
+ *
+ * (C) Copyright 2004
+ * Texas Instruments, <www.ti.com>
+ * Richard Woodruff <r-woodruff2@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <mach/io.h>
+#include <mach/pm.h>
+#include <mach/control.h>
+
+#include "prm.h"
+#include "sdrc.h"
+
+#define PM_PREPWSTST_CORE_V OMAP34XX_PRM_REGADDR(CORE_MOD, \
+ OMAP3430_PM_PREPWSTST)
+#define PM_PREPWSTST_MPU_V OMAP34XX_PRM_REGADDR(MPU_MOD, \
+ OMAP3430_PM_PREPWSTST)
+#define PM_PWSTCTRL_MPU_P OMAP34XX_PRM_REGADDR(MPU_MOD, PM_PWSTCTRL)
+#define SCRATCHPAD_MEM_OFFS 0x310 /* Move this as correct place is
+ * available */
+#define SCRATCHPAD_BASE_P OMAP343X_CTRL_REGADDR(\
+ OMAP343X_CONTROL_MEM_WKUP +\
+ SCRATCHPAD_MEM_OFFS)
+#define SDRC_POWER_V OMAP34XX_SDRC_REGADDR(SDRC_POWER)
+
+ .text
+/* Function call to get the restore pointer for resume from OFF */
+ENTRY(get_restore_pointer)
+ stmfd sp!, {lr} @ save registers on stack
+ adr r0, restore
+ ldmfd sp!, {pc} @ restore regs and return
+ENTRY(get_restore_pointer_sz)
+ .word . - get_restore_pointer_sz
+/*
+ * Forces OMAP into idle state
+ *
+ * omap34xx_suspend() - This bit of code just executes the WFI
+ * for normal idles.
+ *
+ * Note: This code get's copied to internal SRAM at boot. When the OMAP
+ * wakes up it continues execution at the point it went to sleep.
+ */
+ENTRY(omap34xx_cpu_suspend)
+ stmfd sp!, {r0-r12, lr} @ save registers on stack
+loop:
+ /*b loop*/ @Enable to debug by stepping through code
+ /* r0 contains restore pointer in sdram */
+ /* r1 contains information about saving context */
+ ldr r4, sdrc_power @ read the SDRC_POWER register
+ ldr r5, [r4] @ read the contents of SDRC_POWER
+ orr r5, r5, #0x40 @ enable self refresh on idle req
+ str r5, [r4] @ write back to SDRC_POWER register
+
+ cmp r1, #0x0
+ /* If context save is required, do that and execute wfi */
+ bne save_context_wfi
+ /* Data memory barrier and Data sync barrier */
+ mov r1, #0
+ mcr p15, 0, r1, c7, c10, 4
+ mcr p15, 0, r1, c7, c10, 5
+
+ wfi @ wait for interrupt
+
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ bl i_dll_wait
+
+ ldmfd sp!, {r0-r12, pc} @ restore regs and return
+restore:
+ /* b restore*/ @ Enable to debug restore code
+ /* Check what was the reason for mpu reset and store the reason in r9*/
+ /* 1 - Only L1 and logic lost */
+ /* 2 - Only L2 lost - In this case, we wont be here */
+ /* 3 - Both L1 and L2 lost */
+ ldr r1, pm_pwstctrl_mpu
+ ldr r2, [r1]
+ and r2, r2, #0x3
+ cmp r2, #0x0 @ Check if target power state was OFF or RET
+ moveq r9, #0x3 @ MPU OFF => L1 and L2 lost
+ movne r9, #0x1 @ Only L1 and L2 lost => avoid L2 invalidation
+ bne logic_l1_restore
+ /* Execute smi to invalidate L2 cache */
+ mov r12, #0x1 @ set up to invalide L2
+smi: .word 0xE1600070 @ Call SMI monitor (smieq)
+logic_l1_restore:
+ mov r1, #0
+ /* Invalidate all instruction caches to PoU
+ * and flush branch target cache */
+ mcr p15, 0, r1, c7, c5, 0
+
+ ldr r4, scratchpad_base
+ ldr r3, [r4,#0xBC]
+ ldmia r3!, {r4-r6}
+ mov sp, r4
+ msr spsr_cxsf, r5
+ mov lr, r6
+
+ ldmia r3!, {r4-r9}
+ /* Coprocessor access Control Register */
+ mcr p15, 0, r4, c1, c0, 2
+
+ /* TTBR0 */
+ MCR p15, 0, r5, c2, c0, 0
+ /* TTBR1 */
+ MCR p15, 0, r6, c2, c0, 1
+ /* Translation table base control register */
+ MCR p15, 0, r7, c2, c0, 2
+ /*domain access Control Register */
+ MCR p15, 0, r8, c3, c0, 0
+ /* data fault status Register */
+ MCR p15, 0, r9, c5, c0, 0
+
+ ldmia r3!,{r4-r8}
+ /* instruction fault status Register */
+ MCR p15, 0, r4, c5, c0, 1
+ /*Data Auxiliary Fault Status Register */
+ MCR p15, 0, r5, c5, c1, 0
+ /*Instruction Auxiliary Fault Status Register*/
+ MCR p15, 0, r6, c5, c1, 1
+ /*Data Fault Address Register */
+ MCR p15, 0, r7, c6, c0, 0
+ /*Instruction Fault Address Register*/
+ MCR p15, 0, r8, c6, c0, 2
+ ldmia r3!,{r4-r7}
+
+ /* user r/w thread and process ID */
+ MCR p15, 0, r4, c13, c0, 2
+ /* user ro thread and process ID */
+ MCR p15, 0, r5, c13, c0, 3
+ /*Privileged only thread and process ID */
+ MCR p15, 0, r6, c13, c0, 4
+ /* cache size selection */
+ MCR p15, 2, r7, c0, c0, 0
+ ldmia r3!,{r4-r8}
+ /* Data TLB lockdown registers */
+ MCR p15, 0, r4, c10, c0, 0
+ /* Instruction TLB lockdown registers */
+ MCR p15, 0, r5, c10, c0, 1
+ /* Secure or Nonsecure Vector Base Address */
+ MCR p15, 0, r6, c12, c0, 0
+ /* FCSE PID */
+ MCR p15, 0, r7, c13, c0, 0
+ /* Context PID */
+ MCR p15, 0, r8, c13, c0, 1
+
+ ldmia r3!,{r4-r5}
+ /* primary memory remap register */
+ MCR p15, 0, r4, c10, c2, 0
+ /*normal memory remap register */
+ MCR p15, 0, r5, c10, c2, 1
+
+ /* Restore registers for other modes from SDRAM */
+ /* Save current mode */
+ mrs r7, cpsr
+
+ /* FIQ mode */
+ bic r0, r7, #0x1F
+ orr r0, r0, #0x11
+ msr cpsr, r0
+ ldmia r3!, {r8-r12}
+ /* load the SP and LR from SDRAM */
+ ldmia r3!,{r4-r6}
+ mov sp, r4 /*update the SP */
+ mov lr, r5 /*update the LR */
+ msr spsr, r6 /*update the SPSR*/
+
+ /* IRQ mode */
+ bic r0, r7, #0x1F
+ orr r0, r0, #0x12
+ msr cpsr, r0 /*go into IRQ mode*/
+ ldmia r3!,{r4-r6} /*load the SP and LR from SDRAM*/
+ mov sp, r4 /*update the SP */
+ mov lr, r5 /*update the LR */
+ msr spsr, r6 /*update the SPSR */
+
+ /* ABORT mode */
+ bic r0, r7, #0x1F
+ orr r0, r0, #0x17
+ msr cpsr, r0 /* go into ABORT mode */
+ ldmia r3!,{r4-r6} /*load the SP and LR from SDRAM */
+ mov sp, r4 /*update the SP */
+ mov lr, r5 /*update the LR */
+ msr spsr, r6 /*update the SPSR */
+
+ /* UNDEEF mode */
+ bic r0, r7, #0x1F
+ orr r0, r0, #0x1B
+ msr cpsr, r0 /*go into UNDEF mode */
+ ldmia r3!,{r4-r6} /*load the SP and LR from SDRAM */
+ mov sp, r4 /*update the SP*/
+ mov lr, r5 /*update the LR*/
+ msr spsr, r6 /*update the SPSR*/
+
+ /* SYSTEM (USER) mode */
+ bic r0, r7, #0x1F
+ orr r0, r0, #0x1F
+ msr cpsr, r0 /*go into USR mode */
+ ldmia r3!,{r4-r6} /*load the SP and LR from SDRAM*/
+ mov sp, r4 /*update the SP */
+ mov lr, r5 /*update the LR */
+ msr spsr, r6 /*update the SPSR */
+ msr cpsr, r7 /*back to original mode*/
+
+ /* Restore cpsr */
+ ldmia r3!,{r4} /*load CPSR from SDRAM*/
+ msr cpsr, r4 /*store cpsr */
+
+ /* Enabling MMU here */
+ mrc p15, 0, r7, c2, c0, 2 /* Read TTBRControl */
+ /* Extract N (0:2) bits and decide whether to use TTBR0 or TTBR1*/
+ and r7, #0x7
+ cmp r7, #0x0
+ beq usettbr0
+ttbr_error:
+ /* More work needs to be done to support N[0:2] value other than 0
+ * So looping here so that the error can be detected
+ */
+ b ttbr_error
+usettbr0:
+ mrc p15, 0, r2, c2, c0, 0
+ ldr r5, ttbrbit_mask
+ and r2, r5
+ mov r4, pc
+ ldr r5, table_index_mask
+ and r4, r5 /* r4 = 31 to 20 bits of pc */
+ /* Extract the value to be written to table entry */
+ ldr r1, table_entry
+ add r1, r1, r4 /* r1 has value to be written to table entry*/
+ /* Getting the address of table entry to modify */
+ lsr r4, #18
+ add r2, r4 /* r2 has the location which needs to be modified */
+ /* Storing previous entry of location being modified */
+ ldr r5, scratchpad_base
+ ldr r4, [r2]
+ str r4, [r5, #0xC0]
+ /* Modify the table entry */
+ str r1, [r2]
+ /* Storing address of entry being modified
+ * - will be restored after enabling MMU */
+ ldr r5, scratchpad_base
+ str r2, [r5, #0xC4]
+
+ mov r0, #0
+ mcr p15, 0, r0, c7, c5, 4 @ Flush prefetch buffer
+ mcr p15, 0, r0, c7, c5, 6 @ Invalidate branch predictor array
+ mcr p15, 0, r0, c8, c5, 0 @ Invalidate instruction TLB
+ mcr p15, 0, r0, c8, c6, 0 @ Invalidate data TLB
+ /* Restore control register but dont enable caches here*/
+ /* Caches will be enabled after restoring MMU table entry */
+ ldmia r3!, {r4}
+ /* Store previous value of control register in scratchpad */
+ str r4, [r5, #0xC8]
+ ldr r2, cache_pred_disable_mask
+ and r4, r2
+ mcr p15, 0, r4, c1, c0, 0
+
+ ldmfd sp!, {r0-r12, pc} @ restore regs and return
+save_context_wfi:
+ /*b save_context_wfi*/ @ enable to debug save code
+ mov r8, r0 /* Store SDRAM address in r8 */
+ /* Check what that target sleep state is:stored in r1*/
+ /* 1 - Only L1 and logic lost */
+ /* 2 - Only L2 lost */
+ /* 3 - Both L1 and L2 lost */
+ cmp r1, #0x2 /* Only L2 lost */
+ beq clean_l2
+ cmp r1, #0x1 /* L2 retained */
+ /* r9 stores whether to clean L2 or not*/
+ moveq r9, #0x0 /* Dont Clean L2 */
+ movne r9, #0x1 /* Clean L2 */
+l1_logic_lost:
+ /* Store sp and spsr to SDRAM */
+ mov r4, sp
+ mrs r5, spsr
+ mov r6, lr
+ stmia r8!, {r4-r6}
+ /* Save all ARM registers */
+ /* Coprocessor access control register */
+ mrc p15, 0, r6, c1, c0, 2
+ stmia r8!, {r6}
+ /* TTBR0, TTBR1 and Translation table base control */
+ mrc p15, 0, r4, c2, c0, 0
+ mrc p15, 0, r5, c2, c0, 1
+ mrc p15, 0, r6, c2, c0, 2
+ stmia r8!, {r4-r6}
+ /* Domain access control register, data fault status register,
+ and instruction fault status register */
+ mrc p15, 0, r4, c3, c0, 0
+ mrc p15, 0, r5, c5, c0, 0
+ mrc p15, 0, r6, c5, c0, 1
+ stmia r8!, {r4-r6}
+ /* Data aux fault status register, instruction aux fault status,
+ datat fault address register and instruction fault address register*/
+ mrc p15, 0, r4, c5, c1, 0
+ mrc p15, 0, r5, c5, c1, 1
+ mrc p15, 0, r6, c6, c0, 0
+ mrc p15, 0, r7, c6, c0, 2
+ stmia r8!, {r4-r7}
+ /* user r/w thread and process ID, user r/o thread and process ID,
+ priv only thread and process ID, cache size selection */
+ mrc p15, 0, r4, c13, c0, 2
+ mrc p15, 0, r5, c13, c0, 3
+ mrc p15, 0, r6, c13, c0, 4
+ mrc p15, 2, r7, c0, c0, 0
+ stmia r8!, {r4-r7}
+ /* Data TLB lockdown, instruction TLB lockdown registers */
+ mrc p15, 0, r5, c10, c0, 0
+ mrc p15, 0, r6, c10, c0, 1
+ stmia r8!, {r5-r6}
+ /* Secure or non secure vector base address, FCSE PID, Context PID*/
+ mrc p15, 0, r4, c12, c0, 0
+ mrc p15, 0, r5, c13, c0, 0
+ mrc p15, 0, r6, c13, c0, 1
+ stmia r8!, {r4-r6}
+ /* Primary remap, normal remap registers */
+ mrc p15, 0, r4, c10, c2, 0
+ mrc p15, 0, r5, c10, c2, 1
+ stmia r8!,{r4-r5}
+ /* Store SP, LR, SPSR registers for SUP, FIQ, IRQ, ABORT and USER
+ modes into SDRAM */
+
+ /* move SDRAM address to r7 as r8 is banked in FIQ*/
+ mov r7, r8
+
+ /* Save current mode */
+ mrs r2, cpsr
+ /* FIQ mode */
+ bic r0, r2, #0x1F
+ orr r0, r0, #0x11
+ msr cpsr, r0 /* go to FIQ mode */
+ stmia r7!, {r8-r12}
+ mov r4, r13 /* move SP into r4*/
+ mov r5, r14
+ mrs r6, spsr
+ stmia r7!, {r4-r6}
+
+ /* IRQ mode */
+ bic r0, r2, #0x1F
+ orr r0, r0, #0x12
+ msr cpsr, r0
+ mov r4, r13
+ mov r5, r14
+ mrs r6, spsr
+ stmia r7!, {r4-r6}
+
+ /* Abort mode */
+ bic r0, r2, #0x1F
+ orr r0, r0, #0x17
+ msr cpsr, r0
+ mov r4, r13
+ mov r5, r14
+ mrs r6, spsr
+ stmia r7!, {r4-r6}
+
+ /* UNDEF mode */
+ bic r0, r2, #0x1F
+ orr r0, r0, #0x1B
+ msr cpsr, r0
+ mov r4, r13
+ mov r5, r14
+ mrs r6, spsr
+ stmia r7!, {r4-r6}
+
+ /* System (USER mode) */
+ bic r0, r2, #0x1F
+ orr r0, r0, #0x1F
+ msr cpsr, r0
+ mov r4, r13
+ mov r5, r14
+ mrs r6, spsr
+ stmia r7!, {r4-r6}
+
+ /* Back to original mode */
+ msr cpsr, r2
+
+ /* Store current cpsr*/
+ stmia r7!, {r2}
+
+ mrc p15, 0, r4, c1, c0, 0
+ /* save control register */
+ stmia r7!, {r4}
+clean_caches:
+ /* Clean Data or unified cache to POU*/
+ /* How to invalidate only L1 cache???? - #FIX_ME# */
+ /* mcr p15, 0, r11, c7, c11, 1 */
+ cmp r9, #1 /* Check whether L2 inval is required or not*/
+ bne skip_l2_inval
+clean_l2:
+ /* read clidr */
+ mrc p15, 1, r0, c0, c0, 1
+ /* extract loc from clidr */
+ ands r3, r0, #0x7000000
+ /* left align loc bit field */
+ mov r3, r3, lsr #23
+ /* if loc is 0, then no need to clean */
+ beq finished
+ /* start clean at cache level 0 */
+ mov r10, #0
+loop1:
+ /* work out 3x current cache level */
+ add r2, r10, r10, lsr #1
+ /* extract cache type bits from clidr*/
+ mov r1, r0, lsr r2
+ /* mask of the bits for current cache only */
+ and r1, r1, #7
+ /* see what cache we have at this level */
+ cmp r1, #2
+ /* skip if no cache, or just i-cache */
+ blt skip
+ /* select current cache level in cssr */
+ mcr p15, 2, r10, c0, c0, 0
+ /* isb to sych the new cssr&csidr */
+ isb
+ /* read the new csidr */
+ mrc p15, 1, r1, c0, c0, 0
+ /* extract the length of the cache lines */
+ and r2, r1, #7
+ /* add 4 (line length offset) */
+ add r2, r2, #4
+ ldr r4, assoc_mask
+ /* find maximum number on the way size */
+ ands r4, r4, r1, lsr #3
+ /* find bit position of way size increment */
+ clz r5, r4
+ ldr r7, numset_mask
+ /* extract max number of the index size*/
+ ands r7, r7, r1, lsr #13
+loop2:
+ mov r9, r4
+ /* create working copy of max way size*/
+loop3:
+ /* factor way and cache number into r11 */
+ orr r11, r10, r9, lsl r5
+ /* factor index number into r11 */
+ orr r11, r11, r7, lsl r2
+ /*clean & invalidate by set/way */
+ mcr p15, 0, r11, c7, c10, 2
+ /* decrement the way*/
+ subs r9, r9, #1
+ bge loop3
+ /*decrement the index */
+ subs r7, r7, #1
+ bge loop2
+skip:
+ add r10, r10, #2
+ /* increment cache number */
+ cmp r3, r10
+ bgt loop1
+finished:
+ /*swith back to cache level 0 */
+ mov r10, #0
+ /* select current cache level in cssr */
+ mcr p15, 2, r10, c0, c0, 0
+ isb
+skip_l2_inval:
+ /* Data memory barrier and Data sync barrier */
+ mov r1, #0
+ mcr p15, 0, r1, c7, c10, 4
+ mcr p15, 0, r1, c7, c10, 5
+
+ wfi @ wait for interrupt
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ bl i_dll_wait
+ /* restore regs and return */
+ ldmfd sp!, {r0-r12, pc}
+
+i_dll_wait:
+ ldr r4, clk_stabilize_delay
+
+i_dll_delay:
+ subs r4, r4, #0x1
+ bne i_dll_delay
+ ldr r4, sdrc_power
+ ldr r5, [r4]
+ bic r5, r5, #0x40
+ str r5, [r4]
+ bx lr
+pm_prepwstst_core:
+ .word PM_PREPWSTST_CORE_V
+pm_prepwstst_mpu:
+ .word PM_PREPWSTST_MPU_V
+pm_pwstctrl_mpu:
+ .word PM_PWSTCTRL_MPU_P
+scratchpad_base:
+ .word SCRATCHPAD_BASE_P
+sdrc_power:
+ .word SDRC_POWER_V
+context_mem:
+ .word 0x803E3E14
+clk_stabilize_delay:
+ .word 0x000001FF
+assoc_mask:
+ .word 0x3ff
+numset_mask:
+ .word 0x7fff
+ttbrbit_mask:
+ .word 0xFFFFC000
+table_index_mask:
+ .word 0xFFF00000
+table_entry:
+ .word 0x00000C02
+cache_pred_disable_mask:
+ .word 0xFFFFE7FB
+ENTRY(omap34xx_cpu_suspend_sz)
+ .word . - omap34xx_cpu_suspend
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap3/smartreflex.c
+ *
+ * OMAP34XX SmartReflex Voltage Control
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Kalle Jokiniemi
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ * Lesly A M <x0080970@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/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/sysfs.h>
+#include <linux/kobject.h>
+#include <linux/i2c/twl4030.h>
+#include <linux/io.h>
+
+#include <mach/omap34xx.h>
+#include <mach/control.h>
+#include <mach/clock.h>
+
+#include "prm.h"
+#include "smartreflex.h"
+#include "prm-regbits-34xx.h"
+
+/* XXX: These should be relocated where-ever the OPP implementation will be */
+u32 current_vdd1_opp;
+u32 current_vdd2_opp;
+
+struct omap_sr {
+ int srid;
+ int is_sr_reset;
+ int is_autocomp_active;
+ struct clk *clk;
+ u32 clk_length;
+ u32 req_opp_no;
+ u32 opp1_nvalue, opp2_nvalue, opp3_nvalue, opp4_nvalue;
+ u32 opp5_nvalue;
+ u32 senp_mod, senn_mod;
+ void __iomem *srbase_addr;
+ void __iomem *vpbase_addr;
+};
+
+#define SR_REGADDR(offs) (sr->srbase_addr + offset)
+
+static inline void sr_write_reg(struct omap_sr *sr, unsigned offset, u32 value)
+{
+ __raw_writel(value, SR_REGADDR(offset));
+}
+
+static inline void sr_modify_reg(struct omap_sr *sr, unsigned offset, u32 mask,
+ u32 value)
+{
+ u32 reg_val;
+
+ reg_val = __raw_readl(SR_REGADDR(offset));
+ reg_val &= ~mask;
+ reg_val |= value;
+
+ __raw_writel(reg_val, SR_REGADDR(offset));
+}
+
+static inline u32 sr_read_reg(struct omap_sr *sr, unsigned offset)
+{
+ return __raw_readl(SR_REGADDR(offset));
+}
+
+static int sr_clk_enable(struct omap_sr *sr)
+{
+ if (clk_enable(sr->clk) != 0) {
+ printk(KERN_ERR "Could not enable %s\n", sr->clk->name);
+ return -1;
+ }
+
+ /* set fclk- active , iclk- idle */
+ sr_modify_reg(sr, ERRCONFIG, SR_CLKACTIVITY_MASK,
+ SR_CLKACTIVITY_IOFF_FON);
+
+ return 0;
+}
+
+static void sr_clk_disable(struct omap_sr *sr)
+{
+ /* set fclk, iclk- idle */
+ sr_modify_reg(sr, ERRCONFIG, SR_CLKACTIVITY_MASK,
+ SR_CLKACTIVITY_IOFF_FOFF);
+
+ clk_disable(sr->clk);
+ sr->is_sr_reset = 1;
+}
+
+static struct omap_sr sr1 = {
+ .srid = SR1,
+ .is_sr_reset = 1,
+ .is_autocomp_active = 0,
+ .clk_length = 0,
+ .srbase_addr = OMAP2_IO_ADDRESS(OMAP34XX_SR1_BASE),
+};
+
+static struct omap_sr sr2 = {
+ .srid = SR2,
+ .is_sr_reset = 1,
+ .is_autocomp_active = 0,
+ .clk_length = 0,
+ .srbase_addr = OMAP2_IO_ADDRESS(OMAP34XX_SR2_BASE),
+};
+
+static void cal_reciprocal(u32 sensor, u32 *sengain, u32 *rnsen)
+{
+ u32 gn, rn, mul;
+
+ for (gn = 0; gn < GAIN_MAXLIMIT; gn++) {
+ mul = 1 << (gn + 8);
+ rn = mul / sensor;
+ if (rn < R_MAXLIMIT) {
+ *sengain = gn;
+ *rnsen = rn;
+ }
+ }
+}
+
+static u32 cal_test_nvalue(u32 sennval, u32 senpval)
+{
+ u32 senpgain, senngain;
+ u32 rnsenp, rnsenn;
+
+ /* Calculating the gain and reciprocal of the SenN and SenP values */
+ cal_reciprocal(senpval, &senpgain, &rnsenp);
+ cal_reciprocal(sennval, &senngain, &rnsenn);
+
+ return ((senpgain << NVALUERECIPROCAL_SENPGAIN_SHIFT) |
+ (senngain << NVALUERECIPROCAL_SENNGAIN_SHIFT) |
+ (rnsenp << NVALUERECIPROCAL_RNSENP_SHIFT) |
+ (rnsenn << NVALUERECIPROCAL_RNSENN_SHIFT));
+}
+
+static void sr_set_clk_length(struct omap_sr *sr)
+{
+ struct clk *osc_sys_ck;
+ u32 sys_clk = 0;
+
+ osc_sys_ck = clk_get(NULL, "osc_sys_ck");
+ sys_clk = clk_get_rate(osc_sys_ck);
+ clk_put(osc_sys_ck);
+
+ switch (sys_clk) {
+ case 12000000:
+ sr->clk_length = SRCLKLENGTH_12MHZ_SYSCLK;
+ break;
+ case 13000000:
+ sr->clk_length = SRCLKLENGTH_13MHZ_SYSCLK;
+ break;
+ case 19200000:
+ sr->clk_length = SRCLKLENGTH_19MHZ_SYSCLK;
+ break;
+ case 26000000:
+ sr->clk_length = SRCLKLENGTH_26MHZ_SYSCLK;
+ break;
+ case 38400000:
+ sr->clk_length = SRCLKLENGTH_38MHZ_SYSCLK;
+ break;
+ default :
+ printk(KERN_ERR "Invalid sysclk value: %d\n", sys_clk);
+ break;
+ }
+}
+
+static void sr_set_efuse_nvalues(struct omap_sr *sr)
+{
+ if (sr->srid == SR1) {
+ sr->senn_mod = (omap_ctrl_readl(OMAP343X_CONTROL_FUSE_SR) &
+ OMAP343X_SR1_SENNENABLE_MASK) >>
+ OMAP343X_SR1_SENNENABLE_SHIFT;
+
+ sr->senp_mod = (omap_ctrl_readl(OMAP343X_CONTROL_FUSE_SR) &
+ OMAP343X_SR1_SENPENABLE_MASK) >>
+ OMAP343X_SR1_SENPENABLE_SHIFT;
+
+ sr->opp5_nvalue = omap_ctrl_readl(
+ OMAP343X_CONTROL_FUSE_OPP5_VDD1);
+ sr->opp4_nvalue = omap_ctrl_readl(
+ OMAP343X_CONTROL_FUSE_OPP4_VDD1);
+ sr->opp3_nvalue = omap_ctrl_readl(
+ OMAP343X_CONTROL_FUSE_OPP3_VDD1);
+ sr->opp2_nvalue = omap_ctrl_readl(
+ OMAP343X_CONTROL_FUSE_OPP2_VDD1);
+ sr->opp1_nvalue = omap_ctrl_readl(
+ OMAP343X_CONTROL_FUSE_OPP1_VDD1);
+ } else if (sr->srid == SR2) {
+ sr->senn_mod = (omap_ctrl_readl(OMAP343X_CONTROL_FUSE_SR) &
+ OMAP343X_SR2_SENNENABLE_MASK) >>
+ OMAP343X_SR2_SENNENABLE_SHIFT;
+
+ sr->senp_mod = (omap_ctrl_readl(OMAP343X_CONTROL_FUSE_SR) &
+ OMAP343X_SR2_SENPENABLE_MASK) >>
+ OMAP343X_SR2_SENPENABLE_SHIFT;
+
+ sr->opp3_nvalue = omap_ctrl_readl(
+ OMAP343X_CONTROL_FUSE_OPP3_VDD2);
+ sr->opp2_nvalue = omap_ctrl_readl(
+ OMAP343X_CONTROL_FUSE_OPP2_VDD2);
+ sr->opp1_nvalue = omap_ctrl_readl(
+ OMAP343X_CONTROL_FUSE_OPP1_VDD2);
+ }
+}
+
+/* Hard coded nvalues for testing purposes, may cause device to hang! */
+static void sr_set_testing_nvalues(struct omap_sr *sr)
+{
+ if (sr->srid == SR1) {
+ sr->senp_mod = 0x03; /* SenN-M5 enabled */
+ sr->senn_mod = 0x03;
+
+ /* calculate nvalues for each opp */
+ sr->opp5_nvalue = cal_test_nvalue(0xacd + 0x330, 0x848 + 0x330);
+ sr->opp4_nvalue = cal_test_nvalue(0x964 + 0x2a0, 0x727 + 0x2a0);
+ sr->opp3_nvalue = cal_test_nvalue(0x85b + 0x200, 0x655 + 0x200);
+ sr->opp2_nvalue = cal_test_nvalue(0x506 + 0x1a0, 0x3be + 0x1a0);
+ sr->opp1_nvalue = cal_test_nvalue(0x373 + 0x100, 0x28c + 0x100);
+ } else if (sr->srid == SR2) {
+ sr->senp_mod = 0x03;
+ sr->senn_mod = 0x03;
+
+ sr->opp3_nvalue = cal_test_nvalue(0x76f + 0x200, 0x579 + 0x200);
+ sr->opp2_nvalue = cal_test_nvalue(0x4f5 + 0x1c0, 0x390 + 0x1c0);
+ sr->opp1_nvalue = cal_test_nvalue(0x359, 0x25d);
+ }
+
+}
+
+static void sr_set_nvalues(struct omap_sr *sr)
+{
+ if (SR_TESTING_NVALUES)
+ sr_set_testing_nvalues(sr);
+ else
+ sr_set_efuse_nvalues(sr);
+}
+
+static void sr_configure_vp(int srid)
+{
+ u32 vpconfig;
+
+ if (srid == SR1) {
+ vpconfig = PRM_VP1_CONFIG_ERROROFFSET | PRM_VP1_CONFIG_ERRORGAIN
+ | PRM_VP1_CONFIG_INITVOLTAGE
+ | PRM_VP1_CONFIG_TIMEOUTEN;
+
+ prm_write_mod_reg(vpconfig, OMAP3430_GR_MOD,
+ OMAP3_PRM_VP1_CONFIG_OFFSET);
+ prm_write_mod_reg(PRM_VP1_VSTEPMIN_SMPSWAITTIMEMIN |
+ PRM_VP1_VSTEPMIN_VSTEPMIN,
+ OMAP3430_GR_MOD,
+ OMAP3_PRM_VP1_VSTEPMIN_OFFSET);
+
+ prm_write_mod_reg(PRM_VP1_VSTEPMAX_SMPSWAITTIMEMAX |
+ PRM_VP1_VSTEPMAX_VSTEPMAX,
+ OMAP3430_GR_MOD,
+ OMAP3_PRM_VP1_VSTEPMAX_OFFSET);
+
+ prm_write_mod_reg(PRM_VP1_VLIMITTO_VDDMAX |
+ PRM_VP1_VLIMITTO_VDDMIN |
+ PRM_VP1_VLIMITTO_TIMEOUT,
+ OMAP3430_GR_MOD,
+ OMAP3_PRM_VP1_VLIMITTO_OFFSET);
+
+ /* Trigger initVDD value copy to voltage processor */
+ prm_set_mod_reg_bits(PRM_VP1_CONFIG_INITVDD, OMAP3430_GR_MOD,
+ OMAP3_PRM_VP1_CONFIG_OFFSET);
+ /* Clear initVDD copy trigger bit */
+ prm_clear_mod_reg_bits(PRM_VP1_CONFIG_INITVDD, OMAP3430_GR_MOD,
+ OMAP3_PRM_VP1_CONFIG_OFFSET);
+
+ } else if (srid == SR2) {
+ vpconfig = PRM_VP2_CONFIG_ERROROFFSET | PRM_VP2_CONFIG_ERRORGAIN
+ | PRM_VP2_CONFIG_INITVOLTAGE
+ | PRM_VP2_CONFIG_TIMEOUTEN;
+
+ prm_write_mod_reg(vpconfig, OMAP3430_GR_MOD,
+ OMAP3_PRM_VP2_CONFIG_OFFSET);
+ prm_write_mod_reg(PRM_VP2_VSTEPMIN_SMPSWAITTIMEMIN |
+ PRM_VP2_VSTEPMIN_VSTEPMIN,
+ OMAP3430_GR_MOD,
+ OMAP3_PRM_VP2_VSTEPMIN_OFFSET);
+
+ prm_write_mod_reg(PRM_VP2_VSTEPMAX_SMPSWAITTIMEMAX |
+ PRM_VP2_VSTEPMAX_VSTEPMAX,
+ OMAP3430_GR_MOD,
+ OMAP3_PRM_VP2_VSTEPMAX_OFFSET);
+
+ prm_write_mod_reg(PRM_VP2_VLIMITTO_VDDMAX |
+ PRM_VP2_VLIMITTO_VDDMIN |
+ PRM_VP2_VLIMITTO_TIMEOUT,
+ OMAP3430_GR_MOD,
+ OMAP3_PRM_VP2_VLIMITTO_OFFSET);
+
+ /* Trigger initVDD value copy to voltage processor */
+ prm_set_mod_reg_bits(PRM_VP2_CONFIG_INITVDD, OMAP3430_GR_MOD,
+ OMAP3_PRM_VP2_CONFIG_OFFSET);
+ /* Reset initVDD copy trigger bit */
+ prm_clear_mod_reg_bits(PRM_VP2_CONFIG_INITVDD, OMAP3430_GR_MOD,
+ OMAP3_PRM_VP2_CONFIG_OFFSET);
+
+ }
+}
+
+static void sr_configure(struct omap_sr *sr)
+{
+ u32 sr_config;
+ u32 senp_en , senn_en;
+
+ if (sr->clk_length == 0)
+ sr_set_clk_length(sr);
+
+ senp_en = sr->senp_mod;
+ senn_en = sr->senn_mod;
+ if (sr->srid == SR1) {
+ sr_config = SR1_SRCONFIG_ACCUMDATA |
+ (sr->clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) |
+ SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN |
+ SRCONFIG_MINMAXAVG_EN |
+ (senn_en << SRCONFIG_SENNENABLE_SHIFT) |
+ (senp_en << SRCONFIG_SENPENABLE_SHIFT) |
+ SRCONFIG_DELAYCTRL;
+
+ sr_write_reg(sr, SRCONFIG, sr_config);
+ sr_write_reg(sr, AVGWEIGHT, SR1_AVGWEIGHT_SENPAVGWEIGHT |
+ SR1_AVGWEIGHT_SENNAVGWEIGHT);
+
+ sr_modify_reg(sr, ERRCONFIG, (SR_ERRWEIGHT_MASK |
+ SR_ERRMAXLIMIT_MASK | SR_ERRMINLIMIT_MASK),
+ (SR1_ERRWEIGHT | SR1_ERRMAXLIMIT | SR1_ERRMINLIMIT));
+
+ } else if (sr->srid == SR2) {
+ sr_config = SR2_SRCONFIG_ACCUMDATA |
+ (sr->clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) |
+ SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN |
+ SRCONFIG_MINMAXAVG_EN |
+ (senn_en << SRCONFIG_SENNENABLE_SHIFT) |
+ (senp_en << SRCONFIG_SENPENABLE_SHIFT) |
+ SRCONFIG_DELAYCTRL;
+
+ sr_write_reg(sr, SRCONFIG, sr_config);
+ sr_write_reg(sr, AVGWEIGHT, SR2_AVGWEIGHT_SENPAVGWEIGHT |
+ SR2_AVGWEIGHT_SENNAVGWEIGHT);
+ sr_modify_reg(sr, ERRCONFIG, (SR_ERRWEIGHT_MASK |
+ SR_ERRMAXLIMIT_MASK | SR_ERRMINLIMIT_MASK),
+ (SR2_ERRWEIGHT | SR2_ERRMAXLIMIT | SR2_ERRMINLIMIT));
+
+ }
+ sr->is_sr_reset = 0;
+}
+
+static int sr_enable(struct omap_sr *sr, u32 target_opp_no)
+{
+ u32 nvalue_reciprocal;
+
+ sr->req_opp_no = target_opp_no;
+
+ if (sr->srid == SR1) {
+ switch (target_opp_no) {
+ case 5:
+ nvalue_reciprocal = sr->opp5_nvalue;
+ break;
+ case 4:
+ nvalue_reciprocal = sr->opp4_nvalue;
+ break;
+ case 3:
+ nvalue_reciprocal = sr->opp3_nvalue;
+ break;
+ case 2:
+ nvalue_reciprocal = sr->opp2_nvalue;
+ break;
+ case 1:
+ nvalue_reciprocal = sr->opp1_nvalue;
+ break;
+ default:
+ nvalue_reciprocal = sr->opp3_nvalue;
+ break;
+ }
+ } else {
+ switch (target_opp_no) {
+ case 3:
+ nvalue_reciprocal = sr->opp3_nvalue;
+ break;
+ case 2:
+ nvalue_reciprocal = sr->opp2_nvalue;
+ break;
+ case 1:
+ nvalue_reciprocal = sr->opp1_nvalue;
+ break;
+ default:
+ nvalue_reciprocal = sr->opp3_nvalue;
+ break;
+ }
+ }
+
+ if (nvalue_reciprocal == 0) {
+ printk(KERN_NOTICE "OPP%d doesn't support SmartReflex\n",
+ target_opp_no);
+ return SR_FALSE;
+ }
+
+ sr_write_reg(sr, NVALUERECIPROCAL, nvalue_reciprocal);
+
+ /* Enable the interrupt */
+ sr_modify_reg(sr, ERRCONFIG,
+ (ERRCONFIG_VPBOUNDINTEN | ERRCONFIG_VPBOUNDINTST),
+ (ERRCONFIG_VPBOUNDINTEN | ERRCONFIG_VPBOUNDINTST));
+ if (sr->srid == SR1) {
+ /* Enable VP1 */
+ prm_set_mod_reg_bits(PRM_VP1_CONFIG_VPENABLE, OMAP3430_GR_MOD,
+ OMAP3_PRM_VP1_CONFIG_OFFSET);
+ } else if (sr->srid == SR2) {
+ /* Enable VP2 */
+ prm_set_mod_reg_bits(PRM_VP2_CONFIG_VPENABLE, OMAP3430_GR_MOD,
+ OMAP3_PRM_VP2_CONFIG_OFFSET);
+ }
+
+ /* SRCONFIG - enable SR */
+ sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, SRCONFIG_SRENABLE);
+ return SR_TRUE;
+}
+
+static void sr_disable(struct omap_sr *sr)
+{
+ sr->is_sr_reset = 1;
+
+ /* SRCONFIG - disable SR */
+ sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, ~SRCONFIG_SRENABLE);
+
+ if (sr->srid == SR1) {
+ /* Disable VP1 */
+ prm_clear_mod_reg_bits(PRM_VP1_CONFIG_VPENABLE, OMAP3430_GR_MOD,
+ OMAP3_PRM_VP1_CONFIG_OFFSET);
+ } else if (sr->srid == SR2) {
+ /* Disable VP2 */
+ prm_clear_mod_reg_bits(PRM_VP2_CONFIG_VPENABLE, OMAP3430_GR_MOD,
+ OMAP3_PRM_VP2_CONFIG_OFFSET);
+ }
+}
+
+
+void sr_start_vddautocomap(int srid, u32 target_opp_no)
+{
+ struct omap_sr *sr = NULL;
+
+ if (srid == SR1)
+ sr = &sr1;
+ else if (srid == SR2)
+ sr = &sr2;
+
+ if (sr->is_sr_reset == 1) {
+ sr_clk_enable(sr);
+ sr_configure(sr);
+ }
+
+ if (sr->is_autocomp_active == 1)
+ printk(KERN_WARNING "SR%d: VDD autocomp is already active\n",
+ srid);
+
+ sr->is_autocomp_active = 1;
+ if (!sr_enable(sr, target_opp_no)) {
+ printk(KERN_WARNING "SR%d: VDD autocomp not activated\n", srid);
+ sr->is_autocomp_active = 0;
+ if (sr->is_sr_reset == 1)
+ sr_clk_disable(sr);
+ }
+}
+EXPORT_SYMBOL(sr_start_vddautocomap);
+
+int sr_stop_vddautocomap(int srid)
+{
+ struct omap_sr *sr = NULL;
+
+ if (srid == SR1)
+ sr = &sr1;
+ else if (srid == SR2)
+ sr = &sr2;
+
+ if (sr->is_autocomp_active == 1) {
+ sr_disable(sr);
+ sr_clk_disable(sr);
+ sr->is_autocomp_active = 0;
+ return SR_TRUE;
+ } else {
+ printk(KERN_WARNING "SR%d: VDD autocomp is not active\n",
+ srid);
+ return SR_FALSE;
+ }
+
+}
+EXPORT_SYMBOL(sr_stop_vddautocomap);
+
+void enable_smartreflex(int srid)
+{
+ u32 target_opp_no = 0;
+ struct omap_sr *sr = NULL;
+
+ if (srid == SR1)
+ sr = &sr1;
+ else if (srid == SR2)
+ sr = &sr2;
+
+ if (sr->is_autocomp_active == 1) {
+ if (sr->is_sr_reset == 1) {
+ /* Enable SR clks */
+ sr_clk_enable(sr);
+
+ if (srid == SR1)
+ target_opp_no = get_opp_no(current_vdd1_opp);
+ else if (srid == SR2)
+ target_opp_no = get_opp_no(current_vdd2_opp);
+
+ sr_configure(sr);
+
+ if (!sr_enable(sr, target_opp_no))
+ sr_clk_disable(sr);
+ }
+ }
+}
+
+void disable_smartreflex(int srid)
+{
+ struct omap_sr *sr = NULL;
+
+ if (srid == SR1)
+ sr = &sr1;
+ else if (srid == SR2)
+ sr = &sr2;
+
+ if (sr->is_autocomp_active == 1) {
+ if (sr->is_sr_reset == 0) {
+
+ sr->is_sr_reset = 1;
+ /* SRCONFIG - disable SR */
+ sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE,
+ ~SRCONFIG_SRENABLE);
+
+ /* Disable SR clk */
+ sr_clk_disable(sr);
+ if (sr->srid == SR1) {
+ /* Disable VP1 */
+ prm_clear_mod_reg_bits(PRM_VP1_CONFIG_VPENABLE,
+ OMAP3430_GR_MOD,
+ OMAP3_PRM_VP1_CONFIG_OFFSET);
+ } else if (sr->srid == SR2) {
+ /* Disable VP2 */
+ prm_clear_mod_reg_bits(PRM_VP2_CONFIG_VPENABLE,
+ OMAP3430_GR_MOD,
+ OMAP3_PRM_VP2_CONFIG_OFFSET);
+ }
+ }
+ }
+}
+
+/* Voltage Scaling using SR VCBYPASS */
+int sr_voltagescale_vcbypass(u32 target_opp, u8 vsel)
+{
+ int sr_status = 0;
+ u32 vdd, target_opp_no;
+ u32 vc_bypass_value;
+ u32 reg_addr = 0;
+ u32 loop_cnt = 0, retries_cnt = 0;
+
+ vdd = get_vdd(target_opp);
+ target_opp_no = get_opp_no(target_opp);
+
+ if (vdd == PRCM_VDD1) {
+ sr_status = sr_stop_vddautocomap(SR1);
+
+ prm_rmw_mod_reg_bits(OMAP3430_VC_CMD_ON_MASK,
+ (vsel << OMAP3430_VC_CMD_ON_SHIFT),
+ OMAP3430_GR_MOD,
+ OMAP3_PRM_VC_CMD_VAL_0_OFFSET);
+ reg_addr = R_VDD1_SR_CONTROL;
+
+ } else if (vdd == PRCM_VDD2) {
+ sr_status = sr_stop_vddautocomap(SR2);
+
+ prm_rmw_mod_reg_bits(OMAP3430_VC_CMD_ON_MASK,
+ (vsel << OMAP3430_VC_CMD_ON_SHIFT),
+ OMAP3430_GR_MOD,
+ OMAP3_PRM_VC_CMD_VAL_1_OFFSET);
+ reg_addr = R_VDD2_SR_CONTROL;
+ }
+
+ vc_bypass_value = (vsel << OMAP3430_DATA_SHIFT) |
+ (reg_addr << OMAP3430_REGADDR_SHIFT) |
+ (R_SRI2C_SLAVE_ADDR << OMAP3430_SLAVEADDR_SHIFT);
+
+ prm_write_mod_reg(vc_bypass_value, OMAP3430_GR_MOD,
+ OMAP3_PRM_VC_BYPASS_VAL_OFFSET);
+
+ vc_bypass_value = prm_set_mod_reg_bits(OMAP3430_VALID, OMAP3430_GR_MOD,
+ OMAP3_PRM_VC_BYPASS_VAL_OFFSET);
+
+ while ((vc_bypass_value & OMAP3430_VALID) != 0x0) {
+ loop_cnt++;
+ if (retries_cnt > 10) {
+ printk(KERN_INFO "Loop count exceeded in check SR I2C"
+ "write\n");
+ return SR_FAIL;
+ }
+ if (loop_cnt > 50) {
+ retries_cnt++;
+ loop_cnt = 0;
+ udelay(10);
+ }
+ vc_bypass_value = prm_read_mod_reg(OMAP3430_GR_MOD,
+ OMAP3_PRM_VC_BYPASS_VAL_OFFSET);
+ }
+
+ udelay(T2_SMPS_UPDATE_DELAY);
+
+ if (sr_status) {
+ if (vdd == PRCM_VDD1)
+ sr_start_vddautocomap(SR1, target_opp_no);
+ else if (vdd == PRCM_VDD2)
+ sr_start_vddautocomap(SR2, target_opp_no);
+ }
+
+ return SR_PASS;
+}
+
+/* Sysfs interface to select SR VDD1 auto compensation */
+static ssize_t omap_sr_vdd1_autocomp_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", sr1.is_autocomp_active);
+}
+
+static ssize_t omap_sr_vdd1_autocomp_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t n)
+{
+ u32 current_vdd1opp_no;
+ unsigned short value;
+
+ if (sscanf(buf, "%hu", &value) != 1 || (value > 1)) {
+ printk(KERN_ERR "sr_vdd1_autocomp: Invalid value\n");
+ return -EINVAL;
+ }
+
+ current_vdd1opp_no = get_opp_no(current_vdd1_opp);
+
+ if (value == 0)
+ sr_stop_vddautocomap(SR1);
+ else
+ sr_start_vddautocomap(SR1, current_vdd1opp_no);
+
+ return n;
+}
+
+static struct kobj_attribute sr_vdd1_autocomp = {
+ .attr = {
+ .name = __stringify(sr_vdd1_autocomp),
+ .mode = 0644,
+ },
+ .show = omap_sr_vdd1_autocomp_show,
+ .store = omap_sr_vdd1_autocomp_store,
+};
+
+/* Sysfs interface to select SR VDD2 auto compensation */
+static ssize_t omap_sr_vdd2_autocomp_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", sr2.is_autocomp_active);
+}
+
+static ssize_t omap_sr_vdd2_autocomp_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t n)
+{
+ u32 current_vdd2opp_no;
+ unsigned short value;
+
+ if (sscanf(buf, "%hu", &value) != 1 || (value > 1)) {
+ printk(KERN_ERR "sr_vdd2_autocomp: Invalid value\n");
+ return -EINVAL;
+ }
+
+ current_vdd2opp_no = get_opp_no(current_vdd2_opp);
+
+ if (value == 0)
+ sr_stop_vddautocomap(SR2);
+ else
+ sr_start_vddautocomap(SR2, current_vdd2opp_no);
+
+ return n;
+}
+
+static struct kobj_attribute sr_vdd2_autocomp = {
+ .attr = {
+ .name = __stringify(sr_vdd2_autocomp),
+ .mode = 0644,
+ },
+ .show = omap_sr_vdd2_autocomp_show,
+ .store = omap_sr_vdd2_autocomp_store,
+};
+
+
+
+static int __init omap3_sr_init(void)
+{
+ int ret = 0;
+ u8 RdReg;
+
+ if (omap_rev() > OMAP3430_REV_ES1_0) {
+ current_vdd1_opp = PRCM_VDD1_OPP3;
+ current_vdd2_opp = PRCM_VDD2_OPP3;
+ } else {
+ current_vdd1_opp = PRCM_VDD1_OPP1;
+ current_vdd2_opp = PRCM_VDD1_OPP1;
+ }
+ if (cpu_is_omap34xx()) {
+ sr1.clk = clk_get(NULL, "sr1_fck");
+ sr2.clk = clk_get(NULL, "sr2_fck");
+ }
+ sr_set_clk_length(&sr1);
+ sr_set_clk_length(&sr2);
+
+ /* Call the VPConfig, VCConfig, set N Values. */
+ sr_set_nvalues(&sr1);
+ sr_configure_vp(SR1);
+
+ sr_set_nvalues(&sr2);
+ sr_configure_vp(SR2);
+
+ /* Enable SR on T2 */
+ ret = twl4030_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &RdReg,
+ R_DCDC_GLOBAL_CFG);
+
+ RdReg |= DCDC_GLOBAL_CFG_ENABLE_SRFLX;
+ ret |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, RdReg,
+ R_DCDC_GLOBAL_CFG);
+
+ printk(KERN_INFO "SmartReflex driver initialized\n");
+
+ ret = sysfs_create_file(power_kobj, &sr_vdd1_autocomp.attr);
+ if (ret)
+ printk(KERN_ERR "sysfs_create_file failed: %d\n", ret);
+
+ ret = sysfs_create_file(power_kobj, &sr_vdd2_autocomp.attr);
+ if (ret)
+ printk(KERN_ERR "sysfs_create_file failed: %d\n", ret);
+
+ return 0;
+}
+
+late_initcall(omap3_sr_init);
--- /dev/null
+#ifndef __ARCH_ARM_MACH_OMAP3_SMARTREFLEX_H
+#define __ARCH_ARM_MACH_OMAP3_SMARTREFLEX_H
+/*
+ * linux/arch/arm/mach-omap2/smartreflex.h
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Kalle Jokiniemi
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ * Lesly A M <x0080970@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.
+ */
+
+#define PHY_TO_OFF_PM_MASTER(p) (p - 0x36)
+#define PHY_TO_OFF_PM_RECIEVER(p) (p - 0x5b)
+#define PHY_TO_OFF_PM_INT(p) (p - 0x2e)
+
+/* SMART REFLEX REG ADDRESS OFFSET */
+#define SRCONFIG 0x00
+#define SRSTATUS 0x04
+#define SENVAL 0x08
+#define SENMIN 0x0C
+#define SENMAX 0x10
+#define SENAVG 0x14
+#define AVGWEIGHT 0x18
+#define NVALUERECIPROCAL 0x1C
+#define SENERROR 0x20
+#define ERRCONFIG 0x24
+
+/* SR Modules */
+#define SR1 1
+#define SR2 2
+
+#define SR_FAIL 1
+#define SR_PASS 0
+
+#define SR_TRUE 1
+#define SR_FALSE 0
+
+#define GAIN_MAXLIMIT 16
+#define R_MAXLIMIT 256
+
+#define SR1_CLK_ENABLE (0x1 << 6)
+#define SR2_CLK_ENABLE (0x1 << 7)
+
+/* PRM_VP1_CONFIG */
+#define PRM_VP1_CONFIG_ERROROFFSET (0x00 << 24)
+#define PRM_VP1_CONFIG_ERRORGAIN (0x20 << 16)
+
+#define PRM_VP1_CONFIG_INITVOLTAGE (0x30 << 8) /* 1.2 volt */
+#define PRM_VP1_CONFIG_TIMEOUTEN (0x1 << 3)
+#define PRM_VP1_CONFIG_INITVDD (0x1 << 2)
+#define PRM_VP1_CONFIG_FORCEUPDATE (0x1 << 1)
+#define PRM_VP1_CONFIG_VPENABLE (0x1 << 0)
+
+/* PRM_VP1_VSTEPMIN */
+#define PRM_VP1_VSTEPMIN_SMPSWAITTIMEMIN (0x01F4 << 8)
+#define PRM_VP1_VSTEPMIN_VSTEPMIN (0x01 << 0)
+
+/* PRM_VP1_VSTEPMAX */
+#define PRM_VP1_VSTEPMAX_SMPSWAITTIMEMAX (0x01F4 << 8)
+#define PRM_VP1_VSTEPMAX_VSTEPMAX (0x04 << 0)
+
+/* PRM_VP1_VLIMITTO */
+#define PRM_VP1_VLIMITTO_VDDMAX (0x3C << 24)
+#define PRM_VP1_VLIMITTO_VDDMIN (0x0 << 16)
+#define PRM_VP1_VLIMITTO_TIMEOUT (0xFFFF << 0)
+
+/* PRM_VP2_CONFIG */
+#define PRM_VP2_CONFIG_ERROROFFSET (0x00 << 24)
+#define PRM_VP2_CONFIG_ERRORGAIN (0x20 << 16)
+
+#define PRM_VP2_CONFIG_INITVOLTAGE (0x30 << 8) /* 1.2 volt */
+#define PRM_VP2_CONFIG_TIMEOUTEN (0x1 << 3)
+#define PRM_VP2_CONFIG_INITVDD (0x1 << 2)
+#define PRM_VP2_CONFIG_FORCEUPDATE (0x1 << 1)
+#define PRM_VP2_CONFIG_VPENABLE (0x1 << 0)
+
+/* PRM_VP2_VSTEPMIN */
+#define PRM_VP2_VSTEPMIN_SMPSWAITTIMEMIN (0x01F4 << 8)
+#define PRM_VP2_VSTEPMIN_VSTEPMIN (0x01 << 0)
+
+/* PRM_VP2_VSTEPMAX */
+#define PRM_VP2_VSTEPMAX_SMPSWAITTIMEMAX (0x01F4 << 8)
+#define PRM_VP2_VSTEPMAX_VSTEPMAX (0x04 << 0)
+
+/* PRM_VP2_VLIMITTO */
+#define PRM_VP2_VLIMITTO_VDDMAX (0x2C << 24)
+#define PRM_VP2_VLIMITTO_VDDMIN (0x0 << 16)
+#define PRM_VP2_VLIMITTO_TIMEOUT (0xFFFF << 0)
+
+/* SRCONFIG */
+#define SR1_SRCONFIG_ACCUMDATA (0x1F4 << 22)
+#define SR2_SRCONFIG_ACCUMDATA (0x1F4 << 22)
+
+#define SRCLKLENGTH_12MHZ_SYSCLK 0x3C
+#define SRCLKLENGTH_13MHZ_SYSCLK 0x41
+#define SRCLKLENGTH_19MHZ_SYSCLK 0x60
+#define SRCLKLENGTH_26MHZ_SYSCLK 0x82
+#define SRCLKLENGTH_38MHZ_SYSCLK 0xC0
+
+#define SRCONFIG_SRCLKLENGTH_SHIFT 12
+#define SRCONFIG_SENNENABLE_SHIFT 5
+#define SRCONFIG_SENPENABLE_SHIFT 3
+
+#define SRCONFIG_SRENABLE (0x01 << 11)
+#define SRCONFIG_SENENABLE (0x01 << 10)
+#define SRCONFIG_ERRGEN_EN (0x01 << 9)
+#define SRCONFIG_MINMAXAVG_EN (0x01 << 8)
+
+#define SRCONFIG_DELAYCTRL (0x01 << 2)
+#define SRCONFIG_CLKCTRL (0x00 << 0)
+
+/* AVGWEIGHT */
+#define SR1_AVGWEIGHT_SENPAVGWEIGHT (0x03 << 2)
+#define SR1_AVGWEIGHT_SENNAVGWEIGHT (0x03 << 0)
+
+#define SR2_AVGWEIGHT_SENPAVGWEIGHT (0x01 << 2)
+#define SR2_AVGWEIGHT_SENNAVGWEIGHT (0x01 << 0)
+
+/* NVALUERECIPROCAL */
+#define NVALUERECIPROCAL_SENPGAIN_SHIFT 20
+#define NVALUERECIPROCAL_SENNGAIN_SHIFT 16
+#define NVALUERECIPROCAL_RNSENP_SHIFT 8
+#define NVALUERECIPROCAL_RNSENN_SHIFT 0
+
+/* ERRCONFIG */
+#define SR_CLKACTIVITY_MASK (0x03 << 20)
+#define SR_ERRWEIGHT_MASK (0x07 << 16)
+#define SR_ERRMAXLIMIT_MASK (0xFF << 8)
+#define SR_ERRMINLIMIT_MASK (0xFF << 0)
+
+#define SR_CLKACTIVITY_IOFF_FOFF (0x00 << 20)
+#define SR_CLKACTIVITY_IOFF_FON (0x02 << 20)
+
+#define ERRCONFIG_VPBOUNDINTEN (0x1 << 31)
+#define ERRCONFIG_VPBOUNDINTST (0x1 << 30)
+
+#define SR1_ERRWEIGHT (0x07 << 16)
+#define SR1_ERRMAXLIMIT (0x02 << 8)
+#define SR1_ERRMINLIMIT (0xFA << 0)
+
+#define SR2_ERRWEIGHT (0x07 << 16)
+#define SR2_ERRMAXLIMIT (0x02 << 8)
+#define SR2_ERRMINLIMIT (0xF9 << 0)
+
+/* T2 SMART REFLEX */
+#define R_SRI2C_SLAVE_ADDR 0x12
+#define R_VDD1_SR_CONTROL 0x00
+#define R_VDD2_SR_CONTROL 0x01
+#define T2_SMPS_UPDATE_DELAY 360 /* In uSec */
+
+/* Vmode control */
+#define R_DCDC_GLOBAL_CFG PHY_TO_OFF_PM_RECIEVER(0x61)
+
+#define R_VDD1_VSEL PHY_TO_OFF_PM_RECIEVER(0xb9)
+#define R_VDD1_VMODE_CFG PHY_TO_OFF_PM_RECIEVER(0xba)
+#define R_VDD1_VFLOOR PHY_TO_OFF_PM_RECIEVER(0xbb)
+#define R_VDD1_VROOF PHY_TO_OFF_PM_RECIEVER(0xbc)
+#define R_VDD1_STEP PHY_TO_OFF_PM_RECIEVER(0xbd)
+
+#define R_VDD2_VSEL PHY_TO_OFF_PM_RECIEVER(0xc7)
+#define R_VDD2_VMODE_CFG PHY_TO_OFF_PM_RECIEVER(0xc8)
+#define R_VDD2_VFLOOR PHY_TO_OFF_PM_RECIEVER(0xc9)
+#define R_VDD2_VROOF PHY_TO_OFF_PM_RECIEVER(0xca)
+#define R_VDD2_STEP PHY_TO_OFF_PM_RECIEVER(0xcb)
+
+/* R_DCDC_GLOBAL_CFG register, SMARTREFLEX_ENABLE values */
+#define DCDC_GLOBAL_CFG_ENABLE_SRFLX 0x08
+
+/* VDDs*/
+#define PRCM_VDD1 1
+#define PRCM_VDD2 2
+#define PRCM_MAX_SYSC_REGS 30
+
+/*
+ * XXX: These should be removed/moved from here once we have a working DVFS
+ * implementation in place
+ */
+#define AT_3430 1 /*3430 ES 1.0 */
+#define AT_3430_ES2 2 /*3430 ES 2.0 */
+
+#define ID_OPP 0xE2 /*OPP*/
+
+/* DEVICE ID/DPLL ID/CLOCK ID: bits 28-31 for OMAP type */
+#define OMAP_TYPE_SHIFT 28
+#define OMAP_TYPE_MASK 0xF
+/* OPP ID: bits: 0-4 for OPP number */
+#define OPP_NO_POS 0
+#define OPP_NO_MASK 0x1F
+/* OPP ID: bits: 5-6 for VDD */
+#define VDD_NO_POS 5
+#define VDD_NO_MASK 0x3
+/* Other IDs: bits 20-27 for ID type */
+/* These IDs have bits 25,26,27 as 1 */
+#define OTHER_ID_TYPE_SHIFT 20
+#define OTHER_ID_TYPE_MASK 0xFF
+
+#define OTHER_ID_TYPE(X) ((X & OTHER_ID_TYPE_MASK) << OTHER_ID_TYPE_SHIFT)
+#define ID_OPP_NO(X) ((X & OPP_NO_MASK) << OPP_NO_POS)
+#define ID_VDD(X) ((X & VDD_NO_MASK) << VDD_NO_POS)
+#define OMAP(X) ((X >> OMAP_TYPE_SHIFT) & OMAP_TYPE_MASK)
+#define get_opp_no(X) ((X >> OPP_NO_POS) & OPP_NO_MASK)
+#define get_vdd(X) ((X >> VDD_NO_POS) & VDD_NO_MASK)
+
+/* VDD1 OPPs */
+#define PRCM_VDD1_OPP1 (OMAP(AT_3430_ES2) | OTHER_ID_TYPE(ID_OPP) | \
+ ID_VDD(PRCM_VDD1) | ID_OPP_NO(0x1))
+#define PRCM_VDD1_OPP2 (OMAP(AT_3430_ES2) | OTHER_ID_TYPE(ID_OPP) | \
+ ID_VDD(PRCM_VDD1) | ID_OPP_NO(0x2))
+#define PRCM_VDD1_OPP3 (OMAP(AT_3430_ES2) | OTHER_ID_TYPE(ID_OPP) | \
+ ID_VDD(PRCM_VDD1) | ID_OPP_NO(0x3))
+#define PRCM_VDD1_OPP4 (OMAP(AT_3430_ES2) | OTHER_ID_TYPE(ID_OPP) | \
+ ID_VDD(PRCM_VDD1) | ID_OPP_NO(0x4))
+#define PRCM_VDD1_OPP5 (OMAP(AT_3430_ES2) | OTHER_ID_TYPE(ID_OPP) | \
+ ID_VDD(PRCM_VDD1) | ID_OPP_NO(0x5))
+#define PRCM_NO_VDD1_OPPS 5
+
+
+/* VDD2 OPPs */
+#define PRCM_VDD2_OPP1 (OMAP(AT_3430_ES2) | OTHER_ID_TYPE(ID_OPP) | \
+ ID_VDD(PRCM_VDD2) | ID_OPP_NO(0x1))
+#define PRCM_VDD2_OPP2 (OMAP(AT_3430_ES2) | OTHER_ID_TYPE(ID_OPP) | \
+ ID_VDD(PRCM_VDD2) | ID_OPP_NO(0x2))
+#define PRCM_VDD2_OPP3 (OMAP(AT_3430_ES2) | OTHER_ID_TYPE(ID_OPP) | \
+ ID_VDD(PRCM_VDD2) | ID_OPP_NO(0x3))
+#define PRCM_NO_VDD2_OPPS 3
+/* XXX: end remove/move */
+
+/* XXX: find more appropriate place for these once DVFS is in place */
+extern u32 current_vdd1_opp;
+extern u32 current_vdd2_opp;
+
+#ifdef CONFIG_OMAP_SMARTREFLEX_TESTING
+#define SR_TESTING_NVALUES 1
+#else
+#define SR_TESTING_NVALUES 0
+#endif
+
+/*
+ * Smartreflex module enable/disable interface.
+ * NOTE: if smartreflex is not enabled from sysfs, these functions will not
+ * do anything.
+ */
+#ifdef CONFIG_OMAP_SMARTREFLEX
+void enable_smartreflex(int srid);
+void disable_smartreflex(int srid);
+int sr_voltagescale_vcbypass(u32 target_opp, u8 vsel);
+void sr_start_vddautocomap(int srid, u32 target_opp_no);
+int sr_stop_vddautocomap(int srid);
+#else
+static inline void enable_smartreflex(int srid) {}
+static inline void disable_smartreflex(int srid) {}
+#endif
+
+#endif
#include "cm.h"
#include "sdrc.h"
+#define OMAP242X_PRCM_VOLTCTRL OMAP2420_PRM_REGADDR(OMAP24XX_GR_MOD, \
+ OMAP24XX_PRCM_VOLTCTRL_OFFSET)
+#define OMAP242X_PRCM_CLKCFG_CTRL OMAP2420_PRM_REGADDR(OMAP24XX_GR_MOD, \
+ OMAP24XX_PRCM_CLKCFG_CTRL_OFFSET)
+
.text
ENTRY(omap242x_sram_ddr_init)
#include "cm.h"
#include "sdrc.h"
+#define OMAP243X_PRCM_VOLTCTRL OMAP2430_PRM_REGADDR(OMAP24XX_GR_MOD, \
+ OMAP24XX_PRCM_VOLTCTRL_OFFSET)
+#define OMAP243X_PRCM_CLKCFG_CTRL OMAP2430_PRM_REGADDR(OMAP24XX_GR_MOD, \
+ OMAP24XX_PRCM_CLKCFG_CTRL_OFFSET)
+
.text
ENTRY(omap243x_sram_ddr_init)
{
u32 tick_rate;
- gptimer = omap_dm_timer_request_specific(1);
+ gptimer = omap_dm_timer_request_specific(CONFIG_OMAP_TICK_GPTIMER);
BUG_ON(gptimer == NULL);
#if defined(CONFIG_OMAP_32K_TIMER)
#endif
tick_rate = clk_get_rate(omap_dm_timer_get_fclk(gptimer));
+ pr_info("OMAP clockevent source: GPTIMER%d at %u Hz\n",
+ CONFIG_OMAP_TICK_GPTIMER, tick_rate);
+
omap2_gp_timer_irq.dev_id = (void *)gptimer;
setup_irq(omap_dm_timer_get_irq(gptimer), &omap2_gp_timer_irq);
omap_dm_timer_set_int_enable(gptimer, OMAP_TIMER_INT_OVERFLOW);
clockevent_gpt.max_delta_ns =
clockevent_delta2ns(0xffffffff, &clockevent_gpt);
clockevent_gpt.min_delta_ns =
- clockevent_delta2ns(1, &clockevent_gpt);
+ clockevent_delta2ns(3, &clockevent_gpt);
+ /* Timer internal resynch latency. */
clockevent_gpt.cpumask = cpumask_of(0);
clockevents_register_device(&clockevent_gpt);
--- /dev/null
+/*
+ * arch/arm/mach-omap2/twl4030-generic-scripts.c
+ *
+ * Generic power control scripts for TWL4030
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Copyright (C) 2006 Texas Instruments, Inc
+ *
+ * Written by Kalle Jokiniemi
+ * 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
+ */
+
+#ifdef CONFIG_TWL4030_POWER
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/i2c/twl4030.h>
+
+/*
+ * This script instructs twl4030 to first put the Reset and Control (RC)
+ * resources to sleep and then all the other resources.
+ */
+
+static struct twl4030_ins sleep_on_seq[] __initdata = {
+ {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_RC, RES_TYPE_ALL, RES_TYPE2_R0,
+ RES_STATE_SLEEP), 4},
+ {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, RES_TYPE_ALL, RES_TYPE2_R0,
+ RES_STATE_SLEEP), 4},
+};
+
+static struct twl4030_script sleep_on_script __initdata = {
+ .script = sleep_on_seq,
+ .size = ARRAY_SIZE(sleep_on_seq),
+ .flags = TRITON_SLEEP_SCRIPT,
+};
+
+/*
+ * This script instructs twl4030 to first enable CLKEN, then wakeup the
+ * regulators and then all other resources.
+ */
+
+static struct twl4030_ins wakeup_seq[] __initdata = {
+ {MSG_SINGULAR(DEV_GRP_NULL, 0x17, RES_STATE_ACTIVE), 0x30},
+ {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_PP_PR, RES_TYPE_ALL, RES_TYPE2_R0,
+ RES_STATE_ACTIVE), 0x37},
+ {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, RES_TYPE_ALL, RES_TYPE2_R0,
+ RES_STATE_ACTIVE), 0x2},
+};
+
+static struct twl4030_script wakeup_script __initdata = {
+ .script = wakeup_seq,
+ .size = ARRAY_SIZE(wakeup_seq),
+ .flags = TRITON_WAKEUP12_SCRIPT | TRITON_WAKEUP3_SCRIPT,
+};
+
+static struct twl4030_script *twl4030_scripts[] __initdata = {
+ &sleep_on_script,
+ &wakeup_script,
+};
+
+struct twl4030_power_data generic3430_t2scripts_data __initdata = {
+ .scripts = twl4030_scripts,
+ .size = ARRAY_SIZE(twl4030_scripts),
+};
+
+
+#endif /* CONFIG_TWL4030_POWER */
--- /dev/null
+#ifndef __TWL4030_GENERIC_SCRIPTS_H
+#define __TWL4030_GENERIC_SCRIPTS_H
+
+#include <linux/i2c/twl4030.h>
+
+#ifdef CONFIG_TWL4030_POWER
+extern struct twl4030_power_data generic3430_t2scripts_data;
+#define GENERIC3430_T2SCRIPTS_DATA &generic3430_t2scripts_data
+#else
+#define GENERIC3430_T2SCRIPTS_DATA NULL
+#endif /* CONFIG_TWL4030_POWER */
+
+#endif
--- /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 <mach/mux.h>
+#include <linux/usb/musb.h>
+
+#include <mach/hardware.h>
+#include <mach/pm.h>
+#include <mach/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 = NULL,
+ },
+ .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 <linux/dma-mapping.h>
+
+#include <asm/io.h>
+
+#include <linux/usb/musb.h>
+
+#include <mach/hardware.h>
+#include <mach/pm.h>
+#include <mach/mux.h>
+#include <mach/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;
+
+ clk_enable(clk);
+ clk_on = 1;
+ } else {
+ if (clk_on == 0)
+ return -ENODEV;
+
+ clk_disable(clk);
+ clk_on = 0;
+ }
+
+ return 0;
+}
+
+static struct musb_hdrc_eps_bits musb_eps[] = {
+ { "ep1_tx", 10, },
+ { "ep1_rx", 10, },
+ { "ep2_tx", 9, },
+ { "ep2_rx", 9, },
+ { "ep3_tx", 3, },
+ { "ep3_rx", 3, },
+ { "ep4_tx", 3, },
+ { "ep4_rx", 3, },
+ { "ep5_tx", 3, },
+ { "ep5_rx", 3, },
+ { "ep6_tx", 3, },
+ { "ep6_rx", 3, },
+ { "ep7_tx", 3, },
+ { "ep7_rx", 3, },
+ { "ep8_tx", 2, },
+ { "ep8_rx", 2, },
+ { "ep9_tx", 2, },
+ { "ep9_rx", 2, },
+ { "ep10_tx", 2, },
+ { "ep10_rx", 2, },
+ { "ep11_tx", 2, },
+ { "ep11_rx", 2, },
+ { "ep12_tx", 2, },
+ { "ep12_rx", 2, },
+ { "ep13_tx", 2, },
+ { "ep13_rx", 2, },
+ { "ep14_tx", 2, },
+ { "ep14_rx", 2, },
+ { "ep15_tx", 2, },
+ { "ep15_rx", 2, },
+};
+
+static struct musb_hdrc_config musb_config = {
+ .multipoint = 1,
+ .dyn_fifo = 1,
+ .soft_con = 1,
+ .dma = 1,
+ .num_eps = 16,
+ .dma_channels = 7,
+ .dma_req_chan = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3),
+ .ram_bits = 12,
+ .eps_bits = musb_eps,
+};
+
+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
+ .clock = cpu_is_omap34xx()
+ ? "hsotgusb_ick"
+ : "usbhs_ick",
+ .set_clock = musb_set_clock,
+ .config = &musb_config,
+
+ /* REVISIT charge pump on TWL4030 can supply up to
+ * 100 mA ... but this value is board-specific, like
+ * "mode", and should be passed to usb_musb_init().
+ */
+ .power = 50, /* up to 100 mA */
+};
+
+static u64 musb_dmamask = DMA_32BIT_MASK;
+
+static struct platform_device musb_device = {
+ .name = "musb_hdrc",
+ .id = -1,
+ .dev = {
+ .dma_mask = &musb_dmamask,
+ .coherent_dma_mask = DMA_32BIT_MASK,
+ .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)
{
for every clockdomain register write. However, the
extra detail costs some memory.
+config OMAP_SMARTREFLEX
+ bool "SmartReflex support"
+ depends on ARCH_OMAP34XX && TWL4030_CORE
+ help
+ Say Y if you want to enable SmartReflex.
+
+ SmartReflex can perform continuous dynamic voltage
+ scaling around the nominal operating point voltage
+ according to silicon characteristics and operating
+ conditions. Enabling SmartReflex reduces power
+ consumption.
+
+ Please note, that by default SmartReflex is only
+ initialized. To enable the automatic voltage
+ compensation for VDD1 and VDD2, user must write 1 to
+ /sys/power/sr_vddX_autocomp, where X is 1 or 2.
+
+config OMAP_SMARTREFLEX_TESTING
+ bool "Smartreflex testing support"
+ depends on OMAP_SMARTREFLEX
+ default n
+ help
+ Say Y if you want to enable SmartReflex testing with SW hardcoded
+ NVALUES intead of E-fuse NVALUES set in factory silicon testing.
+
+ In some devices the E-fuse values have not been set, even though
+ SmartReflex modules are included. Using these hardcoded values set
+ in software, one can test the SmartReflex features without E-fuse.
+
+ WARNING: Enabling this option may cause your device to hang!
+
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, IVA1.0 and IVA2 in OMAP1/2/3.
+
choice
prompt "System timer"
default OMAP_MPU_TIMER
Kernel internal timer frequency should be a divisor of 32768,
such as 64 or 128.
+config OMAP_TICK_GPTIMER
+ int "GPTIMER used for system tick timer"
+ depends on ARCH_OMAP2 || ARCH_OMAP3
+ range 1 12
+ default 1
+ help
+ Linux uses one of the twelve on-board OMAP GPTIMER blocks to generate
+ system tick interrupts. The twelve GPTIMERs have slightly
+ different powerdomain, source clock, and security properties
+ (mostly documented in the OMAP3 TRMs) that can affect the selection
+ of which GPTIMER to use. The historical default is GPTIMER1.
+ If CONFIG_OMAP_32K_TIMER is selected, Beagle may require GPTIMER12
+ due to hardware sensitivity to glitches on the OMAP 32kHz clock
+ input.
+
config OMAP_DM_TIMER
bool "Use dual-mode timer"
depends on ARCH_OMAP16XX || ARCH_OMAP24XX || ARCH_OMAP34XX
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 <mach/board.h>
+
+static char boot_reason[16];
+
+static int omap_bootreason_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = 0;
+
+ len += sprintf(page + len, "%s\n", boot_reason);
+
+ *start = page + off;
+
+ if (len > off)
+ len -= off;
+ else
+ len = 0;
+
+ return len < count ? len : count;
+}
+
+static int __init bootreason_init(void)
+{
+ const struct omap_boot_reason_config *cfg;
+ int reason_valid = 0;
+
+ cfg = omap_get_config(OMAP_TAG_BOOT_REASON, struct omap_boot_reason_config);
+ if (cfg != NULL) {
+ strncpy(boot_reason, cfg->reason_str, sizeof(cfg->reason_str));
+ boot_reason[sizeof(cfg->reason_str)] = 0;
+ reason_valid = 1;
+ } else {
+ /* Read the boot reason from the OMAP registers */
+ }
+
+ if (!reason_valid)
+ return -ENOENT;
+
+ printk(KERN_INFO "Bootup reason: %s\n", boot_reason);
+
+ if (!create_proc_read_entry("bootreason", S_IRUGO, NULL,
+ omap_bootreason_read_proc, NULL))
+ return -ENOMEM;
+
+ return 0;
+}
+
+late_initcall(bootreason_init);
#include <linux/cpufreq.h>
#include <linux/debugfs.h>
#include <linux/io.h>
+#include <linux/bootmem.h>
+#include <linux/slab.h>
#include <mach/clock.h>
static struct clk_functions *arch_clock;
+/**
+ * omap_clk_for_each_child - call callback on each child clock of clk
+ * @clk: struct clk * to use as the "parent"
+ * @parent_rate: rate of the parent of @clk to pass along
+ * @rate_storage: flag indicating whether current or temporary rates are used
+ * @cb: pointer to a callback function
+ *
+ * For each child clock of @clk, call the callback function @cb, passing
+ * along the contents of @parent_rate and @rate_storage. If the callback
+ * function returns non-zero, terminate the function and pass along the
+ * return value.
+ */
+static int omap_clk_for_each_child(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage,
+ int (*cb)(struct clk *clk,
+ unsigned long parent_rate,
+ u8 rate_storage))
+{
+ struct clk_child *child;
+ int ret;
+
+ list_for_each_entry(child, &clk->children, node) {
+ ret = (*cb)(child->clk, parent_rate, rate_storage);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * omap_clk_has_children - does clk @clk have any child clocks?
+ * @clk: struct clk * to test for child clocks
+ *
+ * If clock @clk has any child clocks, return 1; otherwise, return 0.
+ */
+static int omap_clk_has_children(struct clk *clk)
+{
+ return (list_empty(&clk->children)) ? 0 : 1;
+}
+
+/**
+ * _do_propagate_rate - callback function for rate propagation
+ * @clk: struct clk * to recalc and propagate from
+ * @parent_rate: rate of the parent of @clk, to use in recalculation
+ * @rate_storage: flag indicating whether current or temporary rates are used
+ *
+ * If @clk has a recalc function, call it. If @clk has any children,
+ * propagate @clk's rate. Returns 0.
+ */
+static int _do_propagate_rate(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage)
+{
+ if (clk->recalc)
+ clk->recalc(clk, parent_rate, rate_storage);
+ if (omap_clk_has_children(clk))
+ propagate_rate(clk, rate_storage);
+ return 0;
+}
+
+/**
+ * omap_clk_add_child - add a child clock @clk2 to @clk
+ * @clk: parent struct clk *
+ * @clk2: new child struct clk *
+ *
+ * Add a child clock @clk2 to the list of children of parent clock
+ * @clk. Will potentially allocate memory from bootmem or, if
+ * available, from slab. Must only be called with the clock framework
+ * spinlock held. No return value.
+ */
+void omap_clk_add_child(struct clk *clk, struct clk *clk2)
+{
+ struct clk_child *child;
+ int reuse = 0;
+
+ if (!clk->children.next)
+ INIT_LIST_HEAD(&clk->children);
+
+ list_for_each_entry(child, &clk->children, node) {
+ if (child->flags & CLK_CHILD_DELETED) {
+ reuse = 1;
+ child->flags &= ~CLK_CHILD_DELETED;
+ break;
+ }
+ }
+
+ if (!reuse) {
+ if (slab_is_available())
+ child = kmalloc(sizeof(struct clk_child), GFP_ATOMIC);
+ else
+ child = alloc_bootmem(sizeof(struct clk_child));
+
+ if (!child) {
+ WARN_ON(1);
+ return;
+ }
+
+ memset(child, 0, sizeof(struct clk_child));
+
+ if (slab_is_available())
+ child->flags |= CLK_CHILD_SLAB_ALLOC;
+ }
+
+ child->clk = clk2;
+
+ list_add_tail(&child->node, &clk->children);
+}
+
+/**
+ * omap_clk_del_child - add a child clock @clk2 to @clk
+ * @clk: parent struct clk *
+ * @clk2: former child struct clk *
+ *
+ * Remove a child clock @clk2 from the list of children of parent
+ * clock @clk. Must only be called with the clock framework spinlock
+ * held. No return value.
+ */
+void omap_clk_del_child(struct clk *clk, struct clk *clk2)
+{
+ struct clk_child *child, *tmp;
+
+ /* Loop over all existing clk_childs, when found, deallocate */
+ list_for_each_entry_safe(child, tmp, &clk->children, node) {
+ if (child->clk == clk2) {
+ list_del(&child->node);
+ if (child->flags & CLK_CHILD_SLAB_ALLOC) {
+ kfree(child);
+ } else {
+ child->clk = NULL;
+ child->flags |= CLK_CHILD_DELETED;
+ }
+ break;
+ }
+ }
+}
+
/*-------------------------------------------------------------------------
* Standard clock functions defined in include/linux/clk.h
*-------------------------------------------------------------------------*/
mutex_lock(&clocks_mutex);
list_for_each_entry(p, &clocks, node) {
- if (p->id == idno &&
- strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
+ if (p->id == idno && strcmp(id, p->name) == 0) {
clk = p;
goto found;
}
}
list_for_each_entry(p, &clocks, node) {
- if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
+ if (strcmp(id, p->name) == 0) {
clk = p;
break;
}
return -EINVAL;
spin_lock_irqsave(&clockfw_lock, flags);
- if (arch_clock->clk_enable)
+ if (arch_clock->clk_enable) {
ret = arch_clock->clk_enable(clk);
+ if (ret == 0 && clk->flags & RECALC_ON_ENABLE)
+ _do_propagate_rate(clk, clk->parent->rate,
+ CURRENT_RATE);
+ }
+
spin_unlock_irqrestore(&clockfw_lock, flags);
return ret;
goto out;
}
- if (arch_clock->clk_disable)
+ if (arch_clock->clk_disable) {
arch_clock->clk_disable(clk);
+ if (clk->flags & RECALC_ON_ENABLE)
+ _do_propagate_rate(clk, clk->parent->rate,
+ CURRENT_RATE);
+ }
out:
spin_unlock_irqrestore(&clockfw_lock, flags);
}
EXPORT_SYMBOL(clk_disable);
-int clk_get_usecount(struct clk *clk)
-{
- unsigned long flags;
- int ret = 0;
-
- if (clk == NULL || IS_ERR(clk))
- return 0;
-
- spin_lock_irqsave(&clockfw_lock, flags);
- ret = clk->usecount;
- spin_unlock_irqrestore(&clockfw_lock, flags);
-
- return ret;
-}
-EXPORT_SYMBOL(clk_get_usecount);
-
unsigned long clk_get_rate(struct clk *clk)
{
unsigned long flags;
void clk_put(struct clk *clk)
{
- if (clk && !IS_ERR(clk))
- module_put(clk->owner);
}
EXPORT_SYMBOL(clk_put);
return ret;
spin_lock_irqsave(&clockfw_lock, flags);
- if (arch_clock->clk_set_rate)
+
+ if (arch_clock->clk_set_rate) {
ret = arch_clock->clk_set_rate(clk, rate);
+ if (ret == 0)
+ _do_propagate_rate(clk, clk->parent->rate,
+ CURRENT_RATE);
+ }
+
spin_unlock_irqrestore(&clockfw_lock, flags);
return ret;
int clk_set_parent(struct clk *clk, struct clk *parent)
{
unsigned long flags;
+ struct clk *prev_parent;
int ret = -EINVAL;
if (clk == NULL || IS_ERR(clk) || parent == NULL || IS_ERR(parent))
return ret;
spin_lock_irqsave(&clockfw_lock, flags);
- if (arch_clock->clk_set_parent)
- ret = arch_clock->clk_set_parent(clk, parent);
+
+ if (arch_clock->clk_set_parent) {
+ prev_parent = clk->parent;
+ ret = arch_clock->clk_set_parent(clk, parent);
+ if (ret == 0) {
+ omap_clk_del_child(prev_parent, clk);
+ omap_clk_add_child(parent, clk);
+ _do_propagate_rate(clk, clk->parent->rate,
+ CURRENT_RATE);
+ }
+ }
+
spin_unlock_irqrestore(&clockfw_lock, flags);
return ret;
__setup("mpurate=", omap_clk_setup);
/* Used for clocks that always have same value as the parent clock */
-void followparent_recalc(struct clk *clk)
+void followparent_recalc(struct clk *clk, unsigned long new_parent_rate,
+ u8 rate_storage)
{
- if (clk == NULL || IS_ERR(clk))
- return;
-
- clk->rate = clk->parent->rate;
- if (unlikely(clk->flags & RATE_PROPAGATES))
- propagate_rate(clk);
+ if (rate_storage == CURRENT_RATE)
+ clk->rate = new_parent_rate;
+ else if (rate_storage == TEMP_RATE)
+ clk->temp_rate = new_parent_rate;
}
/* Propagate rate to children */
-void propagate_rate(struct clk * tclk)
+void propagate_rate(struct clk *tclk, u8 rate_storage)
{
- struct clk *clkp;
+ unsigned long parent_rate = 0;
if (tclk == NULL || IS_ERR(tclk))
return;
- list_for_each_entry(clkp, &clocks, node) {
- if (likely(clkp->parent != tclk))
- continue;
- if (likely((u32)clkp->recalc))
- clkp->recalc(clkp);
- }
+ if (rate_storage == CURRENT_RATE)
+ parent_rate = tclk->rate;
+ else if (rate_storage == TEMP_RATE)
+ parent_rate = tclk->temp_rate;
+
+ omap_clk_for_each_child(tclk, parent_rate, rate_storage,
+ _do_propagate_rate);
}
/**
{
struct clk *clkp;
- list_for_each_entry(clkp, &clocks, node) {
- if (unlikely(!clkp->parent) && likely((u32)clkp->recalc))
- clkp->recalc(clkp);
- }
+ list_for_each_entry(clkp, &clocks, node)
+ if (unlikely(!clkp->parent))
+ _do_propagate_rate(clkp, 0, CURRENT_RATE);
}
int clk_register(struct clk *clk)
{
+ int ret;
+
if (clk == NULL || IS_ERR(clk))
return -EINVAL;
mutex_lock(&clocks_mutex);
+ if (arch_clock->clk_register) {
+ ret = arch_clock->clk_register(clk);
+ if (ret)
+ goto cr_out;
+ }
list_add(&clk->node, &clocks);
+ if (!clk->children.next)
+ INIT_LIST_HEAD(&clk->children);
+ if (clk->parent)
+ omap_clk_add_child(clk->parent, clk);
if (clk->init)
clk->init(clk);
+ ret = 0;
+cr_out:
mutex_unlock(&clocks_mutex);
- return 0;
+ return ret;
}
EXPORT_SYMBOL(clk_register);
void clk_unregister(struct clk *clk)
{
+ struct clk_child *child, *tmp;
+
if (clk == NULL || IS_ERR(clk))
return;
mutex_lock(&clocks_mutex);
list_del(&clk->node);
+ if (clk->parent)
+ omap_clk_del_child(clk->parent, clk);
+ list_for_each_entry_safe(child, tmp, &clk->children, node)
+ if (child->flags & CLK_CHILD_SLAB_ALLOC)
+ kfree(child);
mutex_unlock(&clocks_mutex);
}
EXPORT_SYMBOL(clk_unregister);
unsigned long flags;
list_for_each_entry(ck, &clocks, node) {
- if (ck->usecount > 0 || (ck->flags & ALWAYS_ENABLED) ||
- ck->enable_reg == 0)
+ if (ck->usecount > 0 ||
+ (ck->flags & (ALWAYS_ENABLED | PARENT_CONTROLS_CLOCK)))
+ continue;
+
+ if (cpu_class_is_omap1() && ck->enable_reg == 0)
continue;
spin_lock_irqsave(&clockfw_lock, flags);
#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;
static void __init __omap2_set_globals(void)
{
omap2_set_globals_tap(omap2_globals);
- omap2_set_globals_memory(omap2_globals);
+ omap2_set_globals_sdrc(omap2_globals);
omap2_set_globals_control(omap2_globals);
omap2_set_globals_prcm(omap2_globals);
}
--- /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 <mach/board.h>
+#include <mach/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 <mach/hardware.h>
#include <asm/system.h>
+#include <mach/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 <linux/init.h>
#include <linux/platform_device.h>
#include <linux/io.h>
+#include <linux/i2c/menelaus.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
#include <asm/mach/map.h>
#include <mach/tc.h>
-#include <mach/control.h>
#include <mach/board.h>
#include <mach/mmc.h>
#include <mach/mux.h>
#include <mach/gpio.h>
-#include <mach/menelaus.h>
-#include <mach/mcbsp.h>
#include <mach/dsp_common.h>
+#include <mach/mcbsp.h>
#if defined(CONFIG_OMAP_DSP) || defined(CONFIG_OMAP_DSP_MODULE)
{
struct platform_device *pdev;
struct resource res[OMAP_MMC_NR_RES];
+ char *name;
int ret;
- pdev = platform_device_alloc("mmci-omap", id);
+ if (cpu_class_is_omap1() || cpu_is_omap242x())
+ name = "mmci-omap";
+ else
+ name = "mmci-omap-hs";
+
+ pdev = platform_device_alloc(name, id);
if (!pdev)
return -ENOMEM;
val = dma_read(CCR(lch));
val &= ~(3 << 19);
- if (dma_trigger > 63)
- val |= 1 << 20;
- if (dma_trigger > 31)
- val |= 1 << 19;
+ val |= ((dma_trigger & ~(0x1f)) << 14);
val &= ~(0x1f);
val |= (dma_trigger & 0x1f);
chan->dev_name = dev_name;
chan->callback = callback;
chan->data = data;
+ chan->flags = 0;
#ifndef CONFIG_ARCH_OMAP1
if (cpu_class_is_omap2()) {
if (cpu_class_is_omap2())
setup_irq(INT_24XX_SDMA_IRQ0, &omap24xx_dma_irq);
+ /* Enable smartidle idlemodes and autoidle */
+ if (cpu_is_omap34xx()) {
+ u32 v = dma_read(OCP_SYSCONFIG);
+ v &= ~(DMA_SYSCONFIG_MIDLEMODE_MASK |
+ DMA_SYSCONFIG_SIDLEMODE_MASK |
+ DMA_SYSCONFIG_AUTOIDLE);
+ v |= (DMA_SYSCONFIG_MIDLEMODE(DMA_IDLEMODE_SMARTIDLE) |
+ DMA_SYSCONFIG_SIDLEMODE(DMA_IDLEMODE_SMARTIDLE) |
+ DMA_SYSCONFIG_AUTOIDLE);
+ dma_write(v , OCP_SYSCONFIG);
+ }
+
+
/* FIXME: Update LCD DMA to work on 24xx */
if (cpu_class_is_omap1()) {
r = request_irq(INT_DMA_LCD, lcd_dma_irq_handler, 0,
{ .phys_base = 0x49040000, .irq = INT_24XX_GPTIMER9 },
{ .phys_base = 0x48086000, .irq = INT_24XX_GPTIMER10 },
{ .phys_base = 0x48088000, .irq = INT_24XX_GPTIMER11 },
- { .phys_base = 0x48304000, .irq = INT_24XX_GPTIMER12 },
+ { .phys_base = 0x48304000, .irq = INT_34XX_GPT12_IRQ },
};
static const char *omap3_dm_source_names[] __initdata = {
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.
+ * Enable wake-up on OMAP2 CPUs.
*/
- if (cpu_class_is_omap2() && (timer == &dm_timers[0]))
+ if (cpu_class_is_omap2())
l |= 1 << 2;
omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_REG, l);
config_invalid = 1;
return;
}
- if (rg.paddr)
+ if (rg.paddr) {
reserve_bootmem(rg.paddr, rg.size, BOOTMEM_DEFAULT);
- reserved += rg.size;
+ reserved += rg.size;
+ }
omapfb_config.mem_desc.region[i] = rg;
configured_regions++;
}
--- /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 <linux/gpio.h>
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+#include <mach/mux.h>
+#include <mach/board.h>
+#include <mach/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 = gpio_get_value(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)
+ sw->state = enable = 0;
+ else if (strcmp(state, str[1]) == 0)
+ sw->state = enable = 1;
+ else
+ return -EINVAL;
+
+ if (sw->flags & OMAP_GPIO_SWITCH_FLAG_INVERTED)
+ enable = !enable;
+ gpio_set_value(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 (gpio_get_value(sw->gpio))
+ set_irq_type(gpio_to_irq(sw->gpio), IRQ_TYPE_EDGE_FALLING);
+ else
+ set_irq_type(gpio_to_irq(sw->gpio), IRQ_TYPE_EDGE_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 = gpio_request(sw->gpio, sw->name);
+ if (r < 0) {
+ platform_device_unregister(&sw->pdev);
+ return r;
+ }
+
+ /* input: 1, output: 0 */
+ direction = !(sw->flags & OMAP_GPIO_SWITCH_FLAG_OUTPUT);
+ if (direction)
+ gpio_direction_input(sw->gpio);
+ else
+ gpio_direction_output(sw->gpio, true);
+
+ 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 (gpio_get_value(sw->gpio))
+ trigger = IRQF_TRIGGER_FALLING;
+ else
+ trigger = IRQF_TRIGGER_RISING;
+ }
+ r = request_irq(gpio_to_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);
+ gpio_free(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(gpio_to_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);
+ gpio_free(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 = gpio_get_value(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");
+++ /dev/null
-/*
- * arch/arm/plat-omap/include/mach/aic23.h
- *
- * Hardware definitions for TI TLV320AIC23 audio codec
- *
- * Copyright (C) 2002 RidgeRun, Inc.
- * Author: Steve Johnson
- *
- * 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_AIC23_H
-#define __ASM_ARCH_AIC23_H
-
-// Codec TLV320AIC23
-#define LEFT_LINE_VOLUME_ADDR 0x00
-#define RIGHT_LINE_VOLUME_ADDR 0x01
-#define LEFT_CHANNEL_VOLUME_ADDR 0x02
-#define RIGHT_CHANNEL_VOLUME_ADDR 0x03
-#define ANALOG_AUDIO_CONTROL_ADDR 0x04
-#define DIGITAL_AUDIO_CONTROL_ADDR 0x05
-#define POWER_DOWN_CONTROL_ADDR 0x06
-#define DIGITAL_AUDIO_FORMAT_ADDR 0x07
-#define SAMPLE_RATE_CONTROL_ADDR 0x08
-#define DIGITAL_INTERFACE_ACT_ADDR 0x09
-#define RESET_CONTROL_ADDR 0x0F
-
-// Left (right) line input volume control register
-#define LRS_ENABLED 0x0100
-#define LIM_MUTED 0x0080
-#define LIV_DEFAULT 0x0017
-#define LIV_MAX 0x001f
-#define LIV_MIN 0x0000
-
-// Left (right) channel headphone volume control register
-#define LZC_ON 0x0080
-#define LHV_DEFAULT 0x0079
-#define LHV_MAX 0x007f
-#define LHV_MIN 0x0000
-
-// Analog audio path control register
-#define STA_REG(x) ((x)<<6)
-#define STE_ENABLED 0x0020
-#define DAC_SELECTED 0x0010
-#define BYPASS_ON 0x0008
-#define INSEL_MIC 0x0004
-#define MICM_MUTED 0x0002
-#define MICB_20DB 0x0001
-
-// Digital audio path control register
-#define DACM_MUTE 0x0008
-#define DEEMP_32K 0x0002
-#define DEEMP_44K 0x0004
-#define DEEMP_48K 0x0006
-#define ADCHP_ON 0x0001
-
-// Power control down register
-#define DEVICE_POWER_OFF 0x0080
-#define CLK_OFF 0x0040
-#define OSC_OFF 0x0020
-#define OUT_OFF 0x0010
-#define DAC_OFF 0x0008
-#define ADC_OFF 0x0004
-#define MIC_OFF 0x0002
-#define LINE_OFF 0x0001
-
-// Digital audio interface register
-#define MS_MASTER 0x0040
-#define LRSWAP_ON 0x0020
-#define LRP_ON 0x0010
-#define IWL_16 0x0000
-#define IWL_20 0x0004
-#define IWL_24 0x0008
-#define IWL_32 0x000C
-#define FOR_I2S 0x0002
-#define FOR_DSP 0x0003
-
-// Sample rate control register
-#define CLKOUT_HALF 0x0080
-#define CLKIN_HALF 0x0040
-#define BOSR_384fs 0x0002 // BOSR_272fs when in USB mode
-#define USB_CLK_ON 0x0001
-#define SR_MASK 0xf
-#define CLKOUT_SHIFT 7
-#define CLKIN_SHIFT 6
-#define SR_SHIFT 2
-#define BOSR_SHIFT 1
-
-// Digital interface register
-#define ACT_ON 0x0001
-
-#define TLV320AIC23ID1 (0x1a) // cs low
-#define TLV320AIC23ID2 (0x1b) // cs high
-
-void aic23_power_up(void);
-void aic23_power_down(void);
-
-#endif /* __ASM_ARCH_AIC23_H */
--- /dev/null
+/*
+ * arch/arm/plat-omap/include/mach/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);
+extern void sdp3430_flash_init(void);
+extern void twl4030_bci_battery_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 */
+
/* In OMAP1710 H3 the Ethernet is directly connected to CS1 */
#define OMAP1710_ETHR_START 0x04000300
+#define H3_TPS_GPIO_BASE (OMAP_MAX_GPIO_LINES + 16 /* MPUIO */)
+# define H3_TPS_GPIO_MMC_PWR_EN (H3_TPS_GPIO_BASE + 4)
+
extern void h3_mmc_init(void);
-extern void h3_mmc_slot_cover_handler(void *arg, int state);
#endif /* __ASM_ARCH_OMAP_H3_H */
/* Placeholder for H4 specific defines */
#define OMAP24XX_ETHR_GPIO_IRQ 92
+
+/* FPGA on debug board has 32 GPIOs: 16 dedicated to leds,
+ * 8 outputs on a header, and 6 inputs from a DIP switch.
+ */
+#define H4_DEBUG_GPIO_BASE OMAP_MAX_GPIO_LINES
+# define H4_DEBUG_GPIO_SW3_1 (H4_DEBUG_GPIO_BASE + 24)
+# define H4_DEBUG_GPIO_SW3_2 (H4_DEBUG_GPIO_BASE + 25)
+# define H4_DEBUG_GPIO_SW3_3 (H4_DEBUG_GPIO_BASE + 26)
+# define H4_DEBUG_GPIO_SW3_4 (H4_DEBUG_GPIO_BASE + 27)
+# define H4_DEBUG_GPIO_SW3_5 (H4_DEBUG_GPIO_BASE + 28)
+# define H4_DEBUG_GPIO_SW3_8 (H4_DEBUG_GPIO_BASE + 29)
+
+/* H4 baseboard has 3 PCF8574 (8 bit) I2C GPIO expanders */
+#define H4_U191_GPIO_BASE (H4_DEBUG_GPIO_BASE + 32)
+# define H4_GPIO_IRDA_FIRSEL (H4_U191_GPIO_BASE + 0)
+# define H4_GPIO_MODEM_MOD_EN (H4_U191_GPIO_BASE + 1)
+# define H4_GPIO_WLAN_MOD_EN (H4_U191_GPIO_BASE + 2)
+# define H4_GPIO_CAM_MODULE_EN (H4_U191_GPIO_BASE + 3)
+# define H4_GPIO_HANDSET_EN (H4_U191_GPIO_BASE + 4)
+# define H4_GPIO_LCD_ENBKL (H4_U191_GPIO_BASE + 5)
+# define H4_GPIO_AUDIO_ENVDD (H4_U191_GPIO_BASE + 6)
+# define H4_GPIO_LCD_ENVDD (H4_U191_GPIO_BASE + 7)
+
+#define H4_U192_GPIO_BASE (H4_U191_GPIO_BASE + 8)
+# define H4_GPIO_IRDA_AGPSn (H4_U192_GPIO_BASE + 0)
+# define H4_GPIO_AGPS_PWREN (H4_U192_GPIO_BASE + 1)
+# define H4_GPIO_AGPS_RSTn (H4_U192_GPIO_BASE + 2)
+# define H4_GPIO_AGPS_SLEEP (H4_U192_GPIO_BASE + 3)
+# define H4_GPIO_AGPS_PA_XMT (H4_U192_GPIO_BASE + 4)
+# define H4_GPIO_MODEM_SPR2 (H4_U192_GPIO_BASE + 5)
+# define H4_GPIO_MODEM_SPR1 (H4_U192_GPIO_BASE + 6)
+# define H4_GPIO_BT_ACLK_ENn (H4_U192_GPIO_BASE + 7)
+
+#define H4_U193_GPIO_BASE (H4_U192_GPIO_BASE + 8)
+# define H4_GPIO_SPR0 (H4_U193_GPIO_BASE + 0)
+# define H4_GPIO_SPR1 (H4_U193_GPIO_BASE + 1)
+# define H4_GPIO_WLAN_SHUTDOWN (H4_U193_GPIO_BASE + 2)
+# define H4_GPIO_WLAN_RESET (H4_U193_GPIO_BASE + 3)
+# define H4_GPIO_WLAN_CLK_ENn (H4_U193_GPIO_BASE + 4)
+ /* 5, 6 not connected */
+# define H4_GPIO_CAM_RST (H4_U193_GPIO_BASE + 7)
+
#endif /* __ASM_ARCH_OMAP_H4_H */
* 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
+/*
+ * arch/arm/plat-omap/include/mach/board-omap2evm.h
+ *
+ * Hardware definitions for Mistral's OMAP2EVM board.
+ *
+ * Based on board-2430sdp.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_OMAP2_EVM_H
+#define __ASM_ARCH_OMAP2_EVM_H
+
+/* Placeholder for OMAP2EVM specific defines */
+#define OMAP2EVM_ETHR_START 0x2c000000
+#define OMAP2EVM_ETHR_SIZE 1024
+#define OMAP2EVM_ETHR_GPIO_IRQ 149
+#define OMAP2_EVM_TS_GPIO 85
+
+#endif /* __ASM_ARCH_OMAP2_EVM_H */
--- /dev/null
+/*
+ * arch/arm/plat-omap/include/mach/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
+
+#define OMAP3EVM_ETHR_START 0x2c000000
+#define OMAP3EVM_ETHR_SIZE 1024
+#define OMAP3EVM_ETHR_GPIO_IRQ 176
+#define OMAP3EVM_SMC911X_CS 5
+
+#endif /* __ASM_ARCH_OMAP3_EVM_H */
+
#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 {
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)
struct omap_gpio_switch_config {
char name[12];
u16 gpio;
- int flags:4;
- int type:4;
- int key_code:24; /* Linux key code */
+ u8 flags:4;
+ u8 type:4;
+ unsigned int key_code:24; /* Linux key code */
};
struct omap_uart_config {
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 <mach/board-nokia.h>
-
struct omap_board_config_entry {
u16 tag;
u16 len;
#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
struct clksel_rate {
- u8 div;
u32 val;
+ u8 div;
u8 flags;
};
};
struct dpll_data {
- 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;
+ u32 max_tolerance;
+ struct clk *bypass_clk;
+ u32 enable_mask;
+ u16 mult_div1_reg;
+ u16 control_reg;
u16 max_multiplier;
+ u16 last_rounded_m;
+ u8 last_rounded_n;
+ u8 min_divider;
u8 max_divider;
- u32 max_tolerance;
# if defined(CONFIG_ARCH_OMAP3)
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;
+ u16 autoidle_reg;
+ u16 idlest_reg;
u32 autoidle_mask;
- void __iomem *idlest_reg;
- u8 idlest_bit;
+ u32 idlest_mask;
+ u32 freqsel_mask;
# endif
};
#endif
+/**
+ * struct clk_child - used to track the children of a clock
+ * @clk: child struct clk *
+ * @node: list_head
+ * @flags: is this entry allocated in bootmem or slab? is it deleted?
+ *
+ * One struct clk_child is allocated for each child clock @clk of a
+ * parent clock. @flags values are listed below and start with CLK_CHILD_*.
+ */
+struct clk_child {
+ struct clk *clk;
+ struct list_head node;
+ u8 flags;
+};
+
struct clk {
struct list_head node;
- struct module *owner;
const char *name;
int id;
struct clk *parent;
unsigned long rate;
+ unsigned long temp_rate;
+ struct list_head children;
__u32 flags;
- void __iomem *enable_reg;
- __u8 enable_bit;
- __s8 usecount;
- void (*recalc)(struct clk *);
+ u32 enable_reg;
+ void (*recalc)(struct clk *, unsigned long, u8);
int (*set_rate)(struct clk *, unsigned long);
long (*round_rate)(struct clk *, unsigned long);
void (*init)(struct clk *);
int (*enable)(struct clk *);
void (*disable)(struct clk *);
+ __u8 enable_bit;
+ __s8 usecount;
+ u8 idlest_bit;
#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
u8 fixed_div;
- void __iomem *clksel_reg;
u32 clksel_mask;
const struct clksel *clksel;
struct dpll_data *dpll_data;
- const char *clkdm_name;
- struct clockdomain *clkdm;
+ union {
+ const char *name;
+ struct clockdomain *ptr;
+ } clkdm;
+ u16 clksel_reg;
+ s16 prcm_mod;
#else
__u8 rate_offset;
__u8 src_offset;
struct cpufreq_frequency_table;
struct clk_functions {
+ int (*clk_register)(struct clk *clk);
int (*clk_enable)(struct clk *clk);
void (*clk_disable)(struct clk *clk);
long (*clk_round_rate)(struct clk *clk, unsigned long rate);
extern unsigned int mpurate;
-extern int clk_init(struct clk_functions * custom_clocks);
+extern int clk_init(struct clk_functions *custom_clocks);
extern int clk_register(struct clk *clk);
extern void clk_unregister(struct clk *clk);
-extern void propagate_rate(struct clk *clk);
+extern void propagate_rate(struct clk *clk, u8 rate_storage);
extern void recalculate_root_clocks(void);
-extern void followparent_recalc(struct clk * clk);
+extern void followparent_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage);
extern void clk_allow_idle(struct clk *clk);
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
+void omap_clk_add_child(struct clk *clk, struct clk *clk2);
+void omap_clk_del_child(struct clk *clk, struct clk *clk2);
/* Clock flags */
#define RATE_CKCTL (1 << 0) /* Main fixed ratio clocks */
-#define RATE_FIXED (1 << 1) /* Fixed clock rate */
-#define RATE_PROPAGATES (1 << 2) /* Program children too */
-#define VIRTUAL_CLOCK (1 << 3) /* Composite clock from table */
+/* bits 1-3 are currently free */
#define ALWAYS_ENABLED (1 << 4) /* Clock cannot be disabled */
#define ENABLE_REG_32BIT (1 << 5) /* Use 32-bit access */
-#define VIRTUAL_IO_ADDRESS (1 << 6) /* Clock in virtual address */
+/* bit 6 is currently free */
#define CLOCK_IDLE_CONTROL (1 << 7)
#define CLOCK_NO_IDLE_PARENT (1 << 8)
#define DELAYED_APP (1 << 9) /* Delay application of clock */
-#define CONFIG_PARTICIPANT (1 << 10) /* Fundamental clock */
+/* bit 10 is currently free */
#define ENABLE_ON_INIT (1 << 11) /* Enable upon framework init */
-#define INVERT_ENABLE (1 << 12) /* 0 enables, 1 disables */
-/* bits 13-20 are currently free */
+#define INVERT_ENABLE (1 << 12) /* 0 enables, 1 disables */
+#define WAIT_READY (1 << 13) /* wait for dev to leave idle */
+#define RECALC_ON_ENABLE (1 << 14) /* recalc/prop on ena/disa */
+/* bits 15-20 are currently free */
#define CLOCK_IN_OMAP310 (1 << 21)
#define CLOCK_IN_OMAP730 (1 << 22)
#define CLOCK_IN_OMAP1510 (1 << 23)
#define CLOCK_IN_OMAP343X (1 << 27) /* clocks common to all 343X */
#define PARENT_CONTROLS_CLOCK (1 << 28)
#define CLOCK_IN_OMAP3430ES1 (1 << 29) /* 3430ES1 clocks only */
-#define CLOCK_IN_OMAP3430ES2 (1 << 30) /* 3430ES2 clocks only */
+#define CLOCK_IN_OMAP3430ES2 (1 << 30) /* 3430ES2+ clocks only */
/* Clksel_rate flags */
#define DEFAULT_RATE (1 << 0)
#define RATE_IN_242X (1 << 1)
#define RATE_IN_243X (1 << 2)
#define RATE_IN_343X (1 << 3) /* rates common to all 343X */
-#define RATE_IN_3430ES2 (1 << 4) /* 3430ES2 rates only */
+#define RATE_IN_3430ES2 (1 << 4) /* 3430ES2+ rates only */
#define RATE_IN_24XX (RATE_IN_242X | RATE_IN_243X)
+/* rate_storage parameter flags */
+#define CURRENT_RATE 0
+#define TEMP_RATE 1
-/* CM_CLKSEL2_PLL.CORE_CLK_SRC options (24XX) */
-#define CORE_CLK_SRC_32K 0
-#define CORE_CLK_SRC_DPLL 1
-#define CORE_CLK_SRC_DPLL_X2 2
+/* clk_child flags */
+#define CLK_CHILD_SLAB_ALLOC (1 << 0) /* if !set, bootmem was used */
+#define CLK_CHILD_DELETED (1 << 1) /* can be reused */
+
+/*
+ * clk.prcm_mod flags (possible since only the top byte in clk.prcm_mod
+ * is significant)
+ */
+#define PRCM_MOD_ADDR_MASK 0xff00
+#define CLK_REG_IN_PRM (1 << 0)
+#define CLK_REG_IN_SCM (1 << 1)
#endif
/*
- * linux/include/asm-arm/arch-omap/clockdomain.h
+ * arch/arm/plat-omap/include/mach/clockdomain.h
*
* OMAP2/3 clockdomain framework functions
*
*/
struct clkdm_pwrdm_autodep {
- /* Name of the powerdomain to add a wkdep/sleepdep on */
- const char *pwrdm_name;
+ union {
+ /* Name of the powerdomain to add a wkdep/sleepdep on */
+ const char *name;
- /* Powerdomain pointer (looked up at clkdm_init() time) */
- struct powerdomain *pwrdm;
+ /* Powerdomain pointer (looked up at clkdm_init() time) */
+ struct powerdomain *ptr;
+ } pwrdm;
/* OMAP chip types that this clockdomain dep is valid on */
const struct omap_chip_id omap_chip;
/* Clockdomain name */
const char *name;
- /* Powerdomain enclosing this clockdomain */
- const char *pwrdm_name;
+ union {
+ /* Powerdomain enclosing this clockdomain */
+ const char *name;
+
+ /* Powerdomain pointer assigned at clkdm_register() */
+ struct powerdomain *ptr;
+ } pwrdm;
/* CLKTRCTRL/AUTOSTATE field mask in CM_CLKSTCTRL reg */
const u16 clktrctrl_mask;
/* Usecount tracking */
atomic_t usecount;
- /* Powerdomain pointer assigned at clkdm_register() */
- struct powerdomain *pwrdm;
-
struct list_head node;
};
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,
/* These get called from omap2_set_globals_xxxx(), do not call these */
void omap2_set_globals_tap(struct omap_globals *);
-void omap2_set_globals_memory(struct omap_globals *);
+void omap2_set_globals_sdrc(struct omap_globals *);
void omap2_set_globals_control(struct omap_globals *);
void omap2_set_globals_prcm(struct omap_globals *);
+#ifdef CONFIG_ARCH_OMAP24XX
+void omap2_set_globals_clock24xx(struct omap_globals *);
+#else
+#define omap2_set_globals_clock24xx(x) do { } while (0)
+#endif
#endif /* __ARCH_ARM_MACH_OMAP_COMMON_H */
#define OMAP343X_CONTROL_TEST_KEY_11 (OMAP2_CONTROL_GENERAL + 0x00f4)
#define OMAP343X_CONTROL_TEST_KEY_12 (OMAP2_CONTROL_GENERAL + 0x00f8)
#define OMAP343X_CONTROL_TEST_KEY_13 (OMAP2_CONTROL_GENERAL + 0x00fc)
+#define OMAP343X_CONTROL_FUSE_OPP1_VDD1 (OMAP2_CONTROL_GENERAL + 0x0110)
+#define OMAP343X_CONTROL_FUSE_OPP2_VDD1 (OMAP2_CONTROL_GENERAL + 0x0114)
+#define OMAP343X_CONTROL_FUSE_OPP3_VDD1 (OMAP2_CONTROL_GENERAL + 0x0118)
+#define OMAP343X_CONTROL_FUSE_OPP4_VDD1 (OMAP2_CONTROL_GENERAL + 0x011c)
+#define OMAP343X_CONTROL_FUSE_OPP5_VDD1 (OMAP2_CONTROL_GENERAL + 0x0120)
+#define OMAP343X_CONTROL_FUSE_OPP1_VDD2 (OMAP2_CONTROL_GENERAL + 0x0124)
+#define OMAP343X_CONTROL_FUSE_OPP2_VDD2 (OMAP2_CONTROL_GENERAL + 0x0128)
+#define OMAP343X_CONTROL_FUSE_OPP3_VDD2 (OMAP2_CONTROL_GENERAL + 0x012c)
+#define OMAP343X_CONTROL_FUSE_SR (OMAP2_CONTROL_GENERAL + 0x0130)
#define OMAP343X_CONTROL_IVA2_BOOTADDR (OMAP2_CONTROL_GENERAL + 0x0190)
#define OMAP343X_CONTROL_IVA2_BOOTMOD (OMAP2_CONTROL_GENERAL + 0x0194)
#define OMAP343X_CONTROL_PBIAS_LITE (OMAP2_CONTROL_GENERAL + 0x02b0)
#define OMAP2_SYSBOOT_1_MASK (1 << 1)
#define OMAP2_SYSBOOT_0_MASK (1 << 0)
+/* CONTROL_FUSE_SR bits */
+#define OMAP343X_SR2_SENNENABLE_MASK (0x3 << 10)
+#define OMAP343X_SR2_SENNENABLE_SHIFT 10
+#define OMAP343X_SR2_SENPENABLE_MASK (0x3 << 8)
+#define OMAP343X_SR2_SENPENABLE_SHIFT 8
+#define OMAP343X_SR1_SENNENABLE_MASK (0x3 << 2)
+#define OMAP343X_SR1_SENNENABLE_SHIFT 2
+#define OMAP343X_SR1_SENPENABLE_MASK (0x3 << 0)
+#define OMAP343X_SR1_SENPENABLE_SHIFT 0
+
/* CONTROL_PBIAS_LITE bits */
#define OMAP343X_PBIASLITESUPPLY_HIGH1 (1 << 15)
#define OMAP343X_PBIASLITEVMODEERROR1 (1 << 11)
#define OMAP2_PBIASLITEPWRDNZ0 (1 << 1)
#define OMAP2_PBIASLITEVMODE0 (1 << 0)
+/* CONTROL_PADCONF_X bits */
+#define OMAP3_PADCONF_WAKEUPEVENT0 (1 << 15)
+#define OMAP3_PADCONF_WAKEUPENABLE0 (1 << 14)
+
+/* CONTROL_IVA2_BOOTMOD bits */
+#define OMAP3_IVA2_BOOTMOD_SHIFT 0
+#define OMAP3_IVA2_BOOTMOD_MASK (0xf << 0)
+#define OMAP3_IVA2_BOOTMOD_IDLE (0x1 << 0)
+
#ifndef __ASSEMBLY__
#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
extern void __iomem *omap_ctrl_base_get(void);
#define DMA_THREAD_FIFO_25 (0x02 << 14)
#define DMA_THREAD_FIFO_50 (0x03 << 14)
+/* DMA4_OCP_SYSCONFIG bits */
+#define DMA_SYSCONFIG_MIDLEMODE_MASK (3 << 12)
+#define DMA_SYSCONFIG_CLOCKACTIVITY_MASK (3 << 8)
+#define DMA_SYSCONFIG_EMUFREE (1 << 5)
+#define DMA_SYSCONFIG_SIDLEMODE_MASK (3 << 3)
+#define DMA_SYSCONFIG_SOFTRESET (1 << 2)
+#define DMA_SYSCONFIG_AUTOIDLE (1 << 0)
+
+#define DMA_SYSCONFIG_MIDLEMODE(n) ((n) << 12)
+#define DMA_SYSCONFIG_SIDLEMODE(n) ((n) << 3)
+
+#define DMA_IDLEMODE_SMARTIDLE 0x2
+#define DMA_IDLEMODE_NO_IDLE 0x1
+#define DMA_IDLEMODE_FORCE_IDLE 0x0
+
/* Chaining modes*/
#ifndef CONFIG_ARCH_OMAP1
#define OMAP_DMA_STATIC_CHAIN 0x1
--- /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);
};
/* 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
+++ /dev/null
-/*
- * arch/arm/plat-omap/include/mach/gpioexpander.h
- *
- *
- * Copyright (C) 2004 Texas Instruments, Inc.
- *
- * This package is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
-#ifndef __ASM_ARCH_OMAP_GPIOEXPANDER_H
-#define __ASM_ARCH_OMAP_GPIOEXPANDER_H
-
-/* Function Prototypes for GPIO Expander functions */
-
-#ifdef CONFIG_GPIOEXPANDER_OMAP
-int read_gpio_expa(u8 *, int);
-int write_gpio_expa(u8 , int);
-#else
-static inline int read_gpio_expa(u8 *val, int addr)
-{
- return 0;
-}
-static inline int write_gpio_expa(u8 val, int addr)
-{
- return 0;
-}
-#endif
-
-#endif /* __ASM_ARCH_OMAP_GPIOEXPANDER_H */
#define GPMC_CS_NAND_ADDRESS 0x20
#define GPMC_CS_NAND_DATA 0x24
+/*
+ * The following gpmc registers are being used by
+ * nand driver and hence is defined here.
+ * TBD: Move them to gpmc.c by providing appropriate
+ * methods to read and write into these registers
+ */
+#define GPMC_IRQSTATUS 0x18
#define GPMC_CONFIG 0x50
#define GPMC_STATUS 0x54
+#define GPMC_CS0_BASE 0x60
+#define GPMC_CS_SIZE 0x30
+
#define GPMC_CONFIG1_WRAPBURST_SUPP (1 << 31)
#define GPMC_CONFIG1_READMULTIPLE_SUPP (1 << 30)
extern void gpmc_cs_free(int cs);
extern int gpmc_cs_set_reserved(int cs, int reserved);
extern int gpmc_cs_reserved(int cs);
-extern void gpmc_init(void);
+extern void __init gpmc_init(void);
#endif
#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_OMAP2EVM
+#include "board-omap2evm.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
#define omap_writew(v,a) __raw_writew(v, IO_ADDRESS(a))
#define omap_writel(v,a) __raw_writel(v, IO_ADDRESS(a))
+struct omap_sdrc_params;
+
extern void omap1_map_common_io(void);
extern void omap1_init_common_hw(void);
extern void omap2_map_common_io(void);
-extern void omap2_init_common_hw(void);
+extern void omap2_init_common_hw(struct omap_sdrc_params *sp);
#define __arch_ioremap(p,s,t) omap_ioremap(p,s,t)
#define __arch_iounmap(v) omap_iounmap(v)
#define INT_34XX_MMC3_IRQ 94
#define INT_34XX_GPT12_IRQ 95
-#define INT_34XX_BENCH_MPU_EMUL 3
-
/* Max. 128 level 2 IRQs (OMAP1610), 192 GPIOs (OMAP730) and
* 16 MPUIO lines */
#define OMAP_MAX_GPIO_LINES 192
#ifndef __ASSEMBLY__
extern void omap_init_irq(void);
+extern int omap_irq_pending(void);
#endif
#include <mach/hardware.h>
int rows;
int cols;
int *keymap;
+ int irq;
unsigned int keymapsize;
unsigned int rep:1;
unsigned long delay;
#define GROUP_3 (3 << 16)
#define GROUP_MASK GROUP_3
+#define ROWCOL_MASK 0xFF000000
+#define KEY_PERSISTENT 0x00800000
+#define KEYNUM_MASK 0x00EFFFFF
#define KEY(col, row, val) (((col) << 28) | ((row) << 24) | (val))
+#define PERSISTENT_KEY(col, row) (((col) << 28) | ((row) << 24) | \
+ KEY_PERSISTENT)
#endif
void (*disable_irq)(struct omap_mbox *mbox, omap_mbox_irq_t irq);
void (*ack_irq)(struct omap_mbox *mbox, omap_mbox_irq_t irq);
int (*is_irq)(struct omap_mbox *mbox, omap_mbox_irq_t irq);
+ /* ctx */
+ void (*save_ctx)(struct omap_mbox *mbox);
+ void (*restore_ctx)(struct omap_mbox *mbox);
};
struct omap_mbox_queue {
mbox_msg_t seq_snd, seq_rcv;
- struct device dev;
+ struct device *dev;
struct omap_mbox *next;
void *priv;
struct omap_mbox *omap_mbox_get(const char *);
void omap_mbox_put(struct omap_mbox *);
-int omap_mbox_register(struct omap_mbox *);
+int omap_mbox_register(struct device *parent, struct omap_mbox *);
int omap_mbox_unregister(struct omap_mbox *);
+static inline void omap_mbox_save_ctx(struct omap_mbox *mbox)
+{
+ if (!mbox->ops->save_ctx) {
+ dev_err(mbox->dev, "%s:\tno save\n", __func__);
+ return;
+ }
+
+ mbox->ops->save_ctx(mbox);
+}
+
+static inline void omap_mbox_restore_ctx(struct omap_mbox *mbox)
+{
+ if (!mbox->ops->restore_ctx) {
+ dev_err(mbox->dev, "%s:\tno restore\n", __func__);
+ return;
+ }
+
+ mbox->ops->restore_ctx(mbox);
+}
+
#endif /* MAILBOX_H */
#define OMAP_MCBSP_REG_XCERG 0x3A
#define OMAP_MCBSP_REG_XCERH 0x3C
+/* Dummy defines, these are not available on omap1 */
+#define OMAP_MCBSP_REG_XCCR 0x00
+#define OMAP_MCBSP_REG_RCCR 0x00
+
#define AUDIO_MCBSP_DATAWRITE (OMAP1510_MCBSP1_BASE + OMAP_MCBSP_REG_DXR1)
#define AUDIO_MCBSP_DATAREAD (OMAP1510_MCBSP1_BASE + OMAP_MCBSP_REG_DRR1)
#define XPBBLK(value) ((value)<<7) /* Bits 7:8 */
/*********************** McBSP XCCR bit definitions *************************/
+#define EXTCLKGATE 0x8000
+#define PPCONNECT 0x4000
+#define DXENDLY(value) ((value)<<12) /* Bits 12:13 */
+#define XFULL_CYCLE 0x0800
#define DILB 0x0020
#define XDMAEN 0x0008
#define XDISABLE 0x0001
/********************** McBSP RCCR bit definitions *************************/
+#define RFULL_CYCLE 0x0800
#define RDMAEN 0x0008
#define RDISABLE 0x0001
u16 rcerh;
u16 xcerg;
u16 xcerh;
+ u16 xccr;
+ u16 rccr;
};
typedef enum {
--- /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 */
*/
AH8_34XX_GPIO29,
J25_34XX_GPIO170,
+ AF26_34XX_GPIO0,
+ AF22_34XX_GPIO9,
+ AF6_34XX_GPIO140_UP,
+ AE6_34XX_GPIO141,
+ AF5_34XX_GPIO142,
+ AE5_34XX_GPIO143
};
struct omap_mux_cfg {
#include <sound/pcm.h>
#include <mach/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 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 OMAP34XX_SR1_BASE 0x480C9000
+#define OMAP34XX_SR2_BASE 0x480CB000
+
+#define OMAP34XX_CAMERA_BASE (L4_34XX_BASE + 0xBC000)
+#define OMAP34XX_MAILBOX_BASE (L4_34XX_BASE + 0x94000)
#if defined(CONFIG_ARCH_OMAP3430)
void *fbi);
struct omapfb_mem_region {
- dma_addr_t paddr;
- void *vaddr;
+ u32 paddr;
+ void __iomem *vaddr;
unsigned long size;
u8 type; /* OMAPFB_PLANE_MEM_* */
unsigned alloc:1; /* allocated by the driver */
#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);
extern void omap24xx_cpu_suspend(u32 dll_ctrl, void __iomem *sdrc_dlla_ctrl,
void __iomem *sdrc_power);
+extern void omap34xx_cpu_suspend(u32 *addr, int save_state);
extern void omap730_idle_loop_suspend(void);
extern void omap1510_idle_loop_suspend(void);
extern void omap1610_idle_loop_suspend(void);
extern unsigned int omap1510_cpu_suspend_sz;
extern unsigned int omap1610_cpu_suspend_sz;
extern unsigned int omap24xx_cpu_suspend_sz;
+extern unsigned int omap34xx_cpu_suspend_sz;
extern unsigned int omap730_idle_loop_suspend_sz;
extern unsigned int omap1510_idle_loop_suspend_sz;
extern unsigned int omap1610_idle_loop_suspend_sz;
extern unsigned int omap24xx_idle_loop_suspend_sz;
+extern unsigned int omap34xx_suspend_sz;
#ifdef CONFIG_OMAP_SERIAL_WAKE
extern void omap_serial_wake_trigger(int enable);
#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 */
/*
* Maximum number of clockdomains that can be associated with a powerdomain.
- * CORE powerdomain is probably the worst case.
+ * CORE powerdomain on OMAP3 is the worst case
*/
-#define PWRDM_MAX_CLKDMS 3
+#define PWRDM_MAX_CLKDMS 4
/* XXX A completely arbitrary number. What is reasonable here? */
#define PWRDM_TRANSITION_BAILOUT 100000
int pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst);
int pwrdm_read_next_pwrst(struct powerdomain *pwrdm);
+int pwrdm_read_pwrst(struct powerdomain *pwrdm);
int pwrdm_read_prev_pwrst(struct powerdomain *pwrdm);
int pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm);
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#ifndef __ASM_ARM_ARCH_DPM_PRCM_H
-#define __ASM_ARM_ARCH_DPM_PRCM_H
+#ifndef __ASM_ARM_ARCH_OMAP_PRCM_H
+#define __ASM_ARM_ARCH_OMAP_PRCM_H
u32 omap_prcm_get_reset_sources(void);
+void omap_prcm_arch_reset(char mode);
+
+void cm_write_mod_reg(u32 val, s16 module, u16 idx);
+u32 cm_read_mod_reg(s16 module, u16 idx);
+u32 cm_rmw_mod_reg_bits(u32 mask, u32 bits, s16 module, s16 idx);
#endif
/*
* OMAP2/3 SDRC/SMS 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
+ * Tony Lindgren
+ * Paul Walmsley
+ * Richard Woodruff
*
* 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
/* SDRC register offsets - read/write with sdrc_{read,write}_reg() */
#define SDRC_SYSCONFIG 0x010
+#define SDRC_CS_CFG 0x040
+#define SDRC_SHARING 0x044
+#define SDRC_ERR_TYPE 0x04C
#define SDRC_DLLA_CTRL 0x060
#define SDRC_DLLA_STATUS 0x064
#define SDRC_DLLB_CTRL 0x068
#define SDRC_DLLB_STATUS 0x06C
#define SDRC_POWER 0x070
+#define SDRC_MCFG_0 0x080
#define SDRC_MR_0 0x084
#define SDRC_ACTIM_CTRL_A_0 0x09c
#define SDRC_ACTIM_CTRL_B_0 0x0a0
#define SDRC_RFR_CTRL_0 0x0a4
+#define SDRC_MCFG_1 0x0B0
+#define SDRC_MR_1 0x0B4
+#define SDRC_ACTIM_CTRL_A_1 0x0C4
+#define SDRC_ACTIM_CTRL_B_1 0x0C8
+#define SDRC_RFR_CTRL_1 0x0D4
/*
* These values represent the number of memory clock cycles between
* SMS register access
*/
-
#define OMAP242X_SMS_REGADDR(reg) IO_ADDRESS(OMAP2420_SMS_BASE + reg)
#define OMAP243X_SMS_REGADDR(reg) IO_ADDRESS(OMAP243X_SMS_BASE + reg)
#define OMAP343X_SMS_REGADDR(reg) IO_ADDRESS(OMAP343X_SMS_BASE + reg)
#define SMS_SYSCONFIG 0x010
/* REVISIT: fill in other SMS registers here */
+
+#ifndef __ASSEMBLER__
+
+/**
+ * struct omap_sdrc_params - SDRC parameters for a given SDRC clock rate
+ * @rate: SDRC clock rate (in Hz)
+ * @actim_ctrla: Value to program to SDRC_ACTIM_CTRLA for this rate
+ * @actim_ctrlb: Value to program to SDRC_ACTIM_CTRLB for this rate
+ * @rfr_ctrl: Value to program to SDRC_RFR_CTRL for this rate
+ * @mr: Value to program to SDRC_MR for this rate
+ *
+ * This structure holds a pre-computed set of register values for the
+ * SDRC for a given SDRC clock rate and SDRAM chip. These are
+ * intended to be pre-computed and specified in an array in the board-*.c
+ * files. The structure is keyed off the 'rate' field.
+ */
+struct omap_sdrc_params {
+ unsigned long rate;
+ u32 actim_ctrla;
+ u32 actim_ctrlb;
+ u32 rfr_ctrl;
+ u32 mr;
+};
+
+void __init omap2_sdrc_init(struct omap_sdrc_params *);
+struct omap_sdrc_params *omap2_sdrc_get_params(unsigned long r);
+
+#ifdef CONFIG_ARCH_OMAP2
+
+struct memory_timings {
+ u32 m_type; /* ddr = 1, sdr = 0 */
+ u32 dll_mode; /* use lock mode = 1, unlock mode = 0 */
+ u32 slow_dll_ctrl; /* unlock mode, dll value for slow speed */
+ u32 fast_dll_ctrl; /* unlock mode, dll value for fast speed */
+ u32 base_cs; /* base chip select to use for calculations */
+};
+
+extern void omap2xxx_sdrc_init_params(u32 force_lock_to_unlock_mode);
+
+u32 omap2xxx_sdrc_dll_is_unlocked(void);
+u32 omap2xxx_sdrc_reprogram(u32 level, u32 force);
+
+#endif /* CONFIG_ARCH_OMAP2 */
+
+#endif /* __ASSEMBLER__ */
+
#endif
__ret; \
})
+#ifndef __ASSEMBLER__
+extern void omap_serial_init(void);
+extern int omap_uart_can_sleep(void);
+extern void omap_uart_check_wakeup(void);
+extern void omap_uart_prepare_suspend(void);
+extern void omap_uart_prepare_idle(int num);
+extern void omap_uart_resume_idle(int num);
+#endif
+
#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 void __iomem *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 */
#include <asm/mach-types.h>
#include <mach/hardware.h>
+#include <mach/prcm.h>
+
#ifndef CONFIG_MACH_VOICEBLUE
#define voiceblue_reset() do {} while (0)
#endif
-extern void omap_prcm_arch_reset(char mode);
-
static inline void arch_idle(void)
{
cpu_do_idle();
#define CLOCK_TICK_RATE (HZ * 100000UL)
#endif
+extern struct sys_timer omap_timer;
+
#endif /* __ASM_ARCH_OMAP_TIMEX_H */
--- /dev/null
+/*
+ * arch/arm/plat-omap/include/mach/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
+/*
+ * arch/arm/plat-omap/include/mach/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 */
+
#define UDC_BASE OMAP2_UDC_BASE
#define OMAP_OHCI_BASE OMAP2_OHCI_BASE
+void __init usb_musb_init(void);
+void __init usb_ehci_init(void);
+
#endif
/*-------------------------------------------------------------------------*/
* 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 + 0x18000000)
/*
* OMAP mailbox driver
*
- * Copyright (C) 2006 Nokia Corporation. All rights reserved.
+ * Copyright (C) 2006-2008 Nokia Corporation. All rights reserved.
*
- * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
- * Restructured by Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
+ * 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
*
*/
-#include <linux/init.h>
#include <linux/module.h>
-#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/device.h>
-#include <linux/blkdev.h>
-#include <linux/err.h>
#include <linux/delay.h>
-#include <linux/io.h>
+
#include <mach/mailbox.h>
-#include "mailbox.h"
+
+static int enable_seq_bit;
+module_param(enable_seq_bit, bool, 0);
+MODULE_PARM_DESC(enable_seq_bit, "Enable sequence bit checking.");
static struct omap_mbox *mboxes;
static DEFINE_RWLOCK(mboxes_lock);
+/*
+ * Mailbox sequence bit API
+ */
+
+/* seq_rcv should be initialized with any value other than
+ * 0 and 1 << 31, to allow either value for the first
+ * message. */
+static inline void mbox_seq_init(struct omap_mbox *mbox)
+{
+ if (!enable_seq_bit)
+ return;
+
+ /* any value other than 0 and 1 << 31 */
+ mbox->seq_rcv = 0xffffffff;
+}
+
+static inline void mbox_seq_toggle(struct omap_mbox *mbox, mbox_msg_t * msg)
+{
+ if (!enable_seq_bit)
+ return;
+
+ /* add seq_snd to msg */
+ *msg = (*msg & 0x7fffffff) | mbox->seq_snd;
+ /* flip seq_snd */
+ mbox->seq_snd ^= 1 << 31;
+}
+
+static inline int mbox_seq_test(struct omap_mbox *mbox, mbox_msg_t msg)
+{
+ mbox_msg_t seq;
+
+ if (!enable_seq_bit)
+ return 0;
+
+ seq = msg & (1 << 31);
+ if (seq == mbox->seq_rcv)
+ return -1;
+ mbox->seq_rcv = seq;
+ return 0;
+}
+
+/* Mailbox FIFO handle functions */
+static inline mbox_msg_t mbox_fifo_read(struct omap_mbox *mbox)
+{
+ return mbox->ops->fifo_read(mbox);
+}
+static inline void mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg)
+{
+ mbox->ops->fifo_write(mbox, msg);
+}
+static inline int mbox_fifo_empty(struct omap_mbox *mbox)
+{
+ return mbox->ops->fifo_empty(mbox);
+}
+static inline int mbox_fifo_full(struct omap_mbox *mbox)
+{
+ return mbox->ops->fifo_full(mbox);
+}
+
+/* Mailbox IRQ handle functions */
+static inline void enable_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
+{
+ mbox->ops->enable_irq(mbox, irq);
+}
+static inline void disable_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
+{
+ mbox->ops->disable_irq(mbox, irq);
+}
+static inline void ack_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
+{
+ if (mbox->ops->ack_irq)
+ mbox->ops->ack_irq(mbox, irq);
+}
+static inline int is_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
+{
+ return mbox->ops->is_irq(mbox, irq);
+}
+
/* Mailbox Sequence Bit function */
void omap_mbox_init_seq(struct omap_mbox *mbox)
{
unsigned long flags;
if (mbox->rxq->callback == NULL) {
- sysfs_notify(&mbox->dev.kobj, NULL, "mbox");
+ sysfs_notify(&mbox->dev->kobj, NULL, "mbox");
return;
}
/* no more messages in the fifo. clear IRQ source. */
ack_mbox_irq(mbox, IRQ_RX);
enable_mbox_irq(mbox, IRQ_RX);
- nomem:
+nomem:
schedule_work(&mbox->rxq->work);
}
static CLASS_ATTR(mbox, S_IRUGO, mbox_show, NULL);
static struct class omap_mbox_class = {
- .name = "omap_mbox",
+ .name = "omap-mailbox",
};
static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox,
return ret;
}
- mbox->dev.class = &omap_mbox_class;
- dev_set_name(&mbox->dev, "%s", mbox->name);
- dev_set_drvdata(&mbox->dev, mbox);
-
- ret = device_register(&mbox->dev);
- if (unlikely(ret))
- goto fail_device_reg;
-
- ret = device_create_file(&mbox->dev, &dev_attr_mbox);
- if (unlikely(ret)) {
- printk(KERN_ERR
- "device_create_file failed: %d\n", ret);
- goto fail_create_mbox;
- }
-
ret = request_irq(mbox->irq, mbox_interrupt, IRQF_DISABLED,
mbox->name, mbox);
if (unlikely(ret)) {
fail_alloc_txq:
free_irq(mbox->irq, mbox);
fail_request_irq:
- device_remove_file(&mbox->dev, &dev_attr_mbox);
- fail_create_mbox:
- device_unregister(&mbox->dev);
- fail_device_reg:
if (unlikely(mbox->ops->shutdown))
mbox->ops->shutdown(mbox);
mbox_queue_free(mbox->rxq);
free_irq(mbox->irq, mbox);
- device_remove_file(&mbox->dev, &dev_attr_mbox);
- class_unregister(&omap_mbox_class);
if (unlikely(mbox->ops->shutdown))
mbox->ops->shutdown(mbox);
}
EXPORT_SYMBOL(omap_mbox_put);
-int omap_mbox_register(struct omap_mbox *mbox)
+int omap_mbox_register(struct device *parent, struct omap_mbox *mbox)
{
int ret = 0;
struct omap_mbox **tmp;
if (mbox->next)
return -EBUSY;
+ mbox->dev = device_create(&omap_mbox_class,
+ parent, 0, mbox, "%s", mbox->name);
+ if (IS_ERR(mbox->dev))
+ return PTR_ERR(mbox->dev);
+
+ ret = device_create_file(mbox->dev, &dev_attr_mbox);
+ if (ret)
+ goto err_sysfs;
+
write_lock(&mboxes_lock);
tmp = find_mboxes(mbox->name);
- if (*tmp)
+ if (*tmp) {
ret = -EBUSY;
- else
- *tmp = mbox;
+ write_unlock(&mboxes_lock);
+ goto err_find;
+ }
+ *tmp = mbox;
write_unlock(&mboxes_lock);
+ return 0;
+
+err_find:
+ device_remove_file(mbox->dev, &dev_attr_mbox);
+err_sysfs:
+ device_unregister(mbox->dev);
return ret;
}
EXPORT_SYMBOL(omap_mbox_register);
*tmp = mbox->next;
mbox->next = NULL;
write_unlock(&mboxes_lock);
+ device_remove_file(mbox->dev, &dev_attr_mbox);
+ device_unregister(mbox->dev);
return 0;
}
tmp = &(*tmp)->next;
subsys_initcall(omap_mbox_class_init);
module_exit(omap_mbox_class_exit);
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("omap mailbox: interrupt driven messaging");
+MODULE_AUTHOR("Toshihiro Kobayashi and Hiroshi DOYU");
+++ /dev/null
-/*
- * Mailbox internal functions
- *
- * Copyright (C) 2006 Nokia Corporation
- * Written by: Hiroshi DOYU <Hiroshi.DOYU@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.
- */
-
-#ifndef __ARCH_ARM_PLAT_MAILBOX_H
-#define __ARCH_ARM_PLAT_MAILBOX_H
-
-/*
- * Mailbox sequence bit API
- */
-#if defined(CONFIG_ARCH_OMAP1)
-# define MBOX_USE_SEQ_BIT
-#elif defined(CONFIG_ARCH_OMAP2)
-# define MBOX_USE_SEQ_BIT
-#endif
-
-#ifdef MBOX_USE_SEQ_BIT
-/* seq_rcv should be initialized with any value other than
- * 0 and 1 << 31, to allow either value for the first
- * message. */
-static inline void mbox_seq_init(struct omap_mbox *mbox)
-{
- /* any value other than 0 and 1 << 31 */
- mbox->seq_rcv = 0xffffffff;
-}
-
-static inline void mbox_seq_toggle(struct omap_mbox *mbox, mbox_msg_t * msg)
-{
- /* add seq_snd to msg */
- *msg = (*msg & 0x7fffffff) | mbox->seq_snd;
- /* flip seq_snd */
- mbox->seq_snd ^= 1 << 31;
-}
-
-static inline int mbox_seq_test(struct omap_mbox *mbox, mbox_msg_t msg)
-{
- mbox_msg_t seq = msg & (1 << 31);
- if (seq == mbox->seq_rcv)
- return -1;
- mbox->seq_rcv = seq;
- return 0;
-}
-#else
-static inline void mbox_seq_init(struct omap_mbox *mbox)
-{
-}
-static inline void mbox_seq_toggle(struct omap_mbox *mbox, mbox_msg_t * msg)
-{
-}
-static inline int mbox_seq_test(struct omap_mbox *mbox, mbox_msg_t msg)
-{
- return 0;
-}
-#endif
-
-/* Mailbox FIFO handle functions */
-static inline mbox_msg_t mbox_fifo_read(struct omap_mbox *mbox)
-{
- return mbox->ops->fifo_read(mbox);
-}
-static inline void mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg)
-{
- mbox->ops->fifo_write(mbox, msg);
-}
-static inline int mbox_fifo_empty(struct omap_mbox *mbox)
-{
- return mbox->ops->fifo_empty(mbox);
-}
-static inline int mbox_fifo_full(struct omap_mbox *mbox)
-{
- return mbox->ops->fifo_full(mbox);
-}
-
-/* Mailbox IRQ handle functions */
-static inline void enable_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
-{
- mbox->ops->enable_irq(mbox, irq);
-}
-static inline void disable_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
-{
- mbox->ops->disable_irq(mbox, irq);
-}
-static inline void ack_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
-{
- if (mbox->ops->ack_irq)
- mbox->ops->ack_irq(mbox, irq);
-}
-static inline int is_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
-{
- return mbox->ops->is_irq(mbox, irq);
-}
-
-#endif /* __ARCH_ARM_PLAT_MAILBOX_H */
OMAP_MCBSP_WRITE(io_base, MCR2, config->mcr2);
OMAP_MCBSP_WRITE(io_base, MCR1, config->mcr1);
OMAP_MCBSP_WRITE(io_base, PCR0, config->pcr0);
+ if (cpu_is_omap2430() || cpu_is_omap34xx()) {
+ OMAP_MCBSP_WRITE(io_base, XCCR, config->xccr);
+ OMAP_MCBSP_WRITE(io_base, RCCR, config->rccr);
+ }
}
EXPORT_SYMBOL(omap_mcbsp_config);
--- /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 <linux/uaccess.h>
+#include <linux/io.h>
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+#include <mach/mmu.h>
+#include <asm/sizes.h>
+#include <mach/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, __func__);
+ 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");
#define OMAP1_SRAM_VA VMALLOC_END
#define OMAP2_SRAM_PA 0x40200000
#define OMAP2_SRAM_PUB_PA 0x4020f800
-#define OMAP2_SRAM_VA VMALLOC_END
-#define OMAP2_SRAM_PUB_VA (VMALLOC_END + 0x800)
+#define OMAP2_SRAM_VA 0xe3000000
+#define OMAP2_SRAM_PUB_VA (OMAP2_SRAM_VA + 0x800)
#define OMAP3_SRAM_PA 0x40200000
#define OMAP3_SRAM_VA 0xd7000000
#define OMAP3_SRAM_PUB_PA 0x40208000
u32 m2);
u32 omap3_configure_core_dpll(u32 sdrc_rfr_ctrl, u32 sdrc_actim_ctrla,
u32 sdrc_actim_ctrlb, u32 m2)
-{
+ {
if (!_omap3_sram_configure_core_dpll)
omap_sram_error();
return _omap3_sram_configure_core_dpll(sdrc_rfr_ctrl,
sdrc_actim_ctrla,
sdrc_actim_ctrlb, m2);
-}
+ }
/* REVISIT: Should this be same as omap34xx_sram_init() after off-idle? */
void restore_sram_functions(void)
omap3_sram_configure_core_dpll_sz);
}
-int __init omap34xx_sram_init(void)
+int __init omap3_sram_init(void)
{
_omap3_sram_configure_core_dpll =
omap_sram_push(omap3_sram_configure_core_dpll,
return 0;
}
#else
-static inline int omap34xx_sram_init(void)
+static inline int omap3_sram_init(void)
{
return 0;
}
else if (cpu_is_omap2430())
omap243x_sram_init();
else if (cpu_is_omap34xx())
- omap34xx_sram_init();
+ omap3_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_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 <linux/gpio.h>
+
+#include <mach/hardware.h>
+#include <mach/board.h>
+#include <mach/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;
+ gpio_set_value(info->btinfo->bt_wakeup_gpio, 1);
+ }
+ if (gpio_get_value(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))
+ gpio_set_value(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 = gpio_get_value(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)
+{
+ gpio_set_value(info->btinfo->bt_wakeup_gpio, 0);
+ gpio_set_value(info->btinfo->reset_gpio, 0);
+ current->state = TASK_UNINTERRUPTIBLE;
+ schedule_timeout(msecs_to_jiffies(10));
+ gpio_set_value(info->btinfo->bt_wakeup_gpio, 1);
+ current->state = TASK_UNINTERRUPTIBLE;
+ schedule_timeout(msecs_to_jiffies(100));
+ gpio_set_value(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(gpio_to_irq(info->btinfo->host_wakeup_gpio), IRQ_TYPE_NONE);
+ 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(gpio_to_irq(info->btinfo->host_wakeup_gpio), IRQ_TYPE_EDGE_BOTH);
+ 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);
+ gpio_set_value(info->btinfo->bt_wakeup_gpio, 0);
+ set_irq_type(gpio_to_irq(info->btinfo->host_wakeup_gpio), IRQ_TYPE_NONE);
+
+ 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 = gpio_request(info->btinfo->reset_gpio, "BT reset");
+ if (err < 0)
+ {
+ printk(KERN_WARNING "Cannot get GPIO line %d",
+ info->btinfo->reset_gpio);
+ kfree(info);
+ return err;
+ }
+
+ err = gpio_request(info->btinfo->bt_wakeup_gpio, "BT wakeup");
+ if (err < 0)
+ {
+ printk(KERN_WARNING "Cannot get GPIO line 0x%d",
+ info->btinfo->bt_wakeup_gpio);
+ gpio_free(info->btinfo->reset_gpio);
+ kfree(info);
+ return err;
+ }
+
+ err = gpio_request(info->btinfo->host_wakeup_gpio, "BT host wakeup");
+ if (err < 0)
+ {
+ printk(KERN_WARNING "Cannot get GPIO line %d",
+ info->btinfo->host_wakeup_gpio);
+ gpio_free(info->btinfo->reset_gpio);
+ gpio_free(info->btinfo->bt_wakeup_gpio);
+ kfree(info);
+ return err;
+ }
+
+ gpio_direction_output(info->btinfo->reset_gpio, 0);
+ gpio_direction_output(info->btinfo->bt_wakeup_gpio, 0);
+ gpio_direction_input(info->btinfo->host_wakeup_gpio);
+ set_irq_type(gpio_to_irq(info->btinfo->host_wakeup_gpio), IRQ_TYPE_NONE);
+
+ switch (info->btinfo->bt_uart) {
+ case 1:
+ irq = INT_UART1;
+ info->uart_ck = clk_get(NULL, "uart1_ck");
+ /* FIXME: Use platform_get_resource for the port */
+ info->uart_base = ioremap(OMAP_UART1_BASE, 0x16);
+ if (!info->uart_base)
+ goto cleanup;
+ break;
+ case 2:
+ irq = INT_UART2;
+ info->uart_ck = clk_get(NULL, "uart2_ck");
+ /* FIXME: Use platform_get_resource for the port */
+ info->uart_base = ioremap(OMAP_UART2_BASE, 0x16);
+ if (!info->uart_base)
+ goto cleanup;
+ break;
+ case 3:
+ irq = INT_UART3;
+ info->uart_ck = clk_get(NULL, "uart3_ck");
+ /* FIXME: Use platform_get_resource for the port */
+ info->uart_base = ioremap(OMAP_UART3_BASE, 0x16);
+ if (!info->uart_base)
+ goto cleanup;
+ 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(gpio_to_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",
+ gpio_to_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(gpio_to_irq(info->btinfo->host_wakeup_gpio), (void *)info);
+cleanup:
+ gpio_free(info->btinfo->reset_gpio);
+ gpio_free(info->btinfo->bt_wakeup_gpio);
+ gpio_free(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);
+ gpio_free(exit_info->btinfo->reset_gpio);
+ gpio_free(exit_info->btinfo->bt_wakeup_gpio);
+ gpio_free(exit_info->btinfo->host_wakeup_gpio);
+ free_irq(exit_info->irq, (void *)exit_info);
+ free_irq(gpio_to_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 <mach/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 <linux/gpio.h>
+
+#include <mach/hardware.h>
+#include <mach/board.h>
+#include <mach/irqs.h>
+#include <mach/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);
+ gpio_set_value(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) {
+ gpio_set_value(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 = gpio_get_value(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);
+
+ gpio_set_value(info->reset_gpio, 0);
+ msleep(100);
+ gpio_set_value(info->bt_wakeup_gpio, 1);
+ gpio_set_value(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);
+ gpio_set_value(info->reset_gpio, 0);
+ gpio_set_value(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);
+ gpio_set_value(info->reset_gpio, 0);
+ gpio_set_value(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 = gpio_request(info->reset_gpio, "BT reset");
+ if (err < 0) {
+ dev_err(&pdev->dev, "Cannot get GPIO line %d\n",
+ info->reset_gpio);
+ kfree(info);
+ goto cleanup;
+ }
+
+ err = gpio_request(info->bt_wakeup_gpio, "BT wakeup");
+ if (err < 0)
+ {
+ dev_err(info->dev, "Cannot get GPIO line 0x%d",
+ info->bt_wakeup_gpio);
+ gpio_free(info->reset_gpio);
+ kfree(info);
+ goto cleanup;
+ }
+
+ err = gpio_request(info->host_wakeup_gpio, "BT host wakeup");
+ if (err < 0)
+ {
+ dev_err(info->dev, "Cannot get GPIO line %d",
+ info->host_wakeup_gpio);
+ gpio_free(info->reset_gpio);
+ gpio_free(info->bt_wakeup_gpio);
+ kfree(info);
+ goto cleanup;
+ }
+
+ gpio_direction_output(info->reset_gpio, 0);
+ gpio_direction_output(info->bt_wakeup_gpio, 0);
+ gpio_direction_input(info->host_wakeup_gpio);
+
+ 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");
+ }
+ /* FIXME: Use platform_get_resource for the port */
+ info->uart_base = ioremap(OMAP_UART1_BASE, 0x16);
+ if (!info->uart_base)
+ goto cleanup;
+ 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");
+ }
+ /* FIXME: Use platform_get_resource for the port */
+ info->uart_base = ioremap(OMAP_UART2_BASE, 0x16);
+ if (!info->uart_base)
+ goto cleanup;
+ 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");
+ }
+ /* FIXME: Use platform_get_resource for the port */
+ info->uart_base = ioremap(OMAP_UART3_BASE, 0x16);
+ if (!info->uart_base)
+ goto cleanup;
+ 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(gpio_to_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",
+ gpio_to_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;
+ }
+ gpio_set_value(info->reset_gpio, 0);
+
+ return 0;
+
+cleanup_irq:
+ free_irq(irq, (void *)info);
+ free_irq(gpio_to_irq(info->host_wakeup_gpio), (void *)info);
+cleanup:
+ gpio_set_value(info->reset_gpio, 0);
+ gpio_free(info->reset_gpio);
+ gpio_free(info->bt_wakeup_gpio);
+ gpio_free(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(gpio_to_irq(info->host_wakeup_gpio), (void *) info);
+ hci_free_dev(info->hdev);
+ gpio_free(info->reset_gpio);
+ gpio_free(info->bt_wakeup_gpio);
+ gpio_free(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 <mach/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 <linux/gpio.h>
+
+#include <mach/board.h>
+#include <mach/board-nokia.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;
+}
+
+#define cbus_output(base, gpio, val) cbus_set_gpio_direction(base, gpio, 0)
+
+#else
+
+#define cbus_output(base, gpio, val) gpio_direction_output(gpio, val)
+#define cbus_set_gpio_dataout(base, gpio, enable) gpio_set_value(gpio, enable)
+#define cbus_get_gpio_datain(base, int, gpio) gpio_get_value(gpio)
+
+static void _cbus_send_bit(struct cbus_host *host, int bit, int set_to_input)
+{
+ gpio_set_value(host->dat_gpio, bit ? 1 : 0);
+ gpio_set_value(host->clk_gpio, 1);
+
+ /* The data bit is read on the rising edge of CLK */
+ if (set_to_input)
+ gpio_direction_input(host->dat_gpio);
+
+ gpio_set_value(host->clk_gpio, 0);
+}
+
+static u8 _cbus_receive_bit(struct cbus_host *host)
+{
+ u8 ret;
+
+ gpio_set_value(host->clk_gpio, 1);
+ ret = gpio_get_value(host->dat_gpio);
+ gpio_set_value(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 = OMAP1_IO_ADDRESS(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_output(base, host->dat_gpio, 1);
+
+ /* 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 = gpio_request(chost->clk_gpio, "CBUS clk")) < 0)
+ goto exit1;
+
+ if ((ret = gpio_request(chost->dat_gpio, "CBUS data")) < 0)
+ goto exit2;
+
+ if ((ret = gpio_request(chost->sel_gpio, "CBUS sel")) < 0)
+ goto exit3;
+
+ gpio_direction_output(chost->clk_gpio, 0);
+ gpio_direction_input(chost->dat_gpio);
+ gpio_direction_output(chost->sel_gpio, 1);
+
+ gpio_set_value(chost->clk_gpio, 1);
+ gpio_set_value(chost->clk_gpio, 0);
+
+ cbus_host = chost;
+
+ return 0;
+exit3:
+ gpio_free(chost->dat_gpio);
+exit2:
+ gpio_free(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 DEFINE_MUTEX(retu_wdt_mutex);
+
+/* Current period of watchdog */
+static unsigned int period_val = RETU_WDT_DEFAULT_TIMER;
+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;
+
+ mutex_lock(&retu_wdt_mutex);
+
+ period_val = new;
+ retu_write_reg(RETU_REG_WATCHDOG, (u16)period_val);
+
+ mutex_unlock(&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 <linux/gpio.h>
+
+#include <asm/uaccess.h>
+
+#include <mach/mux.h>
+#include <mach/board.h>
+#include <mach/board-nokia.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);
+
+ if ((channel == 8) && retu_is_vilma) {
+ int scr = retu_read_reg(RETU_REG_ADCSCR);
+ int ch = (retu_read_reg(RETU_REG_ADCR) >> 10) & 0xf;
+ if (((scr & 0xff) != 0) && (ch != 8))
+ retu_write_reg (RETU_REG_ADCSCR, (scr & ~0xff));
+ }
+
+ /* Select the channel and read result */
+ retu_write_reg(RETU_REG_ADCR, channel << 10);
+ res = retu_read_reg(RETU_REG_ADCR) & 0x3ff;
+
+ if (retu_is_vilma)
+ retu_write_reg(RETU_REG_ADCR, (1 << 13));
+
+ /* 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 = gpio_request(retu_irq_pin, "RETU irq")) < 0) {
+ printk(KERN_ERR PFX "Unable to reserve IRQ GPIO\n");
+ return ret;
+ }
+
+ /* Set the pin as input */
+ gpio_direction_input(retu_irq_pin);
+
+ /* Rising edge triggers the IRQ */
+ set_irq_type(gpio_to_irq(retu_irq_pin), IRQ_TYPE_EDGE_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(gpio_to_irq(retu_irq_pin), retu_irq_handler, 0,
+ "retu", 0);
+ if (ret < 0) {
+ printk(KERN_ERR PFX "Unable to register IRQ handler\n");
+ gpio_free(retu_irq_pin);
+ return ret;
+ }
+ set_irq_wake(gpio_to_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(gpio_to_irq(retu_irq_pin), 0);
+ gpio_free(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(gpio_to_irq(retu_irq_pin), 0);
+ gpio_free(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_ADCSCR 0x09 /* ADC sample ctrl */
+#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/io.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 <mach/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 */
+
+/* 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 = omap_readw(OTG_IRQ_SRC);
+ if (otg_irq & OPRT_CHG) {
+ omap_writew(OPRT_CHG, OTG_IRQ_SRC);
+ } else if (otg_irq & B_SRP_TMROUT) {
+ omap_writew(B_SRP_TMROUT, OTG_IRQ_SRC);
+ } else if (otg_irq & B_HNP_FAIL) {
+ omap_writew(B_HNP_FAIL, OTG_IRQ_SRC);
+ } else if (otg_irq & A_SRP_DETECT) {
+ omap_writew(A_SRP_DETECT, OTG_IRQ_SRC);
+ } else if (otg_irq & A_REQ_TMROUT) {
+ omap_writew(A_REQ_TMROUT, OTG_IRQ_SRC);
+ } else if (otg_irq & A_VBUS_ERR) {
+ omap_writew(A_VBUS_ERR, OTG_IRQ_SRC);
+ } else if (otg_irq & DRIVER_SWITCH) {
+ if ((!(omap_readl(OTG_CTRL) & 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);
+ }
+ omap_writew(DRIVER_SWITCH, OTG_IRQ_SRC);
+ } else
+ return IRQ_NONE;
+
+ return IRQ_HANDLED;
+
+}
+
+static int omap_otg_init(void)
+{
+ u32 l;
+
+#ifdef CONFIG_USB_OTG
+ if (!tahvo_otg_dev) {
+ printk("tahvo-usb: no tahvo_otg_dev\n");
+ return -ENODEV;
+ }
+#endif
+
+ l = omap_readl(OTG_SYSCON_1);
+ l &= ~OTG_IDLE_EN;
+ omap_writel(l, OTG_SYSCON_1);
+ udelay(100);
+
+ /* some of these values are board-specific... */
+ l = omap_readl(OTG_SYSCON_2);
+ l |= 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 */
+ omap_writel(l, OTG_SYSCON_2);
+
+ omap_writew(DRIVER_SWITCH | OPRT_CHG
+ | B_SRP_TMROUT | B_HNP_FAIL
+ | A_VBUS_ERR | A_SRP_DETECT | A_REQ_TMROUT,
+ OTG_IRQ_EN);
+ l = omap_readl(OTG_SYSCON_2);
+ l |= OTG_EN;
+ omap_writel(l, OTG_SYSCON_2);
+
+ 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) {
+ u32 l;
+
+ 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. */
+ l = omap_readl(OTG_CTRL);
+ l &= ~OTG_BSESSEND;
+ l |= OTG_BSESSVLD;
+ omap_writel(l, OTG_CTRL);
+
+ 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 = omap_readl(OTG_CTRL);
+ l &= ~(OTG_CTRL_XCVR_MASK | OTG_CTRL_SYS_MASK);
+ l |= OTG_ASESSVLD;
+ omap_writel(l, OTG_CTRL);
+
+ /* 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)
+{
+ u32 l;
+
+ /* Clear system and transceiver controlled bits
+ * and enable ID to mark peripheral mode and
+ * BSESSEND to mark no Vbus */
+ omap_otg_init();
+ l = omap_readl(OTG_CTRL);
+ l &= ~(OTG_CTRL_XCVR_MASK | OTG_CTRL_SYS_MASK | OTG_BSESSVLD);
+ l |= OTG_ID | OTG_BSESSEND;
+ omap_writel(l, OTG_CTRL);
+
+ /* 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)
+{
+ u32 l;
+
+ l = omap_readl(OTG_CTRL);
+ l &= ~OTG_BSESSVLD;
+ l |= OTG_BSESSEND;
+ omap_writel(l, OTG_CTRL);
+
+ 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 = omap_readl(OTG_CTRL);
+ l &= ~(OTG_CTRL_XCVR_MASK | OTG_CTRL_SYS_MASK | OTG_BSESSVLD);
+ l |= id | OTG_BSESSEND;
+ omap_writel(l, OTG_CTRL);
+ omap_writew(0, OTG_IRQ_EN);
+
+ l = omap_readl(OTG_SYSCON_2);
+ l &= ~OTG_EN;
+ omap_writel(l, OTG_SYSCON_2);
+
+ l = omap_readl(OTG_SYSCON_1);
+ l |= OTG_IDLE_EN;
+ omap_writel(l, OTG_SYSCON_1);
+
+ /* 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 = omap_readl(OTG_CTRL);
+ if (!(otg_ctrl & OTG_BSESSEND))
+ return -EINVAL;
+
+ otg_ctrl |= OTG_B_BUSREQ;
+ otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_SYS_MASK;
+ omap_writel(otg_ctrl, 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);
+ u32 l;
+
+ 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;
+ }
+
+ l = omap_readl(OTG_SYSCON_1);
+ l &= ~(OTG_IDLE_EN | HST_IDLE_EN | DEV_IDLE_EN);
+ omap_writel(l, OTG_SYSCON_1);
+
+ 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 <linux/gpio.h>
+
+#include <asm/uaccess.h>
+
+#include <mach/mux.h>
+#include <mach/board.h>
+#include <mach/board-nokia.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 = gpio_request(tahvo_irq_pin, "TAHVO irq")) < 0) {
+ printk(KERN_ERR PFX "Unable to reserve IRQ GPIO\n");
+ return ret;
+ }
+
+ /* Set the pin as input */
+ gpio_direction_input(tahvo_irq_pin);
+
+ /* Rising edge triggers the IRQ */
+ set_irq_type(gpio_to_irq(tahvo_irq_pin), IRQ_TYPE_EDGE_RISING);
+
+ /* Mask all TAHVO interrupts */
+ tahvo_write_reg(TAHVO_REG_IMR, 0xffff);
+
+ ret = request_irq(gpio_to_irq(tahvo_irq_pin), tahvo_irq_handler, 0,
+ "tahvo", 0);
+ if (ret < 0) {
+ printk(KERN_ERR PFX "Unable to register IRQ handler\n");
+ gpio_free(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(gpio_to_irq(tahvo_irq_pin), 0);
+ gpio_free(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(gpio_to_irq(tahvo_irq_pin), 0);
+ gpio_free(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
obj-$(CONFIG_CRYPTO_DEV_TALITOS) += talitos.o
obj-$(CONFIG_CRYPTO_DEV_IXP4XX) += ixp4xx_crypto.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 <mach/dsp_common.h>
+#include <mach/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 <mach/dsp_common.h>
+#include "dsp.h"
+
+#ifdef CONFIG_ARCH_OMAP1
+#include <mach/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 <mach/mailbox.h>
+#include <mach/dsp.h>
+#include <mach/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)
+{
+ 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);
+}
+#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 <mach/mailbox.h>
+#include <mach/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),
+ NULL, 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 <mach/tc.h>
+#include <mach/omapfb.h>
+#include <mach/dsp.h>
+#include <mach/mailbox.h>
+#include <mach/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 <mach/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 <mach/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 <mach/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 <mach/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 <mach/mailbox.h>
+#include <mach/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), NULL,
+ "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_type_ns(PIDTYPE_PID, pl->pid, &init_pid_ns) != 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 <mach/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 <mach/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 SENSORS_OMAP34XX
+ tristate "TI OMAP34xx internal temperature sensor"
+ depends on ARCH_OMAP3 && HIGH_RES_TIMERS
+
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
+obj-$(CONFIG_SENSORS_OMAP34XX) += omap34xx_temp.o
ifeq ($(CONFIG_HWMON_DEBUG_CHIP),y)
EXTRA_CFLAGS += -DDEBUG
--- /dev/null
+/*
+ * omap34xx_temp.c - Linux kernel module for OMAP34xx hardware monitoring
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Written by Peter De Schrijver <peter.de-schrijver@nokia.com>
+ *
+ * Inspired by k8temp.c
+ *
+ * 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/clk.h>
+#include <linux/hrtimer.h>
+#include <linux/module.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <mach/omap34xx.h>
+#include <mach/control.h>
+
+#define TEMP_SENSOR_SOC BIT(8)
+#define TEMP_SENSOR_EOCZ BIT(7)
+
+/* minimum delay for EOCZ rise after SOC rise is
+ * 11 cycles of the 32.768Khz clock */
+#define EOCZ_MIN_RISING_DELAY (11 * 30518)
+
+/* maximum delay for EOCZ rise after SOC rise is
+ * 14 cycles of the 32.768Khz clock */
+#define EOCZ_MAX_RISING_DELAY (14 * 30518)
+
+/* minimum delay for EOCZ falling is
+ * 36 cycles of the 32.768Khz clock */
+#define EOCZ_MIN_FALLING_DELAY (36 * 30518)
+
+/* maximum delay for EOCZ falling is
+ * 40 cycles of the 32.768Khz clock */
+#define EOCZ_MAX_FALLING_DELAY (40 * 30518)
+
+struct omap34xx_data {
+ struct device *hwmon_dev;
+ struct clk *clk_32k;
+ struct mutex update_lock;
+ const char *name;
+ char valid;
+ unsigned long last_updated;
+ u32 temp;
+};
+
+static struct platform_device omap34xx_temp_device = {
+ .name = "omap34xx_temp",
+ .id = -1,
+};
+
+static int adc_to_temp[] = {
+ -40, -40, -40, -40, -40, -39, -38, -36, -34, -32, -31, -29, -28, -26,
+ -25, -24, -22, -21, -19, -18, -17, -15, -14, -12, -11, -9, -8, -7, -5,
+ -4, -2, -1, 0, 1, 3, 4, 5, 7, 8, 10, 11, 13, 14, 15, 17, 18, 20, 21,
+ 22, 24, 25, 27, 28, 30, 31, 32, 34, 35, 37, 38, 39, 41, 42, 44, 45,
+ 47, 48, 49, 51, 52, 53, 55, 56, 58, 59, 60, 62, 63, 65, 66, 67, 69,
+ 70, 72, 73, 74, 76, 77, 79, 80, 81, 83, 84, 85, 87, 88, 89, 91, 92,
+ 94, 95, 96, 98, 99, 100, 102, 103, 105, 106, 107, 109, 110, 111, 113,
+ 114, 116, 117, 118, 120, 121, 122, 124, 124, 125, 125, 125, 125, 125};
+
+static inline u32 wait_for_eocz(int min_delay, int max_delay, u32 level)
+{
+ struct timespec timeout;
+ ktime_t expire;
+ u32 temp_sensor_reg;
+
+ level &= 1;
+ level *= TEMP_SENSOR_EOCZ;
+
+ expire = ktime_add_ns(ktime_get(), max_delay);
+ timeout = ns_to_timespec(min_delay);
+ hrtimer_nanosleep(&timeout, NULL, HRTIMER_MODE_REL, CLOCK_MONOTONIC);
+ do {
+ temp_sensor_reg = omap_ctrl_readl(OMAP343X_CONTROL_TEMP_SENSOR);
+ if ((temp_sensor_reg & TEMP_SENSOR_EOCZ) == level)
+ break;
+ } while (ktime_us_delta(expire, ktime_get()) > 0);
+
+ return (temp_sensor_reg & TEMP_SENSOR_EOCZ) == level;
+}
+
+static void omap34xx_update(struct omap34xx_data *data)
+{
+ u32 temp_sensor_reg;
+
+ mutex_lock(&data->update_lock);
+
+ if (!data->valid
+ || time_after(jiffies, data->last_updated + HZ)) {
+
+ clk_enable(data->clk_32k);
+
+ temp_sensor_reg = omap_ctrl_readl(OMAP343X_CONTROL_TEMP_SENSOR);
+ temp_sensor_reg |= TEMP_SENSOR_SOC;
+ omap_ctrl_writel(temp_sensor_reg, OMAP343X_CONTROL_TEMP_SENSOR);
+
+ if (!wait_for_eocz(EOCZ_MIN_RISING_DELAY,
+ EOCZ_MAX_RISING_DELAY, 1))
+ goto err;
+
+ temp_sensor_reg = omap_ctrl_readl(OMAP343X_CONTROL_TEMP_SENSOR);
+ temp_sensor_reg &= ~TEMP_SENSOR_SOC;
+ omap_ctrl_writel(temp_sensor_reg, OMAP343X_CONTROL_TEMP_SENSOR);
+
+ if (!wait_for_eocz(EOCZ_MIN_FALLING_DELAY,
+ EOCZ_MAX_FALLING_DELAY, 0))
+ goto err;
+
+ data->temp = omap_ctrl_readl(OMAP343X_CONTROL_TEMP_SENSOR) &
+ ((1<<7) - 1);
+ data->last_updated = jiffies;
+ data->valid = 1;
+
+err:
+ clk_disable(data->clk_32k);
+ }
+
+ mutex_unlock(&data->update_lock);
+}
+
+static ssize_t show_name(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct omap34xx_data *data = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%s\n", data->name);
+}
+
+static ssize_t show_temp_raw(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct omap34xx_data *data = dev_get_drvdata(dev);
+
+ omap34xx_update(data);
+
+ return sprintf(buf, "%d\n", data->temp);
+}
+
+static ssize_t show_temp(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct omap34xx_data *data = dev_get_drvdata(dev);
+
+ omap34xx_update(data);
+
+ return sprintf(buf, "%d\n", adc_to_temp[data->temp]);
+}
+
+static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_input_raw, S_IRUGO, show_temp_raw,
+ NULL, 0, 0);
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+static int __devinit omap34xx_temp_probe(void)
+{
+ int err;
+ struct omap34xx_data *data;
+
+ err = platform_device_register(&omap34xx_temp_device);
+ if (err) {
+ printk(KERN_ERR
+ "Unable to register omap34xx temperature device\n");
+ goto exit;
+ }
+
+ data = kzalloc(sizeof(struct omap34xx_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit_platform;
+ }
+
+ dev_set_drvdata(&omap34xx_temp_device.dev, data);
+ mutex_init(&data->update_lock);
+ data->name = "omap34xx_temp";
+
+ data->clk_32k = clk_get(&omap34xx_temp_device.dev, "ts_fck");
+ if (IS_ERR(data->clk_32k)) {
+ err = PTR_ERR(data->clk_32k);
+ goto exit_free;
+ }
+
+ err = device_create_file(&omap34xx_temp_device.dev,
+ &sensor_dev_attr_temp1_input.dev_attr);
+ if (err)
+ goto clock_free;
+
+ err = device_create_file(&omap34xx_temp_device.dev,
+ &sensor_dev_attr_temp1_input_raw.dev_attr);
+ if (err)
+ goto exit_remove;
+
+ err = device_create_file(&omap34xx_temp_device.dev, &dev_attr_name);
+ if (err)
+ goto exit_remove_raw;
+
+ data->hwmon_dev = hwmon_device_register(&omap34xx_temp_device.dev);
+
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
+ goto exit_remove_all;
+ }
+
+ return 0;
+
+exit_remove_all:
+ device_remove_file(&omap34xx_temp_device.dev,
+ &dev_attr_name);
+exit_remove_raw:
+ device_remove_file(&omap34xx_temp_device.dev,
+ &sensor_dev_attr_temp1_input_raw.dev_attr);
+exit_remove:
+ device_remove_file(&omap34xx_temp_device.dev,
+ &sensor_dev_attr_temp1_input.dev_attr);
+clock_free:
+ clk_put(data->clk_32k);
+
+exit_free:
+ kfree(data);
+exit_platform:
+ platform_device_unregister(&omap34xx_temp_device);
+exit:
+ return err;
+}
+
+static int __init omap34xx_temp_init(void)
+{
+ return omap34xx_temp_probe();
+}
+
+static void __exit omap34xx_temp_exit(void)
+{
+ struct omap34xx_data *data =
+ dev_get_drvdata(&omap34xx_temp_device.dev);
+
+ clk_put(data->clk_32k);
+ hwmon_device_unregister(data->hwmon_dev);
+ device_remove_file(&omap34xx_temp_device.dev,
+ &sensor_dev_attr_temp1_input.dev_attr);
+ device_remove_file(&omap34xx_temp_device.dev, &dev_attr_name);
+ kfree(data);
+ platform_device_unregister(&omap34xx_temp_device);
+}
+
+MODULE_AUTHOR("Peter De Schrijver");
+MODULE_DESCRIPTION("Omap34xx temperature sensor");
+MODULE_LICENSE("GPL");
+
+module_init(omap34xx_temp_init)
+module_exit(omap34xx_temp_exit)
+
--- /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,
default y if MACH_OMAP_H3 || MACH_OMAP_OSK
help
If you say yes to this option, support will be included for the
- I2C interface on the Texas Instruments OMAP1/2 family of processors.
- Like OMAP1510/1610/1710/5912 and OMAP242x.
+ I2C interface on the Texas Instruments OMAP1/2/3 family of
+ processors.
+ Like OMAP1510/1610/1710/5912, OMAP242x, OMAP34x and OMAP35x.
For details see http://www.ti.com/omap.
+config I2C2_OMAP_BEAGLE
+ bool "Enable I2C2 for OMAP3 BeagleBoard"
+ depends on ARCH_OMAP && MACH_OMAP3_BEAGLE
+ select OMAP_MUX
+ default n
+ help
+ Say Y here if you want to enable I2C bus 2 at OMAP3 based
+ BeagleBoard.
+ I2C2 at BeagleBoard is connected to expansion connector, i.e. unused
+ if nothing is connected to this connector. As internal OMAP3 pull up
+ resistors are not strong enough, enabled but unused I2C2 bus results
+ in error messages (e.g. I2C timeouts). Enable this only if you have
+ something connected to I2C2 at board's expansion connector and this
+ extension has additional pull up resistors for I2C2 bus.
+
config I2C_PASEMI
tristate "PA Semi SMBus interface"
depends on PPC_PASEMI && PCI
if (cpu_is_omap2430() || cpu_is_omap34xx()) {
/* HSI2C controller internal clk rate should be 19.2 Mhz */
- internal_clk = 19200;
+ if (dev->speed > 400)
+ internal_clk = 19200;
+ else if (dev->speed > 100)
+ internal_clk = 9600;
+ else
+ internal_clk = 4000;
+
fclk_rate = clk_get_rate(dev->fclk) / 1000;
/* Compute prescaler divisor */
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;
+ fsscll = internal_clk / (dev->speed * 2) - 3;
+ fssclh = internal_clk / (dev->speed * 2) - 9;
}
scll = (hsscll << OMAP_I2C_SCLL_HSSCLL) | fsscll;
sclh = (hssclh << OMAP_I2C_SCLH_HSSCLH) | fssclh;
if (stat & OMAP_I2C_STAT_RRDY)
num_bytes = dev->fifo_size;
else
- num_bytes = omap_i2c_read_reg(dev,
- OMAP_I2C_BUFSTAT_REG);
+ num_bytes = (omap_i2c_read_reg(dev,
+ OMAP_I2C_BUFSTAT_REG)
+ >> 8) & 0x3F;
}
while (num_bytes) {
num_bytes--;
if (stat & OMAP_I2C_STAT_XRDY)
num_bytes = dev->fifo_size;
else
- num_bytes = omap_i2c_read_reg(dev,
- OMAP_I2C_BUFSTAT_REG);
+ num_bytes = (omap_i2c_read_reg(dev,
+ OMAP_I2C_BUFSTAT_REG))
+ & 0x3F;
}
while (num_bytes) {
num_bytes--;
struct omap_i2c_dev *dev;
struct i2c_adapter *adap;
struct resource *mem, *irq, *ioarea;
- irq_handler_t isr;
+ void *isr;
int r;
u32 speed = 0;
-#
+
# Miscellaneous I2C chip drivers configuration
#
# *** DEPRECATED! Do not add new entries! See Makefile ***
These devices are hard to detect and rarely found on mainstream
hardware. If unsure, say N.
+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_PWRBUTTON
+ tristate "TWL4030 Power button Driver"
+ depends on TWL4030_CORE
+
+config TWL4030_POWEROFF
+ tristate "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
+ help
+ If you say yes here you get support for the Texas Instruments
+ TWL92330/Menelaus Power Management chip. This include voltage
+ regulators, Dual slot memory card tranceivers, real-time clock
+ and other features that are often used in portable devices like
+ cell phones and PDAs.
+
config MCU_MPC8349EMITX
tristate "MPC8349E-mITX MCU driver"
depends on I2C && PPC_83xx
obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o
obj-$(CONFIG_PCF8575) += pcf8575.o
obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
+obj-$(CONFIG_MENELAUS) += menelaus.o
obj-$(CONFIG_SENSORS_TSL2550) += tsl2550.o
obj-$(CONFIG_MCU_MPC8349EMITX) += mcu_mpc8349emitx.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/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 <mach/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,
+ const struct i2c_device_id *id)
+{
+ 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 const struct i2c_device_id lp5521_id[] = {
+ { LP5521_DRIVER_NAME, 0},
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, lp5521_id);
+
+static struct i2c_driver lp5521_driver = {
+ .driver = {
+ .name = LP5521_DRIVER_NAME,
+ },
+ .probe = lp5521_probe,
+ .remove = __devexit_p(lp5521_remove),
+ .id_table = lp5521_id,
+};
+
+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);
--- /dev/null
+
+/*
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *
+ * Some parts based tps65010.c:
+ * Copyright (C) 2004 Texas Instruments and
+ * Copyright (C) 2004-2005 David Brownell
+ *
+ * Some parts based on tlv320aic24.c:
+ * Copyright (C) by Kai Svahn <kai.svahn@nokia.com>
+ *
+ * Changes for interrupt handling and clean-up by
+ * Tony Lindgren <tony@atomide.com> and Imre Deak <imre.deak@nokia.com>
+ * Cleanup and generalized support for voltage setting by
+ * Juha Yrjola
+ * Added support for controlling VCORE and regulator sleep states,
+ * Amit Kucheria <amit.kucheria@nokia.com>
+ * 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/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+#include <linux/i2c/menelaus.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/irq.h>
+
+#include <mach/gpio.h>
+
+#define DRIVER_NAME "menelaus"
+
+
+static void menelaus_work(struct work_struct *_menelaus);
+
+struct menelaus_chip {
+ struct mutex lock;
+ struct i2c_client *client;
+ struct work_struct work;
+#ifdef CONFIG_RTC_DRV_TWL92330
+ struct rtc_device *rtc;
+ u8 rtc_control;
+ unsigned uie:1;
+#endif
+ unsigned vcore_hw_mode:1;
+ u8 mask1, mask2;
+ void (*handlers[16])(struct menelaus_chip *);
+ void (*mmc_callback)(void *data, u8 mask);
+ void *mmc_callback_data;
+};
+
+static struct menelaus_chip *the_menelaus;
+
+static int menelaus_write_reg(int reg, u8 value)
+{
+ int val = i2c_smbus_write_byte_data(the_menelaus->client, reg, value);
+
+ if (val < 0) {
+ dev_err(&the_menelaus->client->dev, "write error");
+ return val;
+ }
+
+ return 0;
+}
+
+static int menelaus_read_reg(int reg)
+{
+ int val = i2c_smbus_read_byte_data(the_menelaus->client, reg);
+
+ if (val < 0)
+ dev_err(&the_menelaus->client->dev, "read error");
+
+ return val;
+}
+
+static int menelaus_enable_irq(int irq)
+{
+ if (irq > 7) {
+ irq -= 8;
+ the_menelaus->mask2 &= ~(1 << irq);
+ return menelaus_write_reg(MENELAUS_INT_MASK2,
+ the_menelaus->mask2);
+ } else {
+ the_menelaus->mask1 &= ~(1 << irq);
+ return menelaus_write_reg(MENELAUS_INT_MASK1,
+ the_menelaus->mask1);
+ }
+}
+
+static int menelaus_disable_irq(int irq)
+{
+ if (irq > 7) {
+ irq -= 8;
+ the_menelaus->mask2 |= (1 << irq);
+ return menelaus_write_reg(MENELAUS_INT_MASK2,
+ the_menelaus->mask2);
+ } else {
+ the_menelaus->mask1 |= (1 << irq);
+ return menelaus_write_reg(MENELAUS_INT_MASK1,
+ the_menelaus->mask1);
+ }
+}
+
+static int menelaus_ack_irq(int irq)
+{
+ if (irq > 7)
+ return menelaus_write_reg(MENELAUS_INT_ACK2, 1 << (irq - 8));
+ else
+ return menelaus_write_reg(MENELAUS_INT_ACK1, 1 << irq);
+}
+
+/* Adds a handler for an interrupt. Does not run in interrupt context */
+static int menelaus_add_irq_work(int irq,
+ void (*handler)(struct menelaus_chip *))
+{
+ int ret = 0;
+
+ mutex_lock(&the_menelaus->lock);
+ the_menelaus->handlers[irq] = handler;
+ ret = menelaus_enable_irq(irq);
+ mutex_unlock(&the_menelaus->lock);
+
+ return ret;
+}
+
+/* Removes handler for an interrupt */
+static int menelaus_remove_irq_work(int irq)
+{
+ int ret = 0;
+
+ mutex_lock(&the_menelaus->lock);
+ ret = menelaus_disable_irq(irq);
+ the_menelaus->handlers[irq] = NULL;
+ mutex_unlock(&the_menelaus->lock);
+
+ return ret;
+}
+
+/*
+ * Gets scheduled when a card detect interrupt happens. Note that in some cases
+ * this line is wired to card cover switch rather than the card detect switch
+ * in each slot. In this case the cards are not seen by menelaus.
+ * FIXME: Add handling for D1 too
+ */
+static void menelaus_mmc_cd_work(struct menelaus_chip *menelaus_hw)
+{
+ int reg;
+ unsigned char card_mask = 0;
+
+ reg = menelaus_read_reg(MENELAUS_MCT_PIN_ST);
+ if (reg < 0)
+ return;
+
+ if (!(reg & 0x1))
+ card_mask |= MCT_PIN_ST_S1_CD_ST;
+
+ if (!(reg & 0x2))
+ card_mask |= MCT_PIN_ST_S2_CD_ST;
+
+ if (menelaus_hw->mmc_callback)
+ menelaus_hw->mmc_callback(menelaus_hw->mmc_callback_data,
+ card_mask);
+}
+
+/*
+ * Toggles the MMC slots between open-drain and push-pull mode.
+ */
+int menelaus_set_mmc_opendrain(int slot, int enable)
+{
+ int ret, val;
+
+ if (slot != 1 && slot != 2)
+ return -EINVAL;
+ mutex_lock(&the_menelaus->lock);
+ ret = menelaus_read_reg(MENELAUS_MCT_CTRL1);
+ if (ret < 0) {
+ mutex_unlock(&the_menelaus->lock);
+ return ret;
+ }
+ val = ret;
+ if (slot == 1) {
+ if (enable)
+ val |= MCT_CTRL1_S1_CMD_OD;
+ else
+ val &= ~MCT_CTRL1_S1_CMD_OD;
+ } else {
+ if (enable)
+ val |= MCT_CTRL1_S2_CMD_OD;
+ else
+ val &= ~MCT_CTRL1_S2_CMD_OD;
+ }
+ ret = menelaus_write_reg(MENELAUS_MCT_CTRL1, val);
+ mutex_unlock(&the_menelaus->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(menelaus_set_mmc_opendrain);
+
+int menelaus_set_slot_sel(int enable)
+{
+ int ret;
+
+ mutex_lock(&the_menelaus->lock);
+ ret = menelaus_read_reg(MENELAUS_GPIO_CTRL);
+ if (ret < 0)
+ goto out;
+ ret |= GPIO2_DIR_INPUT;
+ if (enable)
+ ret |= GPIO_CTRL_SLOTSELEN;
+ else
+ ret &= ~GPIO_CTRL_SLOTSELEN;
+ ret = menelaus_write_reg(MENELAUS_GPIO_CTRL, ret);
+out:
+ mutex_unlock(&the_menelaus->lock);
+ return ret;
+}
+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 |= MCT_CTRL3_SLOT1_EN;
+ else
+ val &= ~MCT_CTRL3_SLOT1_EN;
+ } else {
+ if (enable)
+ val |= MCT_CTRL3_SLOT2_EN;
+ else
+ val &= MCT_CTRL3_SLOT2_EN;
+ }
+ 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;
+
+ if (slot != 1 && slot != 2)
+ return -EINVAL;
+ if (power >= 3)
+ return -EINVAL;
+
+ mutex_lock(&the_menelaus->lock);
+
+ ret = menelaus_read_reg(MENELAUS_MCT_CTRL2);
+ if (ret < 0)
+ goto out;
+ val = ret;
+ if (slot == 1) {
+ if (cd_en)
+ val |= MCT_CTRL2_S1CD_BUFEN | MCT_CTRL2_S1CD_DBEN;
+ else
+ val &= ~(MCT_CTRL2_S1CD_BUFEN | MCT_CTRL2_S1CD_DBEN);
+ } else {
+ if (cd_en)
+ val |= MCT_CTRL2_S2CD_BUFEN | MCT_CTRL2_S2CD_BEN;
+ else
+ val &= ~(MCT_CTRL2_S2CD_BUFEN | MCT_CTRL2_S2CD_BEN);
+ }
+ ret = menelaus_write_reg(MENELAUS_MCT_CTRL2, val);
+ if (ret < 0)
+ goto out;
+
+ ret = menelaus_read_reg(MENELAUS_MCT_CTRL3);
+ if (ret < 0)
+ goto out;
+ val = ret;
+ if (slot == 1) {
+ if (enable)
+ val |= MCT_CTRL3_SLOT1_EN;
+ else
+ val &= ~MCT_CTRL3_SLOT1_EN;
+ } else {
+ int b;
+
+ if (enable)
+ val |= MCT_CTRL3_SLOT2_EN;
+ else
+ val &= ~MCT_CTRL3_SLOT2_EN;
+ b = menelaus_read_reg(MENELAUS_MCT_CTRL2);
+ b &= ~(MCT_CTRL2_VS2_SEL_D0 | MCT_CTRL2_VS2_SEL_D1);
+ b |= power;
+ ret = menelaus_write_reg(MENELAUS_MCT_CTRL2, b);
+ if (ret < 0)
+ goto out;
+ }
+ /* Disable autonomous shutdown */
+ val &= ~(MCT_CTRL3_S1_AUTO_EN | MCT_CTRL3_S2_AUTO_EN);
+ ret = menelaus_write_reg(MENELAUS_MCT_CTRL3, val);
+out:
+ mutex_unlock(&the_menelaus->lock);
+ return ret;
+}
+EXPORT_SYMBOL(menelaus_set_mmc_slot);
+
+int menelaus_register_mmc_callback(void (*callback)(void *data, u8 card_mask),
+ void *data)
+{
+ int ret = 0;
+
+ the_menelaus->mmc_callback_data = data;
+ the_menelaus->mmc_callback = callback;
+ ret = menelaus_add_irq_work(MENELAUS_MMC_S1CD_IRQ,
+ menelaus_mmc_cd_work);
+ if (ret < 0)
+ return ret;
+ ret = menelaus_add_irq_work(MENELAUS_MMC_S2CD_IRQ,
+ menelaus_mmc_cd_work);
+ if (ret < 0)
+ return ret;
+ ret = menelaus_add_irq_work(MENELAUS_MMC_S1D1_IRQ,
+ menelaus_mmc_cd_work);
+ if (ret < 0)
+ return ret;
+ ret = menelaus_add_irq_work(MENELAUS_MMC_S2D1_IRQ,
+ menelaus_mmc_cd_work);
+
+ return ret;
+}
+EXPORT_SYMBOL(menelaus_register_mmc_callback);
+
+void menelaus_unregister_mmc_callback(void)
+{
+ menelaus_remove_irq_work(MENELAUS_MMC_S1CD_IRQ);
+ menelaus_remove_irq_work(MENELAUS_MMC_S2CD_IRQ);
+ menelaus_remove_irq_work(MENELAUS_MMC_S1D1_IRQ);
+ menelaus_remove_irq_work(MENELAUS_MMC_S2D1_IRQ);
+
+ the_menelaus->mmc_callback = NULL;
+ the_menelaus->mmc_callback_data = 0;
+}
+EXPORT_SYMBOL(menelaus_unregister_mmc_callback);
+
+struct menelaus_vtg {
+ const char *name;
+ u8 vtg_reg;
+ u8 vtg_shift;
+ u8 vtg_bits;
+ u8 mode_reg;
+};
+
+struct menelaus_vtg_value {
+ u16 vtg;
+ u16 val;
+};
+
+static int menelaus_set_voltage(const struct menelaus_vtg *vtg, int mV,
+ int vtg_val, int mode)
+{
+ int val, ret;
+ struct i2c_client *c = the_menelaus->client;
+
+ mutex_lock(&the_menelaus->lock);
+ if (vtg == 0)
+ goto set_voltage;
+
+ ret = menelaus_read_reg(vtg->vtg_reg);
+ if (ret < 0)
+ goto out;
+ val = ret & ~(((1 << vtg->vtg_bits) - 1) << vtg->vtg_shift);
+ val |= vtg_val << vtg->vtg_shift;
+
+ dev_dbg(&c->dev, "Setting voltage '%s'"
+ "to %d mV (reg 0x%02x, val 0x%02x)\n",
+ vtg->name, mV, vtg->vtg_reg, val);
+
+ ret = menelaus_write_reg(vtg->vtg_reg, val);
+ if (ret < 0)
+ goto out;
+set_voltage:
+ ret = menelaus_write_reg(vtg->mode_reg, mode);
+out:
+ mutex_unlock(&the_menelaus->lock);
+ if (ret == 0) {
+ /* Wait for voltage to stabilize */
+ msleep(1);
+ }
+ return ret;
+}
+
+static int menelaus_get_vtg_value(int vtg, const struct menelaus_vtg_value *tbl,
+ int n)
+{
+ int i;
+
+ for (i = 0; i < n; i++, tbl++)
+ if (tbl->vtg == vtg)
+ return tbl->val;
+ return -EINVAL;
+}
+
+/*
+ * Vcore can be programmed in two ways:
+ * SW-controlled: Required voltage is programmed into VCORE_CTRL1
+ * HW-controlled: Required range (roof-floor) is programmed into VCORE_CTRL3
+ * and VCORE_CTRL4
+ *
+ * Call correct 'set' function accordingly
+ */
+
+static const struct menelaus_vtg_value vcore_values[] = {
+ { 1000, 0 },
+ { 1025, 1 },
+ { 1050, 2 },
+ { 1075, 3 },
+ { 1100, 4 },
+ { 1125, 5 },
+ { 1150, 6 },
+ { 1175, 7 },
+ { 1200, 8 },
+ { 1225, 9 },
+ { 1250, 10 },
+ { 1275, 11 },
+ { 1300, 12 },
+ { 1325, 13 },
+ { 1350, 14 },
+ { 1375, 15 },
+ { 1400, 16 },
+ { 1425, 17 },
+ { 1450, 18 },
+};
+
+int menelaus_set_vcore_sw(unsigned int mV)
+{
+ int val, ret;
+ struct i2c_client *c = the_menelaus->client;
+
+ val = menelaus_get_vtg_value(mV, vcore_values,
+ ARRAY_SIZE(vcore_values));
+ if (val < 0)
+ return -EINVAL;
+
+ dev_dbg(&c->dev, "Setting VCORE to %d mV (val 0x%02x)\n", mV, val);
+
+ /* Set SW mode and the voltage in one go. */
+ mutex_lock(&the_menelaus->lock);
+ ret = menelaus_write_reg(MENELAUS_VCORE_CTRL1, val);
+ if (ret == 0)
+ the_menelaus->vcore_hw_mode = 0;
+ mutex_unlock(&the_menelaus->lock);
+ msleep(1);
+
+ return ret;
+}
+
+int menelaus_set_vcore_hw(unsigned int roof_mV, unsigned int floor_mV)
+{
+ int fval, rval, val, ret;
+ struct i2c_client *c = the_menelaus->client;
+
+ rval = menelaus_get_vtg_value(roof_mV, vcore_values,
+ ARRAY_SIZE(vcore_values));
+ if (rval < 0)
+ return -EINVAL;
+ fval = menelaus_get_vtg_value(floor_mV, vcore_values,
+ ARRAY_SIZE(vcore_values));
+ if (fval < 0)
+ return -EINVAL;
+
+ dev_dbg(&c->dev, "Setting VCORE FLOOR to %d mV and ROOF to %d mV\n",
+ floor_mV, roof_mV);
+
+ mutex_lock(&the_menelaus->lock);
+ ret = menelaus_write_reg(MENELAUS_VCORE_CTRL3, fval);
+ if (ret < 0)
+ goto out;
+ ret = menelaus_write_reg(MENELAUS_VCORE_CTRL4, rval);
+ if (ret < 0)
+ goto out;
+ if (!the_menelaus->vcore_hw_mode) {
+ val = menelaus_read_reg(MENELAUS_VCORE_CTRL1);
+ /* HW mode, turn OFF byte comparator */
+ val |= (VCORE_CTRL1_HW_NSW | VCORE_CTRL1_BYP_COMP);
+ ret = menelaus_write_reg(MENELAUS_VCORE_CTRL1, val);
+ the_menelaus->vcore_hw_mode = 1;
+ }
+ msleep(1);
+out:
+ mutex_unlock(&the_menelaus->lock);
+ return ret;
+}
+
+static const struct menelaus_vtg vmem_vtg = {
+ .name = "VMEM",
+ .vtg_reg = MENELAUS_LDO_CTRL1,
+ .vtg_shift = 0,
+ .vtg_bits = 2,
+ .mode_reg = MENELAUS_LDO_CTRL3,
+};
+
+static const struct menelaus_vtg_value vmem_values[] = {
+ { 1500, 0 },
+ { 1800, 1 },
+ { 1900, 2 },
+ { 2500, 3 },
+};
+
+int menelaus_set_vmem(unsigned int mV)
+{
+ int val;
+
+ if (mV == 0)
+ return menelaus_set_voltage(&vmem_vtg, 0, 0, 0);
+
+ val = menelaus_get_vtg_value(mV, vmem_values, ARRAY_SIZE(vmem_values));
+ if (val < 0)
+ return -EINVAL;
+ return menelaus_set_voltage(&vmem_vtg, mV, val, 0x02);
+}
+EXPORT_SYMBOL(menelaus_set_vmem);
+
+static const struct menelaus_vtg vio_vtg = {
+ .name = "VIO",
+ .vtg_reg = MENELAUS_LDO_CTRL1,
+ .vtg_shift = 2,
+ .vtg_bits = 2,
+ .mode_reg = MENELAUS_LDO_CTRL4,
+};
+
+static const struct menelaus_vtg_value vio_values[] = {
+ { 1500, 0 },
+ { 1800, 1 },
+ { 2500, 2 },
+ { 2800, 3 },
+};
+
+int menelaus_set_vio(unsigned int mV)
+{
+ int val;
+
+ if (mV == 0)
+ return menelaus_set_voltage(&vio_vtg, 0, 0, 0);
+
+ val = menelaus_get_vtg_value(mV, vio_values, ARRAY_SIZE(vio_values));
+ if (val < 0)
+ return -EINVAL;
+ return menelaus_set_voltage(&vio_vtg, mV, val, 0x02);
+}
+EXPORT_SYMBOL(menelaus_set_vio);
+
+static const struct menelaus_vtg_value vdcdc_values[] = {
+ { 1500, 0 },
+ { 1800, 1 },
+ { 2000, 2 },
+ { 2200, 3 },
+ { 2400, 4 },
+ { 2800, 5 },
+ { 3000, 6 },
+ { 3300, 7 },
+};
+
+static const struct menelaus_vtg vdcdc2_vtg = {
+ .name = "VDCDC2",
+ .vtg_reg = MENELAUS_DCDC_CTRL1,
+ .vtg_shift = 0,
+ .vtg_bits = 3,
+ .mode_reg = MENELAUS_DCDC_CTRL2,
+};
+
+static const struct menelaus_vtg vdcdc3_vtg = {
+ .name = "VDCDC3",
+ .vtg_reg = MENELAUS_DCDC_CTRL1,
+ .vtg_shift = 3,
+ .vtg_bits = 3,
+ .mode_reg = MENELAUS_DCDC_CTRL3,
+};
+
+int menelaus_set_vdcdc(int dcdc, unsigned int mV)
+{
+ const struct menelaus_vtg *vtg;
+ int val;
+
+ if (dcdc != 2 && dcdc != 3)
+ return -EINVAL;
+ if (dcdc == 2)
+ vtg = &vdcdc2_vtg;
+ else
+ vtg = &vdcdc3_vtg;
+
+ if (mV == 0)
+ return menelaus_set_voltage(vtg, 0, 0, 0);
+
+ val = menelaus_get_vtg_value(mV, vdcdc_values,
+ ARRAY_SIZE(vdcdc_values));
+ if (val < 0)
+ return -EINVAL;
+ return menelaus_set_voltage(vtg, mV, val, 0x03);
+}
+
+static const struct menelaus_vtg_value vmmc_values[] = {
+ { 1850, 0 },
+ { 2800, 1 },
+ { 3000, 2 },
+ { 3100, 3 },
+};
+
+static const struct menelaus_vtg vmmc_vtg = {
+ .name = "VMMC",
+ .vtg_reg = MENELAUS_LDO_CTRL1,
+ .vtg_shift = 6,
+ .vtg_bits = 2,
+ .mode_reg = MENELAUS_LDO_CTRL7,
+};
+
+int menelaus_set_vmmc(unsigned int mV)
+{
+ int val;
+
+ if (mV == 0)
+ return menelaus_set_voltage(&vmmc_vtg, 0, 0, 0);
+
+ val = menelaus_get_vtg_value(mV, vmmc_values, ARRAY_SIZE(vmmc_values));
+ if (val < 0)
+ return -EINVAL;
+ return menelaus_set_voltage(&vmmc_vtg, mV, val, 0x02);
+}
+EXPORT_SYMBOL(menelaus_set_vmmc);
+
+
+static const struct menelaus_vtg_value vaux_values[] = {
+ { 1500, 0 },
+ { 1800, 1 },
+ { 2500, 2 },
+ { 2800, 3 },
+};
+
+static const struct menelaus_vtg vaux_vtg = {
+ .name = "VAUX",
+ .vtg_reg = MENELAUS_LDO_CTRL1,
+ .vtg_shift = 4,
+ .vtg_bits = 2,
+ .mode_reg = MENELAUS_LDO_CTRL6,
+};
+
+int menelaus_set_vaux(unsigned int mV)
+{
+ int val;
+
+ if (mV == 0)
+ return menelaus_set_voltage(&vaux_vtg, 0, 0, 0);
+
+ val = menelaus_get_vtg_value(mV, vaux_values, ARRAY_SIZE(vaux_values));
+ if (val < 0)
+ return -EINVAL;
+ return menelaus_set_voltage(&vaux_vtg, mV, val, 0x02);
+}
+EXPORT_SYMBOL(menelaus_set_vaux);
+
+int menelaus_get_slot_pin_states(void)
+{
+ return menelaus_read_reg(MENELAUS_MCT_PIN_ST);
+}
+EXPORT_SYMBOL(menelaus_get_slot_pin_states);
+
+int menelaus_set_regulator_sleep(int enable, u32 val)
+{
+ int t, ret;
+ struct i2c_client *c = the_menelaus->client;
+
+ mutex_lock(&the_menelaus->lock);
+ ret = menelaus_write_reg(MENELAUS_SLEEP_CTRL2, val);
+ if (ret < 0)
+ goto out;
+
+ dev_dbg(&c->dev, "regulator sleep configuration: %02x\n", val);
+
+ ret = menelaus_read_reg(MENELAUS_GPIO_CTRL);
+ if (ret < 0)
+ goto out;
+ t = (GPIO_CTRL_SLPCTLEN | GPIO3_DIR_INPUT);
+ if (enable)
+ ret |= t;
+ else
+ ret &= ~t;
+ ret = menelaus_write_reg(MENELAUS_GPIO_CTRL, ret);
+out:
+ mutex_unlock(&the_menelaus->lock);
+ return ret;
+}
+
+/*-----------------------------------------------------------------------*/
+
+/* Handles Menelaus interrupts. Does not run in interrupt context */
+static void menelaus_work(struct work_struct *_menelaus)
+{
+ struct menelaus_chip *menelaus =
+ container_of(_menelaus, struct menelaus_chip, work);
+ void (*handler)(struct menelaus_chip *menelaus);
+
+ while (1) {
+ unsigned isr;
+
+ isr = (menelaus_read_reg(MENELAUS_INT_STATUS2)
+ & ~menelaus->mask2) << 8;
+ isr |= menelaus_read_reg(MENELAUS_INT_STATUS1)
+ & ~menelaus->mask1;
+ if (!isr)
+ break;
+
+ while (isr) {
+ int irq = fls(isr) - 1;
+ isr &= ~(1 << irq);
+
+ mutex_lock(&menelaus->lock);
+ menelaus_disable_irq(irq);
+ menelaus_ack_irq(irq);
+ handler = menelaus->handlers[irq];
+ if (handler)
+ handler(menelaus);
+ menelaus_enable_irq(irq);
+ mutex_unlock(&menelaus->lock);
+ }
+ }
+ enable_irq(menelaus->client->irq);
+}
+
+/*
+ * We cannot use I2C in interrupt context, so we just schedule work.
+ */
+static irqreturn_t menelaus_irq(int irq, void *_menelaus)
+{
+ struct menelaus_chip *menelaus = _menelaus;
+
+ disable_irq_nosync(irq);
+ (void)schedule_work(&menelaus->work);
+
+ return IRQ_HANDLED;
+}
+
+/*-----------------------------------------------------------------------*/
+
+/*
+ * The RTC needs to be set once, then it runs on backup battery power.
+ * It supports alarms, including system wake alarms (from some modes);
+ * and 1/second IRQs if requested.
+ */
+#ifdef CONFIG_RTC_DRV_TWL92330
+
+#define RTC_CTRL_RTC_EN (1 << 0)
+#define RTC_CTRL_AL_EN (1 << 1)
+#define RTC_CTRL_MODE12 (1 << 2)
+#define RTC_CTRL_EVERY_MASK (3 << 3)
+#define RTC_CTRL_EVERY_SEC (0 << 3)
+#define RTC_CTRL_EVERY_MIN (1 << 3)
+#define RTC_CTRL_EVERY_HR (2 << 3)
+#define RTC_CTRL_EVERY_DAY (3 << 3)
+
+#define RTC_UPDATE_EVERY 0x08
+
+#define RTC_HR_PM (1 << 7)
+
+static void menelaus_to_time(char *regs, struct rtc_time *t)
+{
+ t->tm_sec = bcd2bin(regs[0]);
+ t->tm_min = bcd2bin(regs[1]);
+ if (the_menelaus->rtc_control & RTC_CTRL_MODE12) {
+ t->tm_hour = bcd2bin(regs[2] & 0x1f) - 1;
+ if (regs[2] & RTC_HR_PM)
+ t->tm_hour += 12;
+ } else
+ t->tm_hour = bcd2bin(regs[2] & 0x3f);
+ t->tm_mday = bcd2bin(regs[3]);
+ t->tm_mon = bcd2bin(regs[4]) - 1;
+ t->tm_year = bcd2bin(regs[5]) + 100;
+}
+
+static int time_to_menelaus(struct rtc_time *t, int regnum)
+{
+ int hour, status;
+
+ status = menelaus_write_reg(regnum++, bin2bcd(t->tm_sec));
+ if (status < 0)
+ goto fail;
+
+ status = menelaus_write_reg(regnum++, bin2bcd(t->tm_min));
+ if (status < 0)
+ goto fail;
+
+ if (the_menelaus->rtc_control & RTC_CTRL_MODE12) {
+ hour = t->tm_hour + 1;
+ if (hour > 12)
+ hour = RTC_HR_PM | bin2bcd(hour - 12);
+ else
+ hour = bin2bcd(hour);
+ } else
+ hour = bin2bcd(t->tm_hour);
+ status = menelaus_write_reg(regnum++, hour);
+ if (status < 0)
+ goto fail;
+
+ status = menelaus_write_reg(regnum++, bin2bcd(t->tm_mday));
+ if (status < 0)
+ goto fail;
+
+ status = menelaus_write_reg(regnum++, bin2bcd(t->tm_mon + 1));
+ if (status < 0)
+ goto fail;
+
+ status = menelaus_write_reg(regnum++, bin2bcd(t->tm_year - 100));
+ if (status < 0)
+ goto fail;
+
+ return 0;
+fail:
+ dev_err(&the_menelaus->client->dev, "rtc write reg %02x, err %d\n",
+ --regnum, status);
+ return status;
+}
+
+static int menelaus_read_time(struct device *dev, struct rtc_time *t)
+{
+ struct i2c_msg msg[2];
+ char regs[7];
+ int status;
+
+ /* block read date and time registers */
+ regs[0] = MENELAUS_RTC_SEC;
+
+ msg[0].addr = MENELAUS_I2C_ADDRESS;
+ msg[0].flags = 0;
+ msg[0].len = 1;
+ msg[0].buf = regs;
+
+ msg[1].addr = MENELAUS_I2C_ADDRESS;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = sizeof(regs);
+ msg[1].buf = regs;
+
+ status = i2c_transfer(the_menelaus->client->adapter, msg, 2);
+ if (status != 2) {
+ dev_err(dev, "%s error %d\n", "read", status);
+ return -EIO;
+ }
+
+ menelaus_to_time(regs, t);
+ t->tm_wday = bcd2bin(regs[6]);
+
+ return 0;
+}
+
+static int menelaus_set_time(struct device *dev, struct rtc_time *t)
+{
+ int status;
+
+ /* write date and time registers */
+ status = time_to_menelaus(t, MENELAUS_RTC_SEC);
+ if (status < 0)
+ 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"
+ "err %d\n", MENELAUS_RTC_WKDAY, status);
+ return status;
+ }
+
+ /* now commit the write */
+ status = menelaus_write_reg(MENELAUS_RTC_UPDATE, RTC_UPDATE_EVERY);
+ if (status < 0)
+ dev_err(&the_menelaus->client->dev, "rtc commit time, err %d\n",
+ status);
+
+ return 0;
+}
+
+static int menelaus_read_alarm(struct device *dev, struct rtc_wkalrm *w)
+{
+ struct i2c_msg msg[2];
+ char regs[6];
+ int status;
+
+ /* block read alarm registers */
+ regs[0] = MENELAUS_RTC_AL_SEC;
+
+ msg[0].addr = MENELAUS_I2C_ADDRESS;
+ msg[0].flags = 0;
+ msg[0].len = 1;
+ msg[0].buf = regs;
+
+ msg[1].addr = MENELAUS_I2C_ADDRESS;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = sizeof(regs);
+ msg[1].buf = regs;
+
+ status = i2c_transfer(the_menelaus->client->adapter, msg, 2);
+ if (status != 2) {
+ dev_err(dev, "%s error %d\n", "alarm read", status);
+ return -EIO;
+ }
+
+ menelaus_to_time(regs, &w->time);
+
+ w->enabled = !!(the_menelaus->rtc_control & RTC_CTRL_AL_EN);
+
+ /* NOTE we *could* check if actually pending... */
+ w->pending = 0;
+
+ return 0;
+}
+
+static int menelaus_set_alarm(struct device *dev, struct rtc_wkalrm *w)
+{
+ int status;
+
+ if (the_menelaus->client->irq <= 0 && w->enabled)
+ return -ENODEV;
+
+ /* clear previous alarm enable */
+ if (the_menelaus->rtc_control & RTC_CTRL_AL_EN) {
+ the_menelaus->rtc_control &= ~RTC_CTRL_AL_EN;
+ status = menelaus_write_reg(MENELAUS_RTC_CTRL,
+ the_menelaus->rtc_control);
+ if (status < 0)
+ return status;
+ }
+
+ /* write alarm registers */
+ status = time_to_menelaus(&w->time, MENELAUS_RTC_AL_SEC);
+ if (status < 0)
+ return status;
+
+ /* enable alarm if requested */
+ if (w->enabled) {
+ the_menelaus->rtc_control |= RTC_CTRL_AL_EN;
+ status = menelaus_write_reg(MENELAUS_RTC_CTRL,
+ the_menelaus->rtc_control);
+ }
+
+ return status;
+}
+
+#ifdef CONFIG_RTC_INTF_DEV
+
+static void menelaus_rtc_update_work(struct menelaus_chip *m)
+{
+ /* report 1/sec update */
+ local_irq_disable();
+ rtc_update_irq(m->rtc, 1, RTC_IRQF | RTC_UF);
+ local_irq_enable();
+}
+
+static int menelaus_ioctl(struct device *dev, unsigned cmd, unsigned long arg)
+{
+ int status;
+
+ if (the_menelaus->client->irq <= 0)
+ return -ENOIOCTLCMD;
+
+ switch (cmd) {
+ /* alarm IRQ */
+ case RTC_AIE_ON:
+ if (the_menelaus->rtc_control & RTC_CTRL_AL_EN)
+ return 0;
+ the_menelaus->rtc_control |= RTC_CTRL_AL_EN;
+ break;
+ case RTC_AIE_OFF:
+ if (!(the_menelaus->rtc_control & RTC_CTRL_AL_EN))
+ return 0;
+ the_menelaus->rtc_control &= ~RTC_CTRL_AL_EN;
+ break;
+ /* 1/second "update" IRQ */
+ case RTC_UIE_ON:
+ if (the_menelaus->uie)
+ return 0;
+ status = menelaus_remove_irq_work(MENELAUS_RTCTMR_IRQ);
+ status = menelaus_add_irq_work(MENELAUS_RTCTMR_IRQ,
+ menelaus_rtc_update_work);
+ if (status == 0)
+ the_menelaus->uie = 1;
+ return status;
+ case RTC_UIE_OFF:
+ if (!the_menelaus->uie)
+ return 0;
+ status = menelaus_remove_irq_work(MENELAUS_RTCTMR_IRQ);
+ if (status == 0)
+ the_menelaus->uie = 0;
+ return status;
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return menelaus_write_reg(MENELAUS_RTC_CTRL, the_menelaus->rtc_control);
+}
+
+#else
+#define menelaus_ioctl NULL
+#endif
+
+/* REVISIT no compensation register support ... */
+
+static const struct rtc_class_ops menelaus_rtc_ops = {
+ .ioctl = menelaus_ioctl,
+ .read_time = menelaus_read_time,
+ .set_time = menelaus_set_time,
+ .read_alarm = menelaus_read_alarm,
+ .set_alarm = menelaus_set_alarm,
+};
+
+static void menelaus_rtc_alarm_work(struct menelaus_chip *m)
+{
+ /* report alarm */
+ local_irq_disable();
+ rtc_update_irq(m->rtc, 1, RTC_IRQF | RTC_AF);
+ local_irq_enable();
+
+ /* then disable it; alarms are oneshot */
+ the_menelaus->rtc_control &= ~RTC_CTRL_AL_EN;
+ menelaus_write_reg(MENELAUS_RTC_CTRL, the_menelaus->rtc_control);
+}
+
+static inline void menelaus_rtc_init(struct menelaus_chip *m)
+{
+ int alarm = (m->client->irq > 0);
+
+ /* assume 32KDETEN pin is pulled high */
+ if (!(menelaus_read_reg(MENELAUS_OSC_CTRL) & 0x80)) {
+ dev_dbg(&m->client->dev, "no 32k oscillator\n");
+ return;
+ }
+
+ /* support RTC alarm; it can issue wakeups */
+ if (alarm) {
+ if (menelaus_add_irq_work(MENELAUS_RTCALM_IRQ,
+ menelaus_rtc_alarm_work) < 0) {
+ dev_err(&m->client->dev, "can't handle RTC alarm\n");
+ return;
+ }
+ device_init_wakeup(&m->client->dev, 1);
+ }
+
+ /* be sure RTC is enabled; allow 1/sec irqs; leave 12hr mode alone */
+ m->rtc_control = menelaus_read_reg(MENELAUS_RTC_CTRL);
+ if (!(m->rtc_control & RTC_CTRL_RTC_EN)
+ || (m->rtc_control & RTC_CTRL_AL_EN)
+ || (m->rtc_control & RTC_CTRL_EVERY_MASK)) {
+ if (!(m->rtc_control & RTC_CTRL_RTC_EN)) {
+ dev_warn(&m->client->dev, "rtc clock needs setting\n");
+ m->rtc_control |= RTC_CTRL_RTC_EN;
+ }
+ m->rtc_control &= ~RTC_CTRL_EVERY_MASK;
+ m->rtc_control &= ~RTC_CTRL_AL_EN;
+ menelaus_write_reg(MENELAUS_RTC_CTRL, m->rtc_control);
+ }
+
+ m->rtc = rtc_device_register(DRIVER_NAME,
+ &m->client->dev,
+ &menelaus_rtc_ops, THIS_MODULE);
+ if (IS_ERR(m->rtc)) {
+ if (alarm) {
+ menelaus_remove_irq_work(MENELAUS_RTCALM_IRQ);
+ device_init_wakeup(&m->client->dev, 0);
+ }
+ dev_err(&m->client->dev, "can't register RTC: %d\n",
+ (int) PTR_ERR(m->rtc));
+ the_menelaus->rtc = NULL;
+ }
+}
+
+#else
+
+static inline void menelaus_rtc_init(struct menelaus_chip *m)
+{
+ /* nothing */
+}
+
+#endif
+
+/*-----------------------------------------------------------------------*/
+
+static struct i2c_driver menelaus_i2c_driver;
+
+static int menelaus_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct menelaus_chip *menelaus;
+ int rev = 0, val;
+ int err = 0;
+ struct menelaus_platform_data *menelaus_pdata =
+ client->dev.platform_data;
+
+ if (the_menelaus) {
+ dev_dbg(&client->dev, "only one %s for now\n",
+ DRIVER_NAME);
+ return -ENODEV;
+ }
+
+ menelaus = kzalloc(sizeof *menelaus, GFP_KERNEL);
+ if (!menelaus)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, menelaus);
+
+ the_menelaus = menelaus;
+ menelaus->client = client;
+
+ /* If a true probe check the device */
+ rev = menelaus_read_reg(MENELAUS_REV);
+ if (rev < 0) {
+ dev_err(&client->dev, "device not found");
+ err = -ENODEV;
+ goto fail1;
+ }
+
+ /* Ack and disable all Menelaus interrupts */
+ menelaus_write_reg(MENELAUS_INT_ACK1, 0xff);
+ menelaus_write_reg(MENELAUS_INT_ACK2, 0xff);
+ menelaus_write_reg(MENELAUS_INT_MASK1, 0xff);
+ menelaus_write_reg(MENELAUS_INT_MASK2, 0xff);
+ menelaus->mask1 = 0xff;
+ menelaus->mask2 = 0xff;
+
+ /* Set output buffer strengths */
+ menelaus_write_reg(MENELAUS_MCT_CTRL1, 0x73);
+
+ if (client->irq > 0) {
+ 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",
+ client->irq, err);
+ goto fail1;
+ }
+ }
+
+ mutex_init(&menelaus->lock);
+ INIT_WORK(&menelaus->work, menelaus_work);
+
+ dev_info(&client->dev, "Menelaus rev %d.%d\n", rev >> 4, rev & 0x0f);
+
+ val = menelaus_read_reg(MENELAUS_VCORE_CTRL1);
+ if (val < 0)
+ goto fail2;
+ if (val & (1 << 7))
+ menelaus->vcore_hw_mode = 1;
+ else
+ menelaus->vcore_hw_mode = 0;
+
+ if (menelaus_pdata != NULL && menelaus_pdata->late_init != NULL) {
+ err = menelaus_pdata->late_init(&client->dev);
+ if (err < 0)
+ goto fail2;
+ }
+
+ menelaus_rtc_init(menelaus);
+
+ return 0;
+fail2:
+ free_irq(client->irq, menelaus);
+ flush_scheduled_work();
+fail1:
+ kfree(menelaus);
+ return err;
+}
+
+static int __exit menelaus_remove(struct i2c_client *client)
+{
+ struct menelaus_chip *menelaus = i2c_get_clientdata(client);
+
+ free_irq(client->irq, menelaus);
+ kfree(menelaus);
+ i2c_set_clientdata(client, NULL);
+ the_menelaus = NULL;
+ return 0;
+}
+
+static const struct i2c_device_id menelaus_id[] = {
+ { "menelaus", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, menelaus_id);
+
+static struct i2c_driver menelaus_i2c_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ },
+ .probe = menelaus_probe,
+ .remove = __exit_p(menelaus_remove),
+ .id_table = menelaus_id,
+};
+
+static int __init menelaus_init(void)
+{
+ return i2c_add_driver(&menelaus_i2c_driver);
+}
+
+static void __exit menelaus_exit(void)
+{
+ i2c_del_driver(&menelaus_i2c_driver);
+
+ /* FIXME: Shutdown menelaus parts that can be shut down */
+}
+
+MODULE_AUTHOR("Texas Instruments, Inc. (and others)");
+MODULE_DESCRIPTION("I2C interface for Menelaus.");
+MODULE_LICENSE("GPL");
+
+module_init(menelaus_init);
+module_exit(menelaus_exit);
--- /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 <mach/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,
+ const struct i2c_device_id *device_id)
+{
+ 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 const struct i2c_device_id tsl2563_id[] = {
+ { DRIVER_NAME, 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, tsl2563_id);
+
+static struct i2c_driver tsl2563_i2c_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ },
+ .suspend = tsl2563_suspend,
+ .resume = tsl2563_resume,
+ .probe = tsl2563_probe,
+ .remove = __devexit_p(tsl2563_remove),
+ .id_table = tsl2563_id,
+};
+
+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
+/*
+ * 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/platform_device.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: "
+
+struct twl4030_madc_data {
+ struct device *dev;
+ struct mutex lock;
+ struct work_struct ws;
+ struct twl4030_madc_request requests[TWL4030_MADC_NUM_METHODS];
+ int imr;
+ int isr;
+};
+
+static struct twl4030_madc_data *the_madc;
+
+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 int twl4030_madc_read(struct twl4030_madc_data *madc, u8 reg)
+{
+ int ret;
+ u8 val;
+
+ ret = twl4030_i2c_read_u8(TWL4030_MODULE_MADC, &val, reg);
+ if (ret) {
+ dev_dbg(madc->dev, "unable to read register 0x%X\n", reg);
+ return ret;
+ }
+
+ return val;
+}
+
+static void twl4030_madc_write(struct twl4030_madc_data *madc, u8 reg, u8 val)
+{
+ int ret;
+
+ ret = twl4030_i2c_write_u8(TWL4030_MODULE_MADC, val, reg);
+ if (ret)
+ dev_err(madc->dev, "unable to write register 0x%X\n", reg);
+}
+
+static int twl4030_madc_channel_raw_read(struct twl4030_madc_data *madc, 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 */
+ msb = twl4030_madc_read(madc, reg + 1);
+ lsb = twl4030_madc_read(madc, reg);
+
+ return (int)(((msb << 8) | lsb) >> 6);
+}
+
+static int twl4030_madc_read_channels(struct twl4030_madc_data *madc,
+ 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(madc, reg);
+ count++;
+ }
+ }
+ return count;
+}
+
+static void twl4030_madc_enable_irq(struct twl4030_madc_data *madc, int id)
+{
+ u8 val;
+
+ val = twl4030_madc_read(madc, madc->imr);
+ val &= ~(1 << id);
+ twl4030_madc_write(madc, madc->imr, val);
+}
+
+static void twl4030_madc_disable_irq(struct twl4030_madc_data *madc, int id)
+{
+ u8 val;
+
+ val = twl4030_madc_read(madc, madc->imr);
+ val |= (1 << id);
+ twl4030_madc_write(madc, madc->imr, val);
+}
+
+static irqreturn_t twl4030_madc_irq_handler(int irq, void *_madc)
+{
+ struct twl4030_madc_data *madc = _madc;
+ u8 isr_val, imr_val;
+ int i;
+
+#ifdef CONFIG_LOCKDEP
+ /* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which
+ * we don't want and can't tolerate. Although it might be
+ * friendlier not to borrow this thread context...
+ */
+ local_irq_enable();
+#endif
+
+ /* Use COR to ack interrupts since we have no shared IRQs in ISRx */
+ isr_val = twl4030_madc_read(madc, madc->isr);
+ imr_val = twl4030_madc_read(madc, madc->imr);
+
+ isr_val &= ~imr_val;
+
+ for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
+
+ if (!(isr_val & (1<<i)))
+ continue;
+
+ twl4030_madc_disable_irq(madc, i);
+ madc->requests[i].result_pending = 1;
+ }
+
+ schedule_work(&madc->ws);
+
+ return IRQ_HANDLED;
+}
+
+static void twl4030_madc_work(struct work_struct *ws)
+{
+ const struct twl4030_madc_conversion_method *method;
+ struct twl4030_madc_data *madc;
+ struct twl4030_madc_request *r;
+ int len, i;
+
+ madc = container_of(ws, struct twl4030_madc_data, ws);
+ mutex_lock(&madc->lock);
+
+ for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
+
+ r = &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(madc, 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(&madc->lock);
+}
+
+static int twl4030_madc_set_irq(struct twl4030_madc_data *madc,
+ struct twl4030_madc_request *req)
+{
+ struct twl4030_madc_request *p;
+
+ p = &madc->requests[req->method];
+
+ memcpy(p, req, sizeof *req);
+
+ twl4030_madc_enable_irq(madc, req->method);
+
+ return 0;
+}
+
+static inline void twl4030_madc_start_conversion(struct twl4030_madc_data *madc,
+ 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(madc, method->ctrl, TWL4030_MADC_SW_START);
+ break;
+ case TWL4030_MADC_RT:
+ default:
+ break;
+ }
+}
+
+static void twl4030_madc_wait_conversion_ready_ms(
+ struct twl4030_madc_data *madc,
+ u8 *time, u8 status_reg)
+{
+ u8 reg = 0;
+
+ do {
+ msleep(1);
+ (*time)--;
+ reg = twl4030_madc_read(madc, 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 (the_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(&the_madc->lock);
+
+ /* Select channels to be converted */
+ twl4030_madc_write(the_madc, method->sel + 1, ch_msb);
+ twl4030_madc_write(the_madc, method->sel, ch_lsb);
+
+ /* Select averaging for all channels if do_avg is set */
+ if (req->do_avg) {
+ twl4030_madc_write(the_madc, method->avg + 1, ch_msb);
+ twl4030_madc_write(the_madc, method->avg, ch_lsb);
+ }
+
+ if ((req->type == TWL4030_MADC_IRQ_ONESHOT) && (req->func_cb != NULL)) {
+ twl4030_madc_set_irq(the_madc, req);
+ twl4030_madc_start_conversion(the_madc, req->method);
+ the_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(the_madc, req->method);
+ the_madc->requests[req->method].active = 1;
+
+ /* Wait until conversion is ready (ctrl register returns EOC) */
+ wait_time = 50;
+ twl4030_madc_wait_conversion_ready_ms(the_madc,
+ &wait_time, method->ctrl);
+ if (wait_time == 0) {
+ dev_dbg(the_madc->dev, "conversion timeout!\n");
+ ret = -EAGAIN;
+ goto out;
+ }
+
+ ret = twl4030_madc_read_channels(the_madc, method->rbase, req->channels,
+ req->rbuf);
+
+ the_madc->requests[req->method].active = 0;
+
+out:
+ mutex_unlock(&the_madc->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(twl4030_madc_conversion);
+
+static int twl4030_madc_set_current_generator(struct twl4030_madc_data *madc,
+ 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(struct twl4030_madc_data *madc, int on)
+{
+ u8 regval;
+
+ regval = twl4030_madc_read(madc, TWL4030_MADC_CTRL1);
+ if (on)
+ regval |= TWL4030_MADC_MADCON;
+ else
+ regval &= ~TWL4030_MADC_MADCON;
+ twl4030_madc_write(madc, 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) {
+ dev_dbg(the_madc->dev, "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;
+ req.func_cb = NULL;
+
+ 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) {
+ dev_dbg(the_madc->dev, "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-madc",
+ .fops = &twl4030_madc_fileops
+};
+
+static int __init twl4030_madc_probe(struct platform_device *pdev)
+{
+ struct twl4030_madc_data *madc;
+ struct twl4030_madc_platform_data *pdata = pdev->dev.platform_data;
+ int ret;
+ u8 regval;
+
+ madc = kzalloc(sizeof *madc, GFP_KERNEL);
+ if (!madc)
+ return -ENOMEM;
+
+ if (!pdata) {
+ dev_dbg(&pdev->dev, "platform_data not available\n");
+ ret = -EINVAL;
+ goto err_pdata;
+ }
+
+ madc->imr = (pdata->irq_line == 1) ? TWL4030_MADC_IMR1 : TWL4030_MADC_IMR2;
+ madc->isr = (pdata->irq_line == 1) ? TWL4030_MADC_ISR1 : TWL4030_MADC_ISR2;
+
+ ret = misc_register(&twl4030_madc_device);
+ if (ret) {
+ dev_dbg(&pdev->dev, "could not register misc_device\n");
+ goto err_misc;
+ }
+ twl4030_madc_set_power(madc, 1);
+ twl4030_madc_set_current_generator(madc, 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(platform_get_irq(pdev, 0), twl4030_madc_irq_handler,
+ 0, "twl4030_madc", madc);
+ if (ret) {
+ dev_dbg(&pdev->dev, "could not request irq\n");
+ goto err_irq;
+ }
+
+ platform_set_drvdata(pdev, madc);
+ mutex_init(&madc->lock);
+ INIT_WORK(&madc->ws, twl4030_madc_work);
+
+ the_madc = madc;
+
+ return 0;
+
+err_irq:
+ misc_deregister(&twl4030_madc_device);
+
+err_misc:
+err_pdata:
+ kfree(madc);
+
+ return ret;
+}
+
+static int __exit twl4030_madc_remove(struct platform_device *pdev)
+{
+ struct twl4030_madc_data *madc = platform_get_drvdata(pdev);
+
+ twl4030_madc_set_power(madc, 0);
+ twl4030_madc_set_current_generator(madc, 0, 0);
+ free_irq(platform_get_irq(pdev, 0), madc);
+ cancel_work_sync(&madc->ws);
+ misc_deregister(&twl4030_madc_device);
+
+ return 0;
+}
+
+static struct platform_driver twl4030_madc_driver = {
+ .probe = twl4030_madc_probe,
+ .remove = __exit_p(twl4030_madc_remove),
+ .driver = {
+ .name = "twl4030_madc",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init twl4030_madc_init(void)
+{
+ return platform_driver_register(&twl4030_madc_driver);
+}
+module_init(twl4030_madc_init);
+
+static void __exit twl4030_madc_exit(void)
+{
+ platform_driver_unregister(&twl4030_madc_driver);
+}
+module_exit(twl4030_madc_exit);
+
+MODULE_ALIAS("platform:twl4030-madc");
+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_ALIAS("i2c:twl4030-poweroff");
+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/interrupt.h>
+#include <linux/i2c/twl4030.h>
+
+
+#define PWR_PWRON_IRQ (1<<0)
+
+#define STS_HW_CONDITIONS 0xf
+
+
+/* FIXME have this constant delivered to us as part of the
+ * twl4030-core setup ...
+ */
+#define TWL4030_PWRIRQ_PWRBTN (TWL4030_PWR_IRQ_BASE + 0)
+
+static struct input_dev *powerbutton_dev;
+
+static irqreturn_t powerbutton_irq(int irq, void *dev_id)
+{
+ int err;
+ u8 value;
+
+#ifdef CONFIG_LOCKDEP
+ /* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which
+ * we don't want and can't tolerate. Although it might be
+ * friendlier not to borrow this thread context...
+ */
+ local_irq_enable();
+#endif
+
+ 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 {
+ pr_err("twl4030: 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;
+
+ /* PWRBTN == PWRON */
+ err = request_irq(TWL4030_PWRIRQ_PWRBTN, powerbutton_irq,
+ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+ "PwrButton", NULL);
+ if (err < 0) {
+ pr_debug("Can't get IRQ for power button: %d\n", err);
+ goto out;
+ }
+
+ powerbutton_dev = input_allocate_device();
+ if (!powerbutton_dev) {
+ pr_debug("Can't allocate 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) {
+ pr_debug("Can't register power button: %d\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;
+}
+module_init(twl4030_pwrbutton_init);
+
+static void __exit twl4030_pwrbutton_exit(void)
+{
+ free_irq(TWL4030_PWRIRQ_PWRBTN, NULL);
+ input_unregister_device(powerbutton_dev);
+ input_free_device(powerbutton_dev);
+}
+module_exit(twl4030_pwrbutton_exit);
+
+MODULE_DESCRIPTION("Triton2 Power Button");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Peter De Schrijver");
+
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
+ 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_PXA930_ROTARY) += pxa930_rotary.o
obj-$(CONFIG_KEYBOARD_AAED2000) += aaed2000_kbd.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/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;
+ int running;
+ struct mutex lock;
+ 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;
+ 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;
+}
+
+static void pwm_done(struct lm8323_pwm *pwm)
+{
+ mutex_lock(&pwm->lock);
+ pwm->running = 0;
+ if (pwm->desired_brightness != pwm->brightness)
+ schedule_work(&pwm->work);
+ mutex_unlock(&pwm->lock);
+}
+
+/*
+ * 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");
+ pwm_done(&lm->pwm1);
+ }
+ if (ints & INT_PWM2) {
+ debug(&lm->client->dev, "pwm2 engine completed\n");
+ pwm_done(&lm->pwm2);
+ }
+ if (ints & INT_PWM3) {
+ debug(&lm->client->dev, "pwm3 engine completed\n");
+ pwm_done(&lm->pwm3);
+ }
+ }
+
+ 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 'kill' is nonzero, the engine will be shut down at the end
+ * of the script, producing a zero output. Otherwise the engine
+ * will be kept running at the final PWM level indefinitely.
+ */
+static void lm8323_write_pwm(struct lm8323_pwm *pwm, int kill,
+ int len, const u16 *cmds)
+{
+ struct lm8323_chip *lm = pwm_to_lm8323(pwm);
+ int i;
+
+ for (i = 0; i < len; i++)
+ lm8323_write_pwm_one(pwm, i, cmds[i]);
+
+ lm8323_write_pwm_one(pwm, i++, PWM_END(kill));
+ lm8323_write(lm, 2, LM8323_CMD_START_PWM, pwm->id);
+ pwm->running = 1;
+}
+
+static void lm8323_pwm_work(struct work_struct *work)
+{
+ struct lm8323_pwm *pwm = work_to_pwm(work);
+ int div512, perstep, steps, hz, up, kill;
+ u16 pwm_cmds[3];
+ int num_cmds = 0;
+
+ mutex_lock(&pwm->lock);
+
+ /*
+ * Do nothing if we're already at the requested level,
+ * or previous setting is not yet complete. In the latter
+ * case we will be called again when the previous PWM script
+ * finishes.
+ */
+ if (pwm->running || pwm->desired_brightness == pwm->brightness) {
+ mutex_unlock(&pwm->lock);
+ return;
+ }
+
+ kill = (pwm->desired_brightness == 0);
+ up = (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)) {
+ div512 = 1;
+ hz = 32768 / 512;
+ }
+ else {
+ div512 = 0;
+ hz = 32768 / 16;
+ }
+
+ perstep = (hz * pwm->fade_time) / (steps * 1000);
+
+ if (perstep == 0)
+ perstep = 1;
+ else if (perstep > 63)
+ perstep = 63;
+
+ while (steps) {
+ int s;
+
+ s = min(126, steps);
+ pwm_cmds[num_cmds++] = PWM_RAMP(div512, perstep, s, up);
+ steps -= s;
+ }
+
+ lm8323_write_pwm(pwm, kill, num_cmds, pwm_cmds);
+
+ pwm->brightness = pwm->desired_brightness;
+ mutex_unlock(&pwm->lock);
+}
+
+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);
+
+ mutex_lock(&pwm->lock);
+ pwm->desired_brightness = brightness;
+ mutex_unlock(&pwm->lock);
+
+ 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;
+ pwm->running = 0;
+ mutex_init(&pwm->lock);
+ 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,
+ const struct i2c_device_id *id)
+{
+ 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;
+
+ 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", client->irq);
+ goto fail6;
+ }
+
+ set_irq_wake(client->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;
+ err = input_register_device(idev);
+ if (err) {
+ 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(client->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(client->irq, lm);
+ cancel_work_sync(&lm->work);
+ input_unregister_device(lm->idev);
+ device_remove_file(&lm->client->dev, &dev_attr_disable_kp);
+ if (lm->pwm3.enabled)
+ led_classdev_unregister(&lm->pwm3.cdev);
+ if (lm->pwm2.enabled)
+ led_classdev_unregister(&lm->pwm2.cdev);
+ if (lm->pwm1.enabled)
+ led_classdev_unregister(&lm->pwm1.cdev);
+ kfree(lm);
+
+ 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(client->irq, 0);
+ disable_irq(client->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(client->irq);
+ set_irq_wake(client->irq, 1);
+
+ return 0;
+}
+
+static const struct i2c_device_id lm8323_id[] = {
+ { DRIVER_NAME, 0 },
+ { }
+};
+
+static struct i2c_driver lm8323_i2c_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ },
+ .probe = lm8323_probe,
+ .remove = __devexit_p(lm8323_remove),
+ .suspend = lm8323_suspend,
+ .resume = lm8323_resume,
+ .id_table = lm8323_id,
+};
+MODULE_DEVICE_TABLE(i2c, lm8323_id);
+
+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("Timo O. Karjalainen <timo.o.karjalainen@nokia.com>, 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 <linux/i2c/menelaus.h>
#include <mach/gpio.h>
#include <mach/keypad.h>
-#include <mach/menelaus.h>
#include <asm/irq.h>
#include <mach/hardware.h>
#include <asm/io.h>
+#include <asm/mach-types.h>
#include <mach/mux.h>
#undef NEW_BOARD_LEARNING_MODE
unsigned int cols;
unsigned long delay;
unsigned int debounce;
+ int suspended;
+ spinlock_t suspend_lock;
};
static 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/mutex.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 <mach/keypad.h>
+
+#include "twl4030-keypad.h"
+
+#define PTV_PRESCALER 4
+
+#define MAX_ROWS 8 /* TWL4030 hardlimit */
+
+/* Global variables */
+
+struct omap_keypad {
+ int *keymap;
+ unsigned int keymapsize;
+ u16 kp_state[MAX_ROWS];
+ int n_rows;
+ int n_cols;
+ int irq;
+
+ struct device *dbg_dev;
+ struct input_dev *omap_twl4030kp;
+
+ /* sync read/write */
+ struct mutex mutex;
+};
+
+static int twl4030_kpread(struct omap_keypad *kp,
+ 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(kp->dbg_dev,
+ "Couldn't read TWL4030: %X - ret %d[%x]\n",
+ reg, ret, ret);
+ return ret;
+ }
+ return ret;
+}
+
+static int twl4030_kpwrite_u8(struct omap_keypad *kp,
+ u32 module, u8 data, u32 reg)
+{
+ int ret;
+
+ ret = twl4030_i2c_write_u8(module, data, reg);
+ if (ret < 0) {
+ dev_warn(kp->dbg_dev,
+ "Could not write TWL4030: %X - ret %d[%x]\n",
+ reg, ret, ret);
+ return ret;
+ }
+ return ret;
+}
+
+static int omap_kp_find_key(struct omap_keypad *kp, int col, int row)
+{
+ int i, rc;
+
+ rc = KEY(col, row, 0);
+ for (i = 0; i < kp->keymapsize; i++)
+ if ((kp->keymap[i] & ROWCOL_MASK) == rc)
+ return kp->keymap[i] & (KEYNUM_MASK | KEY_PERSISTENT);
+
+ return -EINVAL;
+}
+
+static inline u16 omap_kp_col_xlate(struct omap_keypad *kp, 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 << kp->n_cols;
+ else
+ return col & ((1 << kp->n_cols) - 1);
+}
+
+static int omap_kp_read_kp_matrix_state(struct omap_keypad *kp, u16 *state)
+{
+ u8 new_state[MAX_ROWS];
+ int row;
+ int ret = twl4030_kpread(kp, TWL4030_MODULE_KEYPAD,
+ new_state, KEYP_FULL_CODE_7_0, kp->n_rows);
+ if (ret >= 0) {
+ for (row = 0; row < kp->n_rows; row++)
+ state[row] = omap_kp_col_xlate(kp, new_state[row]);
+ }
+ return ret;
+}
+
+static int omap_kp_is_in_ghost_state(struct omap_keypad *kp, u16 *key_state)
+{
+ int i;
+ u16 check = 0;
+
+ for (i = 0; i < kp->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(struct omap_keypad *kp, 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(kp, new_state);
+ if (ret < 0) /* panic ... */
+ return;
+
+ if (omap_kp_is_in_ghost_state(kp, new_state))
+ return;
+ }
+
+ mutex_lock(&kp->mutex);
+
+ /* check for changes and print those */
+ for (row = 0; row < kp->n_rows; row++) {
+ int changed = new_state[row] ^ kp->kp_state[row];
+
+ if (!changed)
+ continue;
+
+ for (col = 0; col < kp->n_cols; col++) {
+ int key;
+
+ if (!(changed & (1 << col)))
+ continue;
+
+ dev_dbg(kp->dbg_dev, "key [%d:%d] %s\n", row, col,
+ (new_state[row] & (1 << col)) ?
+ "press" : "release");
+
+ key = omap_kp_find_key(kp, col, row);
+ if (key < 0)
+ dev_warn(kp->dbg_dev,
+ "Spurious key event %d-%d\n",
+ col, row);
+ else if (key & KEY_PERSISTENT)
+ continue;
+ else
+ input_report_key(kp->omap_twl4030kp, key,
+ new_state[row] & (1 << col));
+ }
+ kp->kp_state[row] = new_state[row];
+ }
+
+ mutex_unlock(&kp->mutex);
+}
+
+/*
+ * Keypad interrupt handler
+ */
+static irqreturn_t do_kp_irq(int irq, void *_kp)
+{
+ struct omap_keypad *kp = _kp;
+ u8 reg;
+ int ret;
+
+#ifdef CONFIG_LOCKDEP
+ /* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which
+ * we don't want and can't tolerate. Although it might be
+ * friendlier not to borrow this thread context...
+ */
+ local_irq_enable();
+#endif
+
+ /* Read & Clear TWL4030 pending interrupt */
+ ret = twl4030_kpread(kp, 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(kp, 0);
+ else
+ twl4030_kp_scan(kp, 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_keypad *kp;
+ struct twl4030_keypad_data *pdata = pdev->dev.platform_data;
+
+ kp = kzalloc(sizeof(*kp), GFP_KERNEL);
+ if (!kp)
+ return -ENOMEM;
+
+ if (!pdata->rows || !pdata->cols || !pdata->keymap) {
+ dev_err(&pdev->dev, "No rows, cols or keymap from pdata\n");
+ kfree(kp);
+ return -EINVAL;
+ }
+
+ dev_set_drvdata(&pdev->dev, kp);
+
+ /* Get the debug Device */
+ kp->dbg_dev = &pdev->dev;
+
+ kp->omap_twl4030kp = input_allocate_device();
+ if (!kp->omap_twl4030kp) {
+ kfree(kp);
+ return -ENOMEM;
+ }
+
+ mutex_init(&kp->mutex);
+
+ kp->keymap = pdata->keymap;
+ kp->keymapsize = pdata->keymapsize;
+ kp->n_rows = pdata->rows;
+ kp->n_cols = pdata->cols;
+ kp->irq = platform_get_irq(pdev, 0);
+
+ /* setup input device */
+ set_bit(EV_KEY, kp->omap_twl4030kp->evbit);
+
+ /* Enable auto repeat feature of Linux input subsystem */
+ if (pdata->rep)
+ set_bit(EV_REP, kp->omap_twl4030kp->evbit);
+
+ for (i = 0; i < kp->keymapsize; i++)
+ set_bit(kp->keymap[i] & KEYNUM_MASK,
+ kp->omap_twl4030kp->keybit);
+
+ kp->omap_twl4030kp->name = "omap_twl4030keypad";
+ kp->omap_twl4030kp->phys = "omap_twl4030keypad/input0";
+ kp->omap_twl4030kp->dev.parent = &pdev->dev;
+
+ kp->omap_twl4030kp->id.bustype = BUS_HOST;
+ kp->omap_twl4030kp->id.vendor = 0x0001;
+ kp->omap_twl4030kp->id.product = 0x0001;
+ kp->omap_twl4030kp->id.version = 0x0003;
+
+ kp->omap_twl4030kp->keycode = kp->keymap;
+ kp->omap_twl4030kp->keycodesize = sizeof(unsigned int);
+ kp->omap_twl4030kp->keycodemax = kp->keymapsize;
+
+ ret = input_register_device(kp->omap_twl4030kp);
+ if (ret < 0) {
+ dev_err(kp->dbg_dev,
+ "Unable to register twl4030 keypad device\n");
+ goto err2;
+ }
+
+ /* Disable auto-repeat */
+ reg = KEYP_CTRL_NOAUTORPT;
+ ret = twl4030_kpwrite_u8(kp, 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(kp, 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(kp, 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(kp, 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(kp, TWL4030_MODULE_KEYPAD,
+ (i & 0xFF), KEYP_TIMEOUT_L);
+ if (ret < 0)
+ goto err3;
+
+ ret = twl4030_kpwrite_u8(kp, 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(kp, 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(kp->irq, do_kp_irq, 0, pdev->name, kp);
+ if (ret < 0) {
+ dev_info(kp->dbg_dev, "request_irq failed for irq no=%d\n",
+ kp->irq);
+ goto err3;
+ } else {
+ /* Enable KP and TO interrupts now. */
+ reg = ~(KEYP_IMR1_KP | KEYP_IMR1_TO);
+ ret = twl4030_kpwrite_u8(kp, TWL4030_MODULE_KEYPAD,
+ reg, KEYP_IMR1);
+ if (ret < 0)
+ goto err5;
+ }
+
+ ret = omap_kp_read_kp_matrix_state(kp, kp->kp_state);
+ if (ret < 0)
+ goto err4;
+
+ return ret;
+err5:
+ /* mask all events - we don't care about the result */
+ (void) twl4030_kpwrite_u8(kp, TWL4030_MODULE_KEYPAD, 0xff, KEYP_IMR1);
+err4:
+ free_irq(kp->irq, NULL);
+err3:
+ input_unregister_device(kp->omap_twl4030kp);
+err2:
+ input_free_device(kp->omap_twl4030kp);
+
+ return -ENODEV;
+}
+
+static int omap_kp_remove(struct platform_device *pdev)
+{
+ struct omap_keypad *kp = dev_get_drvdata(&pdev->dev);
+
+ free_irq(kp->irq, kp);
+ input_unregister_device(kp->omap_twl4030kp);
+ kfree(kp);
+
+ return 0;
+}
+
+
+static struct platform_driver omap_kp_driver = {
+ .probe = omap_kp_probe,
+ .remove = __devexit_p(omap_kp_remove),
+ .driver = {
+ .name = "twl4030_keypad",
+ .owner = THIS_MODULE,
+ },
+};
+
+/*
+ * 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_ALIAS("platform:twl4030_keypad");
+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, IRQ_TYPE_EDGE_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, IRQ_TYPE_NONE);
+ 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, IRQ_TYPE_EDGE_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 atmel_tsadcc.
+config TOUCHSCREEN_TSC2005
+ tristate "TSC2005 touchscreen support"
+ depends on SPI_MASTER
+ help
+ Say Y here for if you are using the touchscreen features of TSC2005.
+
+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"
depends on AC97_BUS
obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o
-obj-$(CONFIG_TOUCHSCREEN_TSC2007) += tsc2007.o
obj-$(CONFIG_TOUCHSCREEN_UCB1400) += ucb1400_ts.o
-obj-$(CONFIG_TOUCHSCREEN_WACOM_W8001) += wacom_w8001.o
+obj-$(CONFIG_TOUCHSCREEN_TSC2005) += tsc2005.o
+obj-$(CONFIG_TOUCHSCREEN_TSC210X) += tsc210x_ts.o
+obj-$(CONFIG_TOUCHSCREEN_TSC2301) += tsc2301_ts.o
obj-$(CONFIG_TOUCHSCREEN_WM97XX) += wm97xx-ts.o
-obj-$(CONFIG_TOUCHSCREEN_DA9034) += da9034-ts.o
wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9705) += wm9705.o
wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9712) += wm9712.o
wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9713) += wm9713.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
+/*
+ * 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/gpio.h>
+#include <linux/spi/spi.h>
+
+#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_VDD_LOWER_27
+
+#ifdef TSC2005_VDD_LOWER_27
+#define TSC2005_HZ (10000000)
+#else
+#define TSC2005_HZ (25000000)
+#endif
+
+#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 };
+
+ xfer.tx_buf = &data;
+ xfer.rx_buf = NULL;
+ xfer.len = 1;
+ xfer.bits_per_word = 8;
+
+ spi_message_init(&msg);
+ 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) << 16;
+ tx |= value;
+
+ xfer.tx_buf = &tx;
+ xfer.rx_buf = NULL;
+ xfer.len = 4;
+ xfer.bits_per_word = 24;
+
+ spi_message_init(&msg);
+ 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 DAV 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);
+
+ 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);
+
+ r = gpio_request(dav_gpio, "TSC2005 dav");
+ if (r < 0) {
+ dev_err(&ts->spi->dev, "unable to get DAV GPIO");
+ goto err1;
+ }
+ gpio_direction_input(dav_gpio);
+ ts->irq = gpio_to_irq(dav_gpio);
+ dev_dbg(&ts->spi->dev, "TSC2005: DAV IRQ = %d\n", ts->irq);
+
+ 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;
+ }
+
+ idev->name = "TSC2005 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:
+ gpio_free(dav_gpio);
+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);
+
+ mutex_lock(&ts->mutex);
+ tsc2005_disable(ts);
+ mutex_unlock(&ts->mutex);
+
+ 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);
+
+ gpio_free(ts->dav_gpio);
+ 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",
+ .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");
+MODULE_ALIAS("platform:tsc2005");
--- /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_ALIX2
- tristate "LED Support for ALIX.2 and ALIX.3 series"
- depends on LEDS_CLASS && X86 && EXPERIMENTAL
+config LEDS_OMAP_DEBUG
+ boolean "LED Support for OMAP debug board LEDs"
+ depends on LEDS_CLASS=y && ARCH_OMAP
help
- This option enables support for the PCEngines ALIX.2 and ALIX.3 LEDs.
+ 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"
config LEDS_COBALT_RAQ
bool "LED Support for the Cobalt Raq series"
- depends on LEDS_CLASS=y && MIPS_COBALT
+ depends on LEDS_CLASS && MIPS_COBALT
select LEDS_TRIGGERS
help
This option enables support for the Cobalt Raq series LEDs.
LED driver chips accessed via the I2C bus. Supported
devices include PCA9550, PCA9551, PCA9552, and PCA9553.
-config LEDS_WM8350
- tristate "LED Support for WM8350 AudioPlus PMIC"
- depends on LEDS_CLASS && MFD_WM8350
- help
- This option enables support for LEDs driven by the Wolfson
- Microelectronics WM8350 AudioPlus PMIC.
-
config LEDS_DA903X
tristate "LED Support for DA9030/DA9034 PMIC"
depends on LEDS_CLASS && PMIC_DA903X
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_ALIX2) += leds-alix2.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
obj-$(CONFIG_LEDS_PCA955X) += leds-pca955x.o
obj-$(CONFIG_LEDS_DA903X) += leds-da903x.o
obj-$(CONFIG_LEDS_HP_DISK) += leds-hp-disk.o
-obj-$(CONFIG_LEDS_WM8350) += leds-wm8350.o
# LED Triggers
obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.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 <mach/board.h>
+#include <mach/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 <linux/gpio.h>
+
+#include <mach/hardware.h>
+#include <mach/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);
+ gpio_set_value(led_dev->gpio, value);
+}
+
+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++) {
+ ret = gpio_request(leds[i].gpio, leds[i].cdev.name);
+ if (ret < 0)
+ break;
+ gpio_direction_output(leds[i].gpio, 0);
+ 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);
+ gpio_free(leds[i].gpio);
+ }
+ }
+
+ 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);
+ gpio_free(leds[i].gpio);
+ }
+
+ 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");
high speed USB OTG transceiver, an audio codec (on most
versions) and many other features.
+config TWL4030_POWER
+ bool "Support power sequencing scripts on TWL4030/TPS659x0"
+ depends on TWL4030_CORE
+ help
+ Say yes here if you want to use the power sequencing scripts on
+ the TWL4030/TPS659x0. These scripts control which regulators or
+ oscillators are switched off or on or reset when a sleep, wakeup
+ or warm reset event occurs.
+
config MFD_TMIO
bool
default n
obj-$(CONFIG_MENELAUS) += menelaus.o
obj-$(CONFIG_TWL4030_CORE) += twl4030-core.o twl4030-irq.o
+obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o
obj-$(CONFIG_MFD_CORE) += mfd-core.o
#include <linux/i2c.h>
#include <linux/i2c/twl4030.h>
+#ifdef CONFIG_ARM
+#include <mach/cpu.h>
+#endif
/*
* The TWL4030 "Triton 2" is one of a family of a multi-function "Power
#define twl_has_madc() false
#endif
+#ifdef CONFIG_TWL4030_POWER
+#define twl_has_power() true
+#else
+#define twl_has_power() false
+#endif
+
#if defined(CONFIG_RTC_DRV_TWL4030) || defined(CONFIG_RTC_DRV_TWL4030_MODULE)
#define twl_has_rtc() true
#else
{ 3, TWL4030_BASEADD_SECURED_REG },
};
+extern void twl4030_power_init(struct twl4030_power_data *triton2_scripts);
+
/*----------------------------------------------------------------------*/
/* Exported Functions */
/* setup clock framework */
clocks_init();
+ /* load power event scripts */
+ if (twl_has_power() && pdata->power)
+ twl4030_power_init(pdata->power);
+
/* Maybe init the T2 Interrupt subsystem */
if (client->irq
&& pdata->irq_base
--- /dev/null
+/*
+ * linux/drivers/i2c/chips/twl4030-power.c
+ *
+ * Handle TWL4030 Power initialization
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Copyright (C) 2006 Texas Instruments, Inc
+ *
+ * Written by Kalle Jokiniemi
+ * 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>
+#include <linux/platform_device.h>
+
+#include <asm/mach-types.h>
+
+static u8 triton_next_free_address = 0x2b;
+
+#define PWR_P1_SW_EVENTS 0x10
+#define PWR_DEVOFF (1<<0)
+
+#define PHY_TO_OFF_PM_MASTER(p) (p - 0x36)
+#define PHY_TO_OFF_PM_RECEIVER(p) (p - 0x5b)
+
+/* resource - hfclk */
+#define R_HFCLKOUT_DEV_GRP PHY_TO_OFF_PM_RECEIVER(0xe6)
+
+/* PM events */
+#define R_P1_SW_EVENTS PHY_TO_OFF_PM_MASTER(0x46)
+#define R_P2_SW_EVENTS PHY_TO_OFF_PM_MASTER(0x47)
+#define R_P3_SW_EVENTS PHY_TO_OFF_PM_MASTER(0x48)
+#define R_CFG_P1_TRANSITION PHY_TO_OFF_PM_MASTER(0x36)
+#define R_CFG_P2_TRANSITION PHY_TO_OFF_PM_MASTER(0x37)
+#define R_CFG_P3_TRANSITION PHY_TO_OFF_PM_MASTER(0x38)
+
+#define LVL_WAKEUP 0x08
+
+#define ENABLE_WARMRESET (1<<4)
+
+#define END_OF_SCRIPT 0x3f
+
+#define R_SEQ_ADD_A2S PHY_TO_OFF_PM_MASTER(0x55)
+#define R_SEQ_ADD_SA12 PHY_TO_OFF_PM_MASTER(0x56)
+#define R_SEQ_ADD_S2A3 PHY_TO_OFF_PM_MASTER(0x57)
+#define R_SEQ_ADD_WARM PHY_TO_OFF_PM_MASTER(0x58)
+#define R_MEMORY_ADDRESS PHY_TO_OFF_PM_MASTER(0x59)
+#define R_MEMORY_DATA PHY_TO_OFF_PM_MASTER(0x5a)
+
+#define R_PROTECT_KEY 0x0E
+#define KEY_1 0xC0
+#define KEY_2 0x0C
+
+static int __init twl4030_write_script_byte(u8 address, u8 byte)
+{
+ int err;
+
+ err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
+ R_MEMORY_ADDRESS);
+ err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, byte,
+ R_MEMORY_DATA);
+
+ return err;
+}
+
+static int __init twl4030_write_script_ins(u8 address, u16 pmb_message,
+ u8 delay, u8 next)
+{
+ int err = 0;
+
+ address *= 4;
+ err |= twl4030_write_script_byte(address++, pmb_message >> 8);
+ err |= twl4030_write_script_byte(address++, pmb_message & 0xff);
+ err |= twl4030_write_script_byte(address++, delay);
+ err |= twl4030_write_script_byte(address++, next);
+
+ return err;
+}
+
+static int __init twl4030_write_script(u8 address, struct twl4030_ins *script,
+ int len)
+{
+ int err = 0;
+
+ for (; len; len--, address++, script++) {
+ if (len == 1)
+ err |= twl4030_write_script_ins(address,
+ script->pmb_message,
+ script->delay,
+ END_OF_SCRIPT);
+ else
+ err |= twl4030_write_script_ins(address,
+ script->pmb_message,
+ script->delay,
+ address + 1);
+ }
+
+ return err;
+}
+
+static int __init config_wakeup3_sequence(u8 address)
+{
+
+ int err = 0;
+
+ /* Set SLEEP to ACTIVE SEQ address for P3 */
+ err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
+ R_SEQ_ADD_S2A3);
+
+ err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, LVL_WAKEUP,
+ R_P3_SW_EVENTS);
+ if (err)
+ printk(KERN_ERR "TWL4030 wakeup sequence for P3" \
+ "config error\n");
+
+ return err;
+}
+
+static int __init config_wakeup12_sequence(u8 address)
+{
+ int err = 0;
+
+ /* Set SLEEP to ACTIVE SEQ address for P1 and P2 */
+ err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
+ R_SEQ_ADD_SA12);
+
+ /* P1/P2/P3 LVL_WAKEUP should be on LEVEL */
+ err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, LVL_WAKEUP,
+ R_P1_SW_EVENTS);
+ err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, LVL_WAKEUP,
+ R_P2_SW_EVENTS);
+
+ if (machine_is_omap_3430sdp() || machine_is_omap_ldp()) {
+ u8 data;
+ /* Disabling AC charger effect on sleep-active transitions */
+ err |= twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data,
+ R_CFG_P1_TRANSITION);
+ data &= ~(1<<1);
+ err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data ,
+ R_CFG_P1_TRANSITION);
+ }
+
+ if (err)
+ printk(KERN_ERR "TWL4030 wakeup sequence for P1 and P2" \
+ "config error\n");
+
+ return err;
+}
+
+static int __init config_sleep_sequence(u8 address)
+{
+ int err = 0;
+
+ /*
+ * CLKREQ is pulled high on the 2430SDP, therefore, we need to take
+ * it out of the HFCLKOUT DEV_GRP for P1 else HFCLKOUT can't be stopped.
+ */
+
+ err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+ 0x20, R_HFCLKOUT_DEV_GRP);
+
+ /* Set ACTIVE to SLEEP SEQ address in T2 memory*/
+ err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
+ R_SEQ_ADD_A2S);
+
+ if (err)
+ printk(KERN_ERR "TWL4030 sleep sequence config error\n");
+
+ return err;
+}
+
+static int __init config_warmreset_sequence(u8 address)
+{
+
+ int err = 0;
+ u8 rd_data;
+
+ /* Set WARM RESET SEQ address for P1 */
+ err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
+ R_SEQ_ADD_WARM);
+
+ /* P1/P2/P3 enable WARMRESET */
+ err |= twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data,
+ R_P1_SW_EVENTS);
+ rd_data |= ENABLE_WARMRESET;
+ err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data,
+ R_P1_SW_EVENTS);
+
+ err |= twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data,
+ R_P2_SW_EVENTS);
+ rd_data |= ENABLE_WARMRESET;
+ err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data,
+ R_P2_SW_EVENTS);
+
+ err |= twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data,
+ R_P3_SW_EVENTS);
+ rd_data |= ENABLE_WARMRESET;
+ err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data,
+ R_P3_SW_EVENTS);
+
+ if (err)
+ printk(KERN_ERR
+ "TWL4030 warmreset seq config error\n");
+ return err;
+}
+
+static int __init load_triton_script(struct twl4030_script *tscript)
+{
+ u8 address = triton_next_free_address;
+ int err;
+
+ err = twl4030_write_script(address, tscript->script, tscript->size);
+ if (err)
+ return err;
+
+ triton_next_free_address += tscript->size;
+
+ if (tscript->flags & TRITON_WRST_SCRIPT)
+ err |= config_warmreset_sequence(address);
+
+ if (tscript->flags & TRITON_WAKEUP12_SCRIPT)
+ err |= config_wakeup12_sequence(address);
+
+ if (tscript->flags & TRITON_WAKEUP3_SCRIPT)
+ err |= config_wakeup3_sequence(address);
+
+ if (tscript->flags & TRITON_SLEEP_SCRIPT)
+ err |= config_sleep_sequence(address);
+
+ return err;
+}
+
+void __init twl4030_power_init(struct twl4030_power_data *triton2_scripts)
+{
+ int err = 0;
+ int i;
+
+ err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_1,
+ R_PROTECT_KEY);
+ err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_2,
+ R_PROTECT_KEY);
+ if (err)
+ printk(KERN_ERR
+ "TWL4030 Unable to unlock registers\n");
+
+ for (i = 0; i < triton2_scripts->size; i++) {
+ err = load_triton_script(triton2_scripts->scripts[i]);
+ if (err)
+ break;
+ }
+
+ if (twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, R_PROTECT_KEY))
+ printk(KERN_ERR
+ "TWL4030 Unable to relock registers\n");
+}
If unsure, say N.
+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"
default n
obj-$(CONFIG_PHANTOM) += phantom.o
obj-$(CONFIG_SGI_IOC4) += ioc4.o
obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o
+obj-$(CONFIG_OMAP_STI) += sti/
obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o
obj-$(CONFIG_KGDB_TESTS) += kgdbts.o
obj-$(CONFIG_SGI_XP) += sgi-xp/
--- /dev/null
+ifeq ($(CONFIG_ARCH_OMAP3),y)
+obj-$(CONFIG_OMAP_STI) += sdti.o
+else
+obj-$(CONFIG_OMAP_STI) += sti.o sti-fifo.o
+endif
+
+obj-$(CONFIG_NET) += sti-netlink.o
+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 <mach/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 SDTI_SYSCONFIG_SOFTRESET (1 << 1)
+#define SDTI_SYSCONFIG_AUTOIDLE (1 << 0)
+
+static struct clk *sdti_fck, *sdti_ick;
+void __iomem *sti_base, *sti_channel_base;
+static DEFINE_SPINLOCK(sdti_lock);
+
+void 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(sti_channel_write_trace);
+
+static void omap_sdti_reset(void)
+{
+ int i;
+
+ sti_writel(SDTI_SYSCONFIG_SOFTRESET, 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");
+}
+
+static int __init omap_sdti_init(void)
+{
+ char buf[64];
+ int i, ret = 0;
+
+ sdti_fck = clk_get(NULL, "pclk_fck");
+ if (IS_ERR(sdti_fck)) {
+ printk(KERN_ERR "Cannot get clk pclk_fck\n");
+ ret = PTR_ERR(sdti_fck);
+ goto err0;
+ }
+ sdti_ick = clk_get(NULL, "pclkx2_fck");
+ if (IS_ERR(sdti_ick)) {
+ printk(KERN_ERR "Cannot get clk pclkx2_fck\n");
+ ret = PTR_ERR(sdti_ick);
+ goto err1;
+ }
+ ret = clk_enable(sdti_fck);
+ if (ret) {
+ printk(KERN_ERR "Cannot enable sdti_fck\n");
+ goto err2;
+ }
+ ret = clk_enable(sdti_ick);
+ if (ret) {
+ printk(KERN_ERR "Cannot enable sdti_ick\n");
+ goto err3;
+ }
+
+ omap_sdti_reset();
+ sti_writel(0xC5ACCE55, SDTI_LOCK_ACCESS);
+
+ /* Autoidle */
+ sti_writel(SDTI_SYSCONFIG_AUTOIDLE, SDTI_SYSCONFIG);
+
+ /* 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);
+
+ /* CPU2 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);
+ sti_channel_write_trace(strlen(buf), 0xc3, buf, 239);
+
+ return ret;
+
+err3:
+ clk_disable(sdti_fck);
+err2:
+ clk_put(sdti_ick);
+err1:
+ clk_put(sdti_fck);
+err0:
+ return ret;
+}
+
+static void omap_sdti_exit(void)
+{
+ sti_writel(0, SDTI_WINCTRL);
+ clk_disable(sdti_fck);
+ clk_disable(sdti_ick);
+ clk_put(sdti_fck);
+ clk_put(sdti_ick);
+}
+
+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 = ioremap(res->start, size);
+ if (unlikely(!sti_base))
+ return -ENODEV;
+
+ size = cres->end - cres->start;
+ sti_channel_base = ioremap(cres->start, size);
+ if (unlikely(!sti_channel_base)) {
+ iounmap(sti_base);
+ return -ENODEV;
+ }
+
+ return omap_sdti_init();
+}
+
+static int __devexit omap_sdti_remove(struct platform_device *pdev)
+{
+ iounmap(sti_channel_base);
+ iounmap(sti_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 <mach/sti.h>
+#include <mach/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 <mach/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 <mach/sti.h>
+
+static struct sock *sti_sock;
+static DEFINE_MUTEX(sti_netlink_mutex);
+
+enum {
+ STI_READ,
+ STI_WRITE,
+};
+
+#if defined(CONFIG_ARCH_OMAP1) || defined(CONFIG_ARCH_OMAP2)
+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;
+}
+#endif
+
+/*
+ * 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;
+ int 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;
+#if defined(CONFIG_ARCH_OMAP1) || defined(CONFIG_ARCH_OMAP2)
+ 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;
+#endif
+ 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 <mach/sti.h>
+#include <asm/byteorder.h>
+
+static struct clk *sti_ck;
+void __iomem *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;
+ unsigned int size;
+ 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;
+
+ size = res->end - res->start + 1;
+ sti_base = ioremap(res->start, size);
+ if (!sti_base) {
+ ret = -ENOMEM;
+ goto err_badremap;
+ }
+
+ size = cres->end - cres->start + 1;
+ sti_channel_base = ioremap(cres->start, size);
+ if (!sti_channel_base) {
+ iounmap(sti_base);
+ ret = -ENOMEM;
+ 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(sti_channel_base);
+ iounmap(sti_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);
+
+ iounmap(sti_channel_base);
+ iounmap(sti_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_OMAP2430 || ARCH_OMAP3
+ help
+ This selects the TI OMAP High Speed Multimedia card Interface.
+ If you have an OMAP2430 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_ATMELMCI) += atmel-mci.o
obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o
--- /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 <linux/semaphore.h>
+#include <mach/dma.h>
+#include <mach/hardware.h>
+#include <mach/board.h>
+#include <mach/mmc.h>
+#include <mach/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 CLKD_SHIFT 6
+#define DTO_MASK 0x000F0000
+#define DTO_SHIFT 16
+#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 SRC (1 << 25)
+#define SRD (1 << 26)
+
+/*
+ * FIXME: Most likely all the data using these _DEVID defines should come
+ * from the platform_data, or implemented in controller and slot specific
+ * functions.
+ */
+#define OMAP_MMC1_DEVID 0
+#define OMAP_MMC2_DEVID 1
+
+#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-hs"
+
+/*
+ * One controller can have multiple slots, like on some omap boards using
+ * omap.c controller driver. Luckily this is not currently done on any known
+ * omap_hsmmc.c device.
+ */
+#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)
+
+enum {OFF = 0, ON};
+#define IDLE_TIMEOUT (jiffies_to_msecs(10))
+
+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 timer_list idle_timer;
+ spinlock_t clk_lock; /* for changing enabled state */
+ unsigned int fclk_enabled:1;
+
+ struct omap_mmc_platform_data *pdata;
+};
+
+static int mmc_omap_fclk_state(struct mmc_omap_host *host, unsigned int state)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&host->clk_lock, flags);
+ del_timer(&host->idle_timer);
+ if (host->fclk_enabled != state) {
+ if (state == ON) {
+ ret = clk_enable(host->fclk);
+ if (ret != 0)
+ goto err_out;
+
+ dev_dbg(mmc_dev(host->mmc), "mmc_fclk: enabled\n");
+ } else {
+ clk_disable(host->fclk);
+ dev_dbg(mmc_dev(host->mmc), "mmc_fclk: disabled\n");
+ }
+ host->fclk_enabled = state;
+ }
+
+err_out:
+ spin_unlock_irqrestore(&host->clk_lock, flags);
+ return ret;
+}
+
+static void mmc_omap_idle_timer(unsigned long data)
+{
+ struct mmc_omap_host *host = (struct mmc_omap_host *) data;
+
+ mmc_omap_fclk_state(host, OFF);
+}
+
+static void mmc_omap_fclk_lazy_disable(struct mmc_omap_host *host)
+{
+ mod_timer(&host->idle_timer, jiffies + IDLE_TIMEOUT);
+}
+
+/*
+ * 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);
+}
+
+static inline
+int mmc_omap_cover_is_closed(struct mmc_omap_host *host)
+{
+ int r = 1;
+
+ if (host->pdata->slots[host->slot_id].get_cover_state)
+ r = host->pdata->slots[host->slot_id].get_cover_state(host->dev,
+ host->slot_id);
+ return r;
+}
+
+static ssize_t
+mmc_omap_show_cover_switch(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct mmc_host *mmc = container_of(dev, struct mmc_host, class_dev);
+ struct mmc_omap_host *host = mmc_priv(mmc);
+
+ return sprintf(buf, "%s\n", mmc_omap_cover_is_closed(host) ? "closed" :
+ "open");
+}
+
+static DEVICE_ATTR(cover_switch, S_IRUGO, mmc_omap_show_cover_switch, NULL);
+
+static ssize_t
+mmc_omap_show_slot_name(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct mmc_host *mmc = container_of(dev, struct mmc_host, class_dev);
+ struct mmc_omap_host *host = mmc_priv(mmc);
+ struct omap_mmc_slot_data slot = host->pdata->slots[host->slot_id];
+
+ return sprintf(buf, "slot:%s\n", slot.name);
+}
+
+static DEVICE_ATTR(slot_name, S_IRUGO, mmc_omap_show_slot_name, NULL);
+
+/*
+ * 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 commands ending an open ended transfer need
+ * a val of 0x3, rest 0x0.
+ */
+ if (cmd == host->mrq->stop)
+ 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_omap_fclk_lazy_disable(host);
+ 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_omap_fclk_lazy_disable(host);
+ 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;
+}
+
+/*
+ * Readable error output
+ */
+#ifdef CONFIG_MMC_DEBUG
+static void mmc_omap_report_irq(struct mmc_omap_host *host, u32 status)
+{
+ /* --- means reserved bit without definition at documentation */
+ static const char *mmc_omap_status_bits[] = {
+ "CC", "TC", "BGE", "---", "BWR", "BRR", "---", "---", "CIRQ",
+ "OBI", "---", "---", "---", "---", "---", "ERRI", "CTO", "CCRC",
+ "CEB", "CIE", "DTO", "DCRC", "DEB", "---", "ACE", "---",
+ "---", "---", "---", "CERR", "CERR", "BADA", "---", "---", "---"
+ };
+ char res[256];
+ char *buf = res;
+ int len, i;
+
+ len = sprintf(buf, "MMC IRQ 0x%x :", status);
+ buf += len;
+
+ for (i = 0; i < ARRAY_SIZE(mmc_omap_status_bits); i++)
+ if (status & (1 << i)) {
+ len = sprintf(buf, " %s", mmc_omap_status_bits[i]);
+ buf += len;
+ }
+
+ dev_dbg(mmc_dev(host->mmc), "%s\n", res);
+}
+#endif /* CONFIG_MMC_DEBUG */
+
+
+/*
+ * MMC controller IRQ handler
+ */
+static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
+{
+ struct mmc_omap_host *host = dev_id;
+ struct mmc_data *data;
+ 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;
+ }
+
+ data = host->data;
+ status = OMAP_HSMMC_READ(host->base, STAT);
+ dev_dbg(mmc_dev(host->mmc), "IRQ Status is %x\n", status);
+
+ if (status & ERR) {
+#ifdef CONFIG_MMC_DEBUG
+ mmc_omap_report_irq(host, status);
+#endif
+ if ((status & CMD_TIMEOUT) ||
+ (status & CMD_CRC)) {
+ if (host->cmd) {
+ if (status & CMD_TIMEOUT) {
+ OMAP_HSMMC_WRITE(host->base, SYSCTL,
+ OMAP_HSMMC_READ(host->base,
+ SYSCTL) | SRC);
+ while (OMAP_HSMMC_READ(host->base,
+ SYSCTL) & SRC)
+ ;
+
+ 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;
+ OMAP_HSMMC_WRITE(host->base, SYSCTL,
+ OMAP_HSMMC_READ(host->base,
+ SYSCTL) | SRD);
+ while (OMAP_HSMMC_READ(host->base,
+ SYSCTL) & SRD)
+ ;
+ 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, 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 */
+ mmc_omap_fclk_state(host, OFF);
+ 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;
+
+ mmc_omap_fclk_state(host, ON);
+ 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, omap_mmc_set_ios sets the VDD back to 3V on MMC_POWER_OFF.
+ *
+ * Only MMC1 supports 3.0V. MMC2 will not function if SDVS30 is
+ * set in HCTL.
+ */
+ if (host->id == OMAP_MMC1_DEVID) {
+ if (((1 << vdd) == MMC_VDD_32_33) ||
+ ((1 << vdd) == MMC_VDD_33_34))
+ reg_val |= SDVS30;
+ else if ((1 << vdd) == MMC_VDD_165_195)
+ reg_val |= SDVS18;
+ } else
+ 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)
+{
+ struct mmc_omap_host *host = container_of(work, struct mmc_omap_host,
+ mmc_carddetect_work);
+
+ sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch");
+ mmc_omap_fclk_state(host, ON);
+ if (host->carddetect) {
+ mmc_detect_change(host->mmc, (HZ * 200) / 1000);
+ } else {
+ OMAP_HSMMC_WRITE(host->base, SYSCTL,
+ OMAP_HSMMC_READ(host->base, SYSCTL) | SRD);
+ while (OMAP_HSMMC_READ(host->base, SYSCTL) & SRD)
+ ;
+
+ mmc_detect_change(host->mmc, (HZ * 50) / 1000);
+ }
+ mmc_omap_fclk_lazy_disable(host);
+}
+
+/*
+ * 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;
+}
+
+static void set_data_timeout(struct mmc_omap_host *host,
+ struct mmc_request *req)
+{
+ unsigned int timeout, cycle_ns;
+ uint32_t reg, clkd, dto = 0;
+
+ reg = OMAP_HSMMC_READ(host->base, SYSCTL);
+ clkd = (reg & CLKD_MASK) >> CLKD_SHIFT;
+ if (clkd == 0)
+ clkd = 1;
+
+ cycle_ns = 1000000000 / (clk_get_rate(host->fclk) / clkd);
+ timeout = req->data->timeout_ns / cycle_ns;
+ timeout += req->data->timeout_clks;
+ if (timeout) {
+ while ((timeout & 0x80000000) == 0) {
+ dto += 1;
+ timeout <<= 1;
+ }
+ dto = 31 - dto;
+ timeout <<= 1;
+ if (timeout && dto)
+ dto += 1;
+ if (dto >= 13)
+ dto -= 13;
+ else
+ dto = 0;
+ if (dto > 14)
+ dto = 14;
+ }
+
+ reg &= ~DTO_MASK;
+ reg |= dto << DTO_SHIFT;
+ OMAP_HSMMC_WRITE(host->base, SYSCTL, reg);
+}
+
+/*
+ * 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));
+ set_data_timeout(host, req);
+
+ 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_fclk_state(host, ON);
+ 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;
+
+ mmc_omap_fclk_state(host, ON);
+
+ switch (ios->power_mode) {
+ case MMC_POWER_OFF:
+ mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0);
+ /*
+ * Reset bus voltage to 3V if it got set to 1.8V earlier.
+ * REVISIT: If we are able to detect cards after unplugging
+ * a 1.8V card, this code should not be needed.
+ */
+ if (!(OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET)) {
+ int vdd = fls(host->mmc->ocr_avail) - 1;
+ if (omap_mmc_switch_opcond(host, vdd) != 0)
+ host->mmc->ios.vdd = vdd;
+ }
+ 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);
+
+ mmc_omap_fclk_lazy_disable(host);
+}
+
+static int omap_hsmmc_get_cd(struct mmc_host *mmc)
+{
+ struct mmc_omap_host *host = mmc_priv(mmc);
+ struct omap_mmc_platform_data *pdata = host->pdata;
+
+ if (!pdata->slots[0].card_detect)
+ return -ENOSYS;
+ return pdata->slots[0].card_detect(pdata->slots[0].card_detect_irq);
+}
+
+static int omap_hsmmc_get_ro(struct mmc_host *mmc)
+{
+ struct mmc_omap_host *host = mmc_priv(mmc);
+ struct omap_mmc_platform_data *pdata = host->pdata;
+
+ if (!pdata->slots[0].get_ro)
+ return -ENOSYS;
+ return pdata->slots[0].get_ro(host->dev, 0);
+}
+
+static struct mmc_host_ops mmc_omap_ops = {
+ .request = omap_mmc_request,
+ .set_ios = omap_mmc_set_ios,
+ .get_cd = omap_hsmmc_get_cd,
+ .get_ro = omap_hsmmc_get_ro,
+ /* NYET -- enable_sdio_irq */
+};
+
+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->dev = &pdev->dev;
+ host->use_dma = 1;
+ host->dev->dma_mask = &pdata->dma_mask;
+ 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);
+
+ platform_set_drvdata(pdev, host);
+ INIT_WORK(&host->mmc_carddetect_work, mmc_omap_detect);
+
+ 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 err1;
+ }
+ 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 err1;
+ }
+
+ spin_lock_init(&host->clk_lock);
+ setup_timer(&host->idle_timer, mmc_omap_idle_timer,
+ (unsigned long) host);
+
+ if (mmc_omap_fclk_state(host, ON) != 0) {
+ clk_put(host->iclk);
+ clk_put(host->fclk);
+ goto err1;
+ }
+ if (clk_enable(host->iclk) != 0) {
+ mmc_omap_fclk_state(host, OFF);
+ clk_put(host->iclk);
+ clk_put(host->fclk);
+ goto err1;
+ }
+
+ host->dbclk = clk_get(&pdev->dev, "mmchsdb_fck");
+ /*
+ * MMC can still work without debounce clock.
+ */
+ if (IS_ERR(host->dbclk))
+ dev_warn(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;
+
+#ifdef CONFIG_MMC_BLOCK_BOUNCE
+ mmc->max_phys_segs = 1;
+ mmc->max_hw_segs = 1;
+#endif
+ mmc->max_blk_size = 512; /* Block Length at max can be 1024 */
+ mmc->max_blk_count = 0xFFFF; /* No. of Blocks is 16 bits */
+ mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
+ mmc->max_seg_size = mmc->max_req_size;
+
+ mmc->ocr_avail = mmc_slot(host).ocr_mask;
+ mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
+
+ if (pdata->slots[host->slot_id].wires >= 4)
+ 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,
+ mmc_hostname(mmc), host);
+ if (ret) {
+ dev_dbg(mmc_dev(host->mmc), "Unable to grab HSMMC IRQ\n");
+ goto err_irq;
+ }
+
+ if (pdata->init != NULL) {
+ if (pdata->init(&pdev->dev) != 0) {
+ dev_dbg(mmc_dev(host->mmc),
+ "Unable to configure MMC IRQs\n");
+ goto err_irq_cd_init;
+ }
+ }
+
+ /* 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_TRIGGER_RISING | IRQF_TRIGGER_FALLING
+ | IRQF_DISABLED,
+ mmc_hostname(mmc), host);
+ if (ret) {
+ dev_dbg(mmc_dev(host->mmc),
+ "Unable to grab MMC CD IRQ\n");
+ goto err_irq_cd;
+ }
+ }
+
+ OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
+ OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
+
+ mmc_add_host(mmc);
+
+ if (host->pdata->slots[host->slot_id].name != NULL) {
+ ret = device_create_file(&mmc->class_dev, &dev_attr_slot_name);
+ if (ret < 0)
+ goto err_slot_name;
+ }
+ if (mmc_slot(host).card_detect_irq && mmc_slot(host).card_detect &&
+ host->pdata->slots[host->slot_id].get_cover_state) {
+ ret = device_create_file(&mmc->class_dev,
+ &dev_attr_cover_switch);
+ if (ret < 0)
+ goto err_cover_switch;
+ }
+ mmc_omap_fclk_lazy_disable(host);
+
+ return 0;
+
+err_cover_switch:
+ device_remove_file(&mmc->class_dev, &dev_attr_cover_switch);
+err_slot_name:
+ mmc_remove_host(mmc);
+err_irq_cd:
+ free_irq(mmc_slot(host).card_detect_irq, host);
+err_irq_cd_init:
+ free_irq(host->irq, host);
+err_irq:
+ mmc_omap_fclk_state(host, OFF);
+ clk_disable(host->iclk);
+ clk_put(host->fclk);
+ clk_put(host->iclk);
+ if (host->dbclk_enabled) {
+ clk_disable(host->dbclk);
+ clk_put(host->dbclk);
+ }
+
+err1:
+ iounmap(host->base);
+err:
+ dev_dbg(mmc_dev(host->mmc), "Probe Failed\n");
+ release_mem_region(res->start, res->end - res->start + 1);
+ 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);
+ struct resource *res;
+
+ if (host) {
+ mmc_remove_host(host->mmc);
+ if (host->pdata->cleanup)
+ 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();
+
+ mmc_omap_fclk_state(host, OFF);
+ 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);
+ iounmap(host->base);
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res)
+ release_mem_region(res->start, res->end - res->start + 1);
+ platform_set_drvdata(pdev, NULL);
+
+ 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;
+
+ mmc_omap_fclk_state(host, ON);
+ OMAP_HSMMC_WRITE(host->base, ISE, 0);
+ OMAP_HSMMC_WRITE(host->base, IE, 0);
+
+ if (host->pdata->suspend) {
+ 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");
+ }
+
+ OMAP_HSMMC_WRITE(host->base, HCTL,
+ OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP);
+ mmc_omap_fclk_state(host, OFF);
+ 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) {
+ int i;
+ if (mmc_omap_fclk_state(host, ON) != 0)
+ goto clk_en_err;
+
+ ret = clk_enable(host->iclk);
+ if (ret) {
+ mmc_omap_fclk_state(host, OFF);
+ 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");
+
+ OMAP_HSMMC_WRITE(host->base, HCTL,
+ OMAP_HSMMC_READ(host->base, HCTL) | SDBP);
+
+ for (i = 0; i < 100; i++)
+ if (OMAP_HSMMC_READ(host->base, HCTL) & SDBP)
+ break;
+
+ if (host->pdata->resume) {
+ 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;
+
+ mmc_omap_fclk_lazy_disable(host);
+ }
+
+ 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,
+ .owner = THIS_MODULE,
+ },
+};
+
+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("platform:" 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;
PhotoMax Digital Picture Frame.
If you have such a device, say 'Y'.
+config MTD_NOR_TOTO
+ tristate "NOR Flash device on TOTO board"
+ depends on ARCH_OMAP && OMAP_TOTO
+ help
+ This enables access to the NOR flash on the Texas Instruments
+ TOTO board.
+
config MTD_H720X
tristate "Hynix evaluation board mappings"
depends on MTD_CFI && ( ARCH_H7201 || ARCH_H7202 )
obj-$(CONFIG_MTD_SCB2_FLASH) += scb2_flash.o
obj-$(CONFIG_MTD_H720X) += h720x-flash.o
obj-$(CONFIG_MTD_SBC8240) += sbc8240.o
+obj-$(CONFIG_MTD_NOR_TOTO) += omap-toto-flash.o
obj-$(CONFIG_MTD_IXP4XX) += ixp4xx.o
obj-$(CONFIG_MTD_IXP2000) += ixp2000.o
obj-$(CONFIG_MTD_WRSBC8260) += wr_sbc82xx_flash.o
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 OMAP2 and OMAP3"
+ depends on ARM && MTD_NAND && (ARCH_OMAP2 || ARCH_OMAP3)
+ help
+ Support for NAND flash on Texas Instruments OMAP2 and OMAP3 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
+ help
+ Support for NAND flash on Texas Instruments Toto platform.
+
config MTD_NAND_TS7250
tristate "NAND Flash device on TS-7250 board"
depends on MACH_TS72XX
obj-$(CONFIG_MTD_NAND_CAFE) += cafe_nand.o
obj-$(CONFIG_MTD_NAND_SPIA) += spia.o
obj-$(CONFIG_MTD_NAND_AMS_DELTA) += ams-delta.o
+obj-$(CONFIG_MTD_NAND_TOTO) += toto.o
obj-$(CONFIG_MTD_NAND_AUTCPU12) += autcpu12.o
obj-$(CONFIG_MTD_NAND_EDB7312) += edb7312.o
obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o
obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o
obj-$(CONFIG_MTD_NAND_ATMEL) += atmel_nand.o
obj-$(CONFIG_MTD_NAND_GPIO) += gpio.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_CM_X270) += cmx270_nand.o
obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o
obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.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/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 <mach/board.h>
+#include <mach/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 = OMAP1_IO_ADDRESS(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 (!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 <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/flash.h>
+#include <mach/tc.h>
+
+#include <mach/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 <mach/gpmc.h>
+#include <mach/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
+
+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;
+};
+
+/*
+ * omap_nand_wp - This function enable or disable the Write Protect feature on
+ * NAND device
+ * @mtd: MTD device structure
+ * @mode: WP ON/OFF
+ */
+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_buf16 - 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_buf16(struct mtd_info *mtd, u_char *buf, int len)
+{
+ struct nand_chip *nand = mtd->priv;
+
+ __raw_readsw(nand->IO_ADDR_R, buf, len / 2);
+}
+
+/*
+ * omap_write_buf16 - write buffer to NAND controller
+ * @mtd: MTD device structure
+ * @buf: data buffer
+ * @len: number of bytes to write
+ */
+static void omap_write_buf16(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;
+
+ /* FIXME try bursts of writesw() or DMA ... */
+ len >>= 1;
+
+ while (len--) {
+ writew(*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;
+}
+
+#ifdef CONFIG_MTD_NAND_OMAP_HWECC
+/*
+ * omap_hwecc_init-Initialize the Hardware ECC for NAND flash in GPMC controller
+ * @mtd: MTD device structure
+ */
+static void omap_hwecc_init(struct mtd_info *mtd)
+{
+ struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
+ mtd);
+ register struct nand_chip *chip = mtd->priv;
+ 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 | Select eccResultsize[0-3] */
+ val = ((((chip->ecc.size >> 1) - 1) << 22) | (0x0000000F));
+ __raw_writel(val, info->gpmc_baseaddr + GPMC_ECC_SIZE_CONFIG);
+}
+
+/*
+ * gen_true_ecc - This function will generate true ECC value, which can be used
+ * when correcting data read from NAND flash memory core
+ * @ecc_buf: buffer to store ecc code
+ */
+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));
+}
+
+/*
+ * omap_compare_ecc - 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
+ * @ecc_data1: ecc code from nand spare area
+ * @ecc_data2: ecc code from hardware register obtained from hardware ecc
+ * @page_data: page data
+ */
+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;
+ }
+}
+
+/*
+ * omap_correct_data - Compares the ecc read from nand spare area with ECC
+ * registers values and corrects one bit error if it has occured
+ * @mtd: MTD device structure
+ * @dat: page data
+ * @read_ecc: ecc read from nand flash
+ * @calc_ecc: ecc read from ECC registers
+ */
+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;
+}
+
+/*
+ * omap_calcuate_ecc - 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.
+ * @mtd: MTD device structure
+ * @dat: The pointer to data on which ecc is computed
+ * @ecc_code: The ecc_code buffer
+ */
+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;
+
+ /* Start Reading from HW ECC1_Result = 0x200 */
+ reg = (unsigned long)(info->gpmc_baseaddr + GPMC_ECC1_RESULT);
+ 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_enable_hwecc - This function enables the hardware ecc functionality
+ * @mtd: MTD device structure
+ * @mode: Read/Write mode
+ */
+static void omap_enable_hwecc(struct mtd_info *mtd, int mode)
+{
+ struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
+ mtd);
+ register struct nand_chip *chip = mtd->priv;
+ unsigned int dev_width = (chip->options & NAND_BUSWIDTH_16) ? 1 : 0;
+ 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 or 8 bit col) | ( CS ) | ECC Enable */
+ val = (dev_width << 7) | (info->gpmc_cs << 1) | (0x1);
+ break;
+ case NAND_ECC_READSYN :
+ __raw_writel(0x100, info->gpmc_baseaddr + GPMC_ECC_CONTROL);
+ /* (ECC 16 or 8 bit col) | ( CS ) | ECC Enable */
+ val = (dev_width << 7) | (info->gpmc_cs << 1) | (0x1);
+ break;
+ case NAND_ECC_WRITE :
+ __raw_writel(0x101, info->gpmc_baseaddr + GPMC_ECC_CONTROL);
+ /* (ECC 16 or 8 bit col) | ( CS ) | ECC Enable */
+ val = (dev_width << 7) | (info->gpmc_cs << 1) | (0x1);
+ break;
+ default:
+ DEBUG(MTD_DEBUG_LEVEL0, "Error: Unrecognized Mode[%d]!\n",
+ mode);
+ break;
+ }
+
+ __raw_writel(val, info->gpmc_baseaddr + GPMC_ECC_CONFIG);
+}
+#endif
+
+/*
+ * omap_wait - Wait function is called during Program and erase
+ * operations and the way it is called from MTD layer, we should wait
+ * till the NAND chip is ready after the programming/erase operation
+ * has completed.
+ * @mtd: MTD device structure
+ * @chip: NAND Chip structure
+ */
+static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip)
+{
+ register struct nand_chip *this = mtd->priv;
+ struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
+ mtd);
+ int status = 0;
+
+ this->IO_ADDR_W = (void *) info->gpmc_cs_baseaddr +
+ GPMC_CS_NAND_COMMAND;
+ this->IO_ADDR_R = (void *) info->gpmc_cs_baseaddr + GPMC_CS_NAND_DATA;
+
+ while (!(status & 0x40)) {
+ __raw_writeb(NAND_CMD_STATUS & 0xFF, this->IO_ADDR_W);
+ status = __raw_readb(this->IO_ADDR_R);
+ }
+ return status;
+}
+
+/*
+ * omap_dev_ready - calls the platform specific dev_ready function
+ * @mtd: MTD device structure
+ */
+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 */
+ if (pdata->dev_ready) {
+ 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);
+
+ /* NAND write protect off */
+ omap_nand_wp(&info->mtd, NAND_WP_OFF);
+
+ 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;
+
+ /* REVISIT: only supports 16-bit NAND flash */
+
+ info->nand.read_buf = omap_read_buf16;
+ info->nand.write_buf = omap_write_buf16;
+ info->nand.verify_buf = omap_verify_buf;
+
+ /*
+ * If RDY/BSY line is connected to OMAP then use the omap ready funcrtion
+ * and the generic nand_wait function which reads the status register
+ * after monitoring the RDY/BSY line.Otherwise use a standard chip delay
+ * which is slightly more than tR (AC Timing) of the NAND device and read
+ * status register until you get a failure or success
+ */
+ if (pdata->dev_ready) {
+ info->nand.dev_ready = omap_dev_ready;
+ info->nand.chip_delay = 0;
+ } else {
+ info->nand.waitfunc = omap_wait;
+ info->nand.chip_delay = 50;
+ }
+
+ info->nand.options |= NAND_SKIP_BBTSCAN;
+ if ((gpmc_cs_read_reg(info->gpmc_cs, GPMC_CS_CONFIG1) & 0x3000)
+ == 0x1000)
+ info->nand.options |= NAND_BUSWIDTH_16;
+
+#ifdef CONFIG_MTD_NAND_OMAP_HWECC
+ info->nand.ecc.bytes = 3;
+ info->nand.ecc.size = 512;
+ 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;
+
+ /* init HW ECC */
+ omap_hwecc_init(&info->mtd);
+#else
+ info->nand.ecc.mode = NAND_ECC_SOFT;
+#endif
+
+ /* 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 (pdata->parts)
+ add_mtd_partitions(&info->mtd, pdata->parts, pdata->nr_parts);
+ else
+#endif
+ add_mtd_device(&info->mtd);
+
+ 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");
}
if (c->gpio_irq) {
- if ((r = omap_request_gpio(c->gpio_irq)) < 0) {
+ if ((r = gpio_request(c->gpio_irq, "OneNAND irq")) < 0) {
dev_err(&pdev->dev, "Failed to request GPIO%d for "
"OneNAND\n", c->gpio_irq);
goto err_iounmap;
c->onenand.base);
c->pdev = pdev;
- c->mtd.name = dev_name(&pdev->dev);
+ c->mtd.name = pdev->dev.bus_id;
c->mtd.priv = &c->onenand;
c->mtd.owner = THIS_MODULE;
free_irq(gpio_to_irq(c->gpio_irq), c);
err_release_gpio:
if (c->gpio_irq)
- omap_free_gpio(c->gpio_irq);
+ gpio_free(c->gpio_irq);
err_iounmap:
iounmap(c->onenand.base);
err_release_mem_region:
platform_set_drvdata(pdev, NULL);
if (c->gpio_irq) {
free_irq(gpio_to_irq(c->gpio_irq), c);
- omap_free_gpio(c->gpio_irq);
+ gpio_free(c->gpio_irq);
}
iounmap(c->onenand.base);
release_mem_region(c->phys_base, ONENAND_IO_SIZE);
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
+ 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 <mach/hardware.h>
+#include <asm/serial.h>
+#include <asm/mach-types.h>
+#include <asm/dma.h>
+#include <mach/mux.h>
+#include <mach/gpio.h>
+#include <mach/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_get_dma_dst_pos(omap_ir->rx_dma_channel) -
+ omap_ir->rx_buf_dma_phys;
+
+ 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");
+
#define SMC_USE_16BIT 0
#define SMC_USE_32BIT 1
#define SMC_IRQ_SENSE IRQF_TRIGGER_LOW
+#elif defined(CONFIG_ARCH_OMAP34XX)
+ #define SMC_USE_16BIT 0
+ #define SMC_USE_32BIT 1
+ #define SMC_IRQ_SENSE IRQF_TRIGGER_LOW
+ #define SMC_MEM_RESERVED 1
+#elif defined(CONFIG_ARCH_OMAP24XX)
+ #define SMC_USE_16BIT 0
+ #define SMC_USE_32BIT 1
+ #define SMC_IRQ_SENSE IRQF_TRIGGER_LOW
+ #define SMC_MEM_RESERVED 1
#else
/*
* Default configuration
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)) {
Say Y to enable support for the battery on the Sharp Zaurus
SL-6000 (tosa) models.
+config TWL4030_BCI_BATTERY
+ tristate "OMAP TWL4030 BCI Battery driver"
+ depends on TWL4030_CORE && TWL4030_MADC
+ help
+ Support for OMAP TWL4030 BCI Battery driver.
+ This driver can give support for TWL4030 Battery Charge Interface.
+
config BATTERY_WM97XX
bool "WM97xx generic battery driver"
depends on TOUCHSCREEN_WM97XX=y
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
+obj-$(CONFIG_TWL4030_BCI_BATTERY) += twl4030_bci_battery.o
obj-$(CONFIG_BATTERY_TOSA) += tosa_battery.o
obj-$(CONFIG_BATTERY_WM97XX) += wm97xx_battery.o
obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o
--- /dev/null
+/*
+ * linux/drivers/power/twl4030_bci_battery.c
+ *
+ * OMAP2430/3430 BCI battery driver for Linux
+ *
+ * Copyright (C) 2008 Texas Instruments, Inc.
+ * Author: 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.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/i2c/twl4030.h>
+#include <linux/power_supply.h>
+#include <linux/i2c/twl4030-madc.h>
+
+#define T2_BATTERY_VOLT 0x04
+#define T2_BATTERY_TEMP 0x06
+#define T2_BATTERY_CUR 0x08
+
+/* charger constants */
+#define NO_PW_CONN 0
+#define AC_PW_CONN 0x01
+#define USB_PW_CONN 0x02
+
+/* TWL4030_MODULE_USB */
+#define REG_POWER_CTRL 0x0AC
+#define OTG_EN 0x020
+#define REG_PHY_CLK_CTRL 0x0FE
+#define REG_PHY_CLK_CTRL_STS 0x0FF
+#define PHY_DPLL_CLK 0x01
+
+#define REG_BCICTL1 0x023
+#define REG_BCICTL2 0x024
+#define CGAIN 0x020
+#define ITHEN 0x010
+#define ITHSENS 0x007
+
+/* Boot BCI flag bits */
+#define BCIAUTOWEN 0x020
+#define CONFIG_DONE 0x010
+#define BCIAUTOUSB 0x002
+#define BCIAUTOAC 0x001
+#define BCIMSTAT_MASK 0x03F
+
+/* Boot BCI register */
+#define REG_BOOT_BCI 0x007
+#define REG_CTRL1 0x00
+#define REG_SW1SELECT_MSB 0x07
+#define SW1_CH9_SEL 0x02
+#define REG_CTRL_SW1 0x012
+#define SW1_TRIGGER 0x020
+#define EOC_SW1 0x002
+#define REG_GPCH9 0x049
+#define REG_STS_HW_CONDITIONS 0x0F
+#define STS_VBUS 0x080
+#define STS_CHG 0x02
+#define REG_BCIMSTATEC 0x02
+#define REG_BCIMFSTS4 0x010
+#define REG_BCIMFSTS2 0x00E
+#define REG_BCIMFSTS3 0x00F
+#define REG_BCIMFSTS1 0x001
+#define USBFASTMCHG 0x004
+#define BATSTSPCHG 0x004
+#define BATSTSMCHG 0x040
+#define VBATOV4 0x020
+#define VBATOV3 0x010
+#define VBATOV2 0x008
+#define VBATOV1 0x004
+#define REG_BB_CFG 0x012
+#define BBCHEN 0x010
+
+/* Power supply charge interrupt */
+#define REG_PWR_ISR1 0x00
+#define REG_PWR_IMR1 0x01
+#define REG_PWR_EDR1 0x05
+#define REG_PWR_SIH_CTRL 0x007
+
+#define USB_PRES 0x004
+#define CHG_PRES 0x002
+
+#define USB_PRES_RISING 0x020
+#define USB_PRES_FALLING 0x010
+#define CHG_PRES_RISING 0x008
+#define CHG_PRES_FALLING 0x004
+#define AC_STATEC 0x20
+#define COR 0x004
+
+/* interrupt status registers */
+#define REG_BCIISR1A 0x0
+#define REG_BCIISR2A 0x01
+
+/* Interrupt flags bits BCIISR1 */
+#define BATSTS_ISR1 0x080
+#define VBATLVL_ISR1 0x001
+
+/* Interrupt mask registers for int1*/
+#define REG_BCIIMR1A 0x002
+#define REG_BCIIMR2A 0x003
+
+ /* Interrupt masks for BCIIMR1 */
+#define BATSTS_IMR1 0x080
+#define VBATLVL_IMR1 0x001
+
+/* Interrupt edge detection register */
+#define REG_BCIEDR1 0x00A
+#define REG_BCIEDR2 0x00B
+#define REG_BCIEDR3 0x00C
+
+/* BCIEDR2 */
+#define BATSTS_EDRRISIN 0x080
+#define BATSTS_EDRFALLING 0x040
+
+/* BCIEDR3 */
+#define VBATLVL_EDRRISIN 0x02
+
+/* Step size and prescaler ratio */
+#define TEMP_STEP_SIZE 147
+#define TEMP_PSR_R 100
+
+#define VOLT_STEP_SIZE 588
+#define VOLT_PSR_R 100
+
+#define CURR_STEP_SIZE 147
+#define CURR_PSR_R1 44
+#define CURR_PSR_R2 80
+
+#define BK_VOLT_STEP_SIZE 441
+#define BK_VOLT_PSR_R 100
+
+#define ENABLE 1
+#define DISABLE 1
+
+/* Ptr to thermistor table */
+int *therm_tbl;
+
+struct twl4030_bci_device_info {
+ struct device *dev;
+
+ unsigned long update_time;
+ int voltage_uV;
+ int bk_voltage_uV;
+ int current_uA;
+ int temp_C;
+ int charge_rsoc;
+ int charge_status;
+
+ struct power_supply bat;
+ struct power_supply bk_bat;
+ struct delayed_work twl4030_bci_monitor_work;
+ struct delayed_work twl4030_bk_bci_monitor_work;
+};
+
+static int usb_charger_flag;
+static int LVL_1, LVL_2, LVL_3, LVL_4;
+
+static int read_bci_val(u8 reg_1);
+static inline int clear_n_set(u8 mod_no, u8 clear, u8 set, u8 reg);
+static int twl4030charger_presence(void);
+
+/*
+ * Report and clear the charger presence event.
+ */
+static inline int twl4030charger_presence_evt(void)
+{
+ int ret;
+ u8 chg_sts, set = 0, clear = 0;
+
+ /* read charger power supply status */
+ ret = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &chg_sts,
+ REG_STS_HW_CONDITIONS);
+ if (ret)
+ return IRQ_NONE;
+
+ if (chg_sts & STS_CHG) { /* If the AC charger have been connected */
+ /* configuring falling edge detection for CHG_PRES */
+ set = CHG_PRES_FALLING;
+ clear = CHG_PRES_RISING;
+ } else { /* If the AC charger have been disconnected */
+ /* configuring rising edge detection for CHG_PRES */
+ set = CHG_PRES_RISING;
+ clear = CHG_PRES_FALLING;
+ }
+
+ /* Update the interrupt edge detection register */
+ clear_n_set(TWL4030_MODULE_INT, clear, set, REG_PWR_EDR1);
+
+ return 0;
+}
+
+/*
+ * Interrupt service routine
+ *
+ * Attends to TWL 4030 power module interruptions events, specifically
+ * USB_PRES (USB charger presence) CHG_PRES (AC charger presence) events
+ *
+ */
+static irqreturn_t twl4030charger_interrupt(int irq, void *_di)
+{
+ struct twl4030_bci_device_info *di = _di;
+
+#ifdef CONFIG_LOCKDEP
+ /* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which
+ * we don't want and can't tolerate. Although it might be
+ * friendlier not to borrow this thread context...
+ */
+ local_irq_enable();
+#endif
+
+ twl4030charger_presence_evt();
+ power_supply_changed(&di->bat);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * This function handles the twl4030 battery presence interrupt
+ */
+static int twl4030battery_presence_evt(void)
+{
+ int ret;
+ u8 batstsmchg, batstspchg;
+
+ /* check for the battery presence in main charge*/
+ ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
+ &batstsmchg, REG_BCIMFSTS3);
+ if (ret)
+ return ret;
+
+ /* check for the battery presence in precharge */
+ ret = twl4030_i2c_read_u8(TWL4030_MODULE_PRECHARGE,
+ &batstspchg, REG_BCIMFSTS1);
+ if (ret)
+ return ret;
+
+ /*
+ * REVISIT: Physically inserting/removing the batt
+ * does not seem to generate an int on 3430ES2 SDP.
+ */
+ if ((batstspchg & BATSTSPCHG) || (batstsmchg & BATSTSMCHG)) {
+ /* In case of the battery insertion event */
+ ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, BATSTS_EDRRISIN,
+ BATSTS_EDRFALLING, REG_BCIEDR2);
+ if (ret)
+ return ret;
+ } else {
+ /* In case of the battery removal event */
+ ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, BATSTS_EDRFALLING,
+ BATSTS_EDRRISIN, REG_BCIEDR2);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/*
+ * This function handles the twl4030 battery voltage level interrupt.
+ */
+static int twl4030battery_level_evt(void)
+{
+ int ret;
+ u8 mfst;
+
+ /* checking for threshold event */
+ ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
+ &mfst, REG_BCIMFSTS2);
+ if (ret)
+ return ret;
+
+ /* REVISIT could use a bitmap */
+ if (mfst & VBATOV4) {
+ LVL_4 = 1;
+ LVL_3 = 0;
+ LVL_2 = 0;
+ LVL_1 = 0;
+ } else if (mfst & VBATOV3) {
+ LVL_4 = 0;
+ LVL_3 = 1;
+ LVL_2 = 0;
+ LVL_1 = 0;
+ } else if (mfst & VBATOV2) {
+ LVL_4 = 0;
+ LVL_3 = 0;
+ LVL_2 = 1;
+ LVL_1 = 0;
+ } else {
+ LVL_4 = 0;
+ LVL_3 = 0;
+ LVL_2 = 0;
+ LVL_1 = 1;
+ }
+
+ return 0;
+}
+
+/*
+ * Interrupt service routine
+ *
+ * Attends to BCI interruptions events,
+ * specifically BATSTS (battery connection and removal)
+ * VBATOV (main battery voltage threshold) events
+ *
+ */
+static irqreturn_t twl4030battery_interrupt(int irq, void *_di)
+{
+ u8 isr1a_val, isr2a_val, clear_2a, clear_1a;
+ int ret;
+
+#ifdef CONFIG_LOCKDEP
+ /* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which
+ * we don't want and can't tolerate. Although it might be
+ * friendlier not to borrow this thread context...
+ */
+ local_irq_enable();
+#endif
+
+ ret = twl4030_i2c_read_u8(TWL4030_MODULE_INTERRUPTS, &isr1a_val,
+ REG_BCIISR1A);
+ if (ret)
+ return IRQ_NONE;
+
+ ret = twl4030_i2c_read_u8(TWL4030_MODULE_INTERRUPTS, &isr2a_val,
+ REG_BCIISR2A);
+ if (ret)
+ return IRQ_NONE;
+
+ clear_2a = (isr2a_val & VBATLVL_ISR1) ? (VBATLVL_ISR1) : 0;
+ clear_1a = (isr1a_val & BATSTS_ISR1) ? (BATSTS_ISR1) : 0;
+
+ /* cleaning BCI interrupt status flags */
+ ret = twl4030_i2c_write_u8(TWL4030_MODULE_INTERRUPTS,
+ clear_1a , REG_BCIISR1A);
+ if (ret)
+ return IRQ_NONE;
+
+ ret = twl4030_i2c_write_u8(TWL4030_MODULE_INTERRUPTS,
+ clear_2a , REG_BCIISR2A);
+ if (ret)
+ return IRQ_NONE;
+
+ /* battery connetion or removal event */
+ if (isr1a_val & BATSTS_ISR1)
+ twl4030battery_presence_evt();
+ /* battery voltage threshold event*/
+ else if (isr2a_val & VBATLVL_ISR1)
+ twl4030battery_level_evt();
+ else
+ return IRQ_NONE;
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * Enable/Disable hardware battery level event notifications.
+ */
+static int twl4030battery_hw_level_en(int enable)
+{
+ int ret;
+
+ if (enable) {
+ /* unmask VBATOV interrupt for INT1 */
+ ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, VBATLVL_IMR1,
+ 0, REG_BCIIMR2A);
+ if (ret)
+ return ret;
+
+ /* configuring interrupt edge detection for VBATOv */
+ ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, 0,
+ VBATLVL_EDRRISIN, REG_BCIEDR3);
+ if (ret)
+ return ret;
+ } else {
+ /* mask VBATOV interrupt for INT1 */
+ ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, 0,
+ VBATLVL_IMR1, REG_BCIIMR2A);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/*
+ * Enable/disable hardware battery presence event notifications.
+ */
+static int twl4030battery_hw_presence_en(int enable)
+{
+ int ret;
+
+ if (enable) {
+ /* unmask BATSTS interrupt for INT1 */
+ ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, BATSTS_IMR1,
+ 0, REG_BCIIMR1A);
+ if (ret)
+ return ret;
+
+ /* configuring interrupt edge for BATSTS */
+ ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, 0,
+ BATSTS_EDRRISIN | BATSTS_EDRFALLING, REG_BCIEDR2);
+ if (ret)
+ return ret;
+ } else {
+ /* mask BATSTS interrupt for INT1 */
+ ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, 0,
+ BATSTS_IMR1, REG_BCIIMR1A);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/*
+ * Enable/Disable AC Charge funtionality.
+ */
+static int twl4030charger_ac_en(int enable)
+{
+ int ret;
+
+ if (enable) {
+ /* forcing the field BCIAUTOAC (BOOT_BCI[0) to 1 */
+ ret = clear_n_set(TWL4030_MODULE_PM_MASTER, 0,
+ (CONFIG_DONE | BCIAUTOWEN | BCIAUTOAC),
+ REG_BOOT_BCI);
+ if (ret)
+ return ret;
+ } else {
+ /* forcing the field BCIAUTOAC (BOOT_BCI[0) to 0*/
+ ret = clear_n_set(TWL4030_MODULE_PM_MASTER, BCIAUTOAC,
+ (CONFIG_DONE | BCIAUTOWEN),
+ REG_BOOT_BCI);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/*
+ * Enable/Disable USB Charge funtionality.
+ */
+int twl4030charger_usb_en(int enable)
+{
+ u8 value;
+ int ret;
+ unsigned long timeout;
+
+ if (enable) {
+ /* Check for USB charger conneted */
+ ret = twl4030charger_presence();
+ if (ret < 0)
+ return ret;
+
+ if (!(ret & USB_PW_CONN))
+ return -ENXIO;
+
+ /* forcing the field BCIAUTOUSB (BOOT_BCI[1]) to 1 */
+ ret = clear_n_set(TWL4030_MODULE_PM_MASTER, 0,
+ (CONFIG_DONE | BCIAUTOWEN | BCIAUTOUSB),
+ REG_BOOT_BCI);
+ if (ret)
+ return ret;
+
+ ret = clear_n_set(TWL4030_MODULE_USB, 0, PHY_DPLL_CLK,
+ REG_PHY_CLK_CTRL);
+ if (ret)
+ return ret;
+
+ value = 0;
+ timeout = jiffies + msecs_to_jiffies(50);
+
+ while ((!(value & PHY_DPLL_CLK)) &&
+ time_before(jiffies, timeout)) {
+ udelay(10);
+ ret = twl4030_i2c_read_u8(TWL4030_MODULE_USB, &value,
+ REG_PHY_CLK_CTRL_STS);
+ if (ret)
+ return ret;
+ }
+
+ /* OTG_EN (POWER_CTRL[5]) to 1 */
+ ret = clear_n_set(TWL4030_MODULE_USB, 0, OTG_EN,
+ REG_POWER_CTRL);
+ if (ret)
+ return ret;
+
+ mdelay(50);
+
+ /* forcing USBFASTMCHG(BCIMFSTS4[2]) to 1 */
+ ret = clear_n_set(TWL4030_MODULE_MAIN_CHARGE, 0,
+ USBFASTMCHG, REG_BCIMFSTS4);
+ if (ret)
+ return ret;
+ } else {
+ twl4030charger_presence();
+ ret = clear_n_set(TWL4030_MODULE_PM_MASTER, BCIAUTOUSB,
+ (CONFIG_DONE | BCIAUTOWEN), REG_BOOT_BCI);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/*
+ * Return battery temperature
+ * Or < 0 on failure.
+ */
+static int twl4030battery_temperature(void)
+{
+ u8 val;
+ int temp, curr, volt, res, ret;
+
+ /* Getting and calculating the thermistor voltage */
+ ret = read_bci_val(T2_BATTERY_TEMP);
+ if (ret < 0)
+ return ret;
+
+ volt = (ret * TEMP_STEP_SIZE) / TEMP_PSR_R;
+
+ /* Getting and calculating the supply current in micro ampers */
+ ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val,
+ REG_BCICTL2);
+ if (ret)
+ return 0;
+
+ curr = ((val & ITHSENS) + 1) * 10;
+
+ /* Getting and calculating the thermistor resistance in ohms*/
+ res = volt * 1000 / curr;
+
+ /*calculating temperature*/
+ for (temp = 58; temp >= 0; temp--) {
+ int actual = therm_tbl[temp];
+ if ((actual - res) >= 0)
+ break;
+ }
+
+ /* Negative temperature */
+ if (temp < 3) {
+ if (temp == 2)
+ temp = -1;
+ else if (temp == 1)
+ temp = -2;
+ else
+ temp = -3;
+ }
+
+ return temp + 1;
+}
+
+/*
+ * Return battery voltage
+ * Or < 0 on failure.
+ */
+static int twl4030battery_voltage(void)
+{
+ int volt = read_bci_val(T2_BATTERY_VOLT);
+
+ return (volt * VOLT_STEP_SIZE) / VOLT_PSR_R;
+}
+
+/*
+ * Return the battery current
+ * Or < 0 on failure.
+ */
+static int twl4030battery_current(void)
+{
+ int ret, curr = read_bci_val(T2_BATTERY_CUR);
+ u8 val;
+
+ ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val,
+ REG_BCICTL1);
+ if (ret)
+ return ret;
+
+ if (val & CGAIN) /* slope of 0.44 mV/mA */
+ return (curr * CURR_STEP_SIZE) / CURR_PSR_R1;
+ else /* slope of 0.88 mV/mA */
+ return (curr * CURR_STEP_SIZE) / CURR_PSR_R2;
+}
+
+/*
+ * Return the battery backup voltage
+ * Or < 0 on failure.
+ */
+static int twl4030backupbatt_voltage(void)
+{
+ struct twl4030_madc_request req;
+ int temp;
+
+ req.channels = (1 << 9);
+ req.do_avg = 0;
+ req.method = TWL4030_MADC_SW1;
+ req.active = 0;
+ req.func_cb = NULL;
+ twl4030_madc_conversion(&req);
+ temp = (u16)req.rbuf[9];
+
+ return (temp * BK_VOLT_STEP_SIZE) / BK_VOLT_PSR_R;
+}
+
+/*
+ * Returns an integer value, that means,
+ * NO_PW_CONN no power supply is connected
+ * AC_PW_CONN if the AC power supply is connected
+ * USB_PW_CONN if the USB power supply is connected
+ * AC_PW_CONN + USB_PW_CONN if USB and AC power supplies are both connected
+ *
+ * Or < 0 on failure.
+ */
+static int twl4030charger_presence(void)
+{
+ int ret;
+ u8 hwsts;
+
+ ret = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &hwsts,
+ REG_STS_HW_CONDITIONS);
+ if (ret) {
+ pr_err("twl4030_bci: error reading STS_HW_CONDITIONS\n");
+ return ret;
+ }
+
+ ret = (hwsts & STS_CHG) ? AC_PW_CONN : NO_PW_CONN;
+ ret += (hwsts & STS_VBUS) ? USB_PW_CONN : NO_PW_CONN;
+
+ if (ret & USB_PW_CONN)
+ usb_charger_flag = 1;
+ else
+ usb_charger_flag = 0;
+
+ return ret;
+
+}
+
+/*
+ * Returns the main charge FSM status
+ * Or < 0 on failure.
+ */
+static int twl4030bci_status(void)
+{
+ int ret;
+ u8 status;
+
+ ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
+ &status, REG_BCIMSTATEC);
+ if (ret) {
+ pr_err("twl4030_bci: error reading BCIMSTATEC\n");
+ return ret;
+ }
+
+ return (int) (status & BCIMSTAT_MASK);
+}
+
+static int read_bci_val(u8 reg)
+{
+ int ret, temp;
+ u8 val;
+
+ /* reading MSB */
+ ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val,
+ reg + 1);
+ if (ret)
+ return ret;
+
+ temp = ((int)(val & 0x03)) << 8;
+
+ /* reading LSB */
+ ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val,
+ reg);
+ if (ret)
+ return ret;
+
+ return temp | val;
+}
+
+/*
+ * Settup the twl4030 BCI module to enable backup
+ * battery charging.
+ */
+static int twl4030backupbatt_voltage_setup(void)
+{
+ int ret;
+
+ /* Starting backup batery charge */
+ ret = clear_n_set(TWL4030_MODULE_PM_RECEIVER, 0, BBCHEN,
+ REG_BB_CFG);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+/*
+ * Settup the twl4030 BCI module to measure battery
+ * temperature
+ */
+static int twl4030battery_temp_setup(void)
+{
+ int ret;
+
+ /* Enabling thermistor current */
+ ret = clear_n_set(TWL4030_MODULE_MAIN_CHARGE, 0, ITHEN,
+ REG_BCICTL1);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+/*
+ * Sets and clears bits on an given register on a given module
+ */
+static inline int clear_n_set(u8 mod_no, u8 clear, u8 set, u8 reg)
+{
+ int ret;
+ u8 val = 0;
+
+ /* Gets the initial register value */
+ ret = twl4030_i2c_read_u8(mod_no, &val, reg);
+ if (ret)
+ return ret;
+
+ /* Clearing all those bits to clear */
+ val &= ~(clear);
+
+ /* Setting all those bits to set */
+ val |= set;
+
+ /* Update the register */
+ ret = twl4030_i2c_write_u8(mod_no, val, reg);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static enum power_supply_property twl4030_bci_battery_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_CAPACITY,
+ POWER_SUPPLY_PROP_TEMP,
+};
+
+static enum power_supply_property twl4030_bk_bci_battery_props[] = {
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+};
+
+static void
+twl4030_bk_bci_battery_read_status(struct twl4030_bci_device_info *di)
+{
+ di->bk_voltage_uV = twl4030backupbatt_voltage();
+}
+
+static void twl4030_bk_bci_battery_work(struct work_struct *work)
+{
+ struct twl4030_bci_device_info *di = container_of(work,
+ struct twl4030_bci_device_info,
+ twl4030_bk_bci_monitor_work.work);
+
+ twl4030_bk_bci_battery_read_status(di);
+ schedule_delayed_work(&di->twl4030_bk_bci_monitor_work, 500);
+}
+
+static void twl4030_bci_battery_read_status(struct twl4030_bci_device_info *di)
+{
+ di->temp_C = twl4030battery_temperature();
+ di->voltage_uV = twl4030battery_voltage();
+ di->current_uA = twl4030battery_current();
+}
+
+static void
+twl4030_bci_battery_update_status(struct twl4030_bci_device_info *di)
+{
+ twl4030_bci_battery_read_status(di);
+ di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN;
+
+ if (power_supply_am_i_supplied(&di->bat))
+ di->charge_status = POWER_SUPPLY_STATUS_CHARGING;
+ else
+ di->charge_status = POWER_SUPPLY_STATUS_DISCHARGING;
+}
+
+static void twl4030_bci_battery_work(struct work_struct *work)
+{
+ struct twl4030_bci_device_info *di = container_of(work,
+ struct twl4030_bci_device_info, twl4030_bci_monitor_work.work);
+
+ twl4030_bci_battery_update_status(di);
+ schedule_delayed_work(&di->twl4030_bci_monitor_work, 100);
+}
+
+
+#define to_twl4030_bci_device_info(x) container_of((x), \
+ struct twl4030_bci_device_info, bat);
+
+static void twl4030_bci_battery_external_power_changed(struct power_supply *psy)
+{
+ struct twl4030_bci_device_info *di = to_twl4030_bci_device_info(psy);
+
+ cancel_delayed_work(&di->twl4030_bci_monitor_work);
+ schedule_delayed_work(&di->twl4030_bci_monitor_work, 0);
+}
+
+#define to_twl4030_bk_bci_device_info(x) container_of((x), \
+ struct twl4030_bci_device_info, bk_bat);
+
+static int twl4030_bk_bci_battery_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct twl4030_bci_device_info *di = to_twl4030_bk_bci_device_info(psy);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ val->intval = di->bk_voltage_uV;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int twl4030_bci_battery_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct twl4030_bci_device_info *di;
+ int status = 0;
+
+ di = to_twl4030_bci_device_info(psy);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ val->intval = di->charge_status;
+ return 0;
+ default:
+ break;
+ }
+
+ 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_TEMP:
+ val->intval = di->temp_C;
+ break;
+ case POWER_SUPPLY_PROP_ONLINE:
+ status = twl4030bci_status();
+ if ((status & AC_STATEC) == AC_STATEC)
+ val->intval = POWER_SUPPLY_TYPE_MAINS;
+ else if (usb_charger_flag)
+ val->intval = POWER_SUPPLY_TYPE_USB;
+ else
+ val->intval = 0;
+ break;
+ case POWER_SUPPLY_PROP_CAPACITY:
+ /*
+ * need to get the correct percentage value per the
+ * battery characteristics. Approx values for now.
+ */
+ if (di->voltage_uV < 2894 || LVL_1) {
+ val->intval = 5;
+ LVL_1 = 0;
+ } else if ((di->voltage_uV < 3451 && di->voltage_uV > 2894)
+ || LVL_2) {
+ val->intval = 20;
+ LVL_2 = 0;
+ } else if ((di->voltage_uV < 3902 && di->voltage_uV > 3451)
+ || LVL_3) {
+ val->intval = 50;
+ LVL_3 = 0;
+ } else if ((di->voltage_uV < 3949 && di->voltage_uV > 3902)
+ || LVL_4) {
+ val->intval = 75;
+ LVL_4 = 0;
+ } else if (di->voltage_uV > 3949)
+ val->intval = 90;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static char *twl4030_bci_supplied_to[] = {
+ "twl4030_bci_battery",
+};
+
+static int __init twl4030_bci_battery_probe(struct platform_device *pdev)
+{
+ struct twl4030_bci_platform_data *pdata = pdev->dev.platform_data;
+ struct twl4030_bci_device_info *di;
+ int irq;
+ int ret;
+
+ therm_tbl = pdata->battery_tmp_tbl;
+
+ di = kzalloc(sizeof(*di), GFP_KERNEL);
+ if (!di)
+ return -ENOMEM;
+
+ di->dev = &pdev->dev;
+ di->bat.name = "twl4030_bci_battery";
+ di->bat.supplied_to = twl4030_bci_supplied_to;
+ di->bat.num_supplicants = ARRAY_SIZE(twl4030_bci_supplied_to);
+ di->bat.type = POWER_SUPPLY_TYPE_BATTERY;
+ di->bat.properties = twl4030_bci_battery_props;
+ di->bat.num_properties = ARRAY_SIZE(twl4030_bci_battery_props);
+ di->bat.get_property = twl4030_bci_battery_get_property;
+ di->bat.external_power_changed =
+ twl4030_bci_battery_external_power_changed;
+
+ di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN;
+
+ di->bk_bat.name = "twl4030_bci_bk_battery";
+ di->bk_bat.type = POWER_SUPPLY_TYPE_BATTERY;
+ di->bk_bat.properties = twl4030_bk_bci_battery_props;
+ di->bk_bat.num_properties = ARRAY_SIZE(twl4030_bk_bci_battery_props);
+ di->bk_bat.get_property = twl4030_bk_bci_battery_get_property;
+ di->bk_bat.external_power_changed = NULL;
+
+ twl4030charger_ac_en(ENABLE);
+ twl4030charger_usb_en(ENABLE);
+ twl4030battery_hw_level_en(ENABLE);
+ twl4030battery_hw_presence_en(ENABLE);
+
+ platform_set_drvdata(pdev, di);
+
+ /* settings for temperature sensing */
+ ret = twl4030battery_temp_setup();
+ if (ret)
+ goto temp_setup_fail;
+
+ /* enabling GPCH09 for read back battery voltage */
+ ret = twl4030backupbatt_voltage_setup();
+ if (ret)
+ goto voltage_setup_fail;
+
+ /* REVISIT do we need to request both IRQs ?? */
+
+ /* request BCI interruption */
+ irq = platform_get_irq(pdev, 1);
+ ret = request_irq(irq, twl4030battery_interrupt,
+ 0, pdev->name, NULL);
+ if (ret) {
+ dev_dbg(&pdev->dev, "could not request irq %d, status %d\n",
+ irq, ret);
+ goto batt_irq_fail;
+ }
+
+ /* request Power interruption */
+ irq = platform_get_irq(pdev, 0);
+ ret = request_irq(irq, twl4030charger_interrupt,
+ 0, pdev->name, di);
+
+ if (ret) {
+ dev_dbg(&pdev->dev, "could not request irq %d, status %d\n",
+ irq, ret);
+ goto chg_irq_fail;
+ }
+
+ ret = power_supply_register(&pdev->dev, &di->bat);
+ if (ret) {
+ dev_dbg(&pdev->dev, "failed to register main battery\n");
+ goto batt_failed;
+ }
+
+ INIT_DELAYED_WORK_DEFERRABLE(&di->twl4030_bci_monitor_work,
+ twl4030_bci_battery_work);
+ schedule_delayed_work(&di->twl4030_bci_monitor_work, 0);
+
+ ret = power_supply_register(&pdev->dev, &di->bk_bat);
+ if (ret) {
+ dev_dbg(&pdev->dev, "failed to register backup battery\n");
+ goto bk_batt_failed;
+ }
+
+ INIT_DELAYED_WORK_DEFERRABLE(&di->twl4030_bk_bci_monitor_work,
+ twl4030_bk_bci_battery_work);
+ schedule_delayed_work(&di->twl4030_bk_bci_monitor_work, 500);
+
+ return 0;
+
+bk_batt_failed:
+ power_supply_unregister(&di->bat);
+batt_failed:
+ free_irq(irq, di);
+chg_irq_fail:
+ irq = platform_get_irq(pdev, 1);
+ free_irq(irq, NULL);
+batt_irq_fail:
+voltage_setup_fail:
+temp_setup_fail:
+ twl4030charger_ac_en(DISABLE);
+ twl4030charger_usb_en(DISABLE);
+ twl4030battery_hw_level_en(DISABLE);
+ twl4030battery_hw_presence_en(DISABLE);
+ kfree(di);
+
+ return ret;
+}
+
+static int __exit twl4030_bci_battery_remove(struct platform_device *pdev)
+{
+ struct twl4030_bci_device_info *di = platform_get_drvdata(pdev);
+ int irq;
+
+ twl4030charger_ac_en(DISABLE);
+ twl4030charger_usb_en(DISABLE);
+ twl4030battery_hw_level_en(DISABLE);
+ twl4030battery_hw_presence_en(DISABLE);
+
+ irq = platform_get_irq(pdev, 0);
+ free_irq(irq, di);
+
+ irq = platform_get_irq(pdev, 1);
+ free_irq(irq, NULL);
+
+ flush_scheduled_work();
+ power_supply_unregister(&di->bat);
+ power_supply_unregister(&di->bk_bat);
+ platform_set_drvdata(pdev, NULL);
+ kfree(di);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int twl4030_bci_battery_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ struct twl4030_bci_device_info *di = platform_get_drvdata(pdev);
+
+ di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN;
+ cancel_delayed_work(&di->twl4030_bci_monitor_work);
+ cancel_delayed_work(&di->twl4030_bk_bci_monitor_work);
+ return 0;
+}
+
+static int twl4030_bci_battery_resume(struct platform_device *pdev)
+{
+ struct twl4030_bci_device_info *di = platform_get_drvdata(pdev);
+
+ schedule_delayed_work(&di->twl4030_bci_monitor_work, 0);
+ schedule_delayed_work(&di->twl4030_bk_bci_monitor_work, 50);
+ return 0;
+}
+#else
+#define twl4030_bci_battery_suspend NULL
+#define twl4030_bci_battery_resume NULL
+#endif /* CONFIG_PM */
+
+static struct platform_driver twl4030_bci_battery_driver = {
+ .probe = twl4030_bci_battery_probe,
+ .remove = __exit_p(twl4030_bci_battery_remove),
+ .suspend = twl4030_bci_battery_suspend,
+ .resume = twl4030_bci_battery_resume,
+ .driver = {
+ .name = "twl4030_bci",
+ },
+};
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:twl4030_bci");
+MODULE_AUTHOR("Texas Instruments Inc");
+
+static int __init twl4030_battery_init(void)
+{
+ return platform_driver_register(&twl4030_bci_battery_driver);
+}
+module_init(twl4030_battery_init);
+
+static void __exit twl4030_battery_exit(void)
+{
+ platform_driver_unregister(&twl4030_bci_battery_driver);
+}
+module_exit(twl4030_battery_exit);
+
charging select between 100 mA and 500 mA charging current
limit.
+config REGULATOR_TWL4030
+ bool "TI TWL4030/TWL5030/TPS695x0 PMIC"
+ depends on TWL4030_CORE
+ help
+ This driver supports the voltage regulators provided by
+ this family of companion chips.
+
config REGULATOR_WM8350
tristate "Wolfson Microelectroncis WM8350 AudioPlus PMIC"
depends on MFD_WM8350
obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o
obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o
+obj-$(CONFIG_REGULATOR_TWL4030) += twl4030-regulator.o
obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o
obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o
obj-$(CONFIG_REGULATOR_DA903X) += da903x.o
--- /dev/null
+/*
+ * twl4030-regulator.c -- support regulators in twl4030 family chips
+ *
+ * Copyright (C) 2008 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/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/i2c/twl4030.h>
+
+
+/*
+ * The TWL4030/TW5030/TPS659x0 family chips include power management, a
+ * USB OTG transceiver, an RTC, ADC, PWM, and lots more. Some versions
+ * include an audio codec, battery charger, and more voltage regulators.
+ * These chips are often used in OMAP-based systems.
+ *
+ * This driver implements software-based resource control for various
+ * voltage regulators. This is usually augmented with state machine
+ * based control.
+ */
+
+struct twlreg_info {
+ /* start of regulator's PM_RECEIVER control register bank */
+ u8 base;
+
+ /* twl4030 resource ID, for resource control state machine */
+ u8 id;
+
+ /* voltage in mV = table[VSEL]; table_len must be a power-of-two */
+ u8 table_len;
+ const u16 *table;
+
+ /* chip constraints on regulator behavior */
+ u16 min_mV;
+ u16 max_mV;
+
+ /* used by regulator core */
+ struct regulator_desc desc;
+};
+
+#ifndef REGULATOR_MODE_OFF
+#define REGULATOR_MODE_OFF 0
+#endif
+
+
+/* LDO control registers ... offset is from the base of its register bank.
+ * The first three registers of all power resource banks help hardware to
+ * manage the various resource groups.
+ */
+#define VREG_GRP 0
+#define VREG_TYPE 1
+#define VREG_REMAP 2
+#define VREG_DEDICATED 3 /* LDO control */
+
+
+static inline int
+twl4030reg_read(struct twlreg_info *info, unsigned offset)
+{
+ u8 value;
+ int status;
+
+ status = twl4030_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER,
+ &value, info->base + offset);
+ return (status < 0) ? status : value;
+}
+
+static inline int
+twl4030reg_write(struct twlreg_info *info, unsigned offset, u8 value)
+{
+ return twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+ value, info->base + offset);
+}
+
+/*----------------------------------------------------------------------*/
+
+/* generic power resource operations, which work on all regulators */
+
+static int twl4030reg_grp(struct regulator_dev *rdev)
+{
+ return twl4030reg_read(rdev_get_drvdata(rdev), VREG_GRP);
+}
+
+static int twl4030reg_is_enabled(struct regulator_dev *rdev)
+{
+ int state = twl4030reg_grp(rdev);
+
+ if (state < 0)
+ return state;
+
+ /* resource state == OFF (vs SLEEP or ACTIVE) */
+ return (state & 0x0f) != 0;
+}
+
+/*
+ * Enable/disable regulators by joining/leaving the P1 (processor) group.
+ * We assume nobody else is updating the DEV_GRP registers.
+ */
+
+#define P3_GRP BIT(7) /* "peripherals" */
+#define P2_GRP BIT(6) /* secondary processor, modem, etc */
+#define P1_GRP BIT(5) /* CPU/Linux */
+
+static int twl4030reg_enable(struct regulator_dev *rdev)
+{
+ struct twlreg_info *info = rdev_get_drvdata(rdev);
+ int grp;
+
+ grp = twl4030reg_read(info, VREG_GRP);
+ if (grp < 0)
+ return grp;
+
+ grp |= P1_GRP;
+ return twl4030reg_write(info, VREG_GRP, grp);
+}
+
+static int twl4030reg_disable(struct regulator_dev *rdev)
+{
+ struct twlreg_info *info = rdev_get_drvdata(rdev);
+ int grp;
+
+ grp = twl4030reg_read(info, VREG_GRP);
+ if (grp < 0)
+ return grp;
+
+ grp &= ~P1_GRP;
+ return twl4030reg_write(info, VREG_GRP, grp);
+}
+
+static unsigned twl4030reg_get_mode(struct regulator_dev *rdev)
+{
+ int state = twl4030reg_grp(rdev);
+
+ if (state < 0)
+ return state;
+ state &= 0x0f;
+
+ /* assume state != WARM_RESET; we'd not be running... */
+ if (!state)
+ return REGULATOR_MODE_OFF;
+ return (state & BIT(3))
+ ? REGULATOR_MODE_NORMAL
+ : REGULATOR_MODE_STANDBY;
+}
+
+static int twl4030reg_set_mode(struct regulator_dev *rdev, unsigned mode)
+{
+ struct twlreg_info *info = rdev_get_drvdata(rdev);
+ unsigned message;
+ int status;
+
+ /* We can only set the mode through state machine commands... */
+ switch (mode) {
+ case REGULATOR_MODE_NORMAL:
+ message = MSG_SINGULAR(DEV_GRP_P1, info->id, RES_STATE_ACTIVE);
+ break;
+ case REGULATOR_MODE_STANDBY:
+ message = MSG_SINGULAR(DEV_GRP_P1, info->id, RES_STATE_SLEEP);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Ensure the resource is associated with some group */
+ status = twl4030reg_grp(rdev);
+ if (status < 0)
+ return status;
+ if (!(status & (P3_GRP | P2_GRP | P1_GRP)))
+ return -EACCES;
+
+ status = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER,
+ message >> 8, 0x15 /* PB_WORD_MSB */ );
+ if (status >= 0)
+ return status;
+
+ return twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER,
+ message, 0x16 /* PB_WORD_LSB */ );
+}
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * Support for adjustable-voltage LDOs uses a four bit (or less) voltage
+ * select field in its control register. We use tables indexed by VSEL
+ * to record voltages in milliVolts. (Accuracy is about three percent.)
+ *
+ * Note that VSEL values for VAUX2 changed in twl5030 and newer silicon;
+ * currently handled by listing two slightly different VAUX2 regulators,
+ * only one of which will be configured.
+ *
+ * VSEL values documented as "TI cannot support these values" are flagged
+ * in these tables as UNSUP() values; we normally won't assign them.
+ */
+#ifdef CONFIG_TWL4030_ALLOW_UNSUPPORTED
+#define UNSUP_MASK 0x0000
+#else
+#define UNSUP_MASK 0x8000
+#endif
+
+#define UNSUP(x) (UNSUP_MASK | (x))
+#define IS_UNSUP(x) (UNSUP_MASK & (x))
+#define LDO_MV(x) (~UNSUP_MASK & (x))
+
+
+static const u16 VAUX1_VSEL_table[] = {
+ UNSUP(1500), UNSUP(1800), 2500, 2800,
+ 3000, 3000, 3000, 3000,
+};
+static const u16 VAUX2_4030_VSEL_table[] = {
+ UNSUP(1000), UNSUP(1000), UNSUP(1200), 1300,
+ 1500, 1800, UNSUP(1850), 2500,
+ UNSUP(2600), 2800, UNSUP(2850), UNSUP(3000),
+ UNSUP(3150), UNSUP(3150), UNSUP(3150), UNSUP(3150),
+};
+static const u16 VAUX2_VSEL_table[] = {
+ 1700, 1700, 1900, 1300,
+ 1500, 1800, 2000, 2500,
+ 2100, 2800, 2200, 2300,
+ 2400, 2400, 2400, 2400,
+};
+static const u16 VAUX3_VSEL_table[] = {
+ 1500, 1800, 2500, 2800,
+ UNSUP(3000), UNSUP(3000), UNSUP(3000), UNSUP(3000),
+};
+static const u16 VAUX4_VSEL_table[] = {
+ 700, 1000, 1200, UNSUP(1300),
+ 1500, 1800, UNSUP(1850), 2500,
+};
+static const u16 VMMC1_VSEL_table[] = {
+ 1850, 2850, 3000, 3150,
+};
+static const u16 VMMC2_VSEL_table[] = {
+ UNSUP(1000), UNSUP(1000), UNSUP(1200), UNSUP(1300),
+ UNSUP(1500), UNSUP(1800), 1850, UNSUP(2500),
+ 2600, 2800, 2850, 3000,
+ 3150, 3150, 3150, 3150,
+};
+static const u16 VPLL1_VSEL_table[] = {
+ 1000, 1200, 1300, 1800,
+ UNSUP(2800), UNSUP(3000), UNSUP(3000), UNSUP(3000),
+};
+static const u16 VPLL2_VSEL_table[] = {
+ 700, 1000, 1200, 1300,
+ UNSUP(1500), 1800, UNSUP(1850), UNSUP(2500),
+ UNSUP(2600), UNSUP(2800), UNSUP(2850), UNSUP(3000),
+ UNSUP(3150), UNSUP(3150), UNSUP(3150), UNSUP(3150),
+};
+static const u16 VSIM_VSEL_table[] = {
+ UNSUP(1000), UNSUP(1200), UNSUP(1300), 1800,
+ 2800, 3000, 3000, 3000,
+};
+static const u16 VDAC_VSEL_table[] = {
+ 1200, 1300, 1800, 1800,
+};
+
+
+static int
+twl4030ldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV)
+{
+ struct twlreg_info *info = rdev_get_drvdata(rdev);
+ int vsel;
+
+ for (vsel = 0; vsel < info->table_len; vsel++) {
+ int mV = info->table[vsel];
+ int uV;
+
+ if (IS_UNSUP(mV))
+ continue;
+ uV = LDO_MV(mV) * 1000;
+
+ /* use the first in-range value */
+ if (min_uV <= uV && uV <= max_uV)
+ return twl4030reg_write(info, VREG_DEDICATED, vsel);
+ }
+
+ return -EDOM;
+}
+
+static int twl4030ldo_get_voltage(struct regulator_dev *rdev)
+{
+ struct twlreg_info *info = rdev_get_drvdata(rdev);
+ int vsel = twl4030reg_read(info, VREG_DEDICATED);
+
+ if (vsel < 0)
+ return vsel;
+
+ vsel &= info->table_len - 1;
+ return LDO_MV(info->table[vsel]) * 1000;
+}
+
+static struct regulator_ops twl4030ldo_ops = {
+ .set_voltage = twl4030ldo_set_voltage,
+ .get_voltage = twl4030ldo_get_voltage,
+
+ .enable = twl4030reg_enable,
+ .disable = twl4030reg_disable,
+ .is_enabled = twl4030reg_is_enabled,
+
+ .set_mode = twl4030reg_set_mode,
+ .get_mode = twl4030reg_get_mode,
+};
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * Fixed voltage LDOs don't have a VSEL field to update.
+ */
+static int twl4030fixed_get_voltage(struct regulator_dev *rdev)
+{
+ struct twlreg_info *info = rdev_get_drvdata(rdev);
+
+ return info->min_mV * 1000;
+}
+
+static struct regulator_ops twl4030fixed_ops = {
+ .get_voltage = twl4030fixed_get_voltage,
+
+ .enable = twl4030reg_enable,
+ .disable = twl4030reg_disable,
+ .is_enabled = twl4030reg_is_enabled,
+
+ .set_mode = twl4030reg_set_mode,
+ .get_mode = twl4030reg_get_mode,
+};
+
+/*----------------------------------------------------------------------*/
+
+#define TWL_ADJUSTABLE_LDO(label, offset, num) { \
+ .base = offset, \
+ .id = num, \
+ .table_len = ARRAY_SIZE(label##_VSEL_table), \
+ .table = label##_VSEL_table, \
+ .desc = { \
+ .name = #label, \
+ .id = TWL4030_REG_##label, \
+ .ops = &twl4030ldo_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ }, \
+ }
+
+#define TWL_FIXED_LDO(label, offset, mVolts, num) { \
+ .base = offset, \
+ .id = num, \
+ .min_mV = mVolts, \
+ .max_mV = mVolts, \
+ .desc = { \
+ .name = #label, \
+ .id = TWL4030_REG_##label, \
+ .ops = &twl4030fixed_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ }, \
+ }
+
+/*
+ * We list regulators here if systems need some level of
+ * software control over them after boot.
+ */
+static struct twlreg_info twl4030_regs[] = {
+ TWL_ADJUSTABLE_LDO(VAUX1, 0x17, 1),
+ TWL_ADJUSTABLE_LDO(VAUX2_4030, 0x1b, 2),
+ TWL_ADJUSTABLE_LDO(VAUX2, 0x1b, 2),
+ TWL_ADJUSTABLE_LDO(VAUX3, 0x1f, 3),
+ TWL_ADJUSTABLE_LDO(VAUX4, 0x23, 4),
+ TWL_ADJUSTABLE_LDO(VMMC1, 0x27, 5),
+ TWL_ADJUSTABLE_LDO(VMMC2, 0x2b, 6),
+ /*
+ TWL_ADJUSTABLE_LDO(VPLL1, 0x2f, 7),
+ TWL_ADJUSTABLE_LDO(VPLL2, 0x33, 8),
+ */
+ TWL_ADJUSTABLE_LDO(VSIM, 0x37, 9),
+ TWL_ADJUSTABLE_LDO(VDAC, 0x3b, 10),
+ /*
+ TWL_ADJUSTABLE_LDO(VINTANA1, 0x3f, 11),
+ TWL_ADJUSTABLE_LDO(VINTANA2, 0x43, 12),
+ TWL_ADJUSTABLE_LDO(VINTDIG, 0x47, 13),
+ TWL_SMPS(VIO, 0x4b, 14),
+ TWL_SMPS(VDD1, 0x55, 15),
+ TWL_SMPS(VDD2, 0x63, 16),
+ */
+ TWL_FIXED_LDO(VUSB1V5, 0x71, 1500, 17),
+ TWL_FIXED_LDO(VUSB1V8, 0x74, 1800, 18),
+ TWL_FIXED_LDO(VUSB3V1, 0x77, 3100, 19),
+ /* VUSBCP is managed *only* by the USB subchip */
+};
+
+static int twl4030reg_probe(struct platform_device *pdev)
+{
+ int i;
+ struct twlreg_info *info;
+ struct regulator_init_data *initdata;
+ struct regulation_constraints *c;
+ struct regulator_dev *rdev;
+ int min_uV, max_uV;
+
+ for (i = 0, info = NULL; i < ARRAY_SIZE(twl4030_regs); i++) {
+ if (twl4030_regs[i].desc.id != pdev->id)
+ continue;
+ info = twl4030_regs + i;
+ min_uV = info->min_mV * 1000;
+ max_uV = info->max_mV * 1000;
+ break;
+ }
+ if (!info)
+ return -ENODEV;
+
+ initdata = pdev->dev.platform_data;
+ if (!initdata)
+ return -EINVAL;
+
+ /* Constrain board-specific capabilities according to what
+ * this driver and the chip itself can actually do.
+ */
+ c = &initdata->constraints;
+ if (!c->min_uV || c->min_uV < min_uV)
+ c->min_uV = min_uV;
+ if (!c->max_uV || c->max_uV > max_uV)
+ c->max_uV = max_uV;
+ c->valid_modes_mask &= REGULATOR_MODE_NORMAL
+ | REGULATOR_MODE_STANDBY
+ | REGULATOR_MODE_OFF;
+ c->valid_ops_mask &= REGULATOR_CHANGE_VOLTAGE
+ | REGULATOR_CHANGE_MODE
+ | REGULATOR_CHANGE_STATUS;
+
+ rdev = regulator_register(&info->desc, &pdev->dev, info);
+ if (IS_ERR(rdev)) {
+ dev_err(&pdev->dev, "can't register %s, %ld\n",
+ info->desc.name, PTR_ERR(rdev));
+ return PTR_ERR(rdev);
+ }
+ platform_set_drvdata(pdev, rdev);
+
+ /* NOTE: many regulators support short-circuit IRQs (presentable
+ * as REGULATOR_OVER_CURRENT notifications?) configured via:
+ * - SC_CONFIG
+ * - SC_DETECT1 (vintana2, vmmc1/2, vaux1/2/3/4)
+ * - SC_DETECT2 (vusb, vdac, vio, vdd1/2, vpll2)
+ * - IT_CONFIG
+ */
+
+ return 0;
+}
+
+static int __devexit twl4030reg_remove(struct platform_device *pdev)
+{
+ regulator_unregister(platform_get_drvdata(pdev));
+ return 0;
+}
+
+MODULE_ALIAS("platform:twl4030_reg");
+
+static struct platform_driver twl4030reg_driver = {
+ .probe = twl4030reg_probe,
+ .remove = __devexit_p(twl4030reg_remove),
+ /* NOTE: short name, to work around driver model truncation of
+ * "twl4030_regulator.12" (and friends) to "twl4030_regulator.1".
+ */
+ .driver.name = "twl4030_reg",
+ .driver.owner = THIS_MODULE,
+};
+
+static int __init twl4030reg_init(void)
+{
+ unsigned i, j;
+
+ /* determine min/max voltage constraints, taking into account
+ * whether set_voltage() will use the "unsupported" settings
+ */
+ for (i = 0; i < ARRAY_SIZE(twl4030_regs); i++) {
+ struct twlreg_info *info = twl4030_regs + i;
+ const u16 *table;
+
+ /* fixed-voltage regulators */
+ if (!info->table_len)
+ continue;
+
+ /* LDO regulators: */
+ for (j = 0, table = info->table;
+ j < info->table_len;
+ j++, table++) {
+ u16 mV = *table;
+
+ if (IS_UNSUP(mV))
+ continue;
+ mV = LDO_MV(mV);
+
+ if (info->min_mV == 0 || info->min_mV > mV)
+ info->min_mV = mV;
+ if (info->max_mV < mV)
+ info->max_mV = mV;
+ }
+ }
+
+ return platform_driver_register(&twl4030reg_driver);
+}
+subsys_initcall(twl4030reg_init);
+
+static void __exit twl4030reg_exit(void)
+{
+ platform_driver_unregister(&twl4030reg_driver);
+}
+module_exit(twl4030reg_exit)
+
+MODULE_DESCRIPTION("TWL4030 regulator driver");
+MODULE_LICENSE("GPL");
static void twl4030_rtc_shutdown(struct platform_device *pdev)
{
- mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M |
- BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
+ /* mask timer interrupts, but leave alarm interrupts on to enable
+ power-on when alarm is triggered */
+ mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
}
#ifdef CONFIG_PM
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);
This driver can also be built as a module. If so, the module
will be called at25.
+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 EXPERIMENTAL
obj-$(CONFIG_SPI_AT25) += at25.o
obj-$(CONFIG_SPI_SPIDEV) += spidev.o
obj-$(CONFIG_SPI_TLE62X0) += tle62x0.o
+obj-$(CONFIG_SPI_TSC210X) += tsc210x.o
+obj-$(CONFIG_SPI_TSC2301) += tsc2301.o
+tsc2301-objs := tsc2301-core.o
# ... add above this line ...
# SPI slave controller drivers (upstream link)
/* per-register bitmasks: */
-#define OMAP2_MCSPI_SYSCONFIG_AUTOIDLE (1 << 0)
-#define OMAP2_MCSPI_SYSCONFIG_SOFTRESET (1 << 1)
+#define OMAP2_MCSPI_SYSCONFIG_SMARTIDLE BIT(4)
+#define OMAP2_MCSPI_SYSCONFIG_ENAWAKEUP BIT(2)
+#define OMAP2_MCSPI_SYSCONFIG_AUTOIDLE BIT(0)
+#define OMAP2_MCSPI_SYSCONFIG_SOFTRESET BIT(1)
-#define OMAP2_MCSPI_SYSSTATUS_RESETDONE (1 << 0)
+#define OMAP2_MCSPI_SYSSTATUS_RESETDONE BIT(0)
-#define OMAP2_MCSPI_MODULCTRL_SINGLE (1 << 0)
-#define OMAP2_MCSPI_MODULCTRL_MS (1 << 2)
-#define OMAP2_MCSPI_MODULCTRL_STEST (1 << 3)
+#define OMAP2_MCSPI_MODULCTRL_SINGLE BIT(0)
+#define OMAP2_MCSPI_MODULCTRL_MS BIT(2)
+#define OMAP2_MCSPI_MODULCTRL_STEST BIT(3)
-#define OMAP2_MCSPI_CHCONF_PHA (1 << 0)
-#define OMAP2_MCSPI_CHCONF_POL (1 << 1)
+#define OMAP2_MCSPI_CHCONF_PHA BIT(0)
+#define OMAP2_MCSPI_CHCONF_POL BIT(1)
#define OMAP2_MCSPI_CHCONF_CLKD_MASK (0x0f << 2)
-#define OMAP2_MCSPI_CHCONF_EPOL (1 << 6)
+#define OMAP2_MCSPI_CHCONF_EPOL BIT(6)
#define OMAP2_MCSPI_CHCONF_WL_MASK (0x1f << 7)
-#define OMAP2_MCSPI_CHCONF_TRM_RX_ONLY (0x01 << 12)
-#define OMAP2_MCSPI_CHCONF_TRM_TX_ONLY (0x02 << 12)
+#define OMAP2_MCSPI_CHCONF_TRM_RX_ONLY BIT(12)
+#define OMAP2_MCSPI_CHCONF_TRM_TX_ONLY BIT(13)
#define OMAP2_MCSPI_CHCONF_TRM_MASK (0x03 << 12)
-#define OMAP2_MCSPI_CHCONF_DMAW (1 << 14)
-#define OMAP2_MCSPI_CHCONF_DMAR (1 << 15)
-#define OMAP2_MCSPI_CHCONF_DPE0 (1 << 16)
-#define OMAP2_MCSPI_CHCONF_DPE1 (1 << 17)
-#define OMAP2_MCSPI_CHCONF_IS (1 << 18)
-#define OMAP2_MCSPI_CHCONF_TURBO (1 << 19)
-#define OMAP2_MCSPI_CHCONF_FORCE (1 << 20)
+#define OMAP2_MCSPI_CHCONF_DMAW BIT(14)
+#define OMAP2_MCSPI_CHCONF_DMAR BIT(15)
+#define OMAP2_MCSPI_CHCONF_DPE0 BIT(16)
+#define OMAP2_MCSPI_CHCONF_DPE1 BIT(17)
+#define OMAP2_MCSPI_CHCONF_IS BIT(18)
+#define OMAP2_MCSPI_CHCONF_TURBO BIT(19)
+#define OMAP2_MCSPI_CHCONF_FORCE BIT(20)
-#define OMAP2_MCSPI_CHSTAT_RXS (1 << 0)
-#define OMAP2_MCSPI_CHSTAT_TXS (1 << 1)
-#define OMAP2_MCSPI_CHSTAT_EOT (1 << 2)
+#define OMAP2_MCSPI_CHSTAT_RXS BIT(0)
+#define OMAP2_MCSPI_CHSTAT_TXS BIT(1)
+#define OMAP2_MCSPI_CHSTAT_EOT BIT(2)
-#define OMAP2_MCSPI_CHCTRL_EN (1 << 0)
+#define OMAP2_MCSPI_CHCTRL_EN BIT(0)
+#define OMAP2_MCSPI_WAKEUPENABLE_WKEN BIT(0)
/* We have 2 DMA channels per CS, one for RX and one for TX */
struct omap2_mcspi_dma {
} while (!(tmp & OMAP2_MCSPI_SYSSTATUS_RESETDONE));
mcspi_write_reg(master, OMAP2_MCSPI_SYSCONFIG,
- /* (3 << 8) | (2 << 3) | */
- OMAP2_MCSPI_SYSCONFIG_AUTOIDLE);
+ OMAP2_MCSPI_SYSCONFIG_AUTOIDLE |
+ OMAP2_MCSPI_SYSCONFIG_ENAWAKEUP |
+ OMAP2_MCSPI_SYSCONFIG_SMARTIDLE);
+
+ mcspi_write_reg(master, OMAP2_MCSPI_WAKEUPENABLE,
+ OMAP2_MCSPI_WAKEUPENABLE_WKEN);
omap2_mcspi_set_master_mode(master);
--- /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/gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/tsc2301.h>
+
+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;
+ r = gpio_request(tsc->reset_gpio, "TSC2301 reset");
+ if (r < 0)
+ goto err1;
+ gpio_direction_output(tsc->reset_gpio, 1);
+ mdelay(1);
+ gpio_set_value(tsc->reset_gpio, 0);
+ } 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;
+ return 0;
+
+ 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_ts_exit(tsc);
+ tsc2301_kp_exit(tsc);
+ if (tsc->reset_gpio >= 0)
+ gpio_free(tsc->reset_gpio);
+ 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_kp_suspend(tsc)) < 0)
+ return r;
+ if ((r = tsc2301_ts_suspend(tsc)) < 0) {
+ tsc2301_kp_resume(tsc);
+ return r;
+ }
+
+ return 0;
+}
+
+static int tsc2301_resume(struct spi_device *spi)
+{
+ struct tsc2301 *tsc = dev_get_drvdata(&spi->dev);
+
+ tsc2301_ts_resume(tsc);
+ tsc2301_kp_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");
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.
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 <mach/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)))
+ cpu_relax();
+
+ 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 */
+ gpio_request(EXT_PHY_RESET_GPIO_PORT1, "USB1 PHY reset");
+ gpio_direction_output(EXT_PHY_RESET_GPIO_PORT1, 0);
+ gpio_request(EXT_PHY_RESET_GPIO_PORT2, "USB2 PHY reset");
+ gpio_direction_output(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)))
+ cpu_relax();
+
+ /* 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)))
+ cpu_relax();
+
+ dev_dbg(hcd->self.controller, "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))
+ cpu_relax();
+
+ dev_dbg(hcd->self.controller, "Entered ULPI PHY MODE: success\n");
+
+#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);
+ gpio_set_value(EXT_PHY_RESET_GPIO_PORT1, 1);
+ gpio_set_value(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)))
+ cpu_relax();
+
+#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)))
+ cpu_relax();
+ while (!(omap_readl(OMAP_UHH_SYSSTATUS) & (1<<1)))
+ cpu_relax();
+ while (!(omap_readl(OMAP_UHH_SYSSTATUS) & (1<<2)))
+ cpu_relax();
+ 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)))
+ cpu_relax();
+ dev_dbg(hcd->self.controller, "TLL RESET DONE\n");
+
+ 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
+ gpio_free(EXT_PHY_RESET_GPIO_PORT1);
+ gpio_free(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()\n");
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ if (dev->resource[1].flags != IORESOURCE_IRQ) {
+ dev_dbg(&dev->dev, "resource[1] is not IORESOURCE_IRQ\n");
+ 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 = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+ if (!hcd->regs) {
+ dev_err(&dev->dev, "ioremap failed\n");
+ return -ENOMEM;
+ }
+
+ ehci = hcd_to_ehci(hcd);
+ ehci->caps = hcd->regs;
+
+ ehci->sbrn = 0x20;
+
+ 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\n");
+ omap_stop_ehc(dev, hcd);
+ iounmap(hcd->regs);
+ 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()\n");
+
+ iounmap(hcd->regs);
+ 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("platform: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 <mach/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*/
help
Frame buffer driver for OMAP based boards.
+config FB_OMAP_LCD_VGA
+ bool "Use LCD in VGA mode"
+ depends on MACH_OMAP_3430SDP || MACH_OMAP_LDP
+
+choice
+ depends on FB_OMAP && MACH_OVERO
+ prompt "Screen resolution"
+ default FB_OMAP_079M3R
+ help
+ Selected desired screen resolution
+
+config FB_OMAP_031M3R
+ boolean "640 x 480 @ 60 Hz Reduced blanking"
+
+config FB_OMAP_048M3R
+ boolean "800 x 600 @ 60 Hz Reduced blanking"
+
+config FB_OMAP_079M3R
+ boolean "1024 x 768 @ 60 Hz Reduced blanking"
+
+config FB_OMAP_092M9R
+ boolean "1280 x 720 @ 60 Hz Reduced blanking"
+
+endchoice
+
+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_PALMTE) += lcd_palmte.o
objs-$(CONFIG_ARCH_OMAP15XX)$(CONFIG_MACH_OMAP_INNOVATOR) += lcd_inn1510.o
objs-y$(CONFIG_MACH_OMAP_OSK) += lcd_osk.o
+objs-y$(CONFIG_MACH_OMAP_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_OMAP_LDP) += lcd_ldp.o
+objs-y$(CONFIG_MACH_OMAP2EVM) += lcd_omap2evm.o
+objs-y$(CONFIG_MACH_OMAP3EVM) += lcd_omap3evm.o
+objs-y$(CONFIG_MACH_OMAP3_BEAGLE) += lcd_omap3beagle.o
+objs-y$(CONFIG_FB_OMAP_LCD_MIPID) += lcd_mipid.o
+objs-y$(CONFIG_MACH_OVERO) += lcd_overo.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
int vid_scaled;
int last_color_mode;
int zoom_on;
+ int zoom_area_gx1;
+ int zoom_area_gx2;
+ int zoom_area_gy1;
+ int zoom_area_gy2;
int screen_width;
int screen_height;
unsigned te_connected:1;
return REQ_PENDING;
}
+static int check_1d_intersect(int a1, int a2, int b1, int b2)
+{
+ if (a2 <= b1 || b2 <= a1) return 0;
+ return 1;
+}
+
/* Setup all planes with an overlapping area with the update window. */
static int do_partial_update(struct blizzard_request *req, int plane,
int x, int y, int w, int h,
int color_mode;
int flags;
int zoom_off;
+ int have_zoom_for_this_update = 0;
/* Global coordinates, relative to pixel 0,0 of the LCD */
gx1 = x + blizzard.plane[plane].pos_x;
gx2_out = gx1_out + w_out;
gy2_out = gy1_out + h_out;
}
- zoom_off = blizzard.zoom_on && gx1 == 0 && gy1 == 0 &&
- w == blizzard.screen_width && h == blizzard.screen_height;
- blizzard.zoom_on = (!zoom_off && blizzard.zoom_on) ||
- (w < w_out || h < h_out);
for (i = 0; i < OMAPFB_PLANE_NUM; i++) {
struct plane_info *p = &blizzard.plane[i];
else
disable_tearsync();
+ if ((gx2_out - gx1_out) != (gx2 - gx1) ||
+ (gy2_out - gy1_out) != (gy2 - gy1))
+ have_zoom_for_this_update = 1;
+
+ /* 'background' type of screen update (as opposed to 'destructive')
+ can be used to disable scaling if scaling is active */
+ zoom_off = blizzard.zoom_on && !have_zoom_for_this_update &&
+ (gx1_out == 0) && (gx2_out == blizzard.screen_width) &&
+ (gy1_out == 0) && (gy2_out == blizzard.screen_height) &&
+ (gx1 == 0) && (gy1 == 0);
+
+ if (blizzard.zoom_on && !have_zoom_for_this_update && !zoom_off &&
+ check_1d_intersect(blizzard.zoom_area_gx1, blizzard.zoom_area_gx2,
+ gx1_out, gx2_out) &&
+ check_1d_intersect(blizzard.zoom_area_gy1, blizzard.zoom_area_gy2,
+ gy1_out, gy2_out)) {
+ /* Previous screen update was using scaling, current update
+ * is not using it. Additionally, current screen update is
+ * going to overlap with the scaled area. Scaling needs to be
+ * disabled in order to avoid 'magnifying glass' effect.
+ * Dummy setup of background window can be used for this.
+ */
+ set_window_regs(0, 0, blizzard.screen_width,
+ blizzard.screen_height,
+ 0, 0, blizzard.screen_width,
+ blizzard.screen_height,
+ BLIZZARD_COLOR_RGB565, 1, flags);
+ blizzard.zoom_on = 0;
+ }
+
+ /* remember scaling settings if we have scaled update */
+ if (have_zoom_for_this_update) {
+ blizzard.zoom_on = 1;
+ blizzard.zoom_area_gx1 = gx1_out;
+ blizzard.zoom_area_gx2 = gx2_out;
+ blizzard.zoom_area_gy1 = gy1_out;
+ blizzard.zoom_area_gy2 = gy2_out;
+ }
+
set_window_regs(gx1, gy1, gx2, gy2, gx1_out, gy1_out, gx2_out, gy2_out,
color_mode, zoom_off, flags);
+ if (zoom_off)
+ blizzard.zoom_on = 0;
blizzard.extif->set_bits_per_cycle(16);
/* set_window_regs has left the register index at the right
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,
unsigned long *map;
};
+#define MAX_IRQ_HANDLERS 4
+
static struct {
void __iomem *base;
int ext_mode;
- unsigned long enabled_irqs;
- void (*irq_callback)(void *);
- void *irq_callback_data;
+ struct {
+ u32 irq_mask;
+ void (*callback)(void *);
+ void *data;
+ } irq_handlers[MAX_IRQ_HANDLERS];
struct completion frame_done;
int fir_hinc[OMAPFB_PLANE_NUM];
BUG_ON(plane > 2);
l = dispc_read_reg(fsz_reg[plane]);
- l &= FLD_MASK(0, 9);
+ l &= FLD_MASK(0, 11);
if (ext_mode) {
low = l * 3 / 4;
high = l;
low = l / 4;
high = l * 3 / 4;
}
- MOD_REG_FLD(ftrs_reg[plane], FLD_MASK(16, 9) | FLD_MASK(0, 9),
+ MOD_REG_FLD(ftrs_reg[plane], FLD_MASK(16, 12) | FLD_MASK(0, 12),
(high << 16) | low);
}
if ((unsigned)plane > OMAPFB_PLANE_NUM)
return -ENODEV;
- if (plane == OMAPFB_PLANE_GFX &&
- (out_width != orig_width || out_height != orig_height))
+ if (out_width != orig_width || out_height != orig_height)
return -EINVAL;
enable_lcd_clocks(1);
panel->pixel_clock = fck / lck_div / pck_div / 1000;
}
-int omap_dispc_request_irq(void (*callback)(void *data), void *data)
+static void recalc_irq_mask(void)
{
- int r = 0;
+ int i;
+ unsigned long irq_mask = DISPC_IRQ_MASK_ERROR;
- BUG_ON(callback == NULL);
+ for (i = 0; i < MAX_IRQ_HANDLERS; i++) {
+ if (!dispc.irq_handlers[i].callback)
+ continue;
- if (dispc.irq_callback)
- r = -EBUSY;
- else {
- dispc.irq_callback = callback;
- dispc.irq_callback_data = data;
+ irq_mask |= dispc.irq_handlers[i].irq_mask;
}
- return r;
-}
-EXPORT_SYMBOL(omap_dispc_request_irq);
-
-void omap_dispc_enable_irqs(int irq_mask)
-{
enable_lcd_clocks(1);
- dispc.enabled_irqs = irq_mask;
- irq_mask |= DISPC_IRQ_MASK_ERROR;
MOD_REG_FLD(DISPC_IRQENABLE, 0x7fff, irq_mask);
enable_lcd_clocks(0);
}
-EXPORT_SYMBOL(omap_dispc_enable_irqs);
-void omap_dispc_disable_irqs(int irq_mask)
+int omap_dispc_request_irq(unsigned long irq_mask, void (*callback)(void *data),
+ void *data)
{
- enable_lcd_clocks(1);
- dispc.enabled_irqs &= ~irq_mask;
- irq_mask &= ~DISPC_IRQ_MASK_ERROR;
- MOD_REG_FLD(DISPC_IRQENABLE, 0x7fff, irq_mask);
- enable_lcd_clocks(0);
+ int i;
+
+ BUG_ON(callback == NULL);
+
+ for (i = 0; i < MAX_IRQ_HANDLERS; i++) {
+ if (dispc.irq_handlers[i].callback)
+ continue;
+
+ dispc.irq_handlers[i].irq_mask = irq_mask;
+ dispc.irq_handlers[i].callback = callback;
+ dispc.irq_handlers[i].data = data;
+ recalc_irq_mask();
+
+ return 0;
+ }
+
+ return -EBUSY;
}
-EXPORT_SYMBOL(omap_dispc_disable_irqs);
+EXPORT_SYMBOL(omap_dispc_request_irq);
-void omap_dispc_free_irq(void)
+void omap_dispc_free_irq(unsigned long irq_mask, void (*callback)(void *data),
+ void *data)
{
- enable_lcd_clocks(1);
- omap_dispc_disable_irqs(DISPC_IRQ_MASK_ALL);
- dispc.irq_callback = NULL;
- dispc.irq_callback_data = NULL;
- enable_lcd_clocks(0);
+ int i;
+
+ for (i = 0; i < MAX_IRQ_HANDLERS; i++) {
+ if (dispc.irq_handlers[i].callback == callback &&
+ dispc.irq_handlers[i].data == data) {
+ dispc.irq_handlers[i].irq_mask = 0;
+ dispc.irq_handlers[i].callback = NULL;
+ dispc.irq_handlers[i].data = NULL;
+ recalc_irq_mask();
+ return;
+ }
+ }
+
+ BUG();
}
EXPORT_SYMBOL(omap_dispc_free_irq);
static irqreturn_t omap_dispc_irq_handler(int irq, void *dev)
{
- u32 stat = dispc_read_reg(DISPC_IRQSTATUS);
+ u32 stat;
+ int i = 0;
+ enable_lcd_clocks(1);
+
+ stat = dispc_read_reg(DISPC_IRQSTATUS);
if (stat & DISPC_IRQ_FRAMEMASK)
complete(&dispc.frame_done);
}
}
- if ((stat & dispc.enabled_irqs) && dispc.irq_callback)
- dispc.irq_callback(dispc.irq_callback_data);
+ for (i = 0; i < MAX_IRQ_HANDLERS; i++) {
+ if (unlikely(dispc.irq_handlers[i].callback &&
+ (stat & dispc.irq_handlers[i].irq_mask)))
+ dispc.irq_handlers[i].callback(dispc.irq_handlers[i].data);
+ }
dispc_write_reg(DISPC_IRQSTATUS, stat);
+ enable_lcd_clocks(0);
+
return IRQ_HANDLED;
}
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);
static void enable_lcd_clocks(int enable)
{
- if (enable)
+ if (enable) {
+ clk_enable(dispc.dss_ick);
clk_enable(dispc.dss1_fck);
- else
+ } else {
clk_disable(dispc.dss1_fck);
-}
-
-static void enable_interface_clocks(int enable)
-{
- if (enable)
- clk_enable(dispc.dss_ick);
- else
clk_disable(dispc.dss_ick);
+ }
}
static void enable_digit_clocks(int enable)
if ((r = get_dss_clocks()) < 0)
goto fail0;
- enable_interface_clocks(1);
enable_lcd_clocks(1);
#ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT
enable_digit_clocks(0);
}
- /* Enable smart idle and autoidle */
- l = dispc_read_reg(DISPC_CONTROL);
+ /* Enable smart standby/idle, autoidle and wakeup */
+ l = dispc_read_reg(DISPC_SYSCONFIG);
l &= ~((3 << 12) | (3 << 3));
- l |= (2 << 12) | (2 << 3) | (1 << 0);
+ l |= (2 << 12) | (2 << 3) | (1 << 2) | (1 << 0);
dispc_write_reg(DISPC_SYSCONFIG, l);
omap_writel(1 << 0, DSS_BASE + DSS_SYSCONFIG);
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);
+ recalc_irq_mask();
if ((r = request_irq(INT_24XX_DSS_IRQ, omap_dispc_irq_handler,
0, MODULE_NAME, fbdev)) < 0) {
free_irq(INT_24XX_DSS_IRQ, fbdev);
fail1:
enable_lcd_clocks(0);
- enable_interface_clocks(0);
put_dss_clocks();
fail0:
iounmap(dispc.base);
cleanup_fbmem();
free_palette_ram();
free_irq(INT_24XX_DSS_IRQ, dispc.fbdev);
- enable_interface_clocks(0);
put_dss_clocks();
iounmap(dispc.base);
}
extern void omap_dispc_enable_lcd_out(int enable);
extern void omap_dispc_enable_digit_out(int enable);
-extern int omap_dispc_request_irq(void (*callback)(void *data), void *data);
-extern void omap_dispc_free_irq(void);
+extern int omap_dispc_request_irq(unsigned long irq_mask,
+ void (*callback)(void *data), void *data);
+extern void omap_dispc_free_irq(unsigned long irq_mask,
+ void (*callback)(void *data), void *data);
extern const struct lcd_ctrl omap2_int_ctrl;
--- /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/delay.h>
+#include <linux/gpio.h>
+#include <linux/i2c/twl4030.h>
+
+#include <mach/mux.h>
+#include <mach/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 ENABLE_VPLL2_DEDICATED 0x05
+#define ENABLE_VPLL2_DEV_GRP 0xE0
+#define TWL4030_VPLL2_DEV_GRP 0x33
+#define TWL4030_VPLL2_DEDICATED 0x36
+
+#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;
+ }
+
+ gpio_request(enable_gpio, "LCD enable"); /* LCD panel */
+ gpio_request(backlight_gpio, "LCD bl"); /* LCD backlight */
+ gpio_direction_output(enable_gpio, 0);
+ gpio_direction_output(backlight_gpio, 0);
+
+ 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;
+
+ if (omap_rev() > OMAP3430_REV_ES1_0) {
+ t2_out(PM_RECEIVER, ENABLE_VPLL2_DEDICATED,
+ TWL4030_VPLL2_DEDICATED);
+ t2_out(PM_RECEIVER, ENABLE_VPLL2_DEV_GRP,
+ TWL4030_VPLL2_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;
+ }
+
+ gpio_set_value(enable_gpio, 1);
+ gpio_set_value(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)
+{
+ gpio_set_value(enable_gpio, 0);
+ gpio_set_value(backlight_gpio, 0);
+ if (omap_rev() > OMAP3430_REV_ES1_0) {
+ t2_out(PM_RECEIVER, 0x0, TWL4030_VPLL2_DEDICATED);
+ t2_out(PM_RECEIVER, 0x0, TWL4030_VPLL2_DEV_GRP);
+ mdelay(4);
+ }
+}
+
+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 <mach/board-ams-delta.h>
+#include <mach/hardware.h>
+#include <mach/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 <mach/gpio.h>
+#include <mach/mux.h>
+#include <mach/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 LDP board
+ *
+ * Copyright (C) 2007 WindRiver
+ * Author: Stanley Miao <stanley.miao@windriver.com>
+ *
+ * Derived from drivers/video/omap/lcd-2430sdp.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/delay.h>
+#include <linux/i2c/twl4030.h>
+
+#include <mach/gpio.h>
+#include <mach/mux.h>
+#include <mach/omapfb.h>
+#include <asm/mach-types.h>
+
+#define LCD_PANEL_BACKLIGHT_GPIO (15 + OMAP_MAX_GPIO_LINES)
+#define LCD_PANEL_ENABLE_GPIO (7 + OMAP_MAX_GPIO_LINES)
+
+#define LCD_PANEL_RESET_GPIO 55
+#define LCD_PANEL_QVGA_GPIO 56
+
+#ifdef CONFIG_FB_OMAP_LCD_VGA
+#define LCD_XRES 480
+#define LCD_YRES 640
+#define LCD_PIXCLOCK_MAX 41700
+#else
+#define LCD_XRES 240
+#define LCD_YRES 320
+#define LCD_PIXCLOCK_MAX 185186
+#endif
+
+#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 ENABLE_VPLL2_DEDICATED 0x05
+#define ENABLE_VPLL2_DEV_GRP 0xE0
+#define TWL4030_VPLL2_DEV_GRP 0x33
+#define TWL4030_VPLL2_DEDICATED 0x36
+
+#define t2_out(c, r, v) twl4030_i2c_write_u8(c, r, v)
+
+
+static int ldp_panel_init(struct lcd_panel *panel,
+ struct omapfb_device *fbdev)
+{
+ gpio_request(LCD_PANEL_RESET_GPIO, "lcd reset");
+ gpio_request(LCD_PANEL_QVGA_GPIO, "lcd qvga");
+ gpio_request(LCD_PANEL_ENABLE_GPIO, "lcd panel");
+ gpio_request(LCD_PANEL_BACKLIGHT_GPIO, "lcd backlight");
+
+ gpio_direction_output(LCD_PANEL_QVGA_GPIO, 0);
+ gpio_direction_output(LCD_PANEL_RESET_GPIO, 0);
+ gpio_direction_output(LCD_PANEL_ENABLE_GPIO, 0);
+ gpio_direction_output(LCD_PANEL_BACKLIGHT_GPIO, 0);
+
+#ifdef CONFIG_FB_OMAP_LCD_VGA
+ gpio_set_value(LCD_PANEL_QVGA_GPIO, 0);
+#else
+ gpio_set_value(LCD_PANEL_QVGA_GPIO, 1);
+#endif
+ gpio_set_value(LCD_PANEL_RESET_GPIO, 1);
+
+ return 0;
+}
+
+static void ldp_panel_cleanup(struct lcd_panel *panel)
+{
+ gpio_free(LCD_PANEL_RESET_GPIO);
+ gpio_free(LCD_PANEL_QVGA_GPIO);
+ gpio_free(LCD_PANEL_ENABLE_GPIO);
+ gpio_free(LCD_PANEL_BACKLIGHT_GPIO);
+}
+
+static int ldp_panel_enable(struct lcd_panel *panel)
+{
+ if (0 != t2_out(PM_RECEIVER, ENABLE_VPLL2_DEDICATED,
+ TWL4030_VPLL2_DEDICATED))
+ return -EIO;
+ if (0 != t2_out(PM_RECEIVER, ENABLE_VPLL2_DEV_GRP,
+ TWL4030_VPLL2_DEV_GRP))
+ return -EIO;
+
+ gpio_direction_output(LCD_PANEL_ENABLE_GPIO, 1);
+ gpio_direction_output(LCD_PANEL_BACKLIGHT_GPIO, 1);
+
+ if (0 != t2_out(PM_RECEIVER, ENABLE_VAUX3_DEDICATED,
+ TWL4030_VAUX3_DEDICATED))
+ return -EIO;
+ if (0 != t2_out(PM_RECEIVER, ENABLE_VAUX3_DEV_GRP,
+ TWL4030_VAUX3_DEV_GRP))
+ return -EIO;
+
+ return 0;
+}
+
+static void ldp_panel_disable(struct lcd_panel *panel)
+{
+ gpio_direction_output(LCD_PANEL_ENABLE_GPIO, 0);
+ gpio_direction_output(LCD_PANEL_BACKLIGHT_GPIO, 0);
+
+ t2_out(PM_RECEIVER, 0x0, TWL4030_VPLL2_DEDICATED);
+ t2_out(PM_RECEIVER, 0x0, TWL4030_VPLL2_DEV_GRP);
+ mdelay(4);
+}
+
+static unsigned long ldp_panel_get_caps(struct lcd_panel *panel)
+{
+ return 0;
+}
+
+struct lcd_panel ldp_panel = {
+ .name = "ldp",
+ .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 = ldp_panel_init,
+ .cleanup = ldp_panel_cleanup,
+ .enable = ldp_panel_enable,
+ .disable = ldp_panel_disable,
+ .get_caps = ldp_panel_get_caps,
+};
+
+static int ldp_panel_probe(struct platform_device *pdev)
+{
+ omapfb_register_panel(&ldp_panel);
+ return 0;
+}
+
+static int ldp_panel_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static int ldp_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+ return 0;
+}
+
+static int ldp_panel_resume(struct platform_device *pdev)
+{
+ return 0;
+}
+
+struct platform_driver ldp_panel_driver = {
+ .probe = ldp_panel_probe,
+ .remove = ldp_panel_remove,
+ .suspend = ldp_panel_suspend,
+ .resume = ldp_panel_resume,
+ .driver = {
+ .name = "ldp_lcd",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init ldp_panel_drv_init(void)
+{
+ return platform_driver_register(&ldp_panel_driver);
+}
+
+static void __exit ldp_panel_drv_exit(void)
+{
+ platform_driver_unregister(&ldp_panel_driver);
+}
+
+module_init(ldp_panel_drv_init);
+module_exit(ldp_panel_drv_exit);
--- /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 <mach/omapfb.h>
+#include <mach/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 MISTRAL OMAP2EVM board
+ *
+ * Author: Arun C <arunedarath@mistralsolutions.com>
+ *
+ * Derived from drivers/video/omap/lcd_omap3evm.c
+ * 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/gpio.h>
+#include <linux/i2c/twl4030.h>
+
+#include <mach/mux.h>
+#include <mach/omapfb.h>
+#include <asm/mach-types.h>
+
+#define LCD_PANEL_ENABLE_GPIO 154
+#define LCD_PANEL_LR 128
+#define LCD_PANEL_UD 129
+#define LCD_PANEL_INI 152
+#define LCD_PANEL_QVGA 148
+#define LCD_PANEL_RESB 153
+
+#define LCD_XRES 480
+#define LCD_YRES 640
+#define LCD_PIXCLOCK_MAX 20000 /* in kHz */
+
+#define TWL_LED_LEDEN 0x00
+#define TWL_PWMA_PWMAON 0x00
+#define TWL_PWMA_PWMAOFF 0x01
+
+static unsigned int bklight_level;
+
+static int omap2evm_panel_init(struct lcd_panel *panel,
+ struct omapfb_device *fbdev)
+{
+ gpio_request(LCD_PANEL_ENABLE_GPIO, "LCD enable");
+ gpio_request(LCD_PANEL_LR, "LCD lr");
+ gpio_request(LCD_PANEL_UD, "LCD ud");
+ gpio_request(LCD_PANEL_INI, "LCD ini");
+ gpio_request(LCD_PANEL_QVGA, "LCD qvga");
+ gpio_request(LCD_PANEL_RESB, "LCD resb");
+
+ gpio_direction_output(LCD_PANEL_ENABLE_GPIO, 1);
+ gpio_direction_output(LCD_PANEL_RESB, 1);
+ gpio_direction_output(LCD_PANEL_INI, 1);
+ gpio_direction_output(LCD_PANEL_QVGA, 0);
+ gpio_direction_output(LCD_PANEL_LR, 1);
+ gpio_direction_output(LCD_PANEL_UD, 1);
+
+ twl4030_i2c_write_u8(TWL4030_MODULE_LED, 0x11, TWL_LED_LEDEN);
+ twl4030_i2c_write_u8(TWL4030_MODULE_PWMA, 0x01, TWL_PWMA_PWMAON);
+ twl4030_i2c_write_u8(TWL4030_MODULE_PWMA, 0x02, TWL_PWMA_PWMAOFF);
+ bklight_level = 100;
+
+ return 0;
+}
+
+static void omap2evm_panel_cleanup(struct lcd_panel *panel)
+{
+}
+
+static int omap2evm_panel_enable(struct lcd_panel *panel)
+{
+ gpio_set_value(LCD_PANEL_ENABLE_GPIO, 0);
+ return 0;
+}
+
+static void omap2evm_panel_disable(struct lcd_panel *panel)
+{
+ gpio_set_value(LCD_PANEL_ENABLE_GPIO, 1);
+}
+
+static unsigned long omap2evm_panel_get_caps(struct lcd_panel *panel)
+{
+ return 0;
+}
+
+static int omap2evm_bklight_setlevel(struct lcd_panel *panel,
+ unsigned int level)
+{
+ u8 c;
+ if ((level >= 0) && (level <= 100)) {
+ c = (125 * (100 - level)) / 100 + 2;
+ twl4030_i2c_write_u8(TWL4030_MODULE_PWMA, c, TWL_PWMA_PWMAOFF);
+ bklight_level = level;
+ }
+ return 0;
+}
+
+static unsigned int omap2evm_bklight_getlevel(struct lcd_panel *panel)
+{
+ return bklight_level;
+}
+
+static unsigned int omap2evm_bklight_getmaxlevel(struct lcd_panel *panel)
+{
+ return 100;
+}
+
+struct lcd_panel omap2evm_panel = {
+ .name = "omap2evm",
+ .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,
+ .hfp = 0,
+ .hbp = 28,
+ .vsw = 2,
+ .vfp = 1,
+ .vbp = 0,
+
+ .pixel_clock = LCD_PIXCLOCK_MAX,
+
+ .init = omap2evm_panel_init,
+ .cleanup = omap2evm_panel_cleanup,
+ .enable = omap2evm_panel_enable,
+ .disable = omap2evm_panel_disable,
+ .get_caps = omap2evm_panel_get_caps,
+ .set_bklight_level = omap2evm_bklight_setlevel,
+ .get_bklight_level = omap2evm_bklight_getlevel,
+ .get_bklight_max = omap2evm_bklight_getmaxlevel,
+};
+
+static int omap2evm_panel_probe(struct platform_device *pdev)
+{
+ omapfb_register_panel(&omap2evm_panel);
+ return 0;
+}
+
+static int omap2evm_panel_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static int omap2evm_panel_suspend(struct platform_device *pdev,
+ pm_message_t mesg)
+{
+ return 0;
+}
+
+static int omap2evm_panel_resume(struct platform_device *pdev)
+{
+ return 0;
+}
+
+struct platform_driver omap2evm_panel_driver = {
+ .probe = omap2evm_panel_probe,
+ .remove = omap2evm_panel_remove,
+ .suspend = omap2evm_panel_suspend,
+ .resume = omap2evm_panel_resume,
+ .driver = {
+ .name = "omap2evm_lcd",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init omap2evm_panel_drv_init(void)
+{
+ return platform_driver_register(&omap2evm_panel_driver);
+}
+
+static void __exit omap2evm_panel_drv_exit(void)
+{
+ platform_driver_unregister(&omap2evm_panel_driver);
+}
+
+module_init(omap2evm_panel_drv_init);
+module_exit(omap2evm_panel_drv_exit);
--- /dev/null
+/*
+ * LCD panel support for the TI OMAP3 Beagle board
+ *
+ * Author: Koen Kooi <koen@openembedded.org>
+ *
+ * Derived from drivers/video/omap/lcd-omap3evm.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/gpio.h>
+#include <linux/i2c/twl4030.h>
+
+#include <mach/mux.h>
+#include <mach/omapfb.h>
+#include <asm/mach-types.h>
+
+#define LCD_PANEL_ENABLE_GPIO 170
+
+#define LCD_XRES 1024
+#define LCD_YRES 768
+#define LCD_PIXCLOCK 64000 /* in kHz */
+
+static int omap3beagle_panel_init(struct lcd_panel *panel,
+ struct omapfb_device *fbdev)
+{
+ gpio_request(LCD_PANEL_ENABLE_GPIO, "LCD enable");
+ return 0;
+}
+
+static void omap3beagle_panel_cleanup(struct lcd_panel *panel)
+{
+}
+
+static int omap3beagle_panel_enable(struct lcd_panel *panel)
+{
+ gpio_set_value(LCD_PANEL_ENABLE_GPIO, 1);
+ return 0;
+}
+
+static void omap3beagle_panel_disable(struct lcd_panel *panel)
+{
+ gpio_set_value(LCD_PANEL_ENABLE_GPIO, 0);
+}
+
+static unsigned long omap3beagle_panel_get_caps(struct lcd_panel *panel)
+{
+ return 0;
+}
+
+struct lcd_panel omap3beagle_panel = {
+ .name = "omap3beagle",
+ .config = OMAP_LCDC_PANEL_TFT,
+
+ .bpp = 16,
+ .data_lines = 24,
+ .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,
+
+ .init = omap3beagle_panel_init,
+ .cleanup = omap3beagle_panel_cleanup,
+ .enable = omap3beagle_panel_enable,
+ .disable = omap3beagle_panel_disable,
+ .get_caps = omap3beagle_panel_get_caps,
+};
+
+static int omap3beagle_panel_probe(struct platform_device *pdev)
+{
+ omapfb_register_panel(&omap3beagle_panel);
+ return 0;
+}
+
+static int omap3beagle_panel_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static int omap3beagle_panel_suspend(struct platform_device *pdev,
+ pm_message_t mesg)
+{
+ return 0;
+}
+
+static int omap3beagle_panel_resume(struct platform_device *pdev)
+{
+ return 0;
+}
+
+struct platform_driver omap3beagle_panel_driver = {
+ .probe = omap3beagle_panel_probe,
+ .remove = omap3beagle_panel_remove,
+ .suspend = omap3beagle_panel_suspend,
+ .resume = omap3beagle_panel_resume,
+ .driver = {
+ .name = "omap3beagle_lcd",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init omap3beagle_panel_drv_init(void)
+{
+ return platform_driver_register(&omap3beagle_panel_driver);
+}
+
+static void __exit omap3beagle_panel_drv_exit(void)
+{
+ platform_driver_unregister(&omap3beagle_panel_driver);
+}
+
+module_init(omap3beagle_panel_drv_init);
+module_exit(omap3beagle_panel_drv_exit);
--- /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/gpio.h>
+#include <linux/i2c/twl4030.h>
+
+#include <mach/mux.h>
+#include <mach/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 26000 /* in kHz */
+
+#define ENABLE_VDAC_DEDICATED 0x03
+#define ENABLE_VDAC_DEV_GRP 0x20
+#define ENABLE_VPLL2_DEDICATED 0x05
+#define ENABLE_VPLL2_DEV_GRP 0xE0
+
+#define TWL_LED_LEDEN 0x00
+#define TWL_PWMA_PWMAON 0x00
+#define TWL_PWMA_PWMAOFF 0x01
+
+static unsigned int bklight_level;
+
+static int omap3evm_panel_init(struct lcd_panel *panel,
+ struct omapfb_device *fbdev)
+{
+ gpio_request(LCD_PANEL_LR, "LCD lr");
+ gpio_request(LCD_PANEL_UD, "LCD ud");
+ gpio_request(LCD_PANEL_INI, "LCD ini");
+ gpio_request(LCD_PANEL_RESB, "LCD resb");
+ gpio_request(LCD_PANEL_QVGA, "LCD qvga");
+
+ gpio_direction_output(LCD_PANEL_RESB, 1);
+ gpio_direction_output(LCD_PANEL_INI, 1);
+ gpio_direction_output(LCD_PANEL_QVGA, 0);
+ gpio_direction_output(LCD_PANEL_LR, 1);
+ gpio_direction_output(LCD_PANEL_UD, 1);
+
+ twl4030_i2c_write_u8(TWL4030_MODULE_LED, 0x11, TWL_LED_LEDEN);
+ twl4030_i2c_write_u8(TWL4030_MODULE_PWMA, 0x01, TWL_PWMA_PWMAON);
+ twl4030_i2c_write_u8(TWL4030_MODULE_PWMA, 0x02, TWL_PWMA_PWMAOFF);
+ bklight_level = 100;
+
+ return 0;
+}
+
+static void omap3evm_panel_cleanup(struct lcd_panel *panel)
+{
+}
+
+static int omap3evm_panel_enable(struct lcd_panel *panel)
+{
+ gpio_set_value(LCD_PANEL_ENABLE_GPIO, 0);
+ return 0;
+}
+
+static void omap3evm_panel_disable(struct lcd_panel *panel)
+{
+ gpio_set_value(LCD_PANEL_ENABLE_GPIO, 1);
+}
+
+static unsigned long omap3evm_panel_get_caps(struct lcd_panel *panel)
+{
+ return 0;
+}
+
+static int omap3evm_bklight_setlevel(struct lcd_panel *panel,
+ unsigned int level)
+{
+ u8 c;
+ if ((level >= 0) && (level <= 100)) {
+ c = (125 * (100 - level)) / 100 + 2;
+ twl4030_i2c_write_u8(TWL4030_MODULE_PWMA, c, TWL_PWMA_PWMAOFF);
+ bklight_level = level;
+ }
+ return 0;
+}
+
+static unsigned int omap3evm_bklight_getlevel(struct lcd_panel *panel)
+{
+ return bklight_level;
+}
+
+static unsigned int omap3evm_bklight_getmaxlevel(struct lcd_panel *panel)
+{
+ return 100;
+}
+
+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,
+
+ .init = omap3evm_panel_init,
+ .cleanup = omap3evm_panel_cleanup,
+ .enable = omap3evm_panel_enable,
+ .disable = omap3evm_panel_disable,
+ .get_caps = omap3evm_panel_get_caps,
+ .set_bklight_level = omap3evm_bklight_setlevel,
+ .get_bklight_level = omap3evm_bklight_getlevel,
+ .get_bklight_max = omap3evm_bklight_getmaxlevel,
+};
+
+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 Gumstix Overo
+ *
+ * Author: Steve Sakoman <steve@sakoman.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/i2c/twl4030.h>
+
+#include <mach/gpio.h>
+#include <mach/mux.h>
+#include <mach/omapfb.h>
+#include <asm/mach-types.h>
+
+#define LCD_ENABLE 144
+
+static int overo_panel_init(struct lcd_panel *panel,
+ struct omapfb_device *fbdev)
+{
+ if ((gpio_request(LCD_ENABLE, "LCD_ENABLE") == 0) &&
+ (gpio_direction_output(LCD_ENABLE, 1) == 0))
+ gpio_export(LCD_ENABLE, 0);
+ else
+ printk(KERN_ERR "could not obtain gpio for LCD_ENABLE\n");
+
+ return 0;
+}
+
+static void overo_panel_cleanup(struct lcd_panel *panel)
+{
+ gpio_free(LCD_ENABLE);
+}
+
+static int overo_panel_enable(struct lcd_panel *panel)
+{
+ gpio_set_value(LCD_ENABLE, 1);
+ return 0;
+}
+
+static void overo_panel_disable(struct lcd_panel *panel)
+{
+ gpio_set_value(LCD_ENABLE, 0);
+}
+
+static unsigned long overo_panel_get_caps(struct lcd_panel *panel)
+{
+ return 0;
+}
+
+struct lcd_panel overo_panel = {
+ .name = "overo",
+ .config = OMAP_LCDC_PANEL_TFT,
+ .bpp = 16,
+ .data_lines = 24,
+
+#if defined CONFIG_FB_OMAP_031M3R
+
+ /* 640 x 480 @ 60 Hz Reduced blanking VESA CVT 0.31M3-R */
+ .x_res = 640,
+ .y_res = 480,
+ .hfp = 48,
+ .hsw = 32,
+ .hbp = 80,
+ .vfp = 3,
+ .vsw = 4,
+ .vbp = 7,
+ .pixel_clock = 23500,
+
+#elif defined CONFIG_FB_OMAP_048M3R
+
+ /* 800 x 600 @ 60 Hz Reduced blanking VESA CVT 0.48M3-R */
+ .x_res = 800,
+ .y_res = 600,
+ .hfp = 48,
+ .hsw = 32,
+ .hbp = 80,
+ .vfp = 3,
+ .vsw = 4,
+ .vbp = 11,
+ .pixel_clock = 35500,
+
+#elif defined CONFIG_FB_OMAP_079M3R
+
+ /* 1024 x 768 @ 60 Hz Reduced blanking VESA CVT 0.79M3-R */
+ .x_res = 1024,
+ .y_res = 768,
+ .hfp = 48,
+ .hsw = 32,
+ .hbp = 80,
+ .vfp = 3,
+ .vsw = 4,
+ .vbp = 15,
+ .pixel_clock = 56000,
+
+#elif defined CONFIG_FB_OMAP_092M9R
+
+ /* 1280 x 720 @ 60 Hz Reduced blanking VESA CVT 0.92M9-R */
+ .x_res = 1280,
+ .y_res = 720,
+ .hfp = 48,
+ .hsw = 32,
+ .hbp = 80,
+ .vfp = 3,
+ .vsw = 5,
+ .vbp = 13,
+ .pixel_clock = 64000,
+
+#else
+
+ /* use 640 x 480 if no config option */
+ /* 640 x 480 @ 60 Hz Reduced blanking VESA CVT 0.31M3-R */
+ .x_res = 640,
+ .y_res = 480,
+ .hfp = 48,
+ .hsw = 32,
+ .hbp = 80,
+ .vfp = 3,
+ .vsw = 4,
+ .vbp = 7,
+ .pixel_clock = 23500,
+
+#endif
+
+ .init = overo_panel_init,
+ .cleanup = overo_panel_cleanup,
+ .enable = overo_panel_enable,
+ .disable = overo_panel_disable,
+ .get_caps = overo_panel_get_caps,
+};
+
+static int overo_panel_probe(struct platform_device *pdev)
+{
+ omapfb_register_panel(&overo_panel);
+ return 0;
+}
+
+static int overo_panel_remove(struct platform_device *pdev)
+{
+ /* omapfb does not have unregister_panel */
+ return 0;
+}
+
+static struct platform_driver overo_panel_driver = {
+ .probe = overo_panel_probe,
+ .remove = overo_panel_remove,
+ .driver = {
+ .name = "overo_lcd",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init overo_panel_drv_init(void)
+{
+ return platform_driver_register(&overo_panel_driver);
+}
+
+static void __exit overo_panel_drv_exit(void)
+{
+ platform_driver_unregister(&overo_panel_driver);
+}
+
+module_init(overo_panel_drv_init);
+module_exit(overo_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 <mach/mux.h>
+#include <mach/gpio.h>
+#include <mach/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 */
+ gpio_direction_output(19, 0);
+ mdelay(2);
+ gpio_set_value(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 */
+ gpio_direction_output(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 (fbdev->ctrl->set_scale != NULL)
+ 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) && (plane->idx > 0))
r = fbdev->ctrl->set_scale(plane->idx,
var->xres, var->yres,
plane->info.out_width,
plane->info.out_height);
+ if (r < 0)
+ return r;
- return r;
+ return 0;
}
/*
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;
+
+ 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;
+ }
- var = &fbi->var;
- if (win->x >= var->xres || win->y >= var->yres ||
- win->out_x > var->xres || win->out_y >= var->yres)
+ 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;
pr_info("omapfb: configured for panel %s\n", fbdev->panel->name);
- def_vxres = def_vxres ? : fbdev->panel->x_res;
- def_vyres = def_vyres ? : fbdev->panel->y_res;
+ def_vxres = def_vxres ? def_vxres : fbdev->panel->x_res;
+ def_vyres = def_vyres ? def_vyres : fbdev->panel->y_res;
init_state++;
{
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
#define DISPC_BASE 0x48050400
#define DISPC_CONTROL 0x0040
+#define DISPC_IRQ_FRAMEMASK 0x0001
static struct {
void __iomem *base;
l = (0x01 << 2);
rfbi_write_reg(RFBI_CONTROL, l);
- if ((r = omap_dispc_request_irq(rfbi_dma_callback, NULL)) < 0) {
+ if ((r = omap_dispc_request_irq(DISPC_IRQ_FRAMEMASK, rfbi_dma_callback,
+ NULL)) < 0) {
dev_err(fbdev->dev, "can't get DISPC irq\n");
rfbi_enable_clocks(0);
return r;
static void rfbi_cleanup(void)
{
- omap_dispc_free_irq();
+ omap_dispc_free_irq(DISPC_IRQ_FRAMEMASK, rfbi_dma_callback, NULL);
rfbi_put_clocks();
iounmap(rfbi.base);
}
* 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
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"
arch
+asm-offsets.h
mach-types.h
--- /dev/null
+/*
+ *
+ * TI TSC2101 Audio CODEC and TS control registers definition
+ *
+ *
+ * Copyright 2003 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * source@mvista.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __ASM_HARDWARE_TSC2101_H
+#define __ASM_HARDWARE_TSC2101_H
+
+/* Page 0 Touch Screen Data Registers */
+#define TSC2101_TS_X (0x00)
+#define TSC2101_TS_Y (0x01)
+#define TSC2101_TS_Z1 (0x02)
+#define TSC2101_TS_Z2 (0x03)
+#define TSC2101_TS_BAT (0x05)
+#define TSC2101_TS_AUX1 (0x07)
+#define TSC2101_TS_AUX2 (0x08)
+#define TSC2101_TS_TEMP1 (0x09)
+#define TSC2101_TS_TEMP2 (0x0A)
+
+/* Page 1 Touch Screen Control registers */
+#define TSC2101_TS_ADC_CTRL (0x00)
+#define TSC2101_TS_STATUS (0x01)
+#define TSC2101_TS_BUFFER_CTRL (0x02)
+#define TSC2101_TS_REF_CTRL (0x03)
+#define TSC2101_TS_RESET_CTRL (0x04)
+#define TSC2101_TS_CONFIG_CTRL (0x05)
+#define TSC2101_TS_TEMP_MAX_THRESHOLD (0x06)
+#define TSC2101_TS_TEMP_MIN_THRESHOLD (0x07)
+#define TSC2101_TS_AUX1_MAX_THRESHOLD (0x08)
+#define TSC2101_TS_AUX1_MIN_THRESHOLD (0x09)
+#define TSC2101_TS_AUX2_MAX_THRESHOLD (0x0A)
+#define TSC2101_TS_AUX2_MIN_THRESHOLD (0x0B)
+#define TSC2101_TS_MEASURE_CONFIG (0x0C)
+#define TSC2101_TS_PROG_DELAY (0x0D)
+
+/* Page 2 Audio codec Control registers */
+#define TSC2101_AUDIO_CTRL_1 (0x00)
+#define TSC2101_HEADSET_GAIN_CTRL (0x01)
+#define TSC2101_DAC_GAIN_CTRL (0x02)
+#define TSC2101_MIXER_PGA_CTRL (0x03)
+#define TSC2101_AUDIO_CTRL_2 (0x04)
+#define TSC2101_CODEC_POWER_CTRL (0x05)
+#define TSC2101_AUDIO_CTRL_3 (0x06)
+#define TSC2101_LCH_BASS_BOOST_N0 (0x07)
+#define TSC2101_LCH_BASS_BOOST_N1 (0x08)
+#define TSC2101_LCH_BASS_BOOST_N2 (0x09)
+#define TSC2101_LCH_BASS_BOOST_N3 (0x0A)
+#define TSC2101_LCH_BASS_BOOST_N4 (0x0B)
+#define TSC2101_LCH_BASS_BOOST_N5 (0x0C)
+#define TSC2101_LCH_BASS_BOOST_D1 (0x0D)
+#define TSC2101_LCH_BASS_BOOST_D2 (0x0E)
+#define TSC2101_LCH_BASS_BOOST_D4 (0x0F)
+#define TSC2101_LCH_BASS_BOOST_D5 (0x10)
+#define TSC2101_RCH_BASS_BOOST_N0 (0x11)
+#define TSC2101_RCH_BASS_BOOST_N1 (0x12)
+#define TSC2101_RCH_BASS_BOOST_N2 (0x13)
+#define TSC2101_RCH_BASS_BOOST_N3 (0x14)
+#define TSC2101_RCH_BASS_BOOST_N4 (0x15)
+#define TSC2101_RCH_BASS_BOOST_N5 (0x16)
+#define TSC2101_RCH_BASS_BOOST_D1 (0x17)
+#define TSC2101_RCH_BASS_BOOST_D2 (0x18)
+#define TSC2101_RCH_BASS_BOOST_D4 (0x19)
+#define TSC2101_RCH_BASS_BOOST_D5 (0x1A)
+#define TSC2101_PLL_PROG_1 (0x1B)
+#define TSC2101_PLL_PROG_2 (0x1C)
+#define TSC2101_AUDIO_CTRL_4 (0x1D)
+#define TSC2101_HANDSET_GAIN_CTRL (0x1E)
+#define TSC2101_BUZZER_GAIN_CTRL (0x1F)
+#define TSC2101_AUDIO_CTRL_5 (0x20)
+#define TSC2101_AUDIO_CTRL_6 (0x21)
+#define TSC2101_AUDIO_CTRL_7 (0x22)
+#define TSC2101_GPIO_CTRL (0x23)
+#define TSC2101_AGC_CTRL (0x24)
+#define TSC2101_POWERDOWN_STS (0x25)
+#define TSC2101_MIC_AGC_CONTROL (0x26)
+#define TSC2101_CELL_AGC_CONTROL (0x27)
+
+/* Bit field definitions for TS Control */
+#define TSC2101_DATA_AVAILABLE 0x4000
+#define TSC2101_BUFFERMODE_DISABLE 0x0
+#define TSC2101_REF_POWERUP 0x16
+#define TSC2101_ENABLE_TOUCHDETECT 0x08
+#define TSC2101_PRG_DELAY 0x0900
+#define TSC2101_ADC_CONTROL 0x8874
+#define TSC2101_ADC_POWERDOWN 0x4000
+
+/* Bit position */
+#define TSC2101_BIT(ARG) ((0x01)<<(ARG))
+
+/* Field masks for Audio Control 1 */
+#define AC1_ADCHPF(ARG) (((ARG) & 0x03) << 14)
+#define AC1_WLEN(ARG) (((ARG) & 0x03) << 10)
+#define AC1_DATFM(ARG) (((ARG) & 0x03) << 8)
+#define AC1_DACFS(ARG) (((ARG) & 0x07) << 3)
+#define AC1_ADCFS(ARG) (((ARG) & 0x07))
+
+/* Field masks for TSC2101_HEADSET_GAIN_CTRL */
+#define HGC_ADMUT_HED TSC2101_BIT(15)
+#define HGC_ADPGA_HED(ARG) (((ARG) & 0x7F) << 8)
+#define HGC_AGCTG_HED(ARG) (((ARG) & 0x07) << 5)
+#define HGC_AGCTC_HED(ARG) (((ARG) & 0x0F) << 1)
+#define HGC_AGCEN_HED (0x01)
+
+/* Field masks for TSC2101_DAC_GAIN_CTRL */
+#define DGC_DALMU TSC2101_BIT(15)
+#define DGC_DALVL(ARG) (((ARG) & 0x7F) << 8)
+#define DGC_DARMU TSC2101_BIT(7)
+#define DGC_DARVL(ARG) (((ARG) & 0x7F))
+
+/* Field masks for TSC2101_MIXER_PGA_CTRL */
+#define MPC_ASTMU TSC2101_BIT(15)
+#define MPC_ASTG(ARG) (((ARG) & 0x7F) << 8)
+#define MPC_MICSEL(ARG) (((ARG) & 0x07) << 5)
+#define MPC_MICADC TSC2101_BIT(4)
+#define MPC_CPADC TSC2101_BIT(3)
+#define MPC_ASTGF (0x01)
+
+/* Field formats for TSC2101_AUDIO_CTRL_2 */
+#define AC2_KCLEN TSC2101_BIT(15)
+#define AC2_KCLAC(ARG) (((ARG) & 0x07) << 12)
+#define AC2_APGASS TSC2101_BIT(11)
+#define AC2_KCLFRQ(ARG) (((ARG) & 0x07) << 8)
+#define AC2_KCLLN(ARG) (((ARG) & 0x0F) << 4)
+#define AC2_DLGAF TSC2101_BIT(3)
+#define AC2_DRGAF TSC2101_BIT(2)
+#define AC2_DASTC TSC2101_BIT(1)
+#define AC2_ADGAF (0x01)
+
+/* Field masks for TSC2101_CODEC_POWER_CTRL */
+#define CPC_MBIAS_HND TSC2101_BIT(15)
+#define CPC_MBIAS_HED TSC2101_BIT(14)
+#define CPC_ASTPWD TSC2101_BIT(13)
+#define CPC_SP1PWDN TSC2101_BIT(12)
+#define CPC_SP2PWDN TSC2101_BIT(11)
+#define CPC_DAPWDN TSC2101_BIT(10)
+#define CPC_ADPWDN TSC2101_BIT(9)
+#define CPC_VGPWDN TSC2101_BIT(8)
+#define CPC_COPWDN TSC2101_BIT(7)
+#define CPC_LSPWDN TSC2101_BIT(6)
+#define CPC_ADPWDF TSC2101_BIT(5)
+#define CPC_LDAPWDF TSC2101_BIT(4)
+#define CPC_RDAPWDF TSC2101_BIT(3)
+#define CPC_ASTPWF TSC2101_BIT(2)
+#define CPC_BASSBC TSC2101_BIT(1)
+#define CPC_DEEMPF (0x01)
+
+/* Field masks for TSC2101_AUDIO_CTRL_3 */
+#define AC3_DMSVOL(ARG) (((ARG) & 0x03) << 14)
+#define AC3_REFFS TSC2101_BIT(13)
+#define AC3_DAXFM TSC2101_BIT(12)
+#define AC3_SLVMS TSC2101_BIT(11)
+#define AC3_ADCOVF TSC2101_BIT(8)
+#define AC3_DALOVF TSC2101_BIT(7)
+#define AC3_DAROVF TSC2101_BIT(6)
+#define AC3_CLPST TSC2101_BIT(3)
+#define AC3_REVID(ARG) (((ARG) & 0x07))
+
+/* Field masks for TSC2101_PLL_PROG_1 */
+#define PLL1_PLLSEL TSC2101_BIT(15)
+#define PLL1_QVAL(ARG) (((ARG) & 0x0F) << 11)
+#define PLL1_PVAL(ARG) (((ARG) & 0x07) << 8)
+#define PLL1_I_VAL(ARG) (((ARG) & 0x3F) << 2)
+
+/* Field masks of TSC2101_PLL_PROG_2 */
+#define PLL2_D_VAL(ARG) (((ARG) & 0x3FFF) << 2)
+
+/* Field masks for TSC2101_AUDIO_CTRL_4 */
+#define AC4_ADSTPD TSC2101_BIT(15)
+#define AC4_DASTPD TSC2101_BIT(14)
+#define AC4_ASSTPD TSC2101_BIT(13)
+#define AC4_CISTPD TSC2101_BIT(12)
+#define AC4_BISTPD TSC2101_BIT(11)
+#define AC4_AGCHYS(ARG) (((ARG) & 0x03) << 9)
+#define AC4_MB_HED(ARG) (((ARG) & 0x03) << 7)
+#define AC4_MB_HND TSC2101_BIT(6)
+#define AC4_SCPFL TSC2101_BIT(1)
+
+/* Field masks settings for TSC2101_HANDSET_GAIN_CTRL */
+#define HNGC_ADMUT_HND TSC2101_BIT(15)
+#define HNGC_ADPGA_HND(ARG) (((ARG) & 0x7F) << 8)
+#define HNGC_AGCTG_HND(ARG) (((ARG) & 0x07) << 5)
+#define HNGC_AGCTC_HND(ARG) (((ARG) & 0x0F) << 1)
+#define HNGC_AGCEN_HND (0x01)
+
+/* Field masks settings for TSC2101_BUZZER_GAIN_CTRL */
+#define BGC_MUT_CP TSC2101_BIT(15)
+#define BGC_CPGA(ARG) (((ARG) & 0x7F) << 8)
+#define BGC_CPGF TSC2101_BIT(7)
+#define BGC_MUT_BU TSC2101_BIT(6)
+#define BGC_BPGA(ARG) (((ARG) & 0x0F) << 2)
+#define BGC_BUGF TSC2101_BIT(1)
+
+/* Field masks settings for TSC2101_AUDIO_CTRL_5 */
+#define AC5_DIFFIN TSC2101_BIT(15)
+#define AC5_DAC2SPK1(ARG) (((ARG) & 0x03) << 13)
+#define AC5_AST2SPK1 TSC2101_BIT(12)
+#define AC5_BUZ2SPK1 TSC2101_BIT(11)
+#define AC5_KCL2SPK1 TSC2101_BIT(10)
+#define AC5_CPI2SPK1 TSC2101_BIT(9)
+#define AC5_DAC2SPK2(ARG) (((ARG) & 0x03) << 7)
+#define AC5_AST2SPK2 TSC2101_BIT(6)
+#define AC5_BUZ2SPK2 TSC2101_BIT(5)
+#define AC5_KCL2SPK2 TSC2101_BIT(4)
+#define AC5_CPI2SPK2 TSC2101_BIT(3)
+#define AC5_MUTSPK1 TSC2101_BIT(2)
+#define AC5_MUTSPK2 TSC2101_BIT(1)
+#define AC5_HDSCPTC (0x01)
+
+/* Field masks settings for TSC2101_AUDIO_CTRL_6 */
+#define AC6_SPL2LSK TSC2101_BIT(15)
+#define AC6_AST2LSK TSC2101_BIT(14)
+#define AC6_BUZ2LSK TSC2101_BIT(13)
+#define AC6_KCL2LSK TSC2101_BIT(12)
+#define AC6_CPI2LSK TSC2101_BIT(11)
+#define AC6_MIC2CPO TSC2101_BIT(10)
+#define AC6_SPL2CPO TSC2101_BIT(9)
+#define AC6_SPR2CPO TSC2101_BIT(8)
+#define AC6_MUTLSPK TSC2101_BIT(7)
+#define AC6_MUTSPK2 TSC2101_BIT(6)
+#define AC6_LDSCPTC TSC2101_BIT(5)
+#define AC6_VGNDSCPTC TSC2101_BIT(4)
+#define AC6_CAPINTF TSC2101_BIT(3)
+
+/* Field masks settings for TSC2101_AUDIO_CTRL_7 */
+#define AC7_DETECT TSC2101_BIT(15)
+#define AC7_HESTYPE(ARG) (((ARG) & 0x03) << 13)
+#define AC7_HDDETFL TSC2101_BIT(12)
+#define AC7_BDETFL TSC2101_BIT(11)
+#define AC7_HDDEBNPG(ARG) (((ARG) & 0x03) << 9)
+#define AC7_BDEBNPG(ARG) (((ARG) & 0x03) << 6)
+#define AC7_DGPIO2 TSC2101_BIT(4)
+#define AC7_DGPIO1 TSC2101_BIT(3)
+#define AC7_CLKGPIO2 TSC2101_BIT(2)
+#define AC7_ADWSF(ARG) (((ARG) & 0x03))
+
+/* Field masks settings for TSC2101_GPIO_CTRL */
+#define GC_GPO2EN TSC2101_BIT(15)
+#define GC_GPO2SG TSC2101_BIT(14)
+#define GC_GPI2EN TSC2101_BIT(13)
+#define GC_GPI2SGF TSC2101_BIT(12)
+#define GC_GPO1EN TSC2101_BIT(11)
+#define GC_GPO1SG TSC2101_BIT(10)
+#define GC_GPI1EN TSC2101_BIT(9)
+#define GC_GPI1SGF TSC2101_BIT(8)
+
+/* Field masks for TSC2101_AGC_CTRL */
+#define AC_AGCNF_CELL TSC2101_BIT(14)
+#define AC_AGCNL(ARG) (((ARG) & 0x07) << 11)
+#define AC_AGCHYS_CELL(ARG) (((ARG) & 0x03) << 9)
+#define AC_CLPST_CELL TSC2101_BIT(8)
+#define AC_AGCTG_CELL(ARG) (((ARG) & 0x07) << 5)
+#define AC_AGCTC_CELL(ARG) (((ARG) & 0x0F) << 1)
+#define AC_AGCEN_CELL (0x01)
+
+/* Field masks for TSC2101_POWERDOWN_STS */
+#define PS_SPK1FL TSC2101_BIT(15)
+#define PS_SPK2FL TSC2101_BIT(14)
+#define PS_HNDFL TSC2101_BIT(13)
+#define PS_VGNDFL TSC2101_BIT(12)
+#define PS_LSPKFL TSC2101_BIT(11)
+#define PS_CELLFL TSC2101_BIT(10)
+#define PS_PSEQ TSC2101_BIT(5)
+#define PS_PSTIME TSC2101_BIT(4)
+
+/* Field masks for Register Mic AGC Control */
+#define MAC_MMPGA(ARG) (((ARG) & 0x7F) << 9)
+#define MAC_MDEBNS(ARG) (((ARG) & 0x07) << 6)
+#define MAC_MDEBSN(ARG) (((ARG) & 0x07) << 3)
+
+/* Field masks for Register Cellphone AGC Control */
+#define CAC_CMPGA(ARG) (((ARG) & 0x7F) << 9)
+#define CAC_CDEBNS(ARG) (((ARG) & 0x07) << 6)
+#define CAC_CDEBSN(ARG) (((ARG) & 0x07) << 3)
+
+#endif /* __ASM_HARDWARE_TSC2101_H */
#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 CN_IDX_BB 0x5 /* BlackBoard, from the TSP GPL sampling framework */
#define I2C_DRIVERID_MSP3400 1
#define I2C_DRIVERID_TUNER 2
+#define I2C_DRIVERID_TDA8425 4 /* stereo sound processor */
#define I2C_DRIVERID_TEA6420 5 /* audio matrix switch */
#define I2C_DRIVERID_TEA6415C 6 /* video matrix switch */
#define I2C_DRIVERID_TDA9840 7 /* stereo sound processor */
#define I2C_DRIVERID_SAA7111A 8 /* video input processor */
#define I2C_DRIVERID_SAA7185B 13 /* video encoder */
+#define I2C_DRIVERID_TEA6300 18 /* audio mixer */
+#define I2C_DRIVERID_TDA9850 20 /* audio mixer */
+#define I2C_DRIVERID_TDA9855 21 /* audio mixer */
#define I2C_DRIVERID_SAA7110 22 /* video decoder */
#define I2C_DRIVERID_SAA5249 24 /* SAA5249 and compatibles */
#define I2C_DRIVERID_PCF8583 25 /* real time clock */
#define I2C_DRIVERID_TDA7432 27 /* Stereo sound processor */
#define I2C_DRIVERID_TVMIXER 28 /* Mixer driver for tv cards */
#define I2C_DRIVERID_TVAUDIO 29 /* Generic TV sound driver */
+#define I2C_DRIVERID_TDA9873 31 /* TV sound decoder chip */
#define I2C_DRIVERID_TDA9875 32 /* TV sound decoder chip */
+#define I2C_DRIVERID_PIC16C54_PV9 33 /* Audio mux/ir receiver */
#define I2C_DRIVERID_BT819 40 /* video decoder */
#define I2C_DRIVERID_BT856 41 /* video encoder */
#define I2C_DRIVERID_VPX3220 42 /* video decoder+vbi/vtxt */
#define I2C_DRIVERID_INDYCAM 58 /* SGI IndyCam */
#define I2C_DRIVERID_OVCAMCHIP 61 /* OmniVision CMOS image sens. */
#define I2C_DRIVERID_MAX6900 63 /* MAX6900 real-time clock */
+#define I2C_DRIVERID_TDA9874 66 /* TV sound decoder */
#define I2C_DRIVERID_SAA6752HS 67 /* MPEG2 encoder */
#define I2C_DRIVERID_TVEEPROM 68 /* TV EEPROM */
#define I2C_DRIVERID_WM8775 69 /* wm8775 audio processor */
#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 */
/*
#define I2C_HW_B_RIVA 0x010010 /* Riva based graphics cards */
#define I2C_HW_B_IOC 0x010011 /* IOC bit-wiggling */
#define I2C_HW_B_IXP2000 0x010016 /* GPIO on IXP2000 systems */
+#define I2C_HW_B_S3VIA 0x010018 /* S3Via ProSavage adapter */
#define I2C_HW_B_ZR36067 0x010019 /* Zoran-36057/36067 based boards */
#define I2C_HW_B_PCILYNX 0x01001a /* TI PCILynx I2C adapter */
#define I2C_HW_B_CX2388x 0x01001b /* connexant 2388x based tv cards */
#define I2C_HW_SMBUS_W9968CF 0x04000d
#define I2C_HW_SMBUS_OV511 0x04000e /* OV511(+) USB 1.1 webcam ICs */
#define I2C_HW_SMBUS_OV518 0x04000f /* OV518(+) USB 1.1 webcam ICs */
+#define I2C_HW_SMBUS_OVFX2 0x040011 /* Cypress/OmniVision FX2 webcam */
#define I2C_HW_SMBUS_CAFE 0x040012 /* Marvell 88ALP01 "CAFE" cam */
#define I2C_HW_SMBUS_ALI1563 0x040013
--- /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 {
+ 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/menelaus.h
+ *
+ * Functions to access Menelaus power management chip
+ */
+
+#ifndef __ASM_ARCH_MENELAUS_H
+#define __ASM_ARCH_MENELAUS_H
+
+#define MENELAUS_I2C_ADDRESS 0x72
+
+#define MENELAUS_REV 0x01
+#define MENELAUS_VCORE_CTRL1 0x02
+#define MENELAUS_VCORE_CTRL2 0x03
+#define MENELAUS_VCORE_CTRL3 0x04
+#define MENELAUS_VCORE_CTRL4 0x05
+#define MENELAUS_VCORE_CTRL5 0x06
+#define MENELAUS_DCDC_CTRL1 0x07
+#define MENELAUS_DCDC_CTRL2 0x08
+#define MENELAUS_DCDC_CTRL3 0x09
+#define MENELAUS_LDO_CTRL1 0x0A
+#define MENELAUS_LDO_CTRL2 0x0B
+#define MENELAUS_LDO_CTRL3 0x0C
+#define MENELAUS_LDO_CTRL4 0x0D
+#define MENELAUS_LDO_CTRL5 0x0E
+#define MENELAUS_LDO_CTRL6 0x0F
+#define MENELAUS_LDO_CTRL7 0x10
+#define MENELAUS_LDO_CTRL8 0x11
+#define MENELAUS_SLEEP_CTRL1 0x12
+#define MENELAUS_SLEEP_CTRL2 0x13
+#define MENELAUS_DEVICE_OFF 0x14
+#define MENELAUS_OSC_CTRL 0x15
+#define MENELAUS_DETECT_CTRL 0x16
+#define MENELAUS_INT_MASK1 0x17
+#define MENELAUS_INT_MASK2 0x18
+#define MENELAUS_INT_STATUS1 0x19
+#define MENELAUS_INT_STATUS2 0x1A
+#define MENELAUS_INT_ACK1 0x1B
+#define MENELAUS_INT_ACK2 0x1C
+#define MENELAUS_GPIO_CTRL 0x1D
+#define MENELAUS_GPIO_IN 0x1E
+#define MENELAUS_GPIO_OUT 0x1F
+#define MENELAUS_BBSMS 0x20
+#define MENELAUS_RTC_CTRL 0x21
+#define MENELAUS_RTC_UPDATE 0x22
+#define MENELAUS_RTC_SEC 0x23
+#define MENELAUS_RTC_MIN 0x24
+#define MENELAUS_RTC_HR 0x25
+#define MENELAUS_RTC_DAY 0x26
+#define MENELAUS_RTC_MON 0x27
+#define MENELAUS_RTC_YR 0x28
+#define MENELAUS_RTC_WKDAY 0x29
+#define MENELAUS_RTC_AL_SEC 0x2A
+#define MENELAUS_RTC_AL_MIN 0x2B
+#define MENELAUS_RTC_AL_HR 0x2C
+#define MENELAUS_RTC_AL_DAY 0x2D
+#define MENELAUS_RTC_AL_MON 0x2E
+#define MENELAUS_RTC_AL_YR 0x2F
+#define MENELAUS_RTC_COMP_MSB 0x30
+#define MENELAUS_RTC_COMP_LSB 0x31
+#define MENELAUS_S1_PULL_EN 0x32
+#define MENELAUS_S1_PULL_DIR 0x33
+#define MENELAUS_S2_PULL_EN 0x34
+#define MENELAUS_S2_PULL_DIR 0x35
+#define MENELAUS_MCT_CTRL1 0x36
+#define MENELAUS_MCT_CTRL2 0x37
+#define MENELAUS_MCT_CTRL3 0x38
+#define MENELAUS_MCT_PIN_ST 0x39
+#define MENELAUS_DEBOUNCE1 0x3A
+
+#define IH_MENELAUS_IRQS 12
+#define MENELAUS_MMC_S1CD_IRQ 0 /* MMC slot 1 card change */
+#define MENELAUS_MMC_S2CD_IRQ 1 /* MMC slot 2 card change */
+#define MENELAUS_MMC_S1D1_IRQ 2 /* MMC DAT1 low in slot 1 */
+#define MENELAUS_MMC_S2D1_IRQ 3 /* MMC DAT1 low in slot 2 */
+#define MENELAUS_LOWBAT_IRQ 4 /* Low battery */
+#define MENELAUS_HOTDIE_IRQ 5 /* Hot die detect */
+#define MENELAUS_UVLO_IRQ 6 /* UVLO detect */
+#define MENELAUS_TSHUT_IRQ 7 /* Thermal shutdown */
+#define MENELAUS_RTCTMR_IRQ 8 /* RTC timer */
+#define MENELAUS_RTCALM_IRQ 9 /* RTC alarm */
+#define MENELAUS_RTCERR_IRQ 10 /* RTC error */
+#define MENELAUS_PSHBTN_IRQ 11 /* Push button */
+#define MENELAUS_RESERVED12_IRQ 12 /* Reserved */
+#define MENELAUS_RESERVED13_IRQ 13 /* Reserved */
+#define MENELAUS_RESERVED14_IRQ 14 /* Reserved */
+#define MENELAUS_RESERVED15_IRQ 15 /* Reserved */
+
+/* VCORE_CTRL1 register */
+#define VCORE_CTRL1_BYP_COMP (1 << 5)
+#define VCORE_CTRL1_HW_NSW (1 << 7)
+
+/* GPIO_CTRL register */
+#define GPIO_CTRL_SLOTSELEN (1 << 5)
+#define GPIO_CTRL_SLPCTLEN (1 << 6)
+#define GPIO1_DIR_INPUT (1 << 0)
+#define GPIO2_DIR_INPUT (1 << 1)
+#define GPIO3_DIR_INPUT (1 << 2)
+
+/* MCT_CTRL1 register */
+#define MCT_CTRL1_S1_CMD_OD (1 << 2)
+#define MCT_CTRL1_S2_CMD_OD (1 << 3)
+
+/* MCT_CTRL2 register */
+#define MCT_CTRL2_VS2_SEL_D0 (1 << 0)
+#define MCT_CTRL2_VS2_SEL_D1 (1 << 1)
+#define MCT_CTRL2_S1CD_BUFEN (1 << 4)
+#define MCT_CTRL2_S2CD_BUFEN (1 << 5)
+#define MCT_CTRL2_S1CD_DBEN (1 << 6)
+#define MCT_CTRL2_S2CD_BEN (1 << 7)
+
+/* MCT_CTRL3 register */
+#define MCT_CTRL3_SLOT1_EN (1 << 0)
+#define MCT_CTRL3_SLOT2_EN (1 << 1)
+#define MCT_CTRL3_S1_AUTO_EN (1 << 2)
+#define MCT_CTRL3_S2_AUTO_EN (1 << 3)
+
+/* MCT_PIN_ST register */
+#define MCT_PIN_ST_S1_CD_ST (1 << 0)
+#define MCT_PIN_ST_S2_CD_ST (1 << 1)
+
+struct device;
+
+struct menelaus_platform_data {
+ int (*late_init)(struct device *dev);
+};
+
+extern int menelaus_register_mmc_callback(void (*callback)(void *data,
+ u8 card_mask),
+ void *data);
+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);
+extern int menelaus_set_vmmc(unsigned int mV);
+extern int menelaus_set_vaux(unsigned int mV);
+extern int menelaus_set_vdcdc(int dcdc, unsigned int mV);
+extern int menelaus_set_slot_sel(int enable);
+extern int menelaus_get_slot_pin_states(void);
+extern int menelaus_set_vcore_sw(unsigned int mV);
+extern int menelaus_set_vcore_hw(unsigned int roof_mV, unsigned int floor_mV);
+
+#define EN_VPLL_SLEEP (1 << 7)
+#define EN_VMMC_SLEEP (1 << 6)
+#define EN_VAUX_SLEEP (1 << 5)
+#define EN_VIO_SLEEP (1 << 4)
+#define EN_VMEM_SLEEP (1 << 3)
+#define EN_DC3_SLEEP (1 << 2)
+#define EN_DC2_SLEEP (1 << 1)
+#define EN_VC_SLEEP (1 << 0)
+
+extern int menelaus_set_regulator_sleep(int enable, u32 val);
+
+#if defined(CONFIG_ARCH_OMAP24XX) && defined(CONFIG_MENELAUS)
+#define omap_has_menelaus() 1
+#else
+#define omap_has_menelaus() 0
+#endif
+
+#endif
--- /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_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
/*----------------------------------------------------------------------*/
+/* Power bus message definitions */
+
+#define DEV_GRP_NULL 0x0
+#define DEV_GRP_P1 0x1
+#define DEV_GRP_P2 0x2
+#define DEV_GRP_P3 0x4
+
+#define RES_GRP_RES 0x0
+#define RES_GRP_PP 0x1
+#define RES_GRP_RC 0x2
+#define RES_GRP_PP_RC 0x3
+#define RES_GRP_PR 0x4
+#define RES_GRP_PP_PR 0x5
+#define RES_GRP_RC_PR 0x6
+#define RES_GRP_ALL 0x7
+
+#define RES_TYPE2_R0 0x0
+
+#define RES_TYPE_ALL 0x7
+
+#define RES_STATE_WRST 0xF
+#define RES_STATE_ACTIVE 0xE
+#define RES_STATE_SLEEP 0x8
+#define RES_STATE_OFF 0x0
+
+/*
+ * Power Bus Message Format ... these can be sent individually by Linux,
+ * but are usually part of downloaded scripts that are run when various
+ * power events are triggered.
+ *
+ * Broadcast Message (16 Bits):
+ * DEV_GRP[15:13] MT[12] RES_GRP[11:9] RES_TYPE2[8:7] RES_TYPE[6:4]
+ * RES_STATE[3:0]
+ *
+ * Singular Message (16 Bits):
+ * DEV_GRP[15:13] MT[12] RES_ID[11:4] RES_STATE[3:0]
+ */
+
+#define MSG_BROADCAST(devgrp, grp, type, type2, state) \
+ ( (devgrp) << 13 | 1 << 12 | (grp) << 9 | (type2) << 7 \
+ | (type) << 4 | (state))
+
+#define MSG_SINGULAR(devgrp, id, state) \
+ ((devgrp) << 13 | 0 << 12 | (id) << 4 | (state))
+
+/*----------------------------------------------------------------------*/
+
struct twl4030_bci_platform_data {
int *battery_tmp_tbl;
unsigned int tblsize;
int rows;
int cols;
int *keymap;
- int irq;
unsigned int keymapsize;
unsigned int rep:1;
};
enum twl4030_usb_mode usb_mode;
};
+struct twl4030_ins {
+ u16 pmb_message;
+ u8 delay;
+};
+
+struct twl4030_script {
+ struct twl4030_ins *script;
+ unsigned size;
+ u8 flags;
+#define TRITON_WRST_SCRIPT (1<<0)
+#define TRITON_WAKEUP12_SCRIPT (1<<1)
+#define TRITON_WAKEUP3_SCRIPT (1<<2)
+#define TRITON_SLEEP_SCRIPT (1<<3)
+};
+
+struct twl4030_power_data {
+ struct twl4030_script **scripts;
+ unsigned size;
+};
+
struct twl4030_platform_data {
unsigned irq_base, irq_end;
struct twl4030_bci_platform_data *bci;
struct twl4030_madc_platform_data *madc;
struct twl4030_keypad_data *keypad;
struct twl4030_usb_data *usb;
+ struct twl4030_power_data *power;
/* LDO regulators */
struct regulator_init_data *vdac;
#define TWL4030_VAUX3_DEV_GRP 0x1F
#define TWL4030_VAUX3_DEDICATED 0x22
-
#if defined(CONFIG_TWL4030_BCI_BATTERY) || \
defined(CONFIG_TWL4030_BCI_BATTERY_MODULE)
extern int twl4030charger_usb_en(int enable);
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
#define UART_OMAP_MVER 0x14 /* Module version register */
#define UART_OMAP_SYSC 0x15 /* System configuration register */
#define UART_OMAP_SYSS 0x16 /* System status register */
+#define UART_OMAP_WER 0x17 /* Wake-up enable register */
#endif /* _LINUX_SERIAL_REG_H */
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/tsc210x.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
+
+extern void tsc2301_mixer_enable_mclk(struct device *tsc_dev);
+extern void tsc2301_mixer_disable_mclk(struct device *tsc_dev);
+
+#endif
#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
come to the local machine instead of passing through. This is
useful for transparent proxies.
+ 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_SELINUX) += selinux/built-in.o
obj-$(CONFIG_SECURITY_SMACK) += smack/built-in.o
obj-$(CONFIG_SECURITY_ROOTPLUG) += 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>
+#include <linux/oom.h>
+
+#define MY_NAME "lowmem"
+
+#define LOWMEM_MAX_UIDS 8
+
+enum {
+ VM_LOWMEM_DENY_PAGES = 1,
+ VM_LOWMEM_NOTIFY_LOW_PAGES,
+ VM_LOWMEM_NOTIFY_HIGH_PAGES,
+ VM_LOWMEM_NR_DECAY_PAGES,
+ VM_LOWMEM_ALLOWED_UIDS,
+ VM_LOWMEM_ALLOWED_PAGES,
+ VM_LOWMEM_FREE_PAGES,
+ VM_LOWMEM_DENY,
+ VM_LOWMEM_LEVEL1_NOTIFY,
+ VM_LOWMEM_LEVEL2_NOTIFY,
+ VM_LOWMEM_USED_PAGES
+};
+
+static long deny_pages;
+static long notify_low_pages, notify_high_pages;
+static unsigned int nr_decay_pages;
+static unsigned long allowed_pages;
+static unsigned long lowmem_free_pages;
+static unsigned int allowed_uids[LOWMEM_MAX_UIDS];
+static unsigned int minuid = 1;
+static unsigned int maxuid = 65535;
+static unsigned int deny_percentage;
+static unsigned int l1_notify, l2_notify;
+static long used_pages;
+
+static int
+proc_dointvec_used(ctl_table *table, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos);
+static int
+proc_dointvec_l1_notify(ctl_table *table, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos);
+static int
+proc_dointvec_l2_notify(ctl_table *table, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos);
+static int
+proc_dointvec_deny(ctl_table *table, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos);
+
+static ctl_table lowmem_table[] = {
+ {
+ .ctl_name = VM_LOWMEM_DENY_PAGES,
+ .procname = "lowmem_deny_watermark_pages",
+ .data = &deny_pages,
+ .maxlen = sizeof(long),
+ .mode = 0644,
+ .child = NULL,
+ .proc_handler = &proc_dointvec,
+ .strategy = &sysctl_intvec,
+ }, {
+ .ctl_name = VM_LOWMEM_DENY,
+ .procname = "lowmem_deny_watermark",
+ .data = &deny_percentage,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0444,
+ .child = NULL,
+ .proc_handler = &proc_dointvec_deny,
+ .strategy = &sysctl_intvec,
+ }, {
+ .ctl_name = VM_LOWMEM_LEVEL1_NOTIFY,
+ .procname = "lowmem_notify_low",
+ .data = &l1_notify,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0444,
+ .child = NULL,
+ .proc_handler = &proc_dointvec_l1_notify,
+ .strategy = &sysctl_intvec,
+ }, {
+ .ctl_name = VM_LOWMEM_LEVEL2_NOTIFY,
+ .procname = "lowmem_notify_high",
+ .data = &l2_notify,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0444,
+ .child = NULL,
+ .proc_handler = &proc_dointvec_l2_notify,
+ .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_used,
+ .strategy = &sysctl_intvec,
+ }, {
+ .ctl_name = VM_LOWMEM_NOTIFY_LOW_PAGES,
+ .procname = "lowmem_notify_low_pages",
+ .data = ¬ify_low_pages,
+ .maxlen = sizeof(long),
+ .mode = 0644,
+ .child = NULL,
+ .proc_handler = &proc_dointvec,
+ .strategy = &sysctl_intvec,
+ }, {
+ .ctl_name = VM_LOWMEM_NOTIFY_HIGH_PAGES,
+ .procname = "lowmem_notify_high_pages",
+ .data = ¬ify_high_pages,
+ .maxlen = sizeof(long),
+ .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,
+ .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,
+ .strategy = &sysctl_intvec,
+ }, {
+ .ctl_name = VM_LOWMEM_FREE_PAGES,
+ .procname = "lowmem_free_pages",
+ .data = &lowmem_free_pages,
+ .maxlen = sizeof(unsigned long),
+ .mode = 0444,
+ .child = NULL,
+ .proc_handler = &proc_dointvec,
+ .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 kobj_attribute _name##_attr = __ATTR_RO(_name)
+
+static int low_watermark_reached, high_watermark_reached;
+
+static int
+proc_dointvec_l1_notify(ctl_table *table, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ l1_notify =
+ 100 - (100 * notify_low_pages + allowed_pages / 2) / allowed_pages;
+ return proc_dointvec(table, write, filp, buffer, lenp, ppos);
+}
+
+static int
+proc_dointvec_l2_notify(ctl_table *table, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ l2_notify =
+ 100 - (100 * notify_high_pages + allowed_pages / 2) / allowed_pages;
+ return proc_dointvec(table, write, filp, buffer, lenp, ppos);
+}
+
+static int
+proc_dointvec_deny(ctl_table *table, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ deny_percentage =
+ 100 - (100 * deny_pages + allowed_pages / 2) / allowed_pages;
+ return proc_dointvec(table, write, filp, buffer, lenp, ppos);
+}
+
+static int
+proc_dointvec_used(ctl_table *table, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ if (lowmem_free_pages > 0 && allowed_pages > lowmem_free_pages)
+ used_pages = allowed_pages - lowmem_free_pages;
+ else
+ used_pages = 0;
+ return proc_dointvec(table, write, filp, buffer, lenp, ppos);
+}
+
+static ssize_t low_watermark_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *page)
+{
+ return sprintf(page, "%u\n", low_watermark_reached);
+}
+
+static ssize_t high_watermark_show(struct kobject *kobj,
+ struct kobj_attribute *attr, 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)
+{
+ if (low_watermark_reached != new_state) {
+ low_watermark_reached = new_state;
+ sysfs_notify(kernel_kobj, NULL, "low_watermark");
+ }
+}
+
+static void high_watermark_state(int new_state)
+{
+ if (high_watermark_reached != new_state) {
+ high_watermark_reached = new_state;
+ sysfs_notify(kernel_kobj, NULL, "high_watermark");
+ }
+}
+
+static int low_vm_enough_memory(struct mm_struct *mm, long pages)
+{
+ unsigned long free, allowed;
+ int cap_sys_admin = 0, notify;
+
+ if (cap_capable(current, CAP_SYS_ADMIN) == 0)
+ cap_sys_admin = 1;
+
+ allowed = totalram_pages - hugetlb_total_pages();
+ allowed_pages = allowed;
+
+ /* We activate ourselves only after both parameters have been
+ * configured. */
+ if (deny_pages == 0 || notify_low_pages == 0 || notify_high_pages == 0)
+ return __vm_enough_memory(mm, pages, cap_sys_admin);
+
+ 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);
+
+ if (likely(free > notify_low_pages))
+ goto enough_memory;
+
+ /* No luck, lets make it more expensive and try again.. */
+ free += nr_free_pages();
+
+ if (free < deny_pages) {
+ int i;
+
+ lowmem_free_pages = free;
+ low_watermark_state(1);
+ high_watermark_state(1);
+ /* Memory allocations by root are always allowed */
+ if (cap_sys_admin)
+ return 0;
+
+ /* OOM unkillable process is allowed to consume memory */
+ if (current->oomkilladj == OOM_DISABLE)
+ 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(free < notify_low_pages);
+
+ /*
+ * 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 = free < notify_high_pages;
+ if (notify || free - nr_decay_pages > notify_high_pages)
+ high_watermark_state(notify);
+
+ /* We have plenty of memory */
+ lowmem_free_pages = free;
+ return 0;
+}
+
+static struct security_operations lowmem_security_ops = {
+ /* Use the capability functions for some of the hooks */
+ .ptrace_may_access = cap_ptrace_may_access,
+ .ptrace_traceme = cap_ptrace_traceme,
+ .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;
+
+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");
+ return -EINVAL;
+ }
+
+ /* 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;
+
+ r = sysfs_create_group(kernel_kobj,
+ &lowmem_attr_group);
+ if (unlikely(r))
+ return r;
+
+ printk(KERN_INFO MY_NAME ": Module initialized.\n");
+
+ return 0;
+}
+
+module_init(lowmem_init);
+
+MODULE_DESCRIPTION("Low watermark LSM module");
+MODULE_LICENSE("GPL");