]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
Merge branch 'master' of /home/tmlind/src/kernel/linux-2.6/
authorTony Lindgren <tony@atomide.com>
Thu, 1 Feb 2007 17:40:19 +0000 (09:40 -0800)
committerTony Lindgren <tony@atomide.com>
Thu, 1 Feb 2007 17:40:19 +0000 (09:40 -0800)
371 files changed:
Documentation/arm/OMAP/README [new file with mode: 0644]
Documentation/arm/OMAP/gpio [new file with mode: 0644]
Makefile
arch/arm/Kconfig
arch/arm/Makefile
arch/arm/boot/.gitignore [new file with mode: 0644]
arch/arm/boot/compressed/.gitignore [new file with mode: 0644]
arch/arm/boot/compressed/Makefile
arch/arm/boot/compressed/head-omap.S [new file with mode: 0644]
arch/arm/configs/ams_delta_defconfig [new file with mode: 0644]
arch/arm/configs/n770_defconfig [new file with mode: 0644]
arch/arm/configs/n800_defconfig [new file with mode: 0644]
arch/arm/configs/omap_2430sdp_defconfig [new file with mode: 0644]
arch/arm/configs/omap_apollon_2420_defconfig [new file with mode: 0644]
arch/arm/configs/omap_generic_1510_defconfig [new file with mode: 0644]
arch/arm/configs/omap_generic_1610_defconfig [new file with mode: 0644]
arch/arm/configs/omap_generic_1710_defconfig [new file with mode: 0644]
arch/arm/configs/omap_generic_2420_defconfig [new file with mode: 0644]
arch/arm/configs/omap_h2_1610_defconfig
arch/arm/configs/omap_h3_1710_defconfig [new file with mode: 0644]
arch/arm/configs/omap_h4_2420_defconfig [new file with mode: 0644]
arch/arm/configs/omap_innovator_1510_defconfig [new file with mode: 0644]
arch/arm/configs/omap_innovator_1610_defconfig [new file with mode: 0644]
arch/arm/configs/omap_osk_5912_defconfig [new file with mode: 0644]
arch/arm/configs/omap_perseus2_730_defconfig [new file with mode: 0644]
arch/arm/configs/palmte_defconfig [new file with mode: 0644]
arch/arm/configs/palmtt_defconfig [new file with mode: 0644]
arch/arm/configs/palmz71_defconfig [new file with mode: 0644]
arch/arm/configs/sx1_defconfig [new file with mode: 0644]
arch/arm/mach-omap1/Kconfig
arch/arm/mach-omap1/Makefile
arch/arm/mach-omap1/board-ams-delta.c
arch/arm/mach-omap1/board-fsample.c
arch/arm/mach-omap1/board-h2.c
arch/arm/mach-omap1/board-h3.c
arch/arm/mach-omap1/board-innovator.c
arch/arm/mach-omap1/board-nokia770.c
arch/arm/mach-omap1/board-osk.c
arch/arm/mach-omap1/board-palmte.c
arch/arm/mach-omap1/board-palmtt.c [new file with mode: 0644]
arch/arm/mach-omap1/board-palmz71.c [new file with mode: 0644]
arch/arm/mach-omap1/board-perseus2.c
arch/arm/mach-omap1/board-sx1.c [new file with mode: 0644]
arch/arm/mach-omap1/board-voiceblue.c
arch/arm/mach-omap1/clock.c
arch/arm/mach-omap1/clock.h
arch/arm/mach-omap1/devices.c
arch/arm/mach-omap1/irq.c
arch/arm/mach-omap1/mailbox.c [new file with mode: 0644]
arch/arm/mach-omap1/mux.c
arch/arm/mach-omap1/pm.c
arch/arm/mach-omap1/serial.c
arch/arm/mach-omap1/time.c
arch/arm/mach-omap2/Kconfig
arch/arm/mach-omap2/Makefile
arch/arm/mach-omap2/board-2430sdp.c [new file with mode: 0644]
arch/arm/mach-omap2/board-apollon.c
arch/arm/mach-omap2/board-h4.c
arch/arm/mach-omap2/board-n800-audio.c [new file with mode: 0644]
arch/arm/mach-omap2/board-n800-bt.c [new file with mode: 0644]
arch/arm/mach-omap2/board-n800-dsp.c [new file with mode: 0644]
arch/arm/mach-omap2/board-n800-flash.c [new file with mode: 0644]
arch/arm/mach-omap2/board-n800-mmc.c [new file with mode: 0644]
arch/arm/mach-omap2/board-n800-pm.c [new file with mode: 0644]
arch/arm/mach-omap2/board-n800-usb.c [new file with mode: 0644]
arch/arm/mach-omap2/board-n800.c [new file with mode: 0644]
arch/arm/mach-omap2/clock.c
arch/arm/mach-omap2/clock.h
arch/arm/mach-omap2/devices.c
arch/arm/mach-omap2/gpmc.c
arch/arm/mach-omap2/id.c
arch/arm/mach-omap2/io.c
arch/arm/mach-omap2/irq.c
arch/arm/mach-omap2/mailbox.c [new file with mode: 0644]
arch/arm/mach-omap2/memory.c
arch/arm/mach-omap2/mux.c
arch/arm/mach-omap2/pm-domain.c [deleted file]
arch/arm/mach-omap2/pm.c
arch/arm/mach-omap2/serial.c
arch/arm/mach-omap2/sleep.S
arch/arm/mach-omap2/timer-gp.c
arch/arm/mach-omap2/usb-tusb6010.c [new file with mode: 0644]
arch/arm/oprofile/Makefile
arch/arm/oprofile/common.c
arch/arm/oprofile/op_arm_model.h
arch/arm/oprofile/op_model_v6.c [new file with mode: 0644]
arch/arm/plat-omap/Kconfig
arch/arm/plat-omap/Makefile
arch/arm/plat-omap/bootreason.c [new file with mode: 0644]
arch/arm/plat-omap/clock.c
arch/arm/plat-omap/common.c
arch/arm/plat-omap/component-version.c [new file with mode: 0644]
arch/arm/plat-omap/debug-devices.c [new file with mode: 0644]
arch/arm/plat-omap/debug-leds.c [new file with mode: 0644]
arch/arm/plat-omap/devices.c
arch/arm/plat-omap/dma.c
arch/arm/plat-omap/dmtimer.c
arch/arm/plat-omap/dsp/Kconfig [new file with mode: 0644]
arch/arm/plat-omap/dsp/Makefile [new file with mode: 0644]
arch/arm/plat-omap/dsp/dsp.h [new file with mode: 0644]
arch/arm/plat-omap/dsp/dsp_common.c [new file with mode: 0644]
arch/arm/plat-omap/dsp/dsp_common.h [new file with mode: 0644]
arch/arm/plat-omap/dsp/dsp_core.c [new file with mode: 0644]
arch/arm/plat-omap/dsp/dsp_ctl.c [new file with mode: 0644]
arch/arm/plat-omap/dsp/dsp_ctl_core.c [new file with mode: 0644]
arch/arm/plat-omap/dsp/dsp_mbcmd.h [new file with mode: 0644]
arch/arm/plat-omap/dsp/dsp_mem.c [new file with mode: 0644]
arch/arm/plat-omap/dsp/error.c [new file with mode: 0644]
arch/arm/plat-omap/dsp/fifo.h [new file with mode: 0644]
arch/arm/plat-omap/dsp/hardware_dsp.h [new file with mode: 0644]
arch/arm/plat-omap/dsp/ioctl.h [new file with mode: 0644]
arch/arm/plat-omap/dsp/ipbuf.c [new file with mode: 0644]
arch/arm/plat-omap/dsp/ipbuf.h [new file with mode: 0644]
arch/arm/plat-omap/dsp/mblog.c [new file with mode: 0644]
arch/arm/plat-omap/dsp/omap1_dsp.h [new file with mode: 0644]
arch/arm/plat-omap/dsp/omap2_dsp.h [new file with mode: 0644]
arch/arm/plat-omap/dsp/proclist.h [new file with mode: 0644]
arch/arm/plat-omap/dsp/task.c [new file with mode: 0644]
arch/arm/plat-omap/dsp/taskwatch.c [new file with mode: 0644]
arch/arm/plat-omap/dsp/uaccess_dsp.S [new file with mode: 0644]
arch/arm/plat-omap/dsp/uaccess_dsp.h [new file with mode: 0644]
arch/arm/plat-omap/fb.c
arch/arm/plat-omap/gpio-switch.c [new file with mode: 0644]
arch/arm/plat-omap/gpio.c
arch/arm/plat-omap/mailbox.c [new file with mode: 0644]
arch/arm/plat-omap/mailbox.h [new file with mode: 0644]
arch/arm/plat-omap/mcbsp.c
arch/arm/plat-omap/mux.c
arch/arm/plat-omap/sram.c
arch/arm/plat-omap/sti/Makefile [new file with mode: 0644]
arch/arm/plat-omap/sti/sti-console.c [new file with mode: 0644]
arch/arm/plat-omap/sti/sti-fifo.c [new file with mode: 0644]
arch/arm/plat-omap/sti/sti-netlink.c [new file with mode: 0644]
arch/arm/plat-omap/sti/sti.c [new file with mode: 0644]
arch/arm/plat-omap/timer32k.c
arch/arm/plat-omap/usb.c
drivers/Kconfig
drivers/Makefile
drivers/bluetooth/Kconfig
drivers/bluetooth/Makefile
drivers/bluetooth/brf6150.c [new file with mode: 0644]
drivers/bluetooth/brf6150.h [new file with mode: 0644]
drivers/cbus/Kconfig [new file with mode: 0644]
drivers/cbus/Makefile [new file with mode: 0644]
drivers/cbus/cbus.c [new file with mode: 0644]
drivers/cbus/cbus.h [new file with mode: 0644]
drivers/cbus/retu-pwrbutton.c [new file with mode: 0644]
drivers/cbus/retu-rtc.c [new file with mode: 0644]
drivers/cbus/retu-user.c [new file with mode: 0644]
drivers/cbus/retu-wdt.c [new file with mode: 0644]
drivers/cbus/retu.c [new file with mode: 0644]
drivers/cbus/retu.h [new file with mode: 0644]
drivers/cbus/tahvo-usb.c [new file with mode: 0644]
drivers/cbus/tahvo-user.c [new file with mode: 0644]
drivers/cbus/tahvo.c [new file with mode: 0644]
drivers/cbus/tahvo.h [new file with mode: 0644]
drivers/cbus/user_retu_tahvo.h [new file with mode: 0644]
drivers/char/Kconfig
drivers/char/Makefile
drivers/char/hw_random/omap-rng.c
drivers/char/omap-rng.c [new file with mode: 0644]
drivers/char/omap-rtc.c [new file with mode: 0644]
drivers/char/omap-rtc.h [new file with mode: 0644]
drivers/char/watchdog/Makefile
drivers/hwmon/hwmon.c
drivers/i2c/Kconfig
drivers/i2c/busses/Makefile
drivers/i2c/busses/i2c-omap.c
drivers/i2c/chips/Kconfig
drivers/i2c/chips/Makefile
drivers/i2c/chips/gpio_expander_omap.c [new file with mode: 0644]
drivers/i2c/chips/isp1301_omap.c
drivers/i2c/chips/menelaus.c [new file with mode: 0644]
drivers/i2c/chips/tlv320aic23.c [new file with mode: 0644]
drivers/i2c/chips/twl4030_core.c [new file with mode: 0644]
drivers/input/keyboard/Kconfig
drivers/input/keyboard/Makefile
drivers/input/keyboard/innovator_ps2.c [new file with mode: 0644]
drivers/input/keyboard/omap-keypad.c
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/Makefile
drivers/input/touchscreen/ads7846.c
drivers/input/touchscreen/omap/Makefile [new file with mode: 0644]
drivers/input/touchscreen/omap/omap_ts.c [new file with mode: 0644]
drivers/input/touchscreen/omap/omap_ts.h [new file with mode: 0644]
drivers/input/touchscreen/omap/ts_hx.c [new file with mode: 0644]
drivers/input/touchscreen/tsc2102_ts.c [new file with mode: 0644]
drivers/leds/Kconfig
drivers/leds/Makefile
drivers/leds/leds-omap-pwm.c [new file with mode: 0644]
drivers/leds/leds-omap.c [new file with mode: 0644]
drivers/media/video/Kconfig
drivers/media/video/Makefile
drivers/media/video/omap/Kconfig [new file with mode: 0644]
drivers/media/video/omap/Makefile [new file with mode: 0644]
drivers/media/video/omap/camera_core.c [new file with mode: 0644]
drivers/media/video/omap/camera_core.h [new file with mode: 0644]
drivers/media/video/omap/camera_hw_if.h [new file with mode: 0644]
drivers/media/video/omap/h3_sensor_power.c [new file with mode: 0644]
drivers/media/video/omap/h3sensorpower.h [new file with mode: 0644]
drivers/media/video/omap/h4_sensor_power.c [new file with mode: 0644]
drivers/media/video/omap/h4sensorpower.h [new file with mode: 0644]
drivers/media/video/omap/omap16xxcam.c [new file with mode: 0644]
drivers/media/video/omap/omap16xxcam.h [new file with mode: 0644]
drivers/media/video/omap/ov9640.h [new file with mode: 0644]
drivers/media/video/omap/sensor_if.h [new file with mode: 0644]
drivers/media/video/omap/sensor_ov9640.c [new file with mode: 0644]
drivers/mmc/omap.c
drivers/mtd/maps/omap_nor.c
drivers/mtd/nand/Kconfig
drivers/mtd/nand/Makefile
drivers/mtd/nand/omap-hw.c [new file with mode: 0644]
drivers/mtd/nand/omap-nand-flash.c [new file with mode: 0644]
drivers/net/irda/Kconfig
drivers/net/irda/Makefile
drivers/net/irda/omap-ir.c [new file with mode: 0644]
drivers/net/smc91x.c
drivers/net/smc91x.h
drivers/rtc/rtc-omap.c
drivers/serial/8250.c
drivers/spi/Kconfig
drivers/spi/Makefile
drivers/spi/omap2_mcspi.c [new file with mode: 0644]
drivers/spi/omap_uwire.c [new file with mode: 0644]
drivers/spi/tsc2102.c [new file with mode: 0644]
drivers/ssi/Kconfig [new file with mode: 0644]
drivers/ssi/Makefile [new file with mode: 0644]
drivers/ssi/omap-tsc2101.c [new file with mode: 0644]
drivers/ssi/omap-tsc2101.h [new file with mode: 0644]
drivers/ssi/omap-uwire.c [new file with mode: 0644]
drivers/ssi/omap-uwire.h [new file with mode: 0644]
drivers/usb/Kconfig
drivers/usb/gadget/Kconfig
drivers/usb/gadget/omap_udc.c
drivers/usb/host/ohci-omap.c
drivers/usb/musb/Kconfig [new file with mode: 0644]
drivers/usb/musb/Makefile [new file with mode: 0644]
drivers/usb/musb/cppi_dma.c [new file with mode: 0644]
drivers/usb/musb/cppi_dma.h [new file with mode: 0644]
drivers/usb/musb/davinci.c [new file with mode: 0644]
drivers/usb/musb/davinci.h [new file with mode: 0644]
drivers/usb/musb/debug.h [new file with mode: 0644]
drivers/usb/musb/dma.h [new file with mode: 0644]
drivers/usb/musb/g_ep0.c [new file with mode: 0644]
drivers/usb/musb/musb_gadget.c [new file with mode: 0644]
drivers/usb/musb/musb_gadget.h [new file with mode: 0644]
drivers/usb/musb/musb_host.c [new file with mode: 0644]
drivers/usb/musb/musb_host.h [new file with mode: 0644]
drivers/usb/musb/musb_procfs.c [new file with mode: 0644]
drivers/usb/musb/musbdefs.h [new file with mode: 0644]
drivers/usb/musb/musbhdrc.h [new file with mode: 0644]
drivers/usb/musb/musbhsdma.c [new file with mode: 0644]
drivers/usb/musb/omap2430.c [new file with mode: 0644]
drivers/usb/musb/omap2430.h [new file with mode: 0644]
drivers/usb/musb/plat_arc.h [new file with mode: 0644]
drivers/usb/musb/plat_uds.c [new file with mode: 0644]
drivers/usb/musb/tusb6010.c [new file with mode: 0644]
drivers/usb/musb/tusb6010.h [new file with mode: 0644]
drivers/usb/musb/tusb6010_omap.c [new file with mode: 0644]
drivers/usb/musb/virthub.c [new file with mode: 0644]
drivers/video/Kconfig
drivers/video/Makefile
drivers/video/backlight/Kconfig
drivers/video/backlight/Makefile
drivers/video/backlight/omap_bl.c [new file with mode: 0644]
drivers/video/omap/Kconfig [new file with mode: 0644]
drivers/video/omap/Makefile [new file with mode: 0644]
drivers/video/omap/dispc.c [new file with mode: 0644]
drivers/video/omap/dispc.h [new file with mode: 0644]
drivers/video/omap/hwa742.c [new file with mode: 0644]
drivers/video/omap/lcd_ams_delta.c [new file with mode: 0644]
drivers/video/omap/lcd_apollon.c [new file with mode: 0644]
drivers/video/omap/lcd_h2.c [new file with mode: 0644]
drivers/video/omap/lcd_h3.c [new file with mode: 0644]
drivers/video/omap/lcd_h4.c [new file with mode: 0644]
drivers/video/omap/lcd_inn1510.c [new file with mode: 0644]
drivers/video/omap/lcd_inn1610.c [new file with mode: 0644]
drivers/video/omap/lcd_mipid.c [new file with mode: 0644]
drivers/video/omap/lcd_osk.c [new file with mode: 0644]
drivers/video/omap/lcd_p2.c [new file with mode: 0644]
drivers/video/omap/lcd_palmte.c [new file with mode: 0644]
drivers/video/omap/lcd_palmtt.c [new file with mode: 0644]
drivers/video/omap/lcd_palmz71.c [new file with mode: 0644]
drivers/video/omap/lcd_sx1.c [new file with mode: 0644]
drivers/video/omap/lcdc.c [new file with mode: 0644]
drivers/video/omap/lcdc.h [new file with mode: 0644]
drivers/video/omap/omapfb_main.c [new file with mode: 0644]
drivers/video/omap/rfbi.c [new file with mode: 0644]
drivers/video/omap/sossi.c [new file with mode: 0644]
include/asm-arm/.gitignore [new file with mode: 0644]
include/asm-arm/arch-omap/aic23.h
include/asm-arm/arch-omap/blizzard.h [new file with mode: 0644]
include/asm-arm/arch-omap/board-2430sdp.h [new file with mode: 0644]
include/asm-arm/arch-omap/board-apollon.h
include/asm-arm/arch-omap/board-h4.h
include/asm-arm/arch-omap/board-palmte.h [new file with mode: 0644]
include/asm-arm/arch-omap/board-palmtt.h [new file with mode: 0644]
include/asm-arm/arch-omap/board-palmz71.h [new file with mode: 0644]
include/asm-arm/arch-omap/board-sx1.h [new file with mode: 0644]
include/asm-arm/arch-omap/board.h
include/asm-arm/arch-omap/dsp.h [deleted file]
include/asm-arm/arch-omap/dsp_common.h
include/asm-arm/arch-omap/eac.h [new file with mode: 0644]
include/asm-arm/arch-omap/gpio-switch.h [new file with mode: 0644]
include/asm-arm/arch-omap/gpmc.h
include/asm-arm/arch-omap/hardware.h
include/asm-arm/arch-omap/io.h
include/asm-arm/arch-omap/irda.h
include/asm-arm/arch-omap/irqs.h
include/asm-arm/arch-omap/lcd_lph8923.h [deleted file]
include/asm-arm/arch-omap/lcd_mipid.h [new file with mode: 0644]
include/asm-arm/arch-omap/led.h [new file with mode: 0644]
include/asm-arm/arch-omap/mailbox.h [new file with mode: 0644]
include/asm-arm/arch-omap/mcspi.h
include/asm-arm/arch-omap/memory.h
include/asm-arm/arch-omap/menelaus.h
include/asm-arm/arch-omap/mmc.h [new file with mode: 0644]
include/asm-arm/arch-omap/mux.h
include/asm-arm/arch-omap/omap-alsa.h
include/asm-arm/arch-omap/omap16xx.h
include/asm-arm/arch-omap/omap24xx.h
include/asm-arm/arch-omap/omapfb.h
include/asm-arm/arch-omap/onenand.h [new file with mode: 0644]
include/asm-arm/arch-omap/pm.h
include/asm-arm/arch-omap/sram.h
include/asm-arm/arch-omap/sti.h [new file with mode: 0644]
include/asm-arm/arch-omap/twl4030.h [new file with mode: 0644]
include/asm-arm/arch-omap/usb.h
include/asm-arm/hardware/tsc2101.h [new file with mode: 0644]
include/asm-arm/mach/flash.h
include/asm-arm/setup.h
include/linux/connector.h
include/linux/fb.h
include/linux/i2c-id.h
include/linux/input.h
include/linux/netfilter_ipv4/ipt_IDLETIMER.h [new file with mode: 0644]
include/linux/spi/ads7846.h
include/linux/spi/tsc2102.h [new file with mode: 0644]
include/linux/spi/tsc2301.h [new file with mode: 0644]
include/linux/usb/musb.h [new file with mode: 0644]
kernel/printk.c
net/ipv4/netfilter/Kconfig
net/ipv4/netfilter/Makefile
net/ipv4/netfilter/ipt_IDLETIMER.c [new file with mode: 0644]
sound/arm/Kconfig
sound/arm/Makefile
sound/arm/omap/Makefile [new file with mode: 0644]
sound/arm/omap/omap-alsa-aic23-mixer.c [new file with mode: 0644]
sound/arm/omap/omap-alsa-aic23.c [new file with mode: 0644]
sound/arm/omap/omap-alsa-aic23.h [new file with mode: 0644]
sound/arm/omap/omap-alsa-dma.c [new file with mode: 0644]
sound/arm/omap/omap-alsa-dma.h [new file with mode: 0644]
sound/arm/omap/omap-alsa-sx1-mixer.c [new file with mode: 0644]
sound/arm/omap/omap-alsa-sx1-mixer.h [new file with mode: 0644]
sound/arm/omap/omap-alsa-sx1.c [new file with mode: 0644]
sound/arm/omap/omap-alsa-sx1.h [new file with mode: 0644]
sound/arm/omap/omap-alsa-tsc2101-mixer.c [new file with mode: 0644]
sound/arm/omap/omap-alsa-tsc2101-mixer.h [new file with mode: 0644]
sound/arm/omap/omap-alsa-tsc2101.c [new file with mode: 0644]
sound/arm/omap/omap-alsa-tsc2101.h [new file with mode: 0644]
sound/arm/omap/omap-alsa-tsc2102-mixer.c [new file with mode: 0644]
sound/arm/omap/omap-alsa-tsc2102.c [new file with mode: 0644]
sound/arm/omap/omap-alsa-tsc2102.h [new file with mode: 0644]
sound/arm/omap/omap-alsa.c [new file with mode: 0644]
sound/oss/Makefile
sound/oss/omap-audio-aic23.c [new file with mode: 0644]
sound/oss/omap-audio-dma-intfc.c [new file with mode: 0644]
sound/oss/omap-audio-dma-intfc.h [new file with mode: 0644]
sound/oss/omap-audio-tsc2101.c [new file with mode: 0644]
sound/oss/omap-audio.c [new file with mode: 0644]
sound/oss/omap-audio.h [new file with mode: 0644]

diff --git a/Documentation/arm/OMAP/README b/Documentation/arm/OMAP/README
new file mode 100644 (file)
index 0000000..f8ffb68
--- /dev/null
@@ -0,0 +1,415 @@
+
+                  README for ARM based OMAP processor from TI
+                  ===========================================
+
+This is the README for Linux 2.6 on ARM based TI OMAP processors.
+
+In the first section it gives some general hints how to start with OMAP Linux.
+When successfully build a OMAP Linux kernel with help of first section and no 
+bootloader is already on the board, section 2 gives some tips how to use
+commercial JTAG tools. 
+
+In March 2004 the Linux Kernel 2.6 for ARM based TI OMAP processors was cleaned.
+The goal was to send clean patches to RMK's official ARM tree and to make it 
+easier to add new OMAP processors or boards to the kernel tree. To keep the
+kernel tree clean now, this document describes also some steps how 
+to add code for a new OMAP processor or OMAP based board to the OMAP Linux 2.6 
+kernel tree. This is what the third section of this document is about.
+
+Section 4 of this README reports some rules to be followed to write 
+clean code to make it ready for easy inclusion into public OMAP Linux kernel.
+
+For more information also see TI's 'Linux Community for Texas Instruments OMAP
+Processors' web page:
+
+http://linux.omap.com
+
+There, various downloads and resources can be found (e.g. documentation how
+to build the kernel, how to use u-boot with OMAP Linux, pre-built tool chain
+etc.).
+
+The mailing list for OMAP Linux is hosted there, too:
+
+http://linux.omap.com/mailman/listinfo
+
+
+1. General hints how to start with OMAP Linux
+--------------------------------------------------------------
+
+The minimal setup is a arm-linux-gcc cross compiler, make, and some editor.
+You will also most likely need a JTAG to flash the bootloader for the first
+time.
+
+The first step is to get a bootloader for your board, u-boot is the
+recommended one:
+
+http://www.denx.de/en/Software/GIT
+
+Then you need to compile it with the same cross compiler as you would use
+for the Linux kernel. Then you need to flash it to the board either via the
+serial port, or by using a JTAG.
+
+Once you have the bootloader running, you can compile the kernel.
+
+You can get the OMAP sources either from the OMAP GIT tree, or by
+applying patches. The OMAP GIT tree has the most up to date sources
+and is the recommended one.
+
+- Using GIT and cloning OMAP GIT tree please follow the README at:
+
+http://www.muru.com/linux/omap/README_OMAP_GIT
+
+Hint: If you are sitting behind a firewall and have to use a proxy for 
+internet access, you can access GIT by http by setting the
+http_proxy envirionment variable:
+
+http_proxy=http://proxy_username:proxy_password@proxy_name:proxy_port/
+
+If you use bash shell, then this might look like:
+
+export http_proxy=http://foo:123@abc.host.com:8080/
+
+with:
+
+foo: Your user name for the proxy
+123: Your password for the proxy
+abc.host.com: The name of your proxy you use for internet access
+8080: The port used on to access the proxy
+
+
+- Using Patches:
+
+If you don't want to use GIT, then you can do the same thing with patch.
+
+Download the latest OMAP Linux patch from:
+
+http://www.muru.com/linux/omap/
+
+Get a matching Linux kernel from:
+
+ftp://ftp.kernel.org/pub/linux/kernel/v2.6/
+
+For example, if you download Linux-2.6.4-omap1 from muru.com, then you need
+linux-2.6.4 kernel from kernel.org:
+
+$ wget ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.4.tar.bz2
+$ tar xjf linux-2.6.4.tar.bz2
+$ cd linux-2.6.4
+$ cat ../Linux-2.6.4-omap1 | patch -p1
+
+Note: If OMAP patch from muru.com is against a kernel release candidate, 
+marked by -rcX, then kernel can be found on kernel.org under v2.6/testing/
+
+Now, if you have a local kernel tree, either by GIT or by patch, you
+should look into arch/arm/configs/ to see which of the various omap_xxx
+configurations there you want to use. For example, if you have a OMAP1510
+based Innovator board, you select omap_innovator_1510_defconfig by 
+
+$ make omap_innovator_1510_defconfig
+
+at top level directory (linux-2.6.4 in the example above).
+
+Then you can compile the kernel with
+
+$ make vmlinux
+
+Or make Image or make zImage or make uImage.
+
+Once you have the kernel compiled, you can upload it to the board via serial
+port or JTAG (see below).
+
+Then you need a root file system either as initrd or on the flash.
+
+Once you have the system booting to Linux, you can use pretty much any Linux
+applications cross compiled for ARM.
+
+
+2. JTAG usage
+--------------------------------------------------------------
+
+If the flash of your board is really 'empty' and no bootloader is on the board
+(e.g. u-boot) then you need a JTAG connection. With JTAG you can write
+a bootloader to board's flash or download OMAP Linux kernel. For OMAP
+commercial JTAG tools are available, so you have to pay for it.
+
+Examples are TI's Code Composer Studio (CCS) or Lauterbach's TRACE32 JTAG.
+
+- Linux kernel download with CCS
+
+You can use CCS to directly load an ELF file to your board. For example, use  
+arch/arm/boot/compressed/vmlinux. zImage isn't suited because it is not an ELF
+file. CCS looks for .out files, so copy arch/arm/boot/compressed/vmlinux 
+to vmlinux.out and load it using CCS. Or use the filter *.* to select
+vmlinux directly. Remember to run arm-linux-strip on ELF file first as CCS 
+get stroppy about unstripped ELF files.
+
+If you want vmlinux to be linked to run at a specific address, you can use 
+the CONFIG_ZBOOT options in the kernel build. But first try without
+CONFIG_ZBOOT as the compressed image should be able to run from address
+zero (if your CCS .gel files map address zero.)
+
+Otherwise, use something like this:
+
+CONFIG_ZBOOT_ROM=y
+CONFIG_ZBOOT_ROM_TEXT=10408000
+CONFIG_ZBOOT_ROM_BSS=10800000
+
+Also note that CCS is pretty useless for debugging Linux as it doesn't
+properly handle virtual memory. In other words, once the MMU is
+turned on and Linux is using virtual memory, CCS can no longer
+properly disassemble, set breakpoints or read memory.
+
+
+- Linux kernel download with Lauterbach TRACE32
+
+To be done.
+
+
+3. How to add new processor or board to OMAP Linux kernel tree
+--------------------------------------------------------------
+
+It is assumed that the OMAP processor to be added is based on an already 
+supported ARM core (e.g. ARM925 or ARM926). How to add support for new ARM 
+processor core that is not supported by ARM Linux is not scope of this document.
+
+1. If a new OMAP processor should be added, identify the ARM core of this 
+processor. E.g. at time of writing this document in March 2004 OMAP730 (ARM926 
+core), OMAP1510 (ARM925 core) and OMAP1610 (ARM926 core) are supported.
+
+For a new board or device, identify the OMAP processor on the board. E.g. at 
+time of writing this document in March 2004 four boards are supported: 
+Innovator1510 (OMAP1510 processor), Innovator1610 (OMAP1610 processor), 
+Perseus2 (OMAP730 processor) and H2 (OMAP1610 processor).
+
+Please refer http://www.muru.com/linux/omap/ to get latest information on the
+list of boards supported.
+
+/* Discussion needed: How to handle the tons of compatible processors? 
+E.g. what to do if OMAP16xx is mainly identical with OMAP16yy? */
+
+2. Start with arch/arm/mach-omap[1/2]/Kconfig and add a new processor or board
+option.
+
+To add a new processor add a new config option to the "OMAP Core Type" choice. 
+See examples for the syntax. The config option has to be called "ARCH_OMAPxxxx" 
+where xxxx is the number of OMAP processor. Don't forget to select a existing
+clock frequency or to add a new one in "OMAP Feature Selections" section for
+your new processor. 
+
+To add a new board or device, add a new config option to the "OMAP Board Type" 
+choice. See examples for the syntax. The config option for boards has to be 
+called "MACH_OMAP_yyyy" where yyyy is the board name. Don't forget to add a 
+short help.
+
+Note: Kernel 2.6 Kconfig system will automatically expand the configuration 
+names with a leading "CONFIG_". So "ARCH_OMAPxxxx" will be expanded to 
+"CONFIG_ARCH_OMAPxxxx" and "MACH_OMAP_yyy" will expand to 
+"CONFIG_MACH_OMAP_yyyy". In code this can then be used by macros like 
+"#ifdef CONFIG_ARCH_OMAPxxxx" and "#ifdef CONFIG_MACH_OMAP_yyyy".
+
+Note: How to handle boards which are compatible or extensions of other boards? 
+See MACH_OMAP_H2 for example. The H2 depends on MACH_OMAP_INNOVATOR and expands 
+it. This is done by an additional select MACH_OMAP_INNOVATOR in MACH_OMAP_H2
+configuration option. With this the whole MACH_OMAP_INNOVATOR configuration is
+selected and an additional symbol CONFIG_MACH_OMAP_H2 is available to
+distinguish between INNOVATOR and H2 where necessary. 
+
+3a. Only for new processors: Add the ARCH_OMAPxxxx to the correct ARM core in 
+arch/arm/mm/Kconfig. E.g. ARCH_OMAP730 in CPU_ARM926T configuration.
+
+3b. Only for new boards: Register the board within ARM Linux machine 
+registration system from RMK. For the CONFIG_ section use the same name like 
+in arch/arm/mach-omap[1/2]/Kconfig. E.g. MACH_OMAP_yyyy. For MACH_TYPE_ section use
+OMAP_yyyy where yyyy is the board name like above.
+
+Note: The elements of RMKs machine registration are used in 
+arch/arm/tools/mach-types. While kernel compilation
+include/asm-arm/mach-types.h is generated automagically from this file. The
+content of mach-types.h then is used for machine identification by kernel
+bootcode and can be used for board identification.
+
+Note: The ARM Linux machine registration system from RMK can be found under:
+
+www.arm.linux.org.uk/developer/machines/
+
+Note: Only OMAP based boards should be registered to RMKs registration
+system. Not processors.
+
+4. Add a processor or board specific header file in include/asm-arm/arch-omap/. 
+Use board-yyyy.h with yyyy board name or omapxxxx.h with xxxx processor number.
+
+5. Add a processor or board specific section into include/asm-arm/arch-omap/
+hardware.h. Use examples for syntax and use CONFIG_ names as defined in 
+arch/arm/mach-omap[1/2]/Kconfig.
+
+6. Add processor or board specific macros to board-yyyy.h or omapxxxx.h. The
+macros to these specific files have to be named OMAPxxxx_ with xxxx processor
+number to make them unique.
+
+7a. Only for new boards: Add a file board-yyyy.c with yyyy board name to 
+arch/arm/mach-omap[1/2]/. Put board specific initialization code and resource
+description into this file. The first element of MACHINE_START must be equal to 
+MACH_TYPE_ section of machine registration (see arch/arm/tools/mach-types after 
+machine registration at RMKs registration system).
+
+Put only code into this file that is board specific and not common. See other 
+board files for examples.
+
+7b. Only for new processors: Add processor specific IO description and
+iotable_init() to arch/arm/mach-omap[1/2]/io.c. See examples for the syntax.
+
+If you have introduced new clock definition in 2., add support for this new
+clock in include/asm-arm/arch-omap/clocks.h and arch/arm/mach-omap[1/2]/clocks.c.
+
+8. Only for new boards: Add "obj-$(CONFIG_MACH_OMAP_yyyy) += board-yyyy.o" with 
+yyyy board name to arch/arm/mach-omap[1/2]/Makefile. This is used to compile your new
+board specific initialization code from 7a.
+
+9. Check if other of the existing files have to be adjusted for the new 
+processor or board. Things to check:
+
+- Pin multiplexing
+- GPIO configuration
+- Power Management
+- Clocking
+- Interrupt controller and interrupt configuration
+- Additional board specific things (e.g. FPGAs)
+
+If other existing files or device drivers have to be changed, use the following 
+mechanism for processor specific things:
+
+#ifdef CONFIG_ARCH_OMAPxxxx
+       if (cpu_is_omapxxxx()) {
+               /* Do the OMAPxxxx processor specific magic */
+       }
+#endif
+
+Note: cpu_is_omapxxxx() macro is defined in include/asm-arm/arch-omap/hardware.h
+and uses OMAP_ID_REG for runtime processor identifcation.
+
+For board differentiation use board macro from include/asm-arm/mach-types.h:
+
+#ifdef CONFIG_MACH_OMAP_yyyy
+       if (machine_is_omap_yyyy()) {
+               /* Do the board specific magic */
+       }
+#endif
+
+Note: If technically possible and already implemented the OMAP Linux kernel
+has support for a "one binary fits all" machanism. That is, the goal is to be
+able to enable support for multiple OMAP processors and/or boards in Kconfig
+system. Then it is decided by bootparameters and at runtime on which processor 
+and/or board the kernel is actually running on. With this machanism it is 
+possible to use the same kernel binary on different OMAP processors or boards 
+without recompiling. This is achived by the cpu_is_omapxxxx() and
+machine_is_omap_yyyy() macros.
+
+On the other hand, for memory limited embedded systems it should be possible
+to compile the kernel with support for only one processor/board combination.
+For this a kernel binary is necessary which isn't bloated with code for all
+other (unused) processors and boards. This is achived by using the preprocessor
+CONFIG_ARCH_OMAPxxxx and CONFIG_MACH_OMAP_yyyy macros around the runtime
+cpu_is_omapxxxx() and machine_is_omap_yyyy() selection.
+
+At the moment, the price for this flexibility is a increased number of #ifdef's
+throughout the code.
+
+10. Configure the kernel by make menuconfig or make xconfig and select the new 
+processor or board.
+
+11. Compile the kernel by an appropriate cross compilation toolchain. Make this
+until the code compiles error and warning free. The kernel should also be 
+compiled with the various debug checking thingies enabled (e.g.
+CONFIG_DEBUG_SPINLOCK,  CONFIG_DEBUG_PAGEALLOC etc.).
+
+/* ToDo: Anything to say about toolchain? */
+
+12. Download the kernel image to the board and test it until it works ;-)
+
+It's not in the scope of this document how to do this (use a appropriate 
+bootloader or JTAG download).
+
+Note: The kernel initialization code expects some special values in the
+registers R0, R1 and R2 of the ARM processor. These registers have to be
+written by bootloader or debugger before starting the kernel. R0 has to be
+zero, R1 has to contain the machine number from machine registration in
+arch/arm/tools/mach-types. R2 points to the physical address of tagged list
+in system RAM. For more information see Documentation/arm/Booting.
+
+While testing a new processor or board configuration, it is recommended to 
+enable low level debugging. This uses low level output functions to print kernel
+messages on serial line before console is working. Enable it by 
+
+Kernel hacking -> Kernel debugging -> Kernel low-level debugging functions
+
+in kernel configuration system.
+
+13. Check that no other processors or boards are broken by the new code. A first
+test is to successful compile the other omap_xxx configurations from 
+arch/arm/configs/. Do this by e.g.
+
+cd linux
+make omap_innovator_1510_defconfig
+Compile the kernel
+
+Even better: Enable support for several processors and boards in Kconfig
+system and compile kernel successfully.
+
+14. Only for new boards: Add a new default board configuration to 
+arch/arm/configs. Use omap_yyyy_xxxx_defconfig with yyyy boardname and xxxx 
+processornumber as filename.
+
+15. If the new code works, compiles without warnings and seems to break no other
+configurations, post a patch to linux-omap-open-source@list.ti.com.
+
+With sending a patch to the community, it is reviewed, can be used and tested by
+other users. It then can be included into the public OMAP kernel tree. 
+
+16. Then adapt device drivers or write additional drivers for non-existing 
+processor peripherals or board devices. Improve and maintain the code for your 
+new processor or board.
+
+
+4. General guidelines to write clean and OMAP Linux compatible code
+-------------------------------------------------------------------
+
+- For register access use the __REG8/16/32() macros. At the moment, see first
+example in include/asm-arm/arch-omap/hardware.h.
+
+Allegedly __REG() makes at least some versions of GCC emit tighter code
+than the more direct wrappers. Presumably by making it easier to use certain 
+addressing modes. 
+
+Make sure that the registers names are clearly marked as being registers
+(and not addresses of registers). This has to be done by adding a '_REG'
+suffix. E.g.
+
+#define OMAP_ID_REG  (__REG32(0xfffed400))
+#define DPLL_CTL_REG (__REG16(0xfffecf00))
+
+__raw_read[bwl] and __raw_write[bwl] are deprecated. They will converted to
+__REG8/16/32() syntax, soon. Don't use anything else like own pointer
+definitions or in[bwl]/out[bwl] etc., too.
+
+- Make read-modify-write register access preemption save. Use spin_lock() and 
+spin_unlock() where necessary. If an IRQ handler can access the registers, 
+use spin_lock_irqsave(), too. 
+
+- Functions declared as __init shouldn't have any references after the kernel 
+initialization phase is complete. Usually they should be static as well.
+
+- Don't use return statements at end of void functions.
+
+- Use consistent indentation style. Don't use space indentations. Use tab 
+indentations.
+
+- In general use Linux formatting style. See Documentation/CodingStyle for more
+information. If you use GNU emacs, see also chapter 8 of that document how to
+add a linux-c-mode to emacs.
+
+
+------------------------------------------------------------------
+Last modified 15. March 2006
+The OMAP Linux Kernel Team
+Dirk Behme <dirk.behme@de.bosch.com>
diff --git a/Documentation/arm/OMAP/gpio b/Documentation/arm/OMAP/gpio
new file mode 100644 (file)
index 0000000..fd6363c
--- /dev/null
@@ -0,0 +1,270 @@
+
+                         OMAP GPIO API's HowTo
+                         =====================
+
+This document is a short summary how to use OMAP Linux GPIO API. It is
+mainly focussed on OMAP5912 OSK, but should fit with extensions (more
+or less GPIOs) to other OMAP processors as well.
+
+If anything is missing, is wrong, needs extension or update, please send
+update to Linux-omap-open-source@linux.omap.com.
+
+I. GPIO Modules/Banks
+---------------------
+
+OMAP5912 OSK has 64 GPIOs (general purpose IO pins). These are organized
+in four modules (banks) with 16 pins each. OMAP GPIO API doesn't distinguish
+between modules and numbers the pins from 0 - 63:
+
+A) GPIO MODULE/BANK 0 - PIN  0-15
+B) GPIO MODULE/BANK 1 - PIN 16-31
+C) GPIO MODULE/BANK 2 - PIN 32-47
+D) GPIO MODULE/BANK 3 - PIN 48-63
+
+See
+
+http://www-s.ti.com/sc/psheets/spru767a/spru767a.pdf
+
+for more details.
+
+II. GPIO API's
+--------------
+
+A) Include
+
+#include <asm/arch/gpio.h>
+
+B) omap_cfg_reg(xxxx);
+
+Description: Configure pin mux.
+
+Parameter: Pin to be configured for GPIO.
+
+Note: This function may only be necessary for some GPIO pins. Because OMAP
+      chip itself has less real hardware pins than necessary to use all
+      its functionality at the same time, some pins share different
+      functions (called pin multiplexing, short pin mux). E.g. one pin may
+      be used for serial interface *or* GPIO. Check if this is the case for
+      the GPIO you want to use and if you have to configure the pin mux.
+
+C) omap_request_gpio(int gpio)
+
+Description: Request GPIO to be used.
+
+Parameter: int gpio - GPIO PIN (Pin 0-63)
+
+Note: Using this function, you dont have to worry about banks/modules where
+      the gpio pin is.
+
+D) omap_set_gpio_direction(int gpio, int is_input)
+
+Description: This function is responsible for setting the gpio pin direction
+             (input or output).
+
+Parameter: int gpio - GPIO PIN (Pin 0-63)
+           int is_input - pin direction (0 = output, 1 = input)
+
+E) omap_set_gpio_dataout(int gpio, int enable)
+
+Description: This function is responsible for writing to a pin.
+
+Parameter: int gpio - GPIO PIN (Pin 0-63)
+           int enable - pin value (0 or 1)
+
+F) omap_get_gpio_datain(int gpio)
+
+Description: This function is responsible for reading pin values.
+
+Parameter: int gpio - GPIO PIN (Pin 0-63)
+
+G) omap_free_gpio(int gpio)
+
+Description: This function is responsible for freeing the pin used.
+
+Parameter: int gpio - GPIO PIN (Pin 0-63)
+
+H) OMAP_GPIO_IRQ(int gpio)
+
+Description: Returns the Interrupt number for the specified gpio pin.
+
+Parameter: int gpio - GPIO PIN (Pin 0-63)
+
+I) set_irq_type(unsigned int irq, unsigned int type)
+
+Description: This function is responsible for setting the type of interrupt
+             (RISING or FALLING).
+
+Parameter: unsigned int irq - The interrupt number for the gpio pin.
+           unsigned int type - (IRQT_RISING = rising, IRQT_FALLING= falling)
+
+
+III. Example
+------------
+
+1) Writing to gpio pin#3 a value 1 and reading the value of gpio pin#3.
+
+#include <asm/arch/gpio.h>
+
+int ret;                       /* Return value */
+
+omap_request_gpio(3);          /* Request for gpio pin */
+omap_set_gpio_direction(3,0);
+omap_set_set_dataout(3,1);     /* Writing a 1 to gpio pin # 3: */
+ret = omap_get_datain(3);      /* Reading the value of pin # 3 */
+printk("value of pin # 3 = %d\n",ret);
+omap_free_gpio(3);             /* Freeing gpio pin # 3 */
+
+2) Interrupt input by gpio pin#3
+
+#include <asm/arch/gpio.h>
+
+omap_request_gpio(3);         /* Request for gpio pin */
+omap_set_gpio_direction(3,0);
+set_irq_type(OMAP_GPIO_IRQ(3),IRQT_RISING); /* Setting up pin for interrupt */
+request_irq(OMAP_GPIO_IRQ(3), (void *)&my_int_handler, SA_SHIRQ,....);
+
+...                         /* Do stuff, handle interrupts in my_int_handler */
+
+free_irq(OMAP_GPIO_IRQ(3),&id); /*  Freeing interrupt and gpio pin */
+omap_free_gpio(3);
+
+------------------------------------------------------------------
+Last modified 14. August 2006
+The OMAP Linux Kernel Team
+Arnold <abo_gwapo@yahoo.com>
+Dirk Behme <dirk.behme@gmail.com>
+
+                         OMAP GPIO API's HowTo
+                         =====================
+
+This document is a short summary how to use OMAP Linux GPIO API. It is
+mainly focussed on OMAP5912 OSK, but should fit with extensions (more
+or less GPIOs) to other OMAP processors as well.
+
+If anything is missing, is wrong, needs extension or update, please send
+update to Linux-omap-open-source@linux.omap.com.
+
+I. GPIO Modules/Banks
+---------------------
+
+OMAP5912 OSK has 64 GPIOs (general purpose IO pins). These are organized
+in four modules (banks) with 16 pins each. OMAP GPIO API doesn't distinguish
+between modules and numbers the pins from 0 - 63:
+
+A) GPIO MODULE/BANK 0 - PIN  0-15
+B) GPIO MODULE/BANK 1 - PIN 16-31
+C) GPIO MODULE/BANK 2 - PIN 32-47
+D) GPIO MODULE/BANK 3 - PIN 48-63
+
+See
+
+http://www-s.ti.com/sc/psheets/spru767a/spru767a.pdf
+
+for more details.
+
+II. GPIO API's
+--------------
+
+A) Include
+
+#include <asm/arch/gpio.h>
+
+B) omap_cfg_reg(xxxx);
+
+Description: Configure pin mux.
+
+Parameter: Pin to be configured for GPIO.
+
+Note: This function may only be necessary for some GPIO pins. Because OMAP
+      chip itself has less real hardware pins than necessary to use all
+      its functionality at the same time, some pins share different
+      functions (called pin multiplexing, short pin mux). E.g. one pin may
+      be used for serial interface *or* GPIO. Check if this is the case for
+      the GPIO you want to use and if you have to configure the pin mux.
+
+C) omap_request_gpio(int gpio)
+
+Description: Request GPIO to be used.
+
+Parameter: int gpio - GPIO PIN (Pin 0-63)
+
+Note: Using this function, you dont have to worry about banks/modules where
+      the gpio pin is.
+
+D) omap_set_gpio_direction(int gpio, int is_input)
+
+Description: This function is responsible for setting the gpio pin direction
+             (input or output).
+
+Parameter: int gpio - GPIO PIN (Pin 0-63)
+           int is_input - pin direction (0 = output, 1 = input)
+
+E) omap_set_gpio_dataout(int gpio, int enable)
+
+Description: This function is responsible for writing to a pin.
+
+Parameter: int gpio - GPIO PIN (Pin 0-63)
+           int enable - pin value (0 or 1)
+
+F) omap_get_gpio_datain(int gpio)
+
+Description: This function is responsible for reading pin values.
+
+Parameter: int gpio - GPIO PIN (Pin 0-63)
+
+G) omap_free_gpio(int gpio)
+
+Description: This function is responsible for freeing the pin used.
+
+Parameter: int gpio - GPIO PIN (Pin 0-63)
+
+H) OMAP_GPIO_IRQ(int gpio)
+
+Description: Returns the Interrupt number for the specified gpio pin.
+
+Parameter: int gpio - GPIO PIN (Pin 0-63)
+
+I) set_irq_type(unsigned int irq, unsigned int type)
+
+Description: This function is responsible for setting the type of interrupt
+             (RISING or FALLING).
+
+Parameter: unsigned int irq - The interrupt number for the gpio pin.
+           unsigned int type - (IRQT_RISING = rising, IRQT_FALLING= falling)
+
+
+III. Example
+------------
+
+1) Writing to gpio pin#3 a value 1 and reading the value of gpio pin#3.
+
+#include <asm/arch/gpio.h>
+
+int ret;                       /* Return value */
+
+omap_request_gpio(3);          /* Request for gpio pin */
+omap_set_gpio_direction(3,0);
+omap_set_set_dataout(3,1);     /* Writing a 1 to gpio pin # 3: */
+ret = omap_get_datain(3);      /* Reading the value of pin # 3 */
+printk("value of pin # 3 = %d\n",ret);
+omap_free_gpio(3);             /* Freeing gpio pin # 3 */
+
+2) Interrupt input by gpio pin#3
+
+#include <asm/arch/gpio.h>
+
+omap_request_gpio(3);         /* Request for gpio pin */
+omap_set_gpio_direction(3,0);
+set_irq_type(OMAP_GPIO_IRQ(3),IRQT_RISING); /* Setting up pin for interrupt */
+request_irq(OMAP_GPIO_IRQ(3), (void *)&my_int_handler, SA_SHIRQ,....);
+
+...                         /* Do stuff, handle interrupts in my_int_handler */
+
+free_irq(OMAP_GPIO_IRQ(3),&id); /*  Freeing interrupt and gpio pin */
+omap_free_gpio(3);
+
+------------------------------------------------------------------
+Last modified 14. August 2006
+The OMAP Linux Kernel Team
+Arnold <abo_gwapo@yahoo.com>
+Dirk Behme <dirk.behme@gmail.com>
index 75adfb539977d42a35ee77913cbb102304b0f81f..772da4b45f387059b1ff64a89bd384a06d34f5c3 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -16,6 +16,9 @@ NAME = Homicidal Dwarf Hamster
 # o  print "Entering directory ...";
 MAKEFLAGS += -rR --no-print-directory
 
+# Add custom flags here to avoid conflict with updates
+EXTRAVERSION := $(EXTRAVERSION)-omap1
+
 # We are using a recursive build, so we need to do a little thinking
 # to get the ordering right.
 #
@@ -163,6 +166,8 @@ SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
                                  -e s/s390x/s390/ -e s/parisc64/parisc/ \
                                  -e s/ppc.*/powerpc/ -e s/mips.*/mips/ )
 
+SUBARCH := arm
+
 # Cross compiling and selecting different set of gcc/bin-utils
 # ---------------------------------------------------------------------------
 #
@@ -183,7 +188,7 @@ SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
 # Note: Some architectures assign CROSS_COMPILE in their arch/*/Makefile
 
 ARCH           ?= $(SUBARCH)
-CROSS_COMPILE  ?=
+CROSS_COMPILE  ?= arm-linux-
 
 # Architecture as present in compile.h
 UTS_MACHINE := $(ARCH)
index 6783c2e5512de6e75bed91d55a45ff0c14ee0cf5..b5e8832e7b34e4484e0173ab88b81412841146df 100644 (file)
@@ -328,6 +328,7 @@ config ARCH_LH7A40X
 
 config ARCH_OMAP
        bool "TI OMAP"
+       select GENERIC_TIME
        help
          Support for TI's OMAP platform (OMAP1 and OMAP2).
 
@@ -620,8 +621,7 @@ config LEDS
          system, but the driver will do nothing.
 
 config LEDS_TIMER
-       bool "Timer LED" if (!ARCH_CDB89712 && !ARCH_OMAP) || \
-                           MACH_OMAP_H2 || MACH_OMAP_PERSEUS2
+       bool "Timer LED" if !ARCH_CDB89712
        depends on LEDS
        default y if ARCH_EBSA110
        help
@@ -636,8 +636,7 @@ config LEDS_TIMER
          will overrule the CPU usage LED.
 
 config LEDS_CPU
-       bool "CPU usage LED" if (!ARCH_CDB89712 && !ARCH_EBSA110 && \
-                       !ARCH_OMAP) || MACH_OMAP_H2 || MACH_OMAP_PERSEUS2
+       bool "CPU usage LED" if (!ARCH_CDB89712 && !ARCH_EBSA110)
        depends on LEDS
        help
          If you say Y here, the red LED will be used to give a good real
@@ -962,6 +961,12 @@ source "drivers/mmc/Kconfig"
 
 source "drivers/rtc/Kconfig"
 
+source "drivers/ssi/Kconfig"
+
+if ARCH_OMAP
+source "drivers/cbus/Kconfig"
+endif
+
 endmenu
 
 source "fs/Kconfig"
index 000f1100b5538f9f69da886fc0054d2d16746864..ea39d8da957c2d6e45defda8fdcb7822f8677aec 100644 (file)
@@ -71,7 +71,7 @@ tune-$(CONFIG_CPU_SA110)      :=-mtune=strongarm110
 tune-$(CONFIG_CPU_SA1100)      :=-mtune=strongarm1100
 tune-$(CONFIG_CPU_XSCALE)      :=$(call cc-option,-mtune=xscale,-mtune=strongarm110) -Wa,-mcpu=xscale
 tune-$(CONFIG_CPU_XSC3)                :=$(call cc-option,-mtune=xscale,-mtune=strongarm110) -Wa,-mcpu=xscale
-tune-$(CONFIG_CPU_V6)          :=$(call cc-option,-mtune=arm1136j-s,-mtune=strongarm)
+tune-$(CONFIG_CPU_V6)          :=$(call cc-option,-mtune=arm1136j-s,-mtune=arm1136jfs)
 
 ifeq ($(CONFIG_AEABI),y)
 CFLAGS_ABI     :=-mabi=aapcs-linux -mno-thumb-interwork
diff --git a/arch/arm/boot/.gitignore b/arch/arm/boot/.gitignore
new file mode 100644 (file)
index 0000000..fc9b99c
--- /dev/null
@@ -0,0 +1,3 @@
+Image
+zImage
+uImage
diff --git a/arch/arm/boot/compressed/.gitignore b/arch/arm/boot/compressed/.gitignore
new file mode 100644 (file)
index 0000000..aefee20
--- /dev/null
@@ -0,0 +1 @@
+piggy.gz
index adddc71316852f5001314faf10678f5fc4e3ef8d..6bebde52d4066c410d211b9e271a6ba088076c8e 100644 (file)
@@ -50,6 +50,10 @@ ifeq ($(CONFIG_ARCH_AT91RM9200),y)
 OBJS           += head-at91rm9200.o
 endif
 
+ifeq ($(CONFIG_MACH_OMAP_PERSEUS2),y)
+OBJS           += head-omap.o
+endif
+
 ifeq ($(CONFIG_CPU_BIG_ENDIAN),y)
 ifeq ($(CONFIG_CPU_CP15),y)
 OBJS           += big-endian.o
diff --git a/arch/arm/boot/compressed/head-omap.S b/arch/arm/boot/compressed/head-omap.S
new file mode 100644 (file)
index 0000000..ba3ecca
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * linux/arch/arm/boot/compressed/head-omap.S
+ *
+ * OMAP specific tweaks.  This is merged into head.S by the linker.
+ *
+ */
+
+#include <linux/linkage.h>
+#include <asm/mach-types.h>
+
+               .section        ".start", "ax"
+
+__OMAP_start:
+#ifdef CONFIG_MACH_OMAP_PERSEUS2
+               /* support for booting without u-boot */
+               mov     r7, #(MACH_TYPE_OMAP_PERSEUS2 & ~0xf)
+               orr     r7, r7, #(MACH_TYPE_OMAP_PERSEUS2 & 0xf)
+#endif
diff --git a/arch/arm/configs/ams_delta_defconfig b/arch/arm/configs/ams_delta_defconfig
new file mode 100644 (file)
index 0000000..1986bca
--- /dev/null
@@ -0,0 +1,1217 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.18-omap1
+# Tue Oct 10 22:26:32 2006
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+# CONFIG_BLK_DEV_IO_TRACE is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+CONFIG_ARCH_OMAP=y
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP1=y
+# CONFIG_ARCH_OMAP2 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+# CONFIG_OMAP_BOOT_TAG is not set
+# CONFIG_OMAP_GPIO_SWITCH is not set
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_WARNINGS=y
+CONFIG_OMAP_MCBSP=y
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+CONFIG_OMAP_DSP=m
+# CONFIG_OMAP_DSP_MBCMD_VERBOSE is not set
+# CONFIG_OMAP_DSP_TASK_MULTIOPEN is not set
+# CONFIG_OMAP_DSP_FBEXPORT is not set
+
+#
+# OMAP Core Type
+#
+# CONFIG_ARCH_OMAP730 is not set
+CONFIG_ARCH_OMAP15XX=y
+# CONFIG_ARCH_OMAP16XX is not set
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_INNOVATOR is not set
+# CONFIG_MACH_VOICEBLUE is not set
+# CONFIG_MACH_OMAP_PALMTE is not set
+CONFIG_MACH_AMS_DELTA=y
+# CONFIG_MACH_OMAP_GENERIC is not set
+
+#
+# OMAP CPU Speed
+#
+# CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER is not set
+# CONFIG_OMAP_ARM_168MHZ is not set
+CONFIG_OMAP_ARM_150MHZ=y
+# CONFIG_OMAP_ARM_120MHZ is not set
+# CONFIG_OMAP_ARM_60MHZ is not set
+# CONFIG_OMAP_ARM_30MHZ is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM925T=y
+CONFIG_CPU_32v4T=y
+CONFIG_CPU_ABRT_EV4T=y
+CONFIG_CPU_CACHE_V4WT=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+CONFIG_CPU_DCACHE_WRITETHROUGH=y
+
+#
+# Bus support
+#
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_PREEMPT=y
+# CONFIG_NO_IDLE_HZ is not set
+CONFIG_HZ=100
+# CONFIG_AEABI is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_RESOURCES_64BIT is not set
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="mem=32M console=ttyS0,115200n8 root=/dev/ram0 initrd=0x11c00000,4M"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+# CONFIG_APM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+CONFIG_IPV6=y
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+CONFIG_INET6_XFRM_MODE_TRANSPORT=y
+CONFIG_INET6_XFRM_MODE_TUNNEL=y
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+CONFIG_MTD_NAND_AMS_DELTA=y
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+# CONFIG_MTD_ONENAND_SYNC_READ is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+CONFIG_PPP=y
+CONFIG_PPP_MULTILINK=y
+# CONFIG_PPP_FILTER is not set
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_PPP_DEFLATE is not set
+# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPP_MPPE is not set
+# CONFIG_PPPOE is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_KEYBOARD_OMAP=y
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_NVRAM is not set
+CONFIG_OMAP_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=y
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_PCA_ISA is not set
+CONFIG_I2C_OMAP=y
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_SENSORS_TLV320AIC23 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Misc devices
+#
+
+#
+# LED devices
+#
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+CONFIG_LEDS_AMS_DELTA=y
+# CONFIG_LEDS_OMAP is not set
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_V4L2=y
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+CONFIG_FIRMWARE_EDID=y
+CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FB_OMAP=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_LCD_MIPID is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=2
+# CONFIG_FB_OMAP_DMA_TUNE is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FONTS=y
+# CONFIG_FONT_8x8 is not set
+# CONFIG_FONT_8x16 is not set
+CONFIG_FONT_6x11=y
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_MUSB_HDRC is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+CONFIG_USB_HIDINPUT=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_ACECAD is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_TOUCHSCREEN is not set
+# CONFIG_USB_YEALINK is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
+# CONFIG_USB_KEYSPAN_REMOTE is not set
+# CONFIG_USB_APPLETOUCH is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB Network Adapters
+#
+CONFIG_USB_CATC=y
+CONFIG_USB_KAWETH=y
+CONFIG_USB_PEGASUS=y
+CONFIG_USB_RTL8150=y
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_AX8817X=y
+CONFIG_USB_NET_CDCETHER=y
+# CONFIG_USB_NET_GL620A is not set
+CONFIG_USB_NET_NET1080=y
+# CONFIG_USB_NET_PLUSB is not set
+# CONFIG_USB_NET_RNDIS_HOST is not set
+CONFIG_USB_NET_CDC_SUBSET=y
+# CONFIG_USB_ALI_M5632 is not set
+# CONFIG_USB_AN2720 is not set
+CONFIG_USB_BELKIN=y
+CONFIG_USB_ARMLINUX=y
+# CONFIG_USB_EPSON2888 is not set
+CONFIG_USB_NET_ZAURUS=y
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGETKIT is not set
+# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+
+#
+# Synchronous Serial Interfaces (SSI)
+#
+# CONFIG_OMAP_UWIRE is not set
+# CONFIG_OMAP_TSC2101 is not set
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+CONFIG_AUTOFS_FS=y
+CONFIG_AUTOFS4_FS=y
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+CONFIG_JFFS2_SUMMARY=y
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+CONFIG_NLS_CODEPAGE_850=y
+CONFIG_NLS_CODEPAGE_852=y
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_2=y
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_RWSEMS is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_DEBUG_VM is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_UNWIND_INFO is not set
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
diff --git a/arch/arm/configs/n770_defconfig b/arch/arm/configs/n770_defconfig
new file mode 100644 (file)
index 0000000..ef33d82
--- /dev/null
@@ -0,0 +1,1342 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.16-rc2-omap1
+# Fri Feb 10 15:29:21 2006
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_UID16=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+
+#
+# Block layer
+#
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+
+#
+# System Type
+#
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_AT91RM9200 is not set
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+CONFIG_ARCH_OMAP1=y
+# CONFIG_ARCH_OMAP2 is not set
+
+#
+# OMAP Feature Selections
+#
+CONFIG_OMAP_RESET_CLOCKS=y
+CONFIG_OMAP_BOOT_TAG=y
+CONFIG_OMAP_BOOT_REASON=y
+CONFIG_OMAP_COMPONENT_VERSION=y
+CONFIG_OMAP_GPIO_SWITCH=y
+# CONFIG_OMAP_MUX is not set
+CONFIG_OMAP_STI=y
+CONFIG_OMAP_STI_CONSOLE=y
+# CONFIG_OMAP_MPU_TIMER is not set
+CONFIG_OMAP_32K_TIMER=y
+CONFIG_OMAP_32K_TIMER_HZ=128
+CONFIG_OMAP_DM_TIMER=y
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+
+#
+# OMAP Core Type
+#
+# CONFIG_ARCH_OMAP730 is not set
+# CONFIG_ARCH_OMAP15XX is not set
+CONFIG_ARCH_OMAP16XX=y
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_INNOVATOR is not set
+# CONFIG_MACH_OMAP_H2 is not set
+# CONFIG_MACH_OMAP_H3 is not set
+# CONFIG_MACH_OMAP_OSK is not set
+CONFIG_MACH_NOKIA770=y
+# CONFIG_MACH_OMAP_GENERIC is not set
+
+#
+# OMAP CPU Speed
+#
+CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER=y
+CONFIG_OMAP_ARM_216MHZ=y
+# CONFIG_OMAP_ARM_192MHZ is not set
+# CONFIG_OMAP_ARM_168MHZ is not set
+# CONFIG_OMAP_ARM_120MHZ is not set
+# CONFIG_OMAP_ARM_60MHZ is not set
+# CONFIG_OMAP_ARM_30MHZ is not set
+CONFIG_OMAP_DSP=y
+# CONFIG_OMAP_DSP_MBCMD_VERBOSE is not set
+CONFIG_OMAP_DSP_TASK_MULTIOPEN=y
+CONFIG_OMAP_DSP_FBEXPORT=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+
+#
+# Bus support
+#
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+CONFIG_NO_IDLE_HZ=y
+# CONFIG_AEABI is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=1f03 rootfstype=jffs2 time"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_PM_LEGACY is not set
+# CONFIG_PM_DEBUG is not set
+# CONFIG_APM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+# CONFIG_IPV6 is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_NETLINK=y
+# CONFIG_NETFILTER_NETLINK_QUEUE is not set
+# CONFIG_NETFILTER_NETLINK_LOG is not set
+# CONFIG_NF_CONNTRACK is not set
+# CONFIG_NETFILTER_XTABLES is not set
+
+#
+# IP: Netfilter Configuration
+#
+# CONFIG_IP_NF_CONNTRACK is not set
+# CONFIG_IP_NF_QUEUE is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+CONFIG_BT=y
+CONFIG_BT_L2CAP=y
+CONFIG_BT_SCO=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+# CONFIG_BT_BNEP_MC_FILTER is not set
+# CONFIG_BT_BNEP_PROTO_FILTER is not set
+CONFIG_BT_HIDP=y
+
+#
+# Bluetooth device drivers
+#
+# CONFIG_BT_HCIUSB is not set
+# CONFIG_BT_HCIUART is not set
+# CONFIG_BT_HCIBCM203X is not set
+# CONFIG_BT_HCIBPA10X is not set
+# CONFIG_BT_HCIBFUSB is not set
+CONFIG_BT_HCIBRF6150=y
+# CONFIG_BT_HCIVHCI is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+CONFIG_CONNECTOR=y
+# CONFIG_PROC_EVENTS is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_TOTO is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+CONFIG_MTD_NAND_OMAP_HW=y
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+# CONFIG_MTD_ONENAND_SYNC_READ is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+# CONFIG_BLK_DEV_RAM is not set
+CONFIG_BLK_DEV_RAM_COUNT=16
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+# CONFIG_SCSI_PROC_FS is not set
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=y
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+
+#
+# Obsolete Wireless cards support (pre-802.11)
+#
+# CONFIG_STRIP is not set
+# CONFIG_ATMEL is not set
+# CONFIG_HOSTAP is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+CONFIG_PPP=y
+# CONFIG_PPP_MULTILINK is not set
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=y
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_BSDCOMP=y
+# CONFIG_PPP_MPPE is not set
+# CONFIG_PPPOE is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_KEYBOARD_OMAP=y
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ADS7846=y
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_OMAP is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_OMAP_WATCHDOG=y
+CONFIG_OMAP_RNG=y
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_OMAP_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+# CONFIG_I2C_CHARDEV is not set
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_PCA_ISA is not set
+CONFIG_I2C_OMAP=y
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_ISP1301_OMAP is not set
+# CONFIG_TPS65010 is not set
+CONFIG_SENSORS_TLV320AIC23=y
+# CONFIG_GPIOEXPANDER_OMAP is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_RTC_X1205_I2C is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_BITBANG=y
+CONFIG_SPI_OMAP_UWIRE=y
+
+#
+# SPI Protocol Masters
+#
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_OMAP=y
+CONFIG_FB_OMAP_LCDC_EXTERNAL=y
+CONFIG_FB_OMAP_LCDC_HWA742=y
+CONFIG_FB_OMAP_MANUAL_UPDATE=y
+CONFIG_FB_OMAP_LCD_LPH8923=y
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+# CONFIG_FB_OMAP_DMA_TUNE is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE is not set
+
+#
+# Logo configuration
+#
+# CONFIG_LOGO is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_HWDEP=y
+CONFIG_SND_RAWMIDI=y
+# CONFIG_SND_SEQUENCER is not set
+# CONFIG_SND_MIXER_OSS is not set
+# CONFIG_SND_PCM_OSS is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+# CONFIG_SND_SUPPORT_OLD_API is not set
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+CONFIG_SND_DUMMY=y
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# ALSA ARM devices
+#
+CONFIG_SND_OMAP_AIC23=y
+
+#
+# USB devices
+#
+CONFIG_SND_USB_AUDIO=y
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_BANDWIDTH=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_OTG=y
+# CONFIG_USB_OTG_WHITELIST is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_OBSOLETE_OSS_USB_DRIVER is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+CONFIG_USB_HIDINPUT=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_ACECAD is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_MTOUCH is not set
+# CONFIG_USB_ITMTOUCH is not set
+# CONFIG_USB_EGALAX is not set
+# CONFIG_USB_YEALINK is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
+# CONFIG_USB_KEYSPAN_REMOTE is not set
+# CONFIG_USB_APPLETOUCH is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_DABUSB is not set
+
+#
+# Video4Linux support is needed for USB Multimedia device support
+#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+CONFIG_USB_USBNET=y
+# CONFIG_USB_NET_AX8817X is not set
+CONFIG_USB_NET_CDCETHER=y
+# CONFIG_USB_NET_GL620A is not set
+CONFIG_USB_NET_NET1080=y
+# CONFIG_USB_NET_PLUSB is not set
+# CONFIG_USB_NET_RNDIS_HOST is not set
+# CONFIG_USB_NET_CDC_SUBSET is not set
+CONFIG_USB_NET_ZAURUS=y
+# CONFIG_USB_ZD1201 is not set
+# CONFIG_USB_MON is not set
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+CONFIG_USB_SERIAL=y
+CONFIG_USB_SERIAL_CONSOLE=y
+# CONFIG_USB_SERIAL_GENERIC is not set
+# CONFIG_USB_SERIAL_AIRPRIME is not set
+# CONFIG_USB_SERIAL_ANYDATA is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_CP2101 is not set
+# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
+# CONFIG_USB_SERIAL_GARMIN is not set
+# CONFIG_USB_SERIAL_IPW is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+CONFIG_USB_SERIAL_PL2303=y
+# CONFIG_USB_SERIAL_HP4X is not set
+# CONFIG_USB_SERIAL_SAFE is not set
+# CONFIG_USB_SERIAL_TI is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGETKIT is not set
+# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+CONFIG_USB_GADGET_OMAP=y
+CONFIG_USB_OMAP=y
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+# CONFIG_USB_GADGET_DUALSPEED is not set
+# CONFIG_USB_ZERO is not set
+CONFIG_USB_ETH=m
+CONFIG_USB_ETH_RNDIS=y
+# CONFIG_USB_GADGETFS is not set
+CONFIG_USB_FILE_STORAGE=m
+CONFIG_USB_FILE_STORAGE_TEST=y
+# CONFIG_USB_G_SERIAL is not set
+
+#
+# MMC/SD Card support
+#
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BROKEN_RFD=y
+CONFIG_MMC_BULKTRANSFER=y
+CONFIG_MMC_OMAP=y
+
+#
+# Synchronous Serial Interfaces (SSI)
+#
+CONFIG_OMAP_UWIRE=y
+# CONFIG_OMAP_TSC2101 is not set
+
+#
+# CBUS support
+#
+CONFIG_CBUS=y
+CONFIG_CBUS_TAHVO=y
+CONFIG_CBUS_TAHVO_USER=y
+CONFIG_CBUS_TAHVO_USB=y
+# CONFIG_CBUS_TAHVO_USB_HOST_BY_DEFAULT is not set
+CONFIG_CBUS_RETU=y
+CONFIG_CBUS_RETU_USER=y
+CONFIG_CBUS_RETU_POWERBUTTON=y
+CONFIG_CBUS_RETU_RTC=y
+CONFIG_CBUS_RETU_WDT=y
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_INOTIFY is not set
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_RELAYFS_FS is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+CONFIG_JFFS2_SUMMARY=y
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_JFFS2_CMODE_NONE is not set
+CONFIG_JFFS2_CMODE_PRIORITY=y
+# CONFIG_JFFS2_CMODE_SIZE is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+# CONFIG_ROOT_NFS is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+CONFIG_NLS_CODEPAGE_852=y
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+CONFIG_NLS_ISO8859_15=y
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=y
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_DEBUG_VM is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_WAITQ is not set
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+CONFIG_SECURITY=y
+# CONFIG_SECURITY_NETWORK is not set
+# CONFIG_SECURITY_CAPABILITIES is not set
+# CONFIG_SECURITY_ROOTPLUG is not set
+# CONFIG_SECURITY_SECLVL is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/arm/configs/n800_defconfig b/arch/arm/configs/n800_defconfig
new file mode 100644 (file)
index 0000000..6664184
--- /dev/null
@@ -0,0 +1,1495 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.20-rc5-omap1
+# Wed Jan 17 17:19:12 2007
+#
+CONFIG_ARM=y
+CONFIG_GENERIC_TIME=y
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+CONFIG_POSIX_MQUEUE=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+CONFIG_ARCH_OMAP=y
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+# CONFIG_ARCH_OMAP1 is not set
+CONFIG_ARCH_OMAP2=y
+
+#
+# OMAP Feature Selections
+#
+CONFIG_OMAP_RESET_CLOCKS=y
+CONFIG_OMAP_BOOT_TAG=y
+CONFIG_OMAP_BOOT_REASON=y
+CONFIG_OMAP_COMPONENT_VERSION=y
+CONFIG_OMAP_GPIO_SWITCH=y
+# CONFIG_OMAP_MUX is not set
+CONFIG_OMAP_STI=y
+CONFIG_OMAP_STI_CONSOLE=y
+# CONFIG_OMAP_MCBSP is not set
+# CONFIG_OMAP_MPU_TIMER is not set
+CONFIG_OMAP_32K_TIMER=y
+CONFIG_OMAP_32K_TIMER_HZ=128
+CONFIG_OMAP_DM_TIMER=y
+# CONFIG_OMAP_LL_DEBUG_UART1 is not set
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+CONFIG_OMAP_LL_DEBUG_UART3=y
+CONFIG_OMAP_DSP=y
+# CONFIG_OMAP_DSP_MBCMD_VERBOSE is not set
+CONFIG_OMAP_DSP_TASK_MULTIOPEN=y
+CONFIG_OMAP_DSP_FBEXPORT=y
+CONFIG_MACH_OMAP_GENERIC=y
+
+#
+# OMAP Core Type
+#
+CONFIG_ARCH_OMAP24XX=y
+CONFIG_ARCH_OMAP2420=y
+# CONFIG_ARCH_OMAP2430 is not set
+
+#
+# OMAP Board Type
+#
+CONFIG_MACH_NOKIA_N800=y
+CONFIG_MACH_OMAP2_TUSB6010=y
+# CONFIG_MACH_OMAP_H4 is not set
+# CONFIG_MACH_OMAP_2430SDP is not set
+# CONFIG_MACH_OMAP_APOLLON is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_V6=y
+# CONFIG_CPU_32v6K is not set
+CONFIG_CPU_32v6=y
+CONFIG_CPU_ABRT_EV6=y
+CONFIG_CPU_CACHE_V6=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V6=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+
+#
+# Bus support
+#
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+CONFIG_NO_IDLE_HZ=y
+CONFIG_HZ=128
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_LEDS=y
+# CONFIG_LEDS_TIMER is not set
+# CONFIG_LEDS_CPU is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x10C08000
+CONFIG_ZBOOT_ROM_BSS=0x10200000
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_CMDLINE="root=1f03 rootfstype=jffs2"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_VFP=y
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_PM_LEGACY is not set
+# CONFIG_PM_DEBUG is not set
+# CONFIG_PM_SYSFS_DEPRECATED is not set
+# CONFIG_APM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETLABEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_NETLINK=y
+# CONFIG_NETFILTER_NETLINK_QUEUE is not set
+# CONFIG_NETFILTER_NETLINK_LOG is not set
+# CONFIG_NF_CONNTRACK_ENABLED is not set
+CONFIG_NETFILTER_XTABLES=y
+# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set
+# CONFIG_NETFILTER_XT_TARGET_MARK is not set
+# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set
+# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set
+# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
+# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
+# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
+# CONFIG_NETFILTER_XT_MATCH_ESP is not set
+# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set
+# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_MAC is not set
+# CONFIG_NETFILTER_XT_MATCH_MARK is not set
+# CONFIG_NETFILTER_XT_MATCH_POLICY is not set
+# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set
+# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set
+# CONFIG_NETFILTER_XT_MATCH_REALM is not set
+# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
+# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set
+# CONFIG_NETFILTER_XT_MATCH_STRING is not set
+# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set
+# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set
+
+#
+# IP: Netfilter Configuration
+#
+# CONFIG_IP_NF_QUEUE is not set
+CONFIG_IP_NF_IPTABLES=y
+# CONFIG_IP_NF_MATCH_IPRANGE is not set
+# CONFIG_IP_NF_MATCH_TOS is not set
+# CONFIG_IP_NF_MATCH_RECENT is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_AH is not set
+# CONFIG_IP_NF_MATCH_TTL is not set
+# CONFIG_IP_NF_MATCH_OWNER is not set
+# CONFIG_IP_NF_MATCH_ADDRTYPE is not set
+CONFIG_IP_NF_FILTER=y
+# CONFIG_IP_NF_TARGET_REJECT is not set
+# CONFIG_IP_NF_TARGET_LOG is not set
+# CONFIG_IP_NF_TARGET_ULOG is not set
+# CONFIG_IP_NF_TARGET_TCPMSS is not set
+CONFIG_IP_NF_TARGET_IDLETIMER=y
+# CONFIG_IP_NF_MANGLE is not set
+# CONFIG_IP_NF_RAW is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+CONFIG_BT=y
+CONFIG_BT_L2CAP=y
+CONFIG_BT_SCO=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+# CONFIG_BT_BNEP_MC_FILTER is not set
+# CONFIG_BT_BNEP_PROTO_FILTER is not set
+CONFIG_BT_HIDP=y
+
+#
+# Bluetooth device drivers
+#
+# CONFIG_BT_HCIUSB is not set
+# CONFIG_BT_HCIUART is not set
+# CONFIG_BT_HCIBCM203X is not set
+# CONFIG_BT_HCIBPA10X is not set
+# CONFIG_BT_HCIBFUSB is not set
+# CONFIG_BT_HCIBRF6150 is not set
+# CONFIG_BT_HCIVHCI is not set
+# CONFIG_IEEE80211 is not set
+CONFIG_WIRELESS_EXT=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+CONFIG_MTD_ONENAND=y
+# CONFIG_MTD_ONENAND_VERIFY_WRITE is not set
+# CONFIG_MTD_ONENAND_GENERIC is not set
+CONFIG_MTD_ONENAND_OMAP2=y
+CONFIG_MTD_ONENAND_OTP=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_SCSI_PROC_FS is not set
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=y
+
+#
+# PHY device support
+#
+
+#
+# Ethernet (10 or 100Mbit)
+#
+# CONFIG_NET_ETHERNET is not set
+CONFIG_MII=y
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+# CONFIG_NET_WIRELESS_RTNETLINK is not set
+
+#
+# Obsolete Wireless cards support (pre-802.11)
+#
+# CONFIG_STRIP is not set
+# CONFIG_USB_ZD1201 is not set
+# CONFIG_HOSTAP is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+CONFIG_PPP=y
+# CONFIG_PPP_MULTILINK is not set
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_BSDCOMP=y
+# CONFIG_PPP_MPPE is not set
+# CONFIG_PPPOE is not set
+# CONFIG_SLIP is not set
+CONFIG_SLHC=y
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_OMAP is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_ADS7846 is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_UCB1400 is not set
+# CONFIG_TOUCHSCREEN_TSC2102 is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_OMAP_WATCHDOG=y
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+# CONFIG_HW_RANDOM is not set
+CONFIG_OMAP_RNG=y
+# CONFIG_NVRAM is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+# CONFIG_I2C_CHARDEV is not set
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_ISP1301_OMAP is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_SENSORS_TLV320AIC23 is not set
+# CONFIG_GPIOEXPANDER_OMAP is not set
+CONFIG_MENELAUS=y
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_OMAP_UWIRE is not set
+CONFIG_SPI_OMAP24XX=y
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_TSC2102 is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM70 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+# CONFIG_TIFM_CORE is not set
+
+#
+# LED devices
+#
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+# CONFIG_LEDS_OMAP_DEBUG is not set
+# CONFIG_LEDS_OMAP is not set
+CONFIG_LEDS_OMAP_PWM=y
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=y
+# CONFIG_VIDEO_V4L1 is not set
+# CONFIG_VIDEO_V4L1_COMPAT is not set
+CONFIG_VIDEO_V4L2=y
+
+#
+# Video Capture Adapters
+#
+
+#
+# Video Capture Adapters
+#
+# CONFIG_VIDEO_ADV_DEBUG is not set
+CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
+# CONFIG_VIDEO_VIVI is not set
+# CONFIG_VIDEO_SAA5246A is not set
+# CONFIG_VIDEO_SAA5249 is not set
+
+#
+# V4L USB devices
+#
+# CONFIG_VIDEO_PVRUSB2 is not set
+# CONFIG_VIDEO_USBVISION is not set
+# CONFIG_VIDEO_OMAP_CAMERA is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_USB_DSBR is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FIRMWARE_EDID is not set
+CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FB_OMAP=y
+CONFIG_FB_OMAP_LCDC_EXTERNAL=y
+# CONFIG_FB_OMAP_LCDC_HWA742 is not set
+CONFIG_FB_OMAP_MANUAL_UPDATE=y
+CONFIG_FB_OMAP_LCD_MIPID=y
+CONFIG_FB_OMAP_BOOTLOADER_INIT=y
+CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=4
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE is not set
+
+#
+# Logo configuration
+#
+# CONFIG_LOGO is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=y
+# CONFIG_SND_SEQUENCER is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=y
+# CONFIG_SND_PCM_OSS is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+# CONFIG_SND_VERBOSE_PROCFS is not set
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# ALSA ARM devices
+#
+# CONFIG_SND_OMAP_AIC23 is not set
+# CONFIG_SND_OMAP_TSC2101 is not set
+# CONFIG_SND_SX1 is not set
+# CONFIG_SND_OMAP_TSC2102 is not set
+
+#
+# USB devices
+#
+# CONFIG_SND_USB_AUDIO is not set
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+
+#
+# HID Devices
+#
+CONFIG_HID=y
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+CONFIG_USB_DYNAMIC_MINORS=y
+CONFIG_USB_SUSPEND=y
+# CONFIG_USB_MULTITHREAD_PROBE is not set
+CONFIG_USB_OTG=y
+CONFIG_USB_OTG_WHITELIST=y
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+CONFIG_USB_MUSB_HDRC=y
+CONFIG_USB_TUSB6010=y
+# CONFIG_USB_MUSB_HOST is not set
+# CONFIG_USB_MUSB_PERIPHERAL is not set
+CONFIG_USB_MUSB_OTG=y
+CONFIG_USB_GADGET_MUSB_HDRC=y
+CONFIG_USB_MUSB_HDRC_HCD=y
+# CONFIG_USB_INVENTRA_FIFO is not set
+# CONFIG_USB_INVENTRA_DMA is not set
+# CONFIG_USB_TI_CPPI_DMA is not set
+CONFIG_USB_TUSB_OMAP_DMA=y
+CONFIG_USB_INVENTRA_HCD_LOGGING=1
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+CONFIG_USB_LIBUSUAL=y
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_ACECAD is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_TOUCHSCREEN is not set
+# CONFIG_USB_YEALINK is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
+# CONFIG_USB_KEYSPAN_REMOTE is not set
+# CONFIG_USB_APPLETOUCH is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+CONFIG_USB_RTL8150=y
+# CONFIG_USB_USBNET_MII is not set
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_CDCETHER=y
+# CONFIG_USB_NET_GL620A is not set
+CONFIG_USB_NET_NET1080=y
+CONFIG_USB_NET_PLUSB=y
+# CONFIG_USB_NET_MCS7830 is not set
+CONFIG_USB_NET_RNDIS_HOST=y
+CONFIG_USB_NET_CDC_SUBSET=y
+# CONFIG_USB_ALI_M5632 is not set
+# CONFIG_USB_AN2720 is not set
+CONFIG_USB_BELKIN=y
+CONFIG_USB_ARMLINUX=y
+# CONFIG_USB_EPSON2888 is not set
+CONFIG_USB_NET_ZAURUS=y
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+# CONFIG_USB_ZERO is not set
+CONFIG_USB_ETH=y
+CONFIG_USB_ETH_RNDIS=y
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+
+#
+# Synchronous Serial Interfaces (SSI)
+#
+# CONFIG_OMAP_TSC2101 is not set
+
+#
+# CBUS support
+#
+CONFIG_CBUS=y
+CONFIG_CBUS_TAHVO=y
+CONFIG_CBUS_TAHVO_USER=y
+# CONFIG_CBUS_TAHVO_USB is not set
+CONFIG_CBUS_RETU=y
+CONFIG_CBUS_RETU_USER=y
+CONFIG_CBUS_RETU_POWERBUTTON=y
+CONFIG_CBUS_RETU_RTC=y
+CONFIG_CBUS_RETU_WDT=y
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=m
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT2_FS_POSIX_ACL is not set
+# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=m
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=m
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+CONFIG_JFFS2_SUMMARY=y
+# CONFIG_JFFS2_FS_XATTR is not set
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_JFFS2_CMODE_NONE is not set
+CONFIG_JFFS2_CMODE_PRIORITY=y
+# CONFIG_JFFS2_CMODE_SIZE is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+CONFIG_NLS_ISO8859_15=y
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=y
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+CONFIG_PRINTK_TIME=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_RWSEMS is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+CONFIG_SECURITY=y
+# CONFIG_SECURITY_NETWORK is not set
+# CONFIG_SECURITY_CAPABILITIES is not set
+# CONFIG_SECURITY_ROOTPLUG is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_IOMAP_COPY=y
diff --git a/arch/arm/configs/omap_2430sdp_defconfig b/arch/arm/configs/omap_2430sdp_defconfig
new file mode 100644 (file)
index 0000000..404405f
--- /dev/null
@@ -0,0 +1,1106 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.19-omap1
+# Sun Dec  3 13:58:24 2006
+#
+CONFIG_ARM=y
+# CONFIG_GENERIC_TIME is not set
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_BLK_DEV_IO_TRACE is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+CONFIG_ARCH_OMAP=y
+
+#
+# TI OMAP Implementations
+#
+# CONFIG_ARCH_OMAP1 is not set
+CONFIG_ARCH_OMAP2=y
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+CONFIG_OMAP_BOOT_TAG=y
+# CONFIG_OMAP_BOOT_REASON is not set
+# CONFIG_OMAP_COMPONENT_VERSION is not set
+# CONFIG_OMAP_GPIO_SWITCH is not set
+CONFIG_OMAP_MUX=y
+CONFIG_OMAP_MUX_DEBUG=y
+CONFIG_OMAP_MUX_WARNINGS=y
+# CONFIG_OMAP_STI is not set
+CONFIG_OMAP_MCBSP=y
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
+CONFIG_OMAP_DM_TIMER=y
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+# CONFIG_OMAP_DSP is not set
+# CONFIG_MACH_OMAP_GENERIC is not set
+
+#
+# OMAP Core Type
+#
+CONFIG_ARCH_OMAP24XX=y
+# CONFIG_ARCH_OMAP2420 is not set
+CONFIG_ARCH_OMAP2430=y
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_H4 is not set
+CONFIG_MACH_OMAP_2430SDP=y
+# CONFIG_MACH_OMAP_APOLLON is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_V6=y
+# CONFIG_CPU_32v6K is not set
+CONFIG_CPU_32v6=y
+CONFIG_CPU_ABRT_EV6=y
+CONFIG_CPU_CACHE_V6=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V6=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+
+#
+# Bus support
+#
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+# CONFIG_NO_IDLE_HZ is not set
+CONFIG_HZ=100
+# CONFIG_AEABI is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/ram0 rw console=ttyS0,115200n8 initrd=0x80600000,8M ramdisk_size=8192"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_MISC=y
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+# CONFIG_APM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+CONFIG_MTD_OMAP_NOR=y
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=16384
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_NETLINK is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_SMC91X=y
+# CONFIG_DM9000 is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+CONFIG_KEYBOARD_OMAP=y
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_OMAP_WATCHDOG=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_OMAP=y
+# CONFIG_OMAP_RNG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+# CONFIG_I2C_CHARDEV is not set
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_SENSORS_TLV320AIC23 is not set
+# CONFIG_GPIOEXPANDER_OMAP is not set
+# CONFIG_MENELAUS is not set
+CONFIG_TWL4030_CORE=y
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Misc devices
+#
+# CONFIG_TIFM_CORE is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FIRMWARE_EDID=y
+CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FB_OMAP=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_LCD_MIPID is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=2
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
+
+#
+# Enable Host or Gadget support to see Inventra options
+#
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_OMAP=y
+# CONFIG_MMC_TIFM_SD is not set
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+
+#
+# Synchronous Serial Interfaces (SSI)
+#
+# CONFIG_OMAP_TSC2101 is not set
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_QUOTA=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_JFFS2_CMODE_NONE is not set
+CONFIG_JFFS2_CMODE_PRIORITY=y
+# CONFIG_JFFS2_CMODE_SIZE is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_RWSEMS is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_FORCED_INLINING=y
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_ERRORS is not set
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
diff --git a/arch/arm/configs/omap_apollon_2420_defconfig b/arch/arm/configs/omap_apollon_2420_defconfig
new file mode 100644 (file)
index 0000000..2cef064
--- /dev/null
@@ -0,0 +1,1009 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.20-rc1-omap1
+# Fri Dec 22 14:31:47 2006
+#
+CONFIG_ARM=y
+# CONFIG_GENERIC_TIME is not set
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+CONFIG_ARCH_OMAP=y
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+# CONFIG_ARCH_OMAP1 is not set
+CONFIG_ARCH_OMAP2=y
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+# CONFIG_OMAP_BOOT_TAG is not set
+# CONFIG_OMAP_GPIO_SWITCH is not set
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_WARNINGS=y
+# CONFIG_OMAP_STI is not set
+# CONFIG_OMAP_MCBSP is not set
+# CONFIG_OMAP_MPU_TIMER is not set
+CONFIG_OMAP_32K_TIMER=y
+CONFIG_OMAP_32K_TIMER_HZ=128
+CONFIG_OMAP_DM_TIMER=y
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+# CONFIG_OMAP_DSP is not set
+# CONFIG_MACH_OMAP_GENERIC is not set
+
+#
+# OMAP Core Type
+#
+CONFIG_ARCH_OMAP24XX=y
+CONFIG_ARCH_OMAP2420=y
+# CONFIG_ARCH_OMAP2430 is not set
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_H4 is not set
+# CONFIG_MACH_OMAP_2430SDP is not set
+CONFIG_MACH_OMAP_APOLLON=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_V6=y
+# CONFIG_CPU_32v6K is not set
+CONFIG_CPU_32v6=y
+CONFIG_CPU_ABRT_EV6=y
+CONFIG_CPU_CACHE_V6=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V6=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+
+#
+# Bus support
+#
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_PREEMPT=y
+CONFIG_NO_IDLE_HZ=y
+CONFIG_HZ=128
+# CONFIG_AEABI is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/ram0 rw mem=128M console=ttyS0,115200n8 initrd=0x80600000,8M ramdisk_size=8192"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+# CONFIG_FPE_NWFPE is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_VFP=y
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+# CONFIG_APM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+CONFIG_MTD_ONENAND=y
+# CONFIG_MTD_ONENAND_VERIFY_WRITE is not set
+CONFIG_MTD_ONENAND_GENERIC=y
+# CONFIG_MTD_ONENAND_OTP is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_NETLINK is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_SMC91X=y
+# CONFIG_DM9000 is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_OMAP_WATCHDOG=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_OMAP=y
+# CONFIG_OMAP_RNG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_OMAP_UWIRE is not set
+CONFIG_SPI_OMAP24XX=y
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_TSC2102 is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Misc devices
+#
+# CONFIG_TIFM_CORE is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FIRMWARE_EDID=y
+CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FB_OMAP=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_LCD_MIPID is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=2
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# HID Devices
+#
+# CONFIG_HID is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
+# CONFIG_USB_MUSB_HDRC is not set
+# CONFIG_USB_GADGET_MUSB_HDRC is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+CONFIG_USB_GADGET_OMAP=y
+CONFIG_USB_OMAP=y
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+# CONFIG_USB_GADGET_DUALSPEED is not set
+# CONFIG_USB_ZERO is not set
+CONFIG_USB_ETH=m
+CONFIG_USB_ETH_RNDIS=y
+# CONFIG_USB_GADGETFS is not set
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_OMAP=y
+# CONFIG_MMC_TIFM_SD is not set
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+
+#
+# Synchronous Serial Interfaces (SSI)
+#
+# CONFIG_OMAP_TSC2101 is not set
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_INOTIFY is not set
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+CONFIG_AUTOFS4_FS=y
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_CRAMFS=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_PREEMPT=y
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_RWSEMS is not set
+CONFIG_DEBUG_SPINLOCK_SLEEP=y
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_IOMAP_COPY=y
diff --git a/arch/arm/configs/omap_generic_1510_defconfig b/arch/arm/configs/omap_generic_1510_defconfig
new file mode 100644 (file)
index 0000000..5091946
--- /dev/null
@@ -0,0 +1,851 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_STANDALONE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_HOTPLUG is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_ADIFCC is not set
+# CONFIG_ARCH_ANAKIN is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_SHARK is not set
+CONFIG_ARCH_OMAP=y
+
+#
+# CLPS711X/EP721X Implementations
+#
+
+#
+# Epxa10db
+#
+
+#
+# Footbridge Implementations
+#
+
+#
+# IOP3xx Implementation Options
+#
+# CONFIG_ARCH_IOP310 is not set
+# CONFIG_ARCH_IOP321 is not set
+
+#
+# IOP3xx Chipset Features
+#
+
+#
+# Intel PXA250/210 Implementations
+#
+
+#
+# SA11x0 Implementations
+#
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP15XX=y
+# CONFIG_ARCH_OMAP1610 is not set
+# CONFIG_OMAP_INNOVATOR is not set
+CONFIG_MACH_OMAP_GENERIC=y
+# CONFIG_INNOVATOR_MISSED_IRQS is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP1510_PM is not set
+CONFIG_OMAP_ARM_168MHZ=y
+# CONFIG_OMAP_ARM_120MHZ is not set
+# CONFIG_OMAP_ARM_60MHZ is not set
+# CONFIG_OMAP_ARM_30MHZ is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM925T=y
+CONFIG_CPU_32v4=y
+CONFIG_CPU_ABRT_EV4T=y
+CONFIG_CPU_CACHE_V4WT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+CONFIG_CPU_DCACHE_WRITETHROUGH=y
+
+#
+# General setup
+#
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+
+#
+# At least one math emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_PM=y
+CONFIG_PREEMPT=y
+# CONFIG_APM is not set
+# CONFIG_ARTHUR is not set
+CONFIG_CMDLINE="mem=64M console=ttyS2,115200 root=0803 ro init=/bin/sh"
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_DCSSBLK is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+# CONFIG_NETLINK_DEV is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_IPV6 is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NETFILTER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+CONFIG_IPV6_SCTP__=y
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_NET_VENDOR_SMC=y
+# CONFIG_SMC9194 is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+CONFIG_PPP=y
+CONFIG_PPP_MULTILINK=y
+# CONFIG_PPP_FILTER is not set
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_PPP_DEFLATE is not set
+# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPPOE is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BT is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_CHR_DEV_SG=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_REPORT_LUNS=y
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_CT82C710 is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_KEYBOARD_OMAP=y
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+CONFIG_OMAP_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=y
+# CONFIG_I2C_ALGOPCF is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_ELV is not set
+# CONFIG_I2C_ISA is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_VELLEMAN is not set
+CONFIG_I2C_OMAP1610=y
+
+#
+# I2C Hardware Sensors Chip support
+#
+# CONFIG_I2C_SENSOR is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# MMC/SD Card support
+#
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BROKEN_RFD=y
+CONFIG_MMC_OMAP=y
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA is not set
+CONFIG_AUTOFS_FS=y
+CONFIG_AUTOFS4_FS=y
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+# CONFIG_ROOT_NFS is not set
+CONFIG_LOCKD=y
+# CONFIG_EXPORTFS is not set
+CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_GSS is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_NEC98_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Misc devices
+#
+
+#
+# USB support
+#
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_EHCI_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811HS is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_BLUETOOTH_TTY is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_DPCM=y
+CONFIG_USB_STORAGE_HP8200e=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+
+#
+# USB Human Interface Devices (HID)
+#
+CONFIG_USB_HID=y
+CONFIG_USB_HIDINPUT=y
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_XPAD is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_HPUSBSCSI is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_DABUSB is not set
+
+#
+# Video4Linux support is needed for USB Multimedia device support
+#
+
+#
+# USB Network adaptors
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+CONFIG_USB_RTL8150=y
+CONFIG_USB_USBNET=y
+
+#
+# USB Host-to-Host Cables
+#
+CONFIG_USB_AN2720=y
+CONFIG_USB_BELKIN=y
+CONFIG_USB_GENESYS=y
+CONFIG_USB_NET1080=y
+CONFIG_USB_PL2301=y
+
+#
+# Intelligent USB Devices/Gadgets
+#
+CONFIG_USB_ARMLINUX=y
+CONFIG_USB_EPSON2888=y
+CONFIG_USB_ZAURUS=y
+CONFIG_USB_CDCETHER=y
+
+#
+# USB Network Adapters
+#
+CONFIG_USB_AX8817X=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_TIGL is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_BRLVGER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# Kernel hacking
+#
+CONFIG_FRAME_POINTER=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_INFO is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_CRC32=y
diff --git a/arch/arm/configs/omap_generic_1610_defconfig b/arch/arm/configs/omap_generic_1610_defconfig
new file mode 100644 (file)
index 0000000..b772e7e
--- /dev/null
@@ -0,0 +1,883 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.9-rc3-omap1
+# Mon Oct  4 10:14:44 2004
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_IOMAP=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_HOTPLUG is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+# CONFIG_TINY_SHMEM is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_VERSATILE_PB is not set
+# CONFIG_ARCH_IMX is not set
+
+#
+# TI OMAP Implementations
+#
+
+#
+# OMAP Core Type
+#
+# CONFIG_ARCH_OMAP730 is not set
+# CONFIG_ARCH_OMAP15XX is not set
+CONFIG_ARCH_OMAP16XX=y
+CONFIG_ARCH_OMAP_OTG=y
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_INNOVATOR is not set
+# CONFIG_MACH_OMAP_H2 is not set
+# CONFIG_MACH_OMAP_H3 is not set
+# CONFIG_MACH_OMAP_H4 is not set
+# CONFIG_MACH_OMAP_OSK is not set
+CONFIG_MACH_OMAP_GENERIC=y
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_BOOT_TAG is not set
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_WARNINGS=y
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_ARM_192MHZ=y
+# CONFIG_OMAP_ARM_168MHZ is not set
+# CONFIG_OMAP_ARM_120MHZ is not set
+# CONFIG_OMAP_ARM_60MHZ is not set
+# CONFIG_OMAP_ARM_30MHZ is not set
+# CONFIG_OMAP_DSP is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+
+#
+# General setup
+#
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+
+#
+# At least one math emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_DEBUG_DRIVER is not set
+CONFIG_PM=y
+CONFIG_PREEMPT=y
+# CONFIG_APM is not set
+# CONFIG_ARTHUR is not set
+CONFIG_CMDLINE="mem=64M console=ttyS2,115200 root=0803 ro init=/bin/sh"
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+# CONFIG_NETLINK_DEV is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_NET_VENDOR_SMC=y
+# CONFIG_SMC91X is not set
+# CONFIG_SMC9194 is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+CONFIG_PPP=y
+CONFIG_PPP_MULTILINK=y
+# CONFIG_PPP_FILTER is not set
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_PPP_DEFLATE is not set
+# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPPOE is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_CHR_DEV_SG=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_RAW is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_KEYBOARD_OMAP=y
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_8250_OMAP is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+CONFIG_OMAP_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=y
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_ISA is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_PCA_ISA is not set
+# CONFIG_I2C_OMAP is not set
+
+#
+# Hardware Sensors Chip support
+#
+# CONFIG_I2C_SENSOR is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+
+#
+# Other I2C Chip support
+#
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_ISP1301_OMAP is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_GPIOEXPANDER_OMAP is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA is not set
+CONFIG_AUTOFS_FS=y
+CONFIG_AUTOFS4_FS=y
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+# CONFIG_ROOT_NFS is not set
+CONFIG_LOCKD=y
+# CONFIG_EXPORTFS is not set
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# Misc devices
+#
+
+#
+# USB support
+#
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_EHCI_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811HS is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_BLUETOOTH_TTY is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_RW_DETECT is not set
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_DPCM=y
+CONFIG_USB_STORAGE_HP8200e=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+
+#
+# USB Human Interface Devices (HID)
+#
+CONFIG_USB_HID=y
+CONFIG_USB_HIDINPUT=y
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_MTOUCH is not set
+# CONFIG_USB_EGALAX is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_HPUSBSCSI is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_DABUSB is not set
+
+#
+# Video4Linux support is needed for USB Multimedia device support
+#
+
+#
+# USB Network adaptors
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+CONFIG_USB_RTL8150=y
+CONFIG_USB_USBNET=y
+
+#
+# USB Host-to-Host Cables
+#
+CONFIG_USB_ALI_M5632=y
+CONFIG_USB_AN2720=y
+CONFIG_USB_BELKIN=y
+CONFIG_USB_GENESYS=y
+CONFIG_USB_NET1080=y
+CONFIG_USB_PL2301=y
+
+#
+# Intelligent USB Devices/Gadgets
+#
+CONFIG_USB_ARMLINUX=y
+CONFIG_USB_EPSON2888=y
+CONFIG_USB_ZAURUS=y
+CONFIG_USB_CDCETHER=y
+
+#
+# USB Network Adapters
+#
+CONFIG_USB_AX8817X=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_TIGL is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# Synchronous Serial Interfaces (SSI)
+#
+# CONFIG_OMAP_UWIRE is not set
+
+#
+# MMC/SD Card support
+#
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BROKEN_RFD=y
+CONFIG_MMC_OMAP=y
+# CONFIG_MMC_OMAP16XX_BLOCK1 is not set
+CONFIG_MMC_OMAP16XX_BLOCK2=y
+
+#
+# Kernel hacking
+#
+CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
diff --git a/arch/arm/configs/omap_generic_1710_defconfig b/arch/arm/configs/omap_generic_1710_defconfig
new file mode 100644 (file)
index 0000000..579cff1
--- /dev/null
@@ -0,0 +1,853 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.9-rc3-omap1
+# Mon Oct  4 10:14:57 2004
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_IOMAP=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_HOTPLUG=y
+# CONFIG_IKCONFIG is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+# CONFIG_TINY_SHMEM is not set
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# System Type
+#
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_VERSATILE_PB is not set
+# CONFIG_ARCH_IMX is not set
+
+#
+# TI OMAP Implementations
+#
+
+#
+# OMAP Core Type
+#
+# CONFIG_ARCH_OMAP730 is not set
+# CONFIG_ARCH_OMAP15XX is not set
+CONFIG_ARCH_OMAP16XX=y
+CONFIG_ARCH_OMAP_OTG=y
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_INNOVATOR is not set
+# CONFIG_MACH_OMAP_H2 is not set
+# CONFIG_MACH_OMAP_H3 is not set
+# CONFIG_MACH_OMAP_H4 is not set
+# CONFIG_MACH_OMAP_OSK is not set
+CONFIG_MACH_OMAP_GENERIC=y
+
+#
+# OMAP Feature Selections
+#
+CONFIG_OMAP_BOOT_TAG=y
+# CONFIG_OMAP_BOOT_REASON is not set
+# CONFIG_OMAP_MUX is not set
+# CONFIG_OMAP_LL_DEBUG_UART1 is not set
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+CONFIG_OMAP_LL_DEBUG_UART3=y
+CONFIG_OMAP_ARM_192MHZ=y
+# CONFIG_OMAP_ARM_168MHZ is not set
+# CONFIG_OMAP_ARM_120MHZ is not set
+# CONFIG_OMAP_ARM_60MHZ is not set
+# CONFIG_OMAP_ARM_30MHZ is not set
+# CONFIG_OMAP_DSP is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+
+#
+# General setup
+#
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+
+#
+# PCMCIA/CardBus support
+#
+# CONFIG_PCMCIA is not set
+
+#
+# At least one math emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+CONFIG_PM=y
+# CONFIG_PREEMPT is not set
+# CONFIG_APM is not set
+CONFIG_ARTHUR=y
+CONFIG_CMDLINE="mem=64M console=tty0 console=ttyS2,115200 root=0801"
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+# CONFIG_NETLINK_DEV is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_NET_VENDOR_SMC=y
+# CONFIG_SMC91X is not set
+# CONFIG_SMC9194 is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+
+#
+# Obsolete Wireless cards support (pre-802.11)
+#
+# CONFIG_STRIP is not set
+# CONFIG_ATMEL is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+CONFIG_PPP=y
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_PPP_DEFLATE is not set
+# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPPOE is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_RAW is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_KEYBOARD_OMAP=y
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_8250_OMAP=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_OMAP_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V4=y
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+# CONFIG_ROOT_NFS is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+# CONFIG_EXPORTFS is not set
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+CONFIG_NLS_CODEPAGE_852=y
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+CONFIG_NLS_ISO8859_15=y
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# Misc devices
+#
+
+#
+# USB support
+#
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_BANDWIDTH=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_EHCI_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811HS is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_BLUETOOTH_TTY is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_RW_DETECT is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_HP8200e is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+
+#
+# USB Human Interface Devices (HID)
+#
+CONFIG_USB_HID=y
+CONFIG_USB_HIDINPUT=y
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_MTOUCH is not set
+# CONFIG_USB_EGALAX is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_HPUSBSCSI is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_DABUSB is not set
+
+#
+# Video4Linux support is needed for USB Multimedia device support
+#
+
+#
+# USB Network adaptors
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+CONFIG_USB_USBNET=y
+
+#
+# USB Host-to-Host Cables
+#
+CONFIG_USB_ALI_M5632=y
+# CONFIG_USB_AN2720 is not set
+# CONFIG_USB_BELKIN is not set
+# CONFIG_USB_GENESYS is not set
+# CONFIG_USB_NET1080 is not set
+# CONFIG_USB_PL2301 is not set
+
+#
+# Intelligent USB Devices/Gadgets
+#
+# CONFIG_USB_ARMLINUX is not set
+# CONFIG_USB_EPSON2888 is not set
+# CONFIG_USB_ZAURUS is not set
+# CONFIG_USB_CDCETHER is not set
+
+#
+# USB Network Adapters
+#
+CONFIG_USB_AX8817X=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_TIGL is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# Synchronous Serial Interfaces (SSI)
+#
+# CONFIG_OMAP_UWIRE is not set
+
+#
+# MMC/SD Card support
+#
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_BLOCK=y
+# CONFIG_MMC_BLOCK_BROKEN_RFD is not set
+CONFIG_MMC_OMAP=y
+# CONFIG_MMC_OMAP16XX_BLOCK1 is not set
+CONFIG_MMC_OMAP16XX_BLOCK2=y
+
+#
+# Kernel hacking
+#
+CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_SLAB=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_DEBUG_USER is not set
+CONFIG_DEBUG_WAITQ=y
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+CONFIG_SECURITY=y
+# CONFIG_SECURITY_NETWORK is not set
+CONFIG_SECURITY_CAPABILITIES=y
+# CONFIG_SECURITY_ROOTPLUG is not set
+# CONFIG_SECURITY_SELINUX is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
diff --git a/arch/arm/configs/omap_generic_2420_defconfig b/arch/arm/configs/omap_generic_2420_defconfig
new file mode 100644 (file)
index 0000000..94d4659
--- /dev/null
@@ -0,0 +1,555 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.13-rc6-omap1
+# Thu Aug 11 10:05:10 2005
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_HOTPLUG=y
+# CONFIG_IKCONFIG is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+
+#
+# System Type
+#
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_AAEC2000 is not set
+
+#
+# TI OMAP Implementations
+#
+# CONFIG_ARCH_OMAP1 is not set
+CONFIG_ARCH_OMAP2=y
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+CONFIG_OMAP_BOOT_TAG=y
+# CONFIG_OMAP_BOOT_REASON is not set
+# CONFIG_OMAP_GPIO_SWITCH is not set
+# CONFIG_OMAP_MUX is not set
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
+# CONFIG_OMAP_LL_DEBUG_UART1 is not set
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+CONFIG_OMAP_LL_DEBUG_UART3=y
+CONFIG_MACH_OMAP_GENERIC=y
+
+#
+# OMAP Core Type
+#
+CONFIG_ARCH_OMAP24XX=y
+CONFIG_ARCH_OMAP2420=y
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_H4 is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_V6=y
+CONFIG_CPU_32v6=y
+CONFIG_CPU_ABRT_EV6=y
+CONFIG_CPU_CACHE_V6=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V6=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+
+#
+# Bus support
+#
+CONFIG_ISA_DMA_API=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_SMP is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_NO_IDLE_HZ is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_LEDS=y
+# CONFIG_LEDS_TIMER is not set
+# CONFIG_LEDS_CPU is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x10C08000
+CONFIG_ZBOOT_ROM_BSS=0x10200000
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_CMDLINE=""
+# CONFIG_XIP_KERNEL is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+
+#
+# Networking
+#
+# CONFIG_NET is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+# CONFIG_I2C_SENSOR is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# Synchronous Serial Interfaces (SSI)
+#
+# CONFIG_OMAP_TSC2101 is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT2_FS_POSIX_ACL is not set
+# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+
+#
+# XFS support
+#
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+CONFIG_ROMFS_FS=y
+CONFIG_INOTIFY=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+# CONFIG_DEVPTS_FS_XATTR is not set
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_FS is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_WAITQ is not set
+CONFIG_DEBUG_ERRORS=y
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=y
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
index b0efd4ca993561437c70058477627efad7845cce..65be6fb97d43b0f8381cb83b3c021fb5680bf1a0 100644 (file)
@@ -1,11 +1,18 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.17
-# Thu Jun 29 15:25:18 2006
+# Linux kernel version: 2.6.20-rc3-omap1
+# Thu Jan  4 16:07:28 2007
 #
 CONFIG_ARM=y
+# CONFIG_GENERIC_TIME is not set
 CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
 CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_VECTORS_BASE=0xffff0000
@@ -16,7 +23,6 @@ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_BROKEN_ON_SMP=y
-CONFIG_LOCK_KERNEL=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
 
 #
@@ -26,17 +32,23 @@ CONFIG_LOCALVERSION=""
 CONFIG_LOCALVERSION_AUTO=y
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
 # CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
 # CONFIG_AUDIT is not set
 # CONFIG_IKCONFIG is not set
+CONFIG_SYSFS_DEPRECATED=y
 # CONFIG_RELAY is not set
 CONFIG_INITRAMFS_SOURCE=""
-CONFIG_UID16=y
 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
@@ -47,6 +59,8 @@ CONFIG_FUTEX=y
 CONFIG_EPOLL=y
 CONFIG_SHMEM=y
 CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
 # CONFIG_SLOB is not set
@@ -64,7 +78,10 @@ CONFIG_MODULE_UNLOAD=y
 #
 # Block layer
 #
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
 # CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
 
 #
 # IO Schedulers
@@ -86,7 +103,7 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
 # CONFIG_ARCH_INTEGRATOR is not set
 # CONFIG_ARCH_REALVIEW is not set
 # CONFIG_ARCH_VERSATILE is not set
-# CONFIG_ARCH_AT91RM9200 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
@@ -96,7 +113,9 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
 # CONFIG_ARCH_NETX is not set
 # CONFIG_ARCH_H720X is not set
 # CONFIG_ARCH_IMX is not set
-# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IOP13XX is not set
 # CONFIG_ARCH_IXP4XX is not set
 # CONFIG_ARCH_IXP2000 is not set
 # CONFIG_ARCH_IXP23XX is not set
@@ -121,17 +140,23 @@ CONFIG_ARCH_OMAP1=y
 # OMAP Feature Selections
 #
 # CONFIG_OMAP_RESET_CLOCKS is not set
+CONFIG_OMAP_BOOT_TAG=y
+# CONFIG_OMAP_BOOT_REASON is not set
+# CONFIG_OMAP_COMPONENT_VERSION is not set
+# CONFIG_OMAP_GPIO_SWITCH is not set
 CONFIG_OMAP_MUX=y
-# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_DEBUG=y
 CONFIG_OMAP_MUX_WARNINGS=y
-# CONFIG_OMAP_MPU_TIMER is not set
-CONFIG_OMAP_32K_TIMER=y
-CONFIG_OMAP_32K_TIMER_HZ=128
+# CONFIG_OMAP_STI is not set
+CONFIG_OMAP_MCBSP=y
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
 # CONFIG_OMAP_DM_TIMER is not set
 CONFIG_OMAP_LL_DEBUG_UART1=y
 # CONFIG_OMAP_LL_DEBUG_UART2 is not set
 # CONFIG_OMAP_LL_DEBUG_UART3 is not set
 CONFIG_OMAP_SERIAL_WAKE=y
+# CONFIG_OMAP_DSP is not set
 
 #
 # OMAP Core Type
@@ -155,10 +180,10 @@ CONFIG_MACH_OMAP_H2=y
 #
 # CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER is not set
 # CONFIG_OMAP_ARM_216MHZ is not set
-CONFIG_OMAP_ARM_192MHZ=y
+# CONFIG_OMAP_ARM_192MHZ is not set
 # CONFIG_OMAP_ARM_168MHZ is not set
 # CONFIG_OMAP_ARM_120MHZ is not set
-# CONFIG_OMAP_ARM_60MHZ is not set
+CONFIG_OMAP_ARM_60MHZ=y
 # CONFIG_OMAP_ARM_30MHZ is not set
 
 #
@@ -171,6 +196,8 @@ CONFIG_CPU_ABRT_EV5TJ=y
 CONFIG_CPU_CACHE_VIVT=y
 CONFIG_CPU_COPY_V4WB=y
 CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
 
 #
 # Processor Features
@@ -193,9 +220,9 @@ CONFIG_ARM_THUMB=y
 #
 # Kernel Features
 #
-CONFIG_PREEMPT=y
-CONFIG_NO_IDLE_HZ=y
-CONFIG_HZ=128
+# CONFIG_PREEMPT is not set
+# CONFIG_NO_IDLE_HZ is not set
+CONFIG_HZ=100
 # CONFIG_AEABI is not set
 # CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
 CONFIG_SELECT_MEMORY_MODEL=y
@@ -206,7 +233,10 @@ CONFIG_FLATMEM=y
 CONFIG_FLAT_NODE_MEM_MAP=y
 # CONFIG_SPARSEMEM_STATIC is not set
 CONFIG_SPLIT_PTLOCK_CPUS=4096
-# CONFIG_LEDS is not set
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_LEDS=y
+# CONFIG_LEDS_TIMER is not set
+# CONFIG_LEDS_CPU is not set
 CONFIG_ALIGNMENT_TRAP=y
 
 #
@@ -214,24 +244,13 @@ CONFIG_ALIGNMENT_TRAP=y
 #
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="mem=32M console=ttyS0,115200n8 root=0801 ro init=/bin/sh"
+CONFIG_CMDLINE="mem=32M console=ttyS0,115200n8 root=/dev/ram0 rw initrd=0x10600000,8M ramdisk_size=8192"
 # CONFIG_XIP_KERNEL is not set
 
 #
 # CPU Frequency scaling
 #
-CONFIG_CPU_FREQ=y
-CONFIG_CPU_FREQ_TABLE=y
-# CONFIG_CPU_FREQ_DEBUG is not set
-CONFIG_CPU_FREQ_STAT=y
-# CONFIG_CPU_FREQ_STAT_DETAILS is not set
-# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
-CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
-# CONFIG_CPU_FREQ_GOV_PERFORMANCE is not set
-# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
-CONFIG_CPU_FREQ_GOV_USERSPACE=y
-# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
-# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+# CONFIG_CPU_FREQ is not set
 
 #
 # Floating point emulation
@@ -259,6 +278,7 @@ CONFIG_BINFMT_AOUT=y
 CONFIG_PM=y
 # CONFIG_PM_LEGACY is not set
 # CONFIG_PM_DEBUG is not set
+# CONFIG_PM_SYSFS_DEPRECATED is not set
 # CONFIG_APM is not set
 
 #
@@ -275,6 +295,7 @@ CONFIG_PACKET=y
 CONFIG_UNIX=y
 CONFIG_XFRM=y
 # CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
 # CONFIG_IP_MULTICAST is not set
@@ -295,10 +316,13 @@ CONFIG_IP_PNP_BOOTP=y
 # CONFIG_INET_TUNNEL is not set
 CONFIG_INET_XFRM_MODE_TRANSPORT=y
 CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
 CONFIG_INET_DIAG=y
 CONFIG_INET_TCP_DIAG=y
 # CONFIG_TCP_CONG_ADVANCED is not set
-CONFIG_TCP_CONG_BIC=y
+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
@@ -328,7 +352,6 @@ CONFIG_TCP_CONG_BIC=y
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
 
@@ -356,6 +379,7 @@ CONFIG_TCP_CONG_BIC=y
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_FW_LOADER is not set
+CONFIG_DEBUG_DRIVER=y
 # CONFIG_SYS_HYPERVISOR is not set
 
 #
@@ -366,7 +390,85 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 #
 # Memory Technology Devices (MTD)
 #
-# CONFIG_MTD is not set
+CONFIG_MTD=y
+CONFIG_MTD_DEBUG=y
+CONFIG_MTD_DEBUG_VERBOSE=3
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_OMAP_NOR is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
 
 #
 # Parallel port support
@@ -384,51 +486,26 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CDROM_PKTCDVD is not set
-CONFIG_ATA_OVER_ETH=m
+# CONFIG_ATA_OVER_ETH is not set
 
 #
 # SCSI device support
 #
 # CONFIG_RAID_ATTRS is not set
-CONFIG_SCSI=y
-CONFIG_SCSI_PROC_FS=y
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_NETLINK is not set
 
 #
-# SCSI support type (disk, tape, CD-ROM)
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
 #
-# CONFIG_BLK_DEV_SD is not set
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_CHR_DEV_OSST is not set
-# CONFIG_BLK_DEV_SR is not set
-# CONFIG_CHR_DEV_SG is not set
-# CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
-# CONFIG_SCSI_MULTI_LUN is not set
-# CONFIG_SCSI_CONSTANTS is not set
-# CONFIG_SCSI_LOGGING is not set
-
-#
-# SCSI Transport Attributes
-#
-# CONFIG_SCSI_SPI_ATTRS is not set
-# CONFIG_SCSI_FC_ATTRS is not set
-# CONFIG_SCSI_ISCSI_ATTRS is not set
-# CONFIG_SCSI_SAS_ATTRS is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_ISCSI_TCP is not set
-# CONFIG_SCSI_SATA is not set
-# CONFIG_SCSI_DEBUG is not set
+# CONFIG_ATA is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -502,6 +579,7 @@ CONFIG_PPP=y
 # CONFIG_PPPOE is not set
 CONFIG_SLIP=y
 CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLHC=y
 # CONFIG_SLIP_SMART is not set
 # CONFIG_SLIP_MODE_SLIP6 is not set
 # CONFIG_SHAPER is not set
@@ -518,6 +596,7 @@ CONFIG_SLIP_COMPRESSED=y
 # Input device support
 #
 CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
 
 #
 # Userland interfaces
@@ -590,26 +669,66 @@ CONFIG_WATCHDOG_NOWAYOUT=y
 # Watchdog Device Drivers
 #
 # CONFIG_SOFT_WATCHDOG is not set
-# CONFIG_HW_RANDOM is not set
-# CONFIG_NVRAM is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
+# CONFIG_OMAP_WATCHDOG is not set
 
 #
-# Ftape, the floppy tape device driver
+# USB-based Watchdog Cards
 #
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_HW_RANDOM=m
+CONFIG_HW_RANDOM_OMAP=m
+# CONFIG_OMAP_RNG is not set
+# CONFIG_NVRAM is not set
+CONFIG_OMAP_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
 # CONFIG_RAW_DRIVER is not set
 
 #
 # TPM devices
 #
 # CONFIG_TCG_TPM is not set
-# CONFIG_TELCLOCK is not set
 
 #
 # I2C support
 #
-# CONFIG_I2C is not set
+CONFIG_I2C=y
+# CONFIG_I2C_CHARDEV is not set
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+CONFIG_ISP1301_OMAP=y
+CONFIG_TPS65010=y
+# CONFIG_SENSORS_TLV320AIC23 is not set
+# CONFIG_GPIOEXPANDER_OMAP is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
 
 #
 # SPI support
@@ -620,6 +739,7 @@ CONFIG_WATCHDOG_NOWAYOUT=y
 #
 # Dallas's 1-wire bus
 #
+# CONFIG_W1 is not set
 
 #
 # Hardware Monitoring support
@@ -627,12 +747,50 @@ CONFIG_WATCHDOG_NOWAYOUT=y
 CONFIG_HWMON=y
 # CONFIG_HWMON_VID is not set
 # CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
 # CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
 # CONFIG_HWMON_DEBUG_CHIP is not set
 
 #
 # Misc devices
 #
+# CONFIG_TIFM_CORE is not set
 
 #
 # LED devices
@@ -651,12 +809,12 @@ CONFIG_HWMON=y
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
-CONFIG_VIDEO_V4L2=y
 
 #
 # Digital Video Broadcasting Devices
 #
 # CONFIG_DVB is not set
+# CONFIG_USB_DABUSB is not set
 
 #
 # Graphics support
@@ -672,6 +830,12 @@ CONFIG_FB_MODE_HELPERS=y
 # CONFIG_FB_TILEBLITTING is not set
 # CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_VIRTUAL is not set
+CONFIG_FB_OMAP=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_LCD_MIPID is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=2
+# CONFIG_FB_OMAP_DMA_TUNE is not set
 
 #
 # Console display driver support
@@ -680,17 +844,9 @@ CONFIG_FB_MODE_HELPERS=y
 CONFIG_DUMMY_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
 # CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
-CONFIG_FONTS=y
+# CONFIG_FONTS is not set
 CONFIG_FONT_8x8=y
 CONFIG_FONT_8x16=y
-# CONFIG_FONT_6x11 is not set
-# CONFIG_FONT_7x14 is not set
-# CONFIG_FONT_PEARL_8x8 is not set
-# CONFIG_FONT_ACORN_8x8 is not set
-# CONFIG_FONT_MINI_4x6 is not set
-# CONFIG_FONT_SUN8x16 is not set
-# CONFIG_FONT_SUN12x22 is not set
-# CONFIG_FONT_10x18 is not set
 
 #
 # Logo configuration
@@ -704,19 +860,12 @@ CONFIG_LOGO_LINUX_CLUT224=y
 #
 # Sound
 #
-CONFIG_SOUND=y
-
-#
-# Advanced Linux Sound Architecture
-#
-# CONFIG_SND is not set
+# CONFIG_SOUND is not set
 
 #
-# Open Sound System
+# HID Devices
 #
-CONFIG_SOUND_PRIME=y
-# CONFIG_SOUND_MSNDCLAS is not set
-# CONFIG_SOUND_MSNDPIN is not set
+CONFIG_HID=y
 
 #
 # USB support
@@ -724,16 +873,142 @@ CONFIG_SOUND_PRIME=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
 # CONFIG_USB_ARCH_HAS_EHCI is not set
-# CONFIG_USB is not set
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_SUSPEND=y
+# CONFIG_USB_MULTITHREAD_PROBE is not set
+CONFIG_USB_OTG=y
+CONFIG_USB_OTG_WHITELIST=y
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_MUSB_HDRC is not set
+# CONFIG_USB_GADGET_MUSB_HDRC is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
 
 #
 # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
 #
 
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Input Devices
+#
+# CONFIG_USB_HID is not set
+
+#
+# USB HID Boot Protocol drivers
+#
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_ACECAD is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_TOUCHSCREEN is not set
+# CONFIG_USB_YEALINK is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
+# CONFIG_USB_KEYSPAN_REMOTE is not set
+# CONFIG_USB_APPLETOUCH is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET_MII is not set
+# CONFIG_USB_USBNET is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+CONFIG_USB_TEST=y
+
+#
+# USB DSL modem support
+#
+
 #
 # USB Gadget Support
 #
-# CONFIG_USB_GADGET is not set
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+CONFIG_USB_GADGET_OMAP=y
+CONFIG_USB_OMAP=y
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+# CONFIG_USB_GADGET_DUALSPEED is not set
+# CONFIG_USB_ZERO is not set
+CONFIG_USB_ETH=y
+CONFIG_USB_ETH_RNDIS=y
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
 
 #
 # MMC/SD Card support
@@ -746,6 +1021,17 @@ CONFIG_USB_ARCH_HAS_OHCI=y
 CONFIG_RTC_LIB=y
 # CONFIG_RTC_CLASS is not set
 
+#
+# Synchronous Serial Interfaces (SSI)
+#
+CONFIG_OMAP_UWIRE=y
+# CONFIG_OMAP_TSC2101 is not set
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
 #
 # File systems
 #
@@ -753,10 +1039,12 @@ CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
 # CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 CONFIG_ROMFS_FS=y
@@ -787,6 +1075,7 @@ CONFIG_FAT_DEFAULT_CODEPAGE=437
 # Pseudo filesystems
 #
 CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
 CONFIG_SYSFS=y
 # CONFIG_TMPFS is not set
 # CONFIG_HUGETLB_PAGE is not set
@@ -803,6 +1092,15 @@ CONFIG_RAMFS=y
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
 CONFIG_CRAMFS=y
 # CONFIG_VXFS_FS is not set
 # CONFIG_HPFS_FS is not set
@@ -814,18 +1112,15 @@ CONFIG_CRAMFS=y
 # Network File Systems
 #
 CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-# CONFIG_NFS_V3_ACL is not set
-CONFIG_NFS_V4=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_V4 is not set
 # CONFIG_NFS_DIRECTIO is not set
 # CONFIG_NFSD is not set
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
 CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=y
-CONFIG_SUNRPC_GSS=y
-CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_CIFS is not set
@@ -884,6 +1179,11 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_NLS_KOI8_U is not set
 # CONFIG_NLS_UTF8 is not set
 
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
 #
 # Profiling support
 #
@@ -893,14 +1193,34 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
 # CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
 CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_RWSEMS is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_BUGVERBOSE=y
-# CONFIG_DEBUG_FS is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
 CONFIG_FRAME_POINTER=y
-# CONFIG_UNWIND_INFO is not set
-# CONFIG_DEBUG_USER is not set
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_LL is not set
 
 #
 # Security options
@@ -911,41 +1231,17 @@ CONFIG_FRAME_POINTER=y
 #
 # Cryptographic options
 #
-CONFIG_CRYPTO=y
-# CONFIG_CRYPTO_HMAC is not set
-# CONFIG_CRYPTO_NULL is not set
-# CONFIG_CRYPTO_MD4 is not set
-CONFIG_CRYPTO_MD5=y
-# CONFIG_CRYPTO_SHA1 is not set
-# CONFIG_CRYPTO_SHA256 is not set
-# CONFIG_CRYPTO_SHA512 is not set
-# CONFIG_CRYPTO_WP512 is not set
-# CONFIG_CRYPTO_TGR192 is not set
-CONFIG_CRYPTO_DES=y
-# CONFIG_CRYPTO_BLOWFISH is not set
-# CONFIG_CRYPTO_TWOFISH is not set
-# CONFIG_CRYPTO_SERPENT is not set
-# CONFIG_CRYPTO_AES is not set
-# CONFIG_CRYPTO_CAST5 is not set
-# CONFIG_CRYPTO_CAST6 is not set
-# CONFIG_CRYPTO_TEA is not set
-# CONFIG_CRYPTO_ARC4 is not set
-# CONFIG_CRYPTO_KHAZAD is not set
-# CONFIG_CRYPTO_ANUBIS is not set
-# CONFIG_CRYPTO_DEFLATE is not set
-# CONFIG_CRYPTO_MICHAEL_MIC is not set
-# CONFIG_CRYPTO_CRC32C is not set
-# CONFIG_CRYPTO_TEST is not set
-
-#
-# Hardware crypto devices
-#
+# CONFIG_CRYPTO is not set
 
 #
 # Library routines
 #
+CONFIG_BITREVERSE=y
 # CONFIG_CRC_CCITT is not set
 # CONFIG_CRC16 is not set
 CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_IOMAP_COPY=y
diff --git a/arch/arm/configs/omap_h3_1710_defconfig b/arch/arm/configs/omap_h3_1710_defconfig
new file mode 100644 (file)
index 0000000..5e2c5b1
--- /dev/null
@@ -0,0 +1,1048 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.14-rc4-omap1
+# Tue Oct 18 17:58:27 2005
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+
+#
+# System Type
+#
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_AAEC2000 is not set
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+CONFIG_ARCH_OMAP1=y
+# CONFIG_ARCH_OMAP2 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+# CONFIG_OMAP_BOOT_TAG is not set
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_WARNINGS=y
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
+# CONFIG_OMAP_DM_TIMER is not set
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+
+#
+# OMAP Core Type
+#
+# CONFIG_ARCH_OMAP730 is not set
+# CONFIG_ARCH_OMAP15XX is not set
+CONFIG_ARCH_OMAP16XX=y
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_INNOVATOR is not set
+# CONFIG_MACH_OMAP_H2 is not set
+CONFIG_MACH_OMAP_H3=y
+# CONFIG_MACH_OMAP_OSK is not set
+# CONFIG_MACH_OMAP_GENERIC is not set
+
+#
+# OMAP CPU Speed
+#
+# CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER is not set
+# CONFIG_OMAP_ARM_216MHZ is not set
+# CONFIG_OMAP_ARM_192MHZ is not set
+CONFIG_OMAP_ARM_168MHZ=y
+# CONFIG_OMAP_ARM_120MHZ is not set
+# CONFIG_OMAP_ARM_60MHZ is not set
+# CONFIG_OMAP_ARM_30MHZ is not set
+# CONFIG_OMAP_DSP is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+
+#
+# Bus support
+#
+CONFIG_ISA_DMA_API=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+# CONFIG_NO_IDLE_HZ is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_LEDS=y
+# CONFIG_LEDS_TIMER is not set
+# CONFIG_LEDS_CPU is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x10C08000
+CONFIG_ZBOOT_ROM_BSS=0x10200000
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_CMDLINE="mem=32M console=ttyS0,115200n8 initrd=0x10A00000,8M root=/dev/ram0 rw ip=dhcp devfs=mount"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+CONFIG_IRDA=y
+
+#
+# IrDA protocols
+#
+# CONFIG_IRLAN is not set
+# CONFIG_IRNET is not set
+# CONFIG_IRCOMM is not set
+# CONFIG_IRDA_ULTRA is not set
+
+#
+# IrDA options
+#
+# CONFIG_IRDA_CACHE_LAST_LSAP is not set
+# CONFIG_IRDA_FAST_RR is not set
+# CONFIG_IRDA_DEBUG is not set
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+# CONFIG_IRTTY_SIR is not set
+
+#
+# Dongle support
+#
+
+#
+# Old SIR device drivers
+#
+# CONFIG_IRPORT_SIR is not set
+
+#
+# Old Serial dongle support
+#
+
+#
+# FIR device drivers
+#
+# CONFIG_USB_IRDA is not set
+# CONFIG_SIGMATEL_FIR is not set
+# CONFIG_NSC_FIR is not set
+# CONFIG_WINBOND_FIR is not set
+CONFIG_OMAP1610_IR=y
+# CONFIG_SMC_IRCC_FIR is not set
+# CONFIG_ALI_FIR is not set
+# CONFIG_VIA_FIR is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_SMC91X=y
+# CONFIG_DM9000 is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+CONFIG_PPP=y
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_PPP_DEFLATE is not set
+# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPPOE is not set
+CONFIG_SLIP=y
+CONFIG_SLIP_COMPRESSED=y
+# CONFIG_SLIP_SMART is not set
+# CONFIG_SLIP_MODE_SLIP6 is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_KEYBOARD_OMAP=y
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+# CONFIG_OMAP_WATCHDOG is not set
+# CONFIG_OMAP_RNG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+CONFIG_OMAP_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+# CONFIG_I2C_CHARDEV is not set
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_PCA_ISA is not set
+CONFIG_I2C_OMAP=y
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+CONFIG_ISP1301_OMAP=m
+CONFIG_TPS65010=y
+# CONFIG_SENSORS_TLV320AIC23 is not set
+CONFIG_GPIOEXPANDER_OMAP=y
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=y
+
+#
+# Video For Linux
+#
+
+#
+# Video Adapters
+#
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_SAA5246A is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_OVCAMCHIP is not set
+# CONFIG_VIDEO_OMAP_CAMERA is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_MAESTRO is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+CONFIG_FB_SOFT_CURSOR=y
+# CONFIG_FB_MACMODES is not set
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_OMAP=y
+CONFIG_FB_OMAP_LCDC_INTERNAL=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_DMA_TUNE is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+# CONFIG_SND is not set
+
+#
+# Open Sound System
+#
+CONFIG_SOUND_PRIME=y
+# CONFIG_SOUND_OMAP is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_OSS is not set
+# CONFIG_SOUND_TVMIXER is not set
+# CONFIG_SOUND_AD1980 is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB=m
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=m
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_OBSOLETE_OSS_USB_DRIVER is not set
+# CONFIG_USB_BLUETOOTH_TTY is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
+# CONFIG_USB_STORAGE is not set
+
+#
+# USB Input Devices
+#
+# CONFIG_USB_HID is not set
+
+#
+# USB HID Boot Protocol drivers
+#
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_ACECAD is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_MTOUCH is not set
+# CONFIG_USB_ITMTOUCH is not set
+# CONFIG_USB_EGALAX is not set
+# CONFIG_USB_YEALINK is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_KEYSPAN_REMOTE is not set
+# CONFIG_USB_APPLETOUCH is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_DABUSB is not set
+# CONFIG_USB_VICAM is not set
+# CONFIG_USB_DSBR is not set
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_KONICAWC is not set
+# CONFIG_USB_OV511 is not set
+# CONFIG_USB_SE401 is not set
+# CONFIG_USB_SN9C102 is not set
+# CONFIG_USB_STV680 is not set
+# CONFIG_USB_PWC is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGETKIT is not set
+# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_LD is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_BLOCK=y
+# CONFIG_MMC_BLOCK_BROKEN_RFD is not set
+# CONFIG_MMC_BULKTRANSFER is not set
+CONFIG_MMC_OMAP=y
+# CONFIG_MMC_WBSD is not set
+
+#
+# Synchronous Serial Interfaces (SSI)
+#
+CONFIG_OMAP_UWIRE=y
+# CONFIG_OMAP_TSC2101 is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT2_FS_POSIX_ACL is not set
+# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+CONFIG_ROMFS_FS=y
+CONFIG_INOTIFY=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_RELAYFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_FS is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_WAITQ is not set
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_LL is not set
+# CONFIG_DEBUG_ICEDCC is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
diff --git a/arch/arm/configs/omap_h4_2420_defconfig b/arch/arm/configs/omap_h4_2420_defconfig
new file mode 100644 (file)
index 0000000..69e3c94
--- /dev/null
@@ -0,0 +1,1073 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.17-rc5-omap1
+# Tue Jun 13 22:02:07 2006
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_VECTORS_BASE=0xffff0000
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_UID16=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+CONFIG_OBSOLETE_INTERMODULE=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+# CONFIG_BLK_DEV_IO_TRACE is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# System Type
+#
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_AT91RM9200 is not set
+
+#
+# TI OMAP Implementations
+#
+# CONFIG_ARCH_OMAP1 is not set
+CONFIG_ARCH_OMAP2=y
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+CONFIG_OMAP_BOOT_TAG=y
+# CONFIG_OMAP_BOOT_REASON is not set
+# CONFIG_OMAP_COMPONENT_VERSION is not set
+# CONFIG_OMAP_GPIO_SWITCH is not set
+CONFIG_OMAP_MUX=y
+CONFIG_OMAP_MUX_DEBUG=y
+CONFIG_OMAP_MUX_WARNINGS=y
+# CONFIG_OMAP_STI is not set
+CONFIG_OMAP_MCBSP=y
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
+CONFIG_OMAP_DM_TIMER=y
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+# CONFIG_MACH_OMAP_GENERIC is not set
+
+#
+# OMAP Core Type
+#
+CONFIG_ARCH_OMAP24XX=y
+CONFIG_ARCH_OMAP2420=y
+
+#
+# OMAP Board Type
+#
+CONFIG_MACH_OMAP_H4=y
+# CONFIG_MACH_OMAP_APOLLON is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_V6=y
+# CONFIG_CPU_32v6K is not set
+CONFIG_CPU_32v6=y
+CONFIG_CPU_ABRT_EV6=y
+CONFIG_CPU_CACHE_V6=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V6=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+
+#
+# Bus support
+#
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+# CONFIG_NO_IDLE_HZ is not set
+CONFIG_HZ=100
+# CONFIG_AEABI is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/ram0 rw console=ttyS0,115200n8 initrd=0x80600000,8M ramdisk_size=8192"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_MISC=y
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+# CONFIG_APM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+CONFIG_IRDA=y
+
+#
+# IrDA protocols
+#
+CONFIG_IRLAN=y
+CONFIG_IRCOMM=y
+# CONFIG_IRDA_ULTRA is not set
+
+#
+# IrDA options
+#
+# CONFIG_IRDA_CACHE_LAST_LSAP is not set
+# CONFIG_IRDA_FAST_RR is not set
+# CONFIG_IRDA_DEBUG is not set
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+# CONFIG_IRTTY_SIR is not set
+
+#
+# Dongle support
+#
+
+#
+# Old SIR device drivers
+#
+# CONFIG_IRPORT_SIR is not set
+
+#
+# Old Serial dongle support
+#
+
+#
+# FIR device drivers
+#
+CONFIG_OMAP_IR=y
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+CONFIG_MTD_OMAP_NOR=y
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+# CONFIG_MTD_ONENAND_SYNC_READ is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=16384
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_SMC91X=y
+# CONFIG_DM9000 is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_KEYBOARD_OMAP=y
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_OMAP_WATCHDOG=y
+# CONFIG_OMAP_RNG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+# CONFIG_I2C_CHARDEV is not set
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_PCA_ISA is not set
+CONFIG_I2C_OMAP=y
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_SENSORS_TLV320AIC23 is not set
+CONFIG_GPIOEXPANDER_OMAP=y
+CONFIG_MENELAUS=y
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Misc devices
+#
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_V4L2=y
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_MACMODES is not set
+CONFIG_FB_FIRMWARE_EDID=y
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_OMAP=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_LCD_LPH8923 is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_OMAP=y
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+
+#
+# Synchronous Serial Interfaces (SSI)
+#
+# CONFIG_OMAP_TSC2101 is not set
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_QUOTA=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_DEBUG_VM is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_UNWIND_INFO is not set
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_ERRORS is not set
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/arm/configs/omap_innovator_1510_defconfig b/arch/arm/configs/omap_innovator_1510_defconfig
new file mode 100644 (file)
index 0000000..28c087e
--- /dev/null
@@ -0,0 +1,1082 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.14-rc4-omap1
+# Tue Oct 18 17:55:19 2005
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_AAEC2000 is not set
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP1=y
+# CONFIG_ARCH_OMAP2 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+# CONFIG_OMAP_BOOT_TAG is not set
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_WARNINGS=y
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+
+#
+# OMAP Core Type
+#
+# CONFIG_ARCH_OMAP730 is not set
+CONFIG_ARCH_OMAP15XX=y
+# CONFIG_ARCH_OMAP16XX is not set
+
+#
+# OMAP Board Type
+#
+CONFIG_MACH_OMAP_INNOVATOR=y
+# CONFIG_MACH_VOICEBLUE is not set
+# CONFIG_MACH_NETSTAR is not set
+# CONFIG_MACH_OMAP_PALMTE is not set
+# CONFIG_MACH_OMAP_GENERIC is not set
+
+#
+# OMAP CPU Speed
+#
+# CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER is not set
+CONFIG_OMAP_ARM_168MHZ=y
+# CONFIG_OMAP_ARM_150MHZ is not set
+# CONFIG_OMAP_ARM_120MHZ is not set
+# CONFIG_OMAP_ARM_60MHZ is not set
+# CONFIG_OMAP_ARM_30MHZ is not set
+# CONFIG_OMAP_DSP is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM925T=y
+CONFIG_CPU_32v4=y
+CONFIG_CPU_ABRT_EV4T=y
+CONFIG_CPU_CACHE_V4WT=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+CONFIG_CPU_DCACHE_WRITETHROUGH=y
+
+#
+# Bus support
+#
+CONFIG_ISA_DMA_API=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_PREEMPT=y
+# CONFIG_NO_IDLE_HZ is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_LEDS=y
+# CONFIG_LEDS_TIMER is not set
+# CONFIG_LEDS_CPU is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="console=ttyS0,115200n8 root=/dev/nfs ip=bootp noinitrd"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_APM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=y
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_SMC91X=y
+# CONFIG_DM9000 is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+CONFIG_PPP=y
+CONFIG_PPP_MULTILINK=y
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=y
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_BSDCOMP=y
+# CONFIG_PPPOE is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=240
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=320
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_KEYBOARD_OMAP=y
+CONFIG_OMAP_PS2=m
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+CONFIG_OMAP_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+# CONFIG_I2C_CHARDEV is not set
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_PCA_ISA is not set
+# CONFIG_I2C_OMAP is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+CONFIG_FB_SOFT_CURSOR=y
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_OMAP=y
+CONFIG_FB_OMAP_LCDC_INTERNAL=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_DMA_TUNE is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_SUSPEND=y
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_BLUETOOTH_TTY is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_DPCM=y
+# CONFIG_USB_STORAGE_USBAT is not set
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+CONFIG_USB_HIDINPUT=y
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_ACECAD is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_MTOUCH is not set
+# CONFIG_USB_ITMTOUCH is not set
+# CONFIG_USB_EGALAX is not set
+# CONFIG_USB_YEALINK is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_KEYSPAN_REMOTE is not set
+# CONFIG_USB_APPLETOUCH is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_DABUSB is not set
+
+#
+# Video4Linux support is needed for USB Multimedia device support
+#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+CONFIG_USB_RTL8150=y
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_AX8817X=y
+CONFIG_USB_NET_CDCETHER=y
+# CONFIG_USB_NET_GL620A is not set
+CONFIG_USB_NET_NET1080=y
+# CONFIG_USB_NET_PLUSB is not set
+# CONFIG_USB_NET_RNDIS_HOST is not set
+# CONFIG_USB_NET_CDC_SUBSET is not set
+CONFIG_USB_NET_ZAURUS=y
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGETKIT is not set
+# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BROKEN_RFD=y
+# CONFIG_MMC_BULKTRANSFER is not set
+CONFIG_MMC_OMAP=y
+# CONFIG_MMC_WBSD is not set
+
+#
+# Synchronous Serial Interfaces (SSI)
+#
+# CONFIG_OMAP_UWIRE is not set
+# CONFIG_OMAP_TSC2101 is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+CONFIG_AUTOFS_FS=y
+CONFIG_AUTOFS4_FS=y
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_RELAYFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_PREEMPT=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/arm/configs/omap_innovator_1610_defconfig b/arch/arm/configs/omap_innovator_1610_defconfig
new file mode 100644 (file)
index 0000000..7baf3bc
--- /dev/null
@@ -0,0 +1,750 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.14-rc4-omap1
+# Tue Oct 18 17:55:48 2005
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_AAEC2000 is not set
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+CONFIG_ARCH_OMAP1=y
+# CONFIG_ARCH_OMAP2 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+# CONFIG_OMAP_BOOT_TAG is not set
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_WARNINGS=y
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
+# CONFIG_OMAP_DM_TIMER is not set
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+
+#
+# OMAP Core Type
+#
+# CONFIG_ARCH_OMAP730 is not set
+# CONFIG_ARCH_OMAP15XX is not set
+CONFIG_ARCH_OMAP16XX=y
+
+#
+# OMAP Board Type
+#
+CONFIG_MACH_OMAP_INNOVATOR=y
+# CONFIG_MACH_OMAP_H2 is not set
+# CONFIG_MACH_OMAP_H3 is not set
+# CONFIG_MACH_OMAP_OSK is not set
+# CONFIG_MACH_OMAP_GENERIC is not set
+
+#
+# OMAP CPU Speed
+#
+# CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER is not set
+# CONFIG_OMAP_ARM_216MHZ is not set
+CONFIG_OMAP_ARM_192MHZ=y
+# CONFIG_OMAP_ARM_168MHZ is not set
+# CONFIG_OMAP_ARM_120MHZ is not set
+# CONFIG_OMAP_ARM_60MHZ is not set
+# CONFIG_OMAP_ARM_30MHZ is not set
+# CONFIG_OMAP_DSP is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+CONFIG_CPU_DCACHE_WRITETHROUGH=y
+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+
+#
+# Bus support
+#
+CONFIG_ISA_DMA_API=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+# CONFIG_NO_IDLE_HZ is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="mem=32M console=tty0 console=ttyS0,115200 initrd=0x10200000,8M root=/dev/ram0 rw"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=m
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_SMC91X=y
+# CONFIG_DM9000 is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+CONFIG_PPP=y
+CONFIG_PPP_MULTILINK=y
+# CONFIG_PPP_FILTER is not set
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_PPP_DEFLATE is not set
+# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPPOE is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_KEYBOARD_OMAP=y
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_OMAP_RNG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_OMAP_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+CONFIG_FB_SOFT_CURSOR=y
+# CONFIG_FB_MACMODES is not set
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_OMAP=y
+CONFIG_FB_OMAP_LCDC_INTERNAL=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_DMA_TUNE is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# Synchronous Serial Interfaces (SSI)
+#
+# CONFIG_OMAP_UWIRE is not set
+# CONFIG_OMAP_TSC2101 is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+CONFIG_AUTOFS_FS=y
+CONFIG_AUTOFS4_FS=y
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_RELAYFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+# CONFIG_ROOT_NFS is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_FRAME_POINTER=y
+# CONFIG_DEBUG_USER is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
diff --git a/arch/arm/configs/omap_osk_5912_defconfig b/arch/arm/configs/omap_osk_5912_defconfig
new file mode 100644 (file)
index 0000000..d190420
--- /dev/null
@@ -0,0 +1,995 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.14-rc4-omap1
+# Tue Oct 18 17:56:19 2005
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_HOTPLUG=y
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_AAEC2000 is not set
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+CONFIG_ARCH_OMAP1=y
+# CONFIG_ARCH_OMAP2 is not set
+
+#
+# OMAP Feature Selections
+#
+CONFIG_OMAP_RESET_CLOCKS=y
+# CONFIG_OMAP_BOOT_TAG is not set
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_WARNINGS=y
+# CONFIG_OMAP_MPU_TIMER is not set
+CONFIG_OMAP_32K_TIMER=y
+CONFIG_OMAP_32K_TIMER_HZ=128
+# CONFIG_OMAP_DM_TIMER is not set
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+
+#
+# OMAP Core Type
+#
+# CONFIG_ARCH_OMAP730 is not set
+# CONFIG_ARCH_OMAP15XX is not set
+CONFIG_ARCH_OMAP16XX=y
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_INNOVATOR is not set
+# CONFIG_MACH_OMAP_H2 is not set
+# CONFIG_MACH_OMAP_H3 is not set
+CONFIG_MACH_OMAP_OSK=y
+# CONFIG_OMAP_OSK_MISTRAL is not set
+# CONFIG_MACH_OMAP_GENERIC is not set
+
+#
+# OMAP CPU Speed
+#
+# CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER is not set
+# CONFIG_OMAP_ARM_216MHZ is not set
+CONFIG_OMAP_ARM_192MHZ=y
+# CONFIG_OMAP_ARM_168MHZ is not set
+# CONFIG_OMAP_ARM_120MHZ is not set
+# CONFIG_OMAP_ARM_60MHZ is not set
+# CONFIG_OMAP_ARM_30MHZ is not set
+# CONFIG_OMAP_DSP is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+
+#
+# Bus support
+#
+CONFIG_ISA_DMA_API=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+CONFIG_PCCARD=y
+# CONFIG_PCMCIA_DEBUG is not set
+CONFIG_PCMCIA=y
+CONFIG_PCMCIA_LOAD_CIS=y
+CONFIG_PCMCIA_IOCTL=y
+
+#
+# PC-card bridges
+#
+CONFIG_OMAP_CF=y
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+CONFIG_NO_IDLE_HZ=y
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="mem=32M console=ttyS0,115200 initrd=0x10400000,8M root=/dev/ram0 rw"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_APM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=m
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_XIP is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_EDB7312 is not set
+CONFIG_MTD_OMAP_NOR=y
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=m
+CONFIG_BLK_DEV_IDE=m
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=m
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECS=m
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_IDE_GENERIC is not set
+# CONFIG_IDE_ARM is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_SMC91X=y
+# CONFIG_DM9000 is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# PCMCIA network device support
+#
+# CONFIG_NET_PCMCIA is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+CONFIG_PPP=y
+CONFIG_PPP_MULTILINK=y
+# CONFIG_PPP_FILTER is not set
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_PPP_DEFLATE is not set
+# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPPOE is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_KEYBOARD_OMAP=y
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+CONFIG_TOUCHSCREEN_OMAP=y
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_CS is not set
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_OMAP_RNG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_OMAP_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+
+#
+# PCMCIA character devices
+#
+# CONFIG_SYNCLINK_CS is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_PCA_ISA is not set
+CONFIG_I2C_OMAP=y
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_ISP1301_OMAP is not set
+CONFIG_TPS65010=y
+# CONFIG_SENSORS_TLV320AIC23 is not set
+# CONFIG_GPIOEXPANDER_OMAP is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+CONFIG_FB_SOFT_CURSOR=y
+# CONFIG_FB_MACMODES is not set
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_OMAP=y
+CONFIG_FB_OMAP_LCDC_INTERNAL=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_DMA_TUNE is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+# CONFIG_FONT_8x16 is not set
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# Synchronous Serial Interfaces (SSI)
+#
+CONFIG_OMAP_UWIRE=y
+CONFIG_OMAP_TSC2101=y
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+CONFIG_AUTOFS_FS=y
+CONFIG_AUTOFS4_FS=y
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_RELAYFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=m
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=m
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_FRAME_POINTER=y
+# CONFIG_DEBUG_USER is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/arm/configs/omap_perseus2_730_defconfig b/arch/arm/configs/omap_perseus2_730_defconfig
new file mode 100644 (file)
index 0000000..7e08ad3
--- /dev/null
@@ -0,0 +1,811 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.14-rc4-omap1
+# Tue Oct 18 17:57:11 2005
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_AAEC2000 is not set
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+CONFIG_ARCH_OMAP1=y
+# CONFIG_ARCH_OMAP2 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+# CONFIG_OMAP_BOOT_TAG is not set
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_WARNINGS=y
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+
+#
+# OMAP Core Type
+#
+CONFIG_ARCH_OMAP730=y
+# CONFIG_ARCH_OMAP15XX is not set
+# CONFIG_ARCH_OMAP16XX is not set
+
+#
+# OMAP Board Type
+#
+CONFIG_MACH_OMAP_PERSEUS2=y
+
+#
+# OMAP CPU Speed
+#
+# CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER is not set
+# CONFIG_OMAP_ARM_195MHZ is not set
+CONFIG_OMAP_ARM_182MHZ=y
+# CONFIG_OMAP_ARM_168MHZ is not set
+# CONFIG_OMAP_ARM_120MHZ is not set
+# CONFIG_OMAP_ARM_60MHZ is not set
+# CONFIG_OMAP_ARM_30MHZ is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+
+#
+# Bus support
+#
+CONFIG_ISA_DMA_API=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_PREEMPT=y
+# CONFIG_NO_IDLE_HZ is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_LEDS=y
+CONFIG_LEDS_TIMER=y
+CONFIG_LEDS_CPU=y
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="mem=32M console=ttyS0,115200 ip=dhcp"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_APM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_XIP is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_EDB7312 is not set
+CONFIG_MTD_OMAP_NOR=y
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+CONFIG_MTD_NAND_OMAP=y
+# CONFIG_MTD_NAND_TOTO is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_SMC91X=y
+# CONFIG_DM9000 is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_KEYBOARD_OMAP=y
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+CONFIG_OMAP_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+CONFIG_FB_SOFT_CURSOR=y
+# CONFIG_FB_MACMODES is not set
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_OMAP=y
+CONFIG_FB_OMAP_LCDC_INTERNAL=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_DMA_TUNE is not set
+CONFIG_FB_VIRTUAL=y
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE is not set
+
+#
+# Logo configuration
+#
+# CONFIG_LOGO is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# Synchronous Serial Interfaces (SSI)
+#
+CONFIG_OMAP_UWIRE=y
+# CONFIG_OMAP_TSC2101 is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_RELAYFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_FRAME_POINTER=y
+# CONFIG_DEBUG_USER is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/arm/configs/palmte_defconfig b/arch/arm/configs/palmte_defconfig
new file mode 100644 (file)
index 0000000..26a8999
--- /dev/null
@@ -0,0 +1,648 @@
+#
+# Palm Tungsten E default kernel configuration
+# Created by Romain Goyet <palmtelinux-developpers@lists.sf.net>
+# Linux kernel version: 2.6.13-rc6-omap1
+# Fri Aug 26 16:01:18 2005
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_CLEAN_COMPILE is not set
+CONFIG_BROKEN=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+CONFIG_SYSCTL=y
+CONFIG_HOTPLUG=y
+# CONFIG_IKCONFIG is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# System Type
+#
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_AAEC2000 is not set
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP1=y
+# CONFIG_ARCH_OMAP2 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+# CONFIG_OMAP_BOOT_TAG is not set
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_WARNINGS=y
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+
+#
+# OMAP Core Type
+#
+# CONFIG_ARCH_OMAP730 is not set
+CONFIG_ARCH_OMAP15XX=y
+# CONFIG_ARCH_OMAP16XX is not set
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_INNOVATOR is not set
+# CONFIG_MACH_VOICEBLUE is not set
+# CONFIG_MACH_NETSTAR is not set
+CONFIG_MACH_OMAP_PALMTE=y
+# CONFIG_MACH_OMAP_GENERIC is not set
+
+#
+# OMAP CPU Speed
+#
+CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER=y
+# CONFIG_OMAP_ARM_168MHZ is not set
+# CONFIG_OMAP_ARM_150MHZ is not set
+# CONFIG_OMAP_ARM_120MHZ is not set
+# CONFIG_OMAP_ARM_60MHZ is not set
+# CONFIG_OMAP_ARM_30MHZ is not set
+# CONFIG_OMAP_DSP is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM925T=y
+CONFIG_CPU_32v4=y
+CONFIG_CPU_ABRT_EV4T=y
+CONFIG_CPU_CACHE_V4WT=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+
+#
+# Bus support
+#
+CONFIG_ISA_DMA_API=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_SMP is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_NO_IDLE_HZ is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE=""
+# CONFIG_XIP_KERNEL is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+
+#
+# Networking
+#
+# CONFIG_NET is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+# CONFIG_STANDALONE is not set
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_FW_LOADER is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_RAM is not set
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=320
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=320
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+CONFIG_OMAP_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+# CONFIG_I2C_SENSOR is not set
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+CONFIG_FB_SOFT_CURSOR=y
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_OMAP=y
+CONFIG_FB_OMAP_INTERNAL_LCDC=y
+# CONFIG_FB_OMAP_EXTERNAL_LCDC is not set
+# CONFIG_FB_OMAP_DMA_TUNE is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+CONFIG_USB_GADGET_OMAP=y
+CONFIG_USB_OMAP=y
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+# CONFIG_USB_GADGET_DUALSPEED is not set
+CONFIG_USB_ZERO=y
+# CONFIG_USB_ETH is not set
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_G_SERIAL is not set
+
+#
+# MMC/SD Card support
+#
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_BLOCK=y
+# CONFIG_MMC_BLOCK_BROKEN_RFD is not set
+# CONFIG_MMC_BULKTRANSFER is not set
+CONFIG_MMC_OMAP=y
+# CONFIG_MMC_WBSD is not set
+
+#
+# Synchronous Serial Interfaces (SSI)
+#
+# CONFIG_OMAP_UWIRE is not set
+# CONFIG_OMAP_TSC2101 is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+
+#
+# XFS support
+#
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_INOTIFY is not set
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=850
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_CRAMFS=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+CONFIG_NLS_CODEPAGE_850=y
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_FRAME_POINTER=y
+# CONFIG_DEBUG_USER is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=y
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
diff --git a/arch/arm/configs/palmtt_defconfig b/arch/arm/configs/palmtt_defconfig
new file mode 100644 (file)
index 0000000..4a5fcb4
--- /dev/null
@@ -0,0 +1,844 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.19-rc3-omap1
+# Sun Oct 29 00:36:12 2006
+#
+CONFIG_ARM=y
+# CONFIG_GENERIC_TIME is not set
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_BLK_DEV_IO_TRACE is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+CONFIG_ARCH_OMAP=y
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP1=y
+# CONFIG_ARCH_OMAP2 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+# CONFIG_OMAP_BOOT_TAG is not set
+# CONFIG_OMAP_GPIO_SWITCH is not set
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_WARNINGS=y
+CONFIG_OMAP_MCBSP=y
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
+# CONFIG_OMAP_LL_DEBUG_UART1 is not set
+CONFIG_OMAP_LL_DEBUG_UART2=y
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+CONFIG_OMAP_DSP=y
+# CONFIG_OMAP_DSP_MBCMD_VERBOSE is not set
+# CONFIG_OMAP_DSP_TASK_MULTIOPEN is not set
+CONFIG_OMAP_DSP_FBEXPORT=y
+
+#
+# OMAP Core Type
+#
+# CONFIG_ARCH_OMAP730 is not set
+CONFIG_ARCH_OMAP15XX=y
+# CONFIG_ARCH_OMAP16XX is not set
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_INNOVATOR is not set
+# CONFIG_MACH_VOICEBLUE is not set
+# CONFIG_MACH_OMAP_PALMTE is not set
+# CONFIG_MACH_OMAP_PALMZ71 is not set
+CONFIG_MACH_OMAP_PALMTT=y
+# CONFIG_MACH_AMS_DELTA is not set
+# CONFIG_MACH_OMAP_GENERIC is not set
+
+#
+# OMAP CPU Speed
+#
+CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER=y
+# CONFIG_OMAP_ARM_168MHZ is not set
+# CONFIG_OMAP_ARM_150MHZ is not set
+# CONFIG_OMAP_ARM_120MHZ is not set
+# CONFIG_OMAP_ARM_60MHZ is not set
+# CONFIG_OMAP_ARM_30MHZ is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM925T=y
+CONFIG_CPU_32v4T=y
+CONFIG_CPU_ABRT_EV4T=y
+CONFIG_CPU_CACHE_V4WT=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+
+#
+# Bus support
+#
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+# CONFIG_NO_IDLE_HZ is not set
+CONFIG_HZ=100
+# CONFIG_AEABI is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_RESOURCES_64BIT is not set
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/mmcblk0p2 rw init=/init"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=y
+CONFIG_BINFMT_MISC=y
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+# CONFIG_APM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_NETLINK is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+# CONFIG_NETDEVICES is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=320
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=320
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_TSDEV=y
+CONFIG_INPUT_TSDEV_SCREEN_X=320
+CONFIG_INPUT_TSDEV_SCREEN_Y=320
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ADS7846=y
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_TSC2102 is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_NVRAM is not set
+# CONFIG_OMAP_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_BITBANG=y
+CONFIG_SPI_OMAP_UWIRE=y
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_TSC2102 is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_LM70 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+
+#
+# LED devices
+#
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+CONFIG_LEDS_OMAP=y
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FIRMWARE_EDID=y
+CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FB_OMAP=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_LCD_MIPID is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=2
+# CONFIG_FB_OMAP_DMA_TUNE is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+# CONFIG_LOGO is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_DEVICE=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_LCD_DEVICE=y
+CONFIG_BACKLIGHT_OMAP=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
+
+#
+# Enable Host or Gadget support to see Inventra options
+#
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+
+#
+# RTC drivers
+#
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+CONFIG_RTC_DRV_OMAP=y
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_TEST is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# Synchronous Serial Interfaces (SSI)
+#
+# CONFIG_OMAP_UWIRE is not set
+# CONFIG_OMAP_TSC2101 is not set
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_INOTIFY is not set
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_FS is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_UNWIND_INFO is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_USER is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=y
+CONFIG_CRC16=y
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=y
+CONFIG_PLIST=y
diff --git a/arch/arm/configs/palmz71_defconfig b/arch/arm/configs/palmz71_defconfig
new file mode 100644 (file)
index 0000000..ec32035
--- /dev/null
@@ -0,0 +1,809 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.18-omap1
+# Fri Oct 20 22:04:08 2006
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION="-z71"
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Block layer
+#
+# CONFIG_BLK_DEV_IO_TRACE is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+CONFIG_ARCH_OMAP=y
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP1=y
+# CONFIG_ARCH_OMAP2 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+# CONFIG_OMAP_BOOT_TAG is not set
+# CONFIG_OMAP_GPIO_SWITCH is not set
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_WARNINGS=y
+CONFIG_OMAP_MCBSP=y
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+# CONFIG_OMAP_DSP is not set
+
+#
+# OMAP Core Type
+#
+# CONFIG_ARCH_OMAP730 is not set
+CONFIG_ARCH_OMAP15XX=y
+# CONFIG_ARCH_OMAP16XX is not set
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_INNOVATOR is not set
+# CONFIG_MACH_VOICEBLUE is not set
+# CONFIG_MACH_OMAP_PALMTE is not set
+CONFIG_MACH_OMAP_PALMZ71=y
+# CONFIG_MACH_AMS_DELTA is not set
+# CONFIG_MACH_OMAP_GENERIC is not set
+
+#
+# OMAP CPU Speed
+#
+CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER=y
+# CONFIG_OMAP_ARM_168MHZ is not set
+# CONFIG_OMAP_ARM_150MHZ is not set
+# CONFIG_OMAP_ARM_120MHZ is not set
+# CONFIG_OMAP_ARM_60MHZ is not set
+# CONFIG_OMAP_ARM_30MHZ is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM925T=y
+CONFIG_CPU_32v4T=y
+CONFIG_CPU_ABRT_EV4T=y
+CONFIG_CPU_CACHE_V4WT=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+
+#
+# Bus support
+#
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+# CONFIG_NO_IDLE_HZ is not set
+CONFIG_HZ=100
+# CONFIG_AEABI is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_RESOURCES_64BIT is not set
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE=""
+# CONFIG_XIP_KERNEL is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=y
+CONFIG_BINFMT_MISC=y
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+# CONFIG_APM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+# CONFIG_NETDEVICES is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# PHY device support
+#
+
+#
+# Ethernet (10 or 100Mbit)
+#
+# CONFIG_NET_ETHERNET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=320
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=320
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_TSDEV=y
+CONFIG_INPUT_TSDEV_SCREEN_X=320
+CONFIG_INPUT_TSDEV_SCREEN_Y=320
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ADS7846=y
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=16
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_NVRAM is not set
+CONFIG_OMAP_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_BITBANG=y
+CONFIG_SPI_OMAP_UWIRE=y
+
+#
+# SPI Protocol Masters
+#
+
+#
+# Dallas's 1-wire bus
+#
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_LM70 is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_V4L2=y
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FIRMWARE_EDID=y
+CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FB_OMAP=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_LCD_MIPID is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=2
+# CONFIG_FB_OMAP_DMA_TUNE is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+# CONFIG_LOGO is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_DEVICE=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_LCD_DEVICE=y
+CONFIG_BACKLIGHT_OMAP=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
+
+#
+# Enable Host or Gadget support to see Inventra options
+#
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_OMAP=y
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+
+#
+# Synchronous Serial Interfaces (SSI)
+#
+CONFIG_OMAP_UWIRE=y
+# CONFIG_OMAP_TSC2101 is not set
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_INOTIFY is not set
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_FS is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_UNWIND_INFO is not set
+# CONFIG_DEBUG_USER is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=y
+CONFIG_CRC16=y
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=y
+CONFIG_PLIST=y
diff --git a/arch/arm/configs/sx1_defconfig b/arch/arm/configs/sx1_defconfig
new file mode 100644 (file)
index 0000000..f6aa4c6
--- /dev/null
@@ -0,0 +1,1037 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.19-rc6-omap1
+# Sat Nov 18 19:03:38 2006
+#
+CONFIG_ARM=y
+# CONFIG_GENERIC_TIME is not set
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+CONFIG_POSIX_MQUEUE=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+CONFIG_IKCONFIG=y
+# CONFIG_IKCONFIG_PROC is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_KALLSYMS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+# CONFIG_ELF_CORE is not set
+# CONFIG_BASE_FULL is not set
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+# CONFIG_SHMEM is not set
+# CONFIG_SLAB is not set
+# CONFIG_VM_EVENT_COUNTERS is not set
+CONFIG_RT_MUTEXES=y
+CONFIG_TINY_SHMEM=y
+CONFIG_BASE_SMALL=1
+CONFIG_SLOB=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_BLK_DEV_IO_TRACE is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+CONFIG_DEFAULT_DEADLINE=y
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="deadline"
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+CONFIG_ARCH_OMAP=y
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP1=y
+# CONFIG_ARCH_OMAP2 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+CONFIG_OMAP_BOOT_TAG=y
+# CONFIG_OMAP_BOOT_REASON is not set
+# CONFIG_OMAP_COMPONENT_VERSION is not set
+# CONFIG_OMAP_GPIO_SWITCH is not set
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_WARNINGS=y
+CONFIG_OMAP_MCBSP=y
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
+# CONFIG_OMAP_LL_DEBUG_UART1 is not set
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+CONFIG_OMAP_LL_DEBUG_UART3=y
+CONFIG_OMAP_SERIAL_WAKE=y
+CONFIG_OMAP_DSP=y
+# CONFIG_OMAP_DSP_MBCMD_VERBOSE is not set
+# CONFIG_OMAP_DSP_TASK_MULTIOPEN is not set
+# CONFIG_OMAP_DSP_FBEXPORT is not set
+
+#
+# OMAP Core Type
+#
+# CONFIG_ARCH_OMAP730 is not set
+CONFIG_ARCH_OMAP15XX=y
+# CONFIG_ARCH_OMAP16XX is not set
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_INNOVATOR is not set
+# CONFIG_MACH_VOICEBLUE is not set
+# CONFIG_MACH_OMAP_PALMTE is not set
+# CONFIG_MACH_OMAP_PALMZ71 is not set
+# CONFIG_MACH_OMAP_PALMTT is not set
+CONFIG_MACH_SX1=y
+# CONFIG_MACH_AMS_DELTA is not set
+# CONFIG_MACH_OMAP_GENERIC is not set
+
+#
+# OMAP CPU Speed
+#
+# CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER is not set
+CONFIG_OMAP_ARM_168MHZ=y
+# CONFIG_OMAP_ARM_150MHZ is not set
+# CONFIG_OMAP_ARM_120MHZ is not set
+# CONFIG_OMAP_ARM_60MHZ is not set
+# CONFIG_OMAP_ARM_30MHZ is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM925T=y
+CONFIG_CPU_32v4T=y
+CONFIG_CPU_ABRT_EV4T=y
+CONFIG_CPU_CACHE_V4WT=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+
+#
+# Bus support
+#
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_PREEMPT=y
+# CONFIG_NO_IDLE_HZ is not set
+CONFIG_HZ=100
+# CONFIG_AEABI is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_RESOURCES_64BIT is not set
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE=""
+# CONFIG_XIP_KERNEL is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_MISC=y
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+# CONFIG_APM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+CONFIG_CONNECTOR=y
+# CONFIG_PROC_EVENTS is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=m
+CONFIG_BLK_DEV_RAM_COUNT=2
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_NETLINK is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# PHY device support
+#
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_FIXED_PHY is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+CONFIG_KEYBOARD_OMAP=y
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_CONSOLE is not set
+CONFIG_SERIAL_8250_NR_UARTS=3
+CONFIG_SERIAL_8250_RUNTIME_UARTS=3
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_NVRAM is not set
+CONFIG_OMAP_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_SENSORS_TLV320AIC23 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Misc devices
+#
+# CONFIG_TIFM_CORE is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FIRMWARE_EDID is not set
+CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FB_OMAP=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_LCD_MIPID is not set
+CONFIG_FB_OMAP_BOOTLOADER_INIT=y
+CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=2
+# CONFIG_FB_OMAP_DMA_TUNE is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FONTS=y
+# CONFIG_FONT_8x8 is not set
+# CONFIG_FONT_8x16 is not set
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+CONFIG_FONT_MINI_4x6=y
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+# CONFIG_SND_SEQUENCER is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=y
+CONFIG_SND_PCM_OSS=y
+CONFIG_SND_PCM_OSS_PLUGINS=y
+# CONFIG_SND_DYNAMIC_MINORS is not set
+# CONFIG_SND_SUPPORT_OLD_API is not set
+# CONFIG_SND_VERBOSE_PROCFS is not set
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# ALSA ARM devices
+#
+# CONFIG_SND_OMAP_AIC23 is not set
+# CONFIG_SND_OMAP_TSC2101 is not set
+CONFIG_SND_SX1=y
+# CONFIG_SND_OMAP_TSC2102 is not set
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
+# CONFIG_USB_MUSB_HDRC is not set
+# CONFIG_USB_GADGET_MUSB_HDRC is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+CONFIG_USB_GADGET_OMAP=y
+CONFIG_USB_OMAP=y
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+# CONFIG_USB_GADGET_DUALSPEED is not set
+# CONFIG_USB_ZERO is not set
+CONFIG_USB_ETH=y
+CONFIG_USB_ETH_RNDIS=y
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_OMAP=y
+# CONFIG_MMC_TIFM_SD is not set
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+
+#
+# Synchronous Serial Interfaces (SSI)
+#
+# CONFIG_OMAP_UWIRE is not set
+# CONFIG_OMAP_TSC2101 is not set
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=866
+CONFIG_FAT_DEFAULT_IOCHARSET="koi8-r"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_CRAMFS=y
+# CONFIG_CRAMFS_LINEAR is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+CONFIG_NLS_CODEPAGE_866=y
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+CONFIG_NLS_CODEPAGE_1251=y
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+CONFIG_NLS_ISO8859_5=y
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+CONFIG_NLS_KOI8_R=y
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=y
+
+#
+# Profiling support
+#
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DETECT_SOFTLOCKUP is not set
+# CONFIG_SCHEDSTATS is not set
+CONFIG_DEBUG_PREEMPT=y
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_RWSEMS is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_FRAME_POINTER is not set
+CONFIG_FORCED_INLINING=y
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=y
+CONFIG_CRC16=y
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_PLIST=y
index 8781aaeb576b2d2738ead294ba6c21a182030b58..5a87aa982dd87739efc2101ef2c3bc29aa7859c0 100644 (file)
@@ -22,6 +22,7 @@ comment "OMAP Board Type"
 config MACH_OMAP_INNOVATOR
        bool "TI Innovator"
        depends on ARCH_OMAP1 && (ARCH_OMAP15XX || ARCH_OMAP16XX)
+       select OMAP_MCBSP
        help
           TI OMAP 1510 or 1610 Innovator board support. Say Y here if you
           have such a board.
@@ -29,6 +30,7 @@ config MACH_OMAP_INNOVATOR
 config MACH_OMAP_H2
        bool "TI H2 Support"
        depends on ARCH_OMAP1 && ARCH_OMAP16XX
+       select OMAP_MCBSP
        help
          TI OMAP 1610/1611B H2 board support. Say Y here if you have such
          a board.
@@ -36,6 +38,7 @@ config MACH_OMAP_H2
 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.
@@ -43,7 +46,7 @@ config MACH_OMAP_H3
 config MACH_OMAP_OSK
        bool "TI OSK Support"
        depends on ARCH_OMAP1 && ARCH_OMAP16XX
-       select TPS65010
+       select OMAP_MCBSP
        help
          TI OMAP 5912 OSK (OMAP Starter Kit) board support. Say Y here
           if you have such a board.
@@ -81,11 +84,39 @@ config MACH_OMAP_PALMTE
        bool "Palm Tungsten E"
        depends on ARCH_OMAP1 && ARCH_OMAP15XX
        help
-          Support for the Palm Tungsten E PDA. Currently only the LCD panel
-          is supported. To boot the kernel, you'll need a PalmOS compatible
-          bootloader; check out http://palmtelinux.sourceforge.net for more
-          informations.
-          Say Y here if you have such a PDA, say NO otherwise.
+         Support for the Palm Tungsten E PDA.  To boot the kernel, you'll
+         need a PalmOS compatible bootloader; check out
+         http://palmtelinux.sourceforge.net/ for more information.
+         Say Y here if you have this PDA model, say N otherwise.
+
+config MACH_OMAP_PALMZ71
+       bool "Palm Zire71"
+       depends on ARCH_OMAP1 && ARCH_OMAP15XX
+       help
+         Support for the Palm Zire71 PDA. To boot the kernel,
+         you'll need a PalmOS compatible bootloader; check out
+         http://hackndev.com/palm/z71 for more informations.
+         Say Y here if you have such a PDA, say N otherwise.
+
+config MACH_OMAP_PALMTT
+       bool "Palm Tungsten|T"
+       depends on ARCH_OMAP1 && ARCH_OMAP15XX
+       help
+         Support for the Palm Tungsten|T PDA. To boot the kernel, you'll
+         need a PalmOS compatible bootloader (Garux); check out
+         http://www.hackndev.com/palm/tt/ for more information.
+         Say Y here if you have this PDA model, say N otherwise.
+
+config MACH_SX1
+       bool "Siemens SX1"
+       depends on ARCH_OMAP1 && ARCH_OMAP15XX
+       help
+         Support for the Siemens SX1 phone. To boot the kernel,
+         you'll need a SX1 compatible bootloader; check out
+         http://forum.oslik.ru and
+         http://www.handhelds.org/moin/moin.cgi/SiemensSX1
+         for more information.
+         Say Y here if you have such a phone, say NO otherwise.
 
 config MACH_NOKIA770
        bool "Nokia 770"
index 7165f74f78dac18f4c5c4f7fc08272ee683a8dd1..ff47ab4510a9a71bef4754de9a0e5da6d9d03d54 100644 (file)
@@ -10,6 +10,10 @@ obj-$(CONFIG_OMAP_MPU_TIMER)         += time.o
 # Power Management
 obj-$(CONFIG_PM) += pm.o sleep.o
 
+# DSP
+obj-$(CONFIG_OMAP_DSP) += mailbox_mach.o
+mailbox_mach-objs      := mailbox.o
+
 led-y := leds.o
 
 # Specific board support
@@ -22,8 +26,11 @@ obj-$(CONFIG_MACH_OMAP_OSK)          += board-osk.o
 obj-$(CONFIG_MACH_OMAP_H3)             += board-h3.o
 obj-$(CONFIG_MACH_VOICEBLUE)           += board-voiceblue.o
 obj-$(CONFIG_MACH_OMAP_PALMTE)         += board-palmte.o
+obj-$(CONFIG_MACH_OMAP_PALMZ71)                += board-palmz71.o
+obj-$(CONFIG_MACH_OMAP_PALMTT)         += board-palmtt.o
 obj-$(CONFIG_MACH_NOKIA770)            += board-nokia770.o
 obj-$(CONFIG_MACH_AMS_DELTA)           += board-ams-delta.o
+obj-$(CONFIG_MACH_SX1)                 += board-sx1.o
 
 ifeq ($(CONFIG_ARCH_OMAP15XX),y)
 # Innovator-1510 FPGA
@@ -37,4 +44,3 @@ led-$(CONFIG_MACH_OMAP_INNOVATOR)     += leds-innovator.o
 led-$(CONFIG_MACH_OMAP_PERSEUS2)       += leds-h2p2-debug.o
 led-$(CONFIG_MACH_OMAP_OSK)            += leds-osk.o
 obj-$(CONFIG_LEDS)                     += $(led-y)
-
index 8437d065ada50530b8d686e9dd42c2486384889e..c73ca61e585ef6f49385e8fc377a7a6974e12082 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/input.h>
 #include <linux/platform_device.h>
 
 #include <asm/hardware.h>
@@ -23,6 +24,7 @@
 
 #include <asm/arch/board-ams-delta.h>
 #include <asm/arch/gpio.h>
+#include <asm/arch/keypad.h>
 #include <asm/arch/mux.h>
 #include <asm/arch/usb.h>
 #include <asm/arch/board.h>
 static u8 ams_delta_latch1_reg;
 static u16 ams_delta_latch2_reg;
 
+static int ams_delta_keymap[] = {
+       KEY(0, 0, KEY_F1),              /* Advert    */
+
+       KEY(3, 0, KEY_COFFEE),          /* Games     */
+       KEY(2, 0, KEY_QUESTION),        /* Directory */
+       KEY(3, 2, KEY_CONNECT),         /* Internet  */
+       KEY(2, 1, KEY_SHOP),            /* Services  */
+       KEY(1, 1, KEY_PHONE),           /* VoiceMail */
+
+       KEY(1, 0, KEY_DELETE),          /* Delete    */
+       KEY(2, 2, KEY_PLAY),            /* Play      */
+       KEY(0, 1, KEY_PAGEUP),          /* Up        */
+       KEY(3, 1, KEY_PAGEDOWN),        /* Down      */
+       KEY(0, 2, KEY_EMAIL),           /* ReadEmail */
+       KEY(1, 2, KEY_STOP),            /* Stop      */
+
+       /* Numeric keypad portion */
+       KEY(7, 0, KEY_KP1),
+       KEY(6, 0, KEY_KP2),
+       KEY(5, 0, KEY_KP3),
+       KEY(7, 1, KEY_KP4),
+       KEY(6, 1, KEY_KP5),
+       KEY(5, 1, KEY_KP6),
+       KEY(7, 2, KEY_KP7),
+       KEY(6, 2, KEY_KP8),
+       KEY(5, 2, KEY_KP9),
+       KEY(6, 3, KEY_KP0),
+       KEY(7, 3, KEY_KPASTERISK),
+       KEY(5, 3, KEY_KPDOT),           /* # key     */
+       KEY(2, 7, KEY_NUMLOCK),         /* Mute      */
+       KEY(1, 7, KEY_KPMINUS),         /* Recall    */
+       KEY(1, 6, KEY_KPPLUS),          /* Redial    */
+       KEY(6, 7, KEY_KPSLASH),         /* Handsfree */
+       KEY(0, 6, KEY_ENTER),           /* Video     */
+
+       KEY(4, 7, KEY_CAMERA),          /* Photo     */
+
+       KEY(4, 0, KEY_F2),              /* Home      */
+       KEY(4, 1, KEY_F3),              /* Office    */
+       KEY(4, 2, KEY_F4),              /* Mobile    */
+       KEY(7, 7, KEY_F5),              /* SMS       */
+       KEY(5, 7, KEY_F6),              /* Email     */
+
+       /* QWERTY portion of keypad */
+       KEY(4, 3, KEY_Q),
+       KEY(3, 3, KEY_W),
+       KEY(2, 3, KEY_E),
+       KEY(1, 3, KEY_R),
+       KEY(0, 3, KEY_T),
+       KEY(7, 4, KEY_Y),
+       KEY(6, 4, KEY_U),
+       KEY(5, 4, KEY_I),
+       KEY(4, 4, KEY_O),
+       KEY(3, 4, KEY_P),
+
+       KEY(2, 4, KEY_A),
+       KEY(1, 4, KEY_S),
+       KEY(0, 4, KEY_D),
+       KEY(7, 5, KEY_F),
+       KEY(6, 5, KEY_G),
+       KEY(5, 5, KEY_H),
+       KEY(4, 5, KEY_J),
+       KEY(3, 5, KEY_K),
+       KEY(2, 5, KEY_L),
+
+       KEY(1, 5, KEY_Z),
+       KEY(0, 5, KEY_X),
+       KEY(7, 6, KEY_C),
+       KEY(6, 6, KEY_V),
+       KEY(5, 6, KEY_B),
+       KEY(4, 6, KEY_N),
+       KEY(3, 6, KEY_M),
+       KEY(2, 6, KEY_SPACE),
+
+       KEY(0, 7, KEY_LEFTSHIFT),       /* Vol up    */
+       KEY(3, 7, KEY_LEFTCTRL),        /* Vol down  */
+
+       0
+};
+
 void ams_delta_latch1_write(u8 mask, u8 value)
 {
        ams_delta_latch1_reg &= ~mask;
@@ -76,6 +158,10 @@ static struct map_desc ams_delta_io_desc[] __initdata = {
        }
 };
 
+static struct omap_lcd_config ams_delta_lcd_config __initdata = {
+       .ctrl_name      = "internal",
+};
+
 static struct omap_uart_config ams_delta_uart_config __initdata = {
        .enabled_uarts = 1,
 };
@@ -87,16 +173,50 @@ static struct omap_usb_config ams_delta_usb_config __initdata = {
 };
 
 static struct omap_board_config_kernel ams_delta_config[] = {
+       { OMAP_TAG_LCD,         &ams_delta_lcd_config },
        { OMAP_TAG_UART,        &ams_delta_uart_config },
        { OMAP_TAG_USB,         &ams_delta_usb_config },
 };
 
+static struct resource ams_delta_kp_resources[] = {
+       [0] = {
+               .start  = INT_KEYBOARD,
+               .end    = INT_KEYBOARD,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct omap_kp_platform_data ams_delta_kp_data = {
+       .rows           = 8,
+       .cols           = 8,
+       .keymap         = ams_delta_keymap,
+       .keymapsize     = ARRAY_SIZE(ams_delta_keymap),
+       .delay          = 9,
+};
+
+static struct platform_device ams_delta_kp_device = {
+       .name           = "omap-keypad",
+       .id             = -1,
+       .dev            = {
+               .platform_data = &ams_delta_kp_data,
+       },
+       .num_resources  = ARRAY_SIZE(ams_delta_kp_resources),
+       .resource       = ams_delta_kp_resources,
+};
+
+static struct platform_device ams_delta_lcd_device = {
+       .name   = "lcd_ams_delta",
+       .id     = -1,
+};
+
 static struct platform_device ams_delta_led_device = {
        .name   = "ams-delta-led",
        .id     = -1
 };
 
 static struct platform_device *ams_delta_devices[] __initdata = {
+       &ams_delta_kp_device,
+       &ams_delta_lcd_device,
        &ams_delta_led_device,
 };
 
index 62e42c7a628e55ac1f86616064667ea2e0188534..f65baa95986ea9717632690404dd77c47a1cc1c5 100644 (file)
@@ -246,7 +246,7 @@ static void __init fsample_init_smc91x(void)
        mdelay(50);
 }
 
-void omap_fsample_init_irq(void)
+static void __init omap_fsample_init_irq(void)
 {
        omap1_init_common_hw();
        omap_init_irq();
index 6e113078f7ab4fa3415f42d68901e3e0ecc0aaaf..f1a824e9cf7bf35c00dc497e5f5d2fdf83b54455 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/input.h>
+#include <linux/workqueue.h>
 
 #include <asm/hardware.h>
 #include <asm/mach-types.h>
@@ -138,6 +139,63 @@ static struct platform_device h2_nor_device = {
        .resource       = &h2_nor_resource,
 };
 
+static struct mtd_partition h2_nand_partitions[] = {
+#if 0
+       /* REVISIT:  enable these partitions if you make NAND BOOT
+        * work on your H2 (rev C or newer); published versions of
+        * x-load only support P2 and H3.
+        */
+       {
+               .name           = "xloader",
+               .offset         = 0,
+               .size           = 64 * 1024,
+               .mask_flags     = MTD_WRITEABLE,        /* force read-only */
+       },
+       {
+               .name           = "bootloader",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = 256 * 1024,
+               .mask_flags     = MTD_WRITEABLE,        /* force read-only */
+       },
+       {
+               .name           = "params",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = 192 * 1024,
+       },
+       {
+               .name           = "kernel",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = 2 * SZ_1M,
+       },
+#endif
+       {
+               .name           = "filesystem",
+               .size           = MTDPART_SIZ_FULL,
+               .offset         = MTDPART_OFS_APPEND,
+       },
+};
+
+/* dip switches control NAND chip access:  8 bit, 16 bit, or neither */
+static struct nand_platform_data h2_nand_data = {
+       .options        = NAND_SAMSUNG_LP_OPTIONS,
+       .parts          = h2_nand_partitions,
+       .nr_parts       = ARRAY_SIZE(h2_nand_partitions),
+};
+
+static struct resource h2_nand_resource = {
+       .flags          = IORESOURCE_MEM,
+};
+
+static struct platform_device h2_nand_device = {
+       .name           = "omapnand",
+       .id             = 0,
+       .dev            = {
+               .platform_data  = &h2_nand_data,
+       },
+       .num_resources  = 1,
+       .resource       = &h2_nand_resource,
+};
+
 static struct resource h2_smc91x_resources[] = {
        [0] = {
                .start  = OMAP1610_ETHR_START,          /* Physical */
@@ -217,11 +275,15 @@ static struct resource h2_irda_resources[] = {
                .flags  = IORESOURCE_IRQ,
        },
 };
+
+static u64 irda_dmamask = 0xffffffff;
+
 static struct platform_device h2_irda_device = {
        .name           = "omapirda",
        .id             = 0,
        .dev            = {
                .platform_data  = &h2_irda_data,
+               .dma_mask       = &irda_dmamask,
        },
        .num_resources  = ARRAY_SIZE(h2_irda_resources),
        .resource       = h2_irda_resources,
@@ -269,6 +331,7 @@ static struct platform_device h2_mcbsp1_device = {
 
 static struct platform_device *h2_devices[] __initdata = {
        &h2_nor_device,
+       &h2_nand_device,
        &h2_smc91x_device,
        &h2_irda_device,
        &h2_kp_device,
@@ -332,6 +395,13 @@ static struct omap_board_config_kernel h2_config[] = {
        { OMAP_TAG_LCD,         &h2_lcd_config },
 };
 
+#define H2_NAND_RB_GPIO_PIN    62
+
+static int h2_nand_dev_ready(struct nand_platform_data *data)
+{
+       return omap_get_gpio_datain(H2_NAND_RB_GPIO_PIN);
+}
+
 static void __init h2_init(void)
 {
        /* Here we assume the NOR boot config:  NOR on CS3 (possibly swapped
@@ -346,6 +416,11 @@ static void __init h2_init(void)
        h2_nor_resource.end = h2_nor_resource.start = omap_cs3_phys();
        h2_nor_resource.end += SZ_32M - 1;
 
+       h2_nand_resource.end = h2_nand_resource.start = OMAP_CS2B_PHYS;
+       h2_nand_resource.end += SZ_4K - 1;
+       if (!(omap_request_gpio(H2_NAND_RB_GPIO_PIN)))
+               h2_nand_data.dev_ready = h2_nand_dev_ready;
+
        omap_cfg_reg(L3_1610_FLASH_CS2B_OE);
        omap_cfg_reg(M8_1610_FLASH_CS2B_WE);
 
index 9d2346fb68f41da85c51dd0211a6e826121c0b33..4167f3480974a268e21a15abbdeabf434c70ddba 100644 (file)
@@ -44,6 +44,8 @@
 #include <asm/arch/keypad.h>
 #include <asm/arch/dma.h>
 #include <asm/arch/common.h>
+#include <asm/arch/mcbsp.h>
+#include <asm/arch/omap-alsa.h>
 
 extern int omap_gpio_init(void);
 
@@ -294,9 +296,11 @@ static int h3_select_irda(struct device *dev, int state)
        return err;
 }
 
-static void set_trans_mode(void *data)
+static void set_trans_mode(struct work_struct *work)
 {
-       int *mode = data;
+       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;
 
@@ -306,7 +310,7 @@ static void set_trans_mode(void *data)
 
        expa &= ~0x03;
 
-       if (*mode & IR_SIRMODE) {
+       if (mode & IR_SIRMODE) {
                expa |= 0x01;
        } else { /* MIR/FIR */
                expa |= 0x03;
@@ -321,9 +325,9 @@ static int h3_transceiver_mode(struct device *dev, int mode)
 {
        struct omap_irda_config *irda_config = dev->platform_data;
 
+       irda_config->mode = mode;
        cancel_delayed_work(&irda_config->gpio_expa);
-       PREPARE_WORK(&irda_config->gpio_expa, set_trans_mode, &mode);
-#error this is not permitted - mode is an argument variable
+       PREPARE_DELAYED_WORK(&irda_config->gpio_expa, set_trans_mode);
        schedule_delayed_work(&irda_config->gpio_expa, 0);
 
        return 0;
@@ -349,11 +353,14 @@ static struct resource h3_irda_resources[] = {
        },
 };
 
+static u64 irda_dmamask = 0xffffffff;
+
 static struct platform_device h3_irda_device = {
        .name           = "omapirda",
        .id             = 0,
        .dev            = {
                .platform_data  = &h3_irda_data,
+               .dma_mask       = &irda_dmamask,
        },
        .num_resources  = ARRAY_SIZE(h3_irda_resources),
        .resource       = h3_irda_resources,
@@ -364,6 +371,41 @@ static struct platform_device h3_lcd_device = {
        .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  = 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,
+       },
+};
+
 static struct platform_device *devices[] __initdata = {
        &nor_device,
        &nand_device,
@@ -372,6 +414,7 @@ static struct platform_device *devices[] __initdata = {
        &h3_irda_device,
        &h3_kp_device,
        &h3_lcd_device,
+       &h3_mcbsp1_device,
 };
 
 static struct omap_usb_config h3_usb_config __initdata = {
@@ -455,7 +498,7 @@ static void __init h3_init_smc91x(void)
        }
 }
 
-void h3_init_irq(void)
+static void __init h3_init_irq(void)
 {
        omap1_init_common_hw();
        omap_init_irq();
index cb00530ad279392725581ae81b57c07a215eb1e6..7e63a41e37c699838471a97ab52004f28bd1a71d 100644 (file)
@@ -308,7 +308,7 @@ static void __init innovator_init_smc91x(void)
        }
 }
 
-void innovator_init_irq(void)
+static void __init innovator_init_irq(void)
 {
        omap1_init_common_hw();
        omap_init_irq();
index cbe909bad79b3fde3e1b064b69bdb78e081b56f1..8ea0cef8bdb10ff177396daee6b10fed9cca660b 100644 (file)
@@ -16,6 +16,8 @@
 
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
 
 #include <asm/hardware.h>
 #include <asm/mach-types.h>
@@ -32,6 +34,8 @@
 #include <asm/arch/aic23.h>
 #include <asm/arch/gpio.h>
 
+#include "../plat-omap/dsp/dsp_common.h"
+
 static void __init omap_nokia770_init_irq(void)
 {
        /* On Nokia 770, the SleepX signal is masked with an
@@ -89,7 +93,7 @@ static struct platform_device nokia770_kp_device = {
 };
 
 static struct platform_device *nokia770_devices[] __initdata = {
-        &nokia770_kp_device,
+       &nokia770_kp_device,
 };
 
 static struct ads7846_platform_data nokia770_ads7846_platform_data __initdata = {
@@ -103,7 +107,7 @@ static struct ads7846_platform_data nokia770_ads7846_platform_data __initdata =
 
 static struct spi_board_info nokia770_spi_board_info[] __initdata = {
        [0] = {
-               .modalias       = "lcd_lph8923",
+               .modalias       = "lcd_mipid",
                .bus_num        = 2,
                .chip_select    = 3,
                .max_speed_hz   = 12000000,
@@ -151,6 +155,7 @@ static struct omap_board_config_kernel nokia770_config[] = {
        { OMAP_TAG_MMC,         &nokia770_mmc_config },
 };
 
+#if    defined(CONFIG_OMAP_DSP)
 /*
  * audio power control
  */
@@ -181,7 +186,7 @@ static void nokia770_audio_pwr_up(void)
        clk_enable(dspxor_ck);
 
        /* Turn on codec */
-       tlv320aic23_power_up();
+       aic23_power_up();
 
        if (omap_get_gpio_datain(HEADPHONE_GPIO))
                /* HP not connected, turn on amplifier */
@@ -195,7 +200,7 @@ static void codec_delayed_power_down(struct work_struct *work)
 {
        down(&audio_pwr_sem);
        if (audio_pwr_state == -1)
-               tlv320aic23_power_down();
+               aic23_power_down();
        clk_disable(dspxor_ck);
        up(&audio_pwr_sem);
 }
@@ -211,7 +216,8 @@ static void nokia770_audio_pwr_down(void)
        schedule_delayed_work(&codec_power_down_work, HZ / 20); /* 50ms */
 }
 
-void nokia770_audio_pwr_up_request(int stage)
+static int
+nokia770_audio_pwr_up_request(struct dsp_kfunc_device *kdev, int stage)
 {
        down(&audio_pwr_sem);
        if (audio_pwr_state == -1)
@@ -219,9 +225,11 @@ void nokia770_audio_pwr_up_request(int stage)
        /* force audio_pwr_state = 0, even if it was 1. */
        audio_pwr_state = 0;
        up(&audio_pwr_sem);
+       return 0;
 }
 
-void nokia770_audio_pwr_down_request(int stage)
+static int
+nokia770_audio_pwr_down_request(struct dsp_kfunc_device *kdev, int stage)
 {
        down(&audio_pwr_sem);
        switch (stage) {
@@ -237,7 +245,38 @@ void nokia770_audio_pwr_down_request(int stage)
                break;
        }
        up(&audio_pwr_sem);
+       return 0;
+}
+
+static struct dsp_kfunc_device nokia770_audio_device = {
+       .name    = "audio",
+       .type    = DSP_KFUNC_DEV_TYPE_AUDIO,
+       .enable  = nokia770_audio_pwr_up_request,
+       .disable = nokia770_audio_pwr_down_request,
+};
+
+static __init int omap_dsp_init(void)
+{
+       int ret;
+
+       dspxor_ck = clk_get(0, "dspxor_ck");
+       if (IS_ERR(dspxor_ck)) {
+               printk(KERN_ERR "couldn't acquire dspxor_ck\n");
+               return PTR_ERR(dspxor_ck);
+       }
+
+       ret = dsp_kfunc_device_register(&nokia770_audio_device);
+       if (ret) {
+               printk(KERN_ERR
+                      "KFUNC device registration faild: %s\n",
+                      nokia770_audio_device.name);
+               goto out;
+       }
+       return 0;
+ out:
+       return ret;
 }
+#endif /* CONFIG_OMAP_DSP */
 
 static void __init omap_nokia770_init(void)
 {
@@ -249,9 +288,7 @@ static void __init omap_nokia770_init(void)
        omap_board_config = nokia770_config;
        omap_board_config_size = ARRAY_SIZE(nokia770_config);
        omap_serial_init();
-       omap_dsp_audio_pwr_up_request = nokia770_audio_pwr_up_request;
-       omap_dsp_audio_pwr_down_request = nokia770_audio_pwr_down_request;
-       dspxor_ck = clk_get(0, "dspxor_ck");
+       omap_dsp_init();
 }
 
 static void __init omap_nokia770_map_io(void)
index 7d0cf7af88ceb8c420b5fdb912edf3f3358170f8..969dec5422344752b73a869a555893b428697377 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
+#include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 
@@ -292,6 +293,18 @@ static struct platform_device osk5912_kp_device = {
        .resource       = osk5912_kp_resources,
 };
 
+static struct omap_backlight_config mistral_bl_data = {
+       .default_intensity      = 0xa0,
+};
+
+static struct platform_device mistral_bl_device = {
+       .name           = "omap-bl",
+       .id             = -1,
+       .dev            = {
+               .platform_data = &mistral_bl_data,
+       },
+};
+
 static struct platform_device osk5912_lcd_device = {
        .name           = "lcd_osk",
        .id             = -1,
@@ -299,6 +312,7 @@ static struct platform_device osk5912_lcd_device = {
 
 static struct platform_device *mistral_devices[] __initdata = {
        &osk5912_kp_device,
+       &mistral_bl_device,
        &osk5912_lcd_device,
 };
 
@@ -342,6 +356,38 @@ static void __init osk_mistral_init(void)
         * can't talk to the ads or even the i2c eeprom.
         */
 
+       /* parallel camera interface */
+       omap_cfg_reg(J15_1610_CAM_LCLK);
+       omap_cfg_reg(J18_1610_CAM_D7);
+       omap_cfg_reg(J19_1610_CAM_D6);
+       omap_cfg_reg(J14_1610_CAM_D5);
+       omap_cfg_reg(K18_1610_CAM_D4);
+       omap_cfg_reg(K19_1610_CAM_D3);
+       omap_cfg_reg(K15_1610_CAM_D2);
+       omap_cfg_reg(K14_1610_CAM_D1);
+       omap_cfg_reg(L19_1610_CAM_D0);
+       omap_cfg_reg(L18_1610_CAM_VS);
+       omap_cfg_reg(L15_1610_CAM_HS);
+       omap_cfg_reg(M19_1610_CAM_RSTZ);
+       omap_cfg_reg(Y15_1610_CAM_OUTCLK);
+
+       /* serial camera interface */
+       omap_cfg_reg(H19_1610_CAM_EXCLK);
+       omap_cfg_reg(W13_1610_CCP_CLKM);
+       omap_cfg_reg(Y12_1610_CCP_CLKP);
+       /* CCP_DATAM CONFLICTS WITH UART1.TX (and serial console) */
+       // omap_cfg_reg(Y14_1610_CCP_DATAM);
+       omap_cfg_reg(W14_1610_CCP_DATAP);
+
+       /* CAM_PWDN */
+       if (omap_request_gpio(11) == 0) {
+               omap_cfg_reg(N20_1610_GPIO11);
+               omap_set_gpio_direction(11, 0 /* out */);
+               omap_set_gpio_dataout(11, 0 /* off */);
+       } else
+               pr_debug("OSK+Mistral: CAM_PWDN is awol\n");
+
+
        // omap_cfg_reg(P19_1610_GPIO6);        // BUSY
        omap_cfg_reg(P20_1610_GPIO4);   // PENIRQ
        set_irq_type(OMAP_GPIO_IRQ(4), IRQT_FALLING);
@@ -372,6 +418,15 @@ static void __init osk_mistral_init(void)
        } else
                printk(KERN_ERR "OSK+Mistral: wakeup button is awol\n");
 
+       /* LCD:  backlight, and power; power controls other devices on the
+        * board, like the touchscreen, EEPROM, and wakeup (!) switch.
+        */
+       omap_cfg_reg(PWL);
+       if (omap_request_gpio(2) == 0) {
+               omap_set_gpio_direction(2, 0 /* out */);
+               omap_set_gpio_dataout(2, 1 /* on */);
+       }
+
        platform_add_devices(mistral_devices, ARRAY_SIZE(mistral_devices));
 }
 #else
index 4bc8a62909b9acc23161bf7041da6360bcc6c268..c23e8b6b0a3481474dd9a658c8b3687ac10a442e 100644 (file)
 
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/input.h>
 #include <linux/platform_device.h>
-#include <linux/notifier.h>
-#include <linux/clk.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/tsc2102.h>
+#include <linux/interrupt.h>
 
+#include <asm/apm.h>
 #include <asm/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
+#include <asm/mach/flash.h>
 
 #include <asm/arch/gpio.h>
 #include <asm/arch/mux.h>
 #include <asm/arch/usb.h>
+#include <asm/arch/tc.h>
+#include <asm/arch/dma.h>
 #include <asm/arch/board.h>
+#include <asm/arch/irda.h>
+#include <asm/arch/keypad.h>
 #include <asm/arch/common.h>
+#include <asm/arch/mcbsp.h>
+#include <asm/arch/omap-alsa.h>
 
-static void __init omap_generic_init_irq(void)
+static void __init omap_palmte_init_irq(void)
 {
        omap1_init_common_hw();
        omap_init_irq();
+       omap_gpio_init();
 }
 
+static int palmte_keymap[] = {
+       KEY(0, 0, KEY_F1),
+       KEY(0, 1, KEY_F2),
+       KEY(0, 2, KEY_F3),
+       KEY(0, 3, KEY_F4),
+       KEY(0, 4, KEY_POWER),
+       KEY(1, 0, KEY_LEFT),
+       KEY(1, 1, KEY_DOWN),
+       KEY(1, 2, KEY_UP),
+       KEY(1, 3, KEY_RIGHT),
+       KEY(1, 4, KEY_CENTER),
+       0,
+};
+
+static struct omap_kp_platform_data palmte_kp_data = {
+       .rows   = 8,
+       .cols   = 8,
+       .keymap = palmte_keymap,
+       .rep    = 1,
+       .delay  = 12,
+};
+
+static struct resource palmte_kp_resources[] = {
+       [0]     = {
+               .start  = INT_KEYBOARD,
+               .end    = INT_KEYBOARD,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device palmte_kp_device = {
+       .name           = "omap-keypad",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = &palmte_kp_data,
+       },
+       .num_resources  = ARRAY_SIZE(palmte_kp_resources),
+       .resource       = palmte_kp_resources,
+};
+
+static struct mtd_partition palmte_rom_partitions[] = {
+       /* PalmOS "Small ROM", contains the bootloader and the debugger */
+       {
+               .name           = "smallrom",
+               .offset         = 0,
+               .size           = 0xa000,
+               .mask_flags     = MTD_WRITEABLE,
+       },
+       /* PalmOS "Big ROM", a filesystem with all the OS code and data */
+       {
+               .name           = "bigrom",
+               .offset         = SZ_128K,
+               /*
+                * 0x5f0000 bytes big in the multi-language ("EFIGS") version,
+                * 0x7b0000 bytes in the English-only ("enUS") version.
+                */
+               .size           = 0x7b0000,
+               .mask_flags     = MTD_WRITEABLE,
+       },
+};
+
+static struct flash_platform_data palmte_rom_data = {
+       .map_name       = "map_rom",
+       .width          = 2,
+       .parts          = palmte_rom_partitions,
+       .nr_parts       = ARRAY_SIZE(palmte_rom_partitions),
+};
+
+static struct resource palmte_rom_resource = {
+       .start          = OMAP_CS0_PHYS,
+       .end            = OMAP_CS0_PHYS + SZ_8M - 1,
+       .flags          = IORESOURCE_MEM,
+};
+
+static struct platform_device palmte_rom_device = {
+       .name           = "omapflash",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = &palmte_rom_data,
+       },
+       .num_resources  = 1,
+       .resource       = &palmte_rom_resource,
+};
+
 static struct platform_device palmte_lcd_device = {
        .name           = "lcd_palmte",
        .id             = -1,
 };
 
+static struct omap_backlight_config palmte_backlight_config = {
+       .default_intensity      = 0xa0,
+};
+
+static struct platform_device palmte_backlight_device = {
+       .name           = "omap-bl",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = &palmte_backlight_config,
+       },
+};
+
+static struct omap_irda_config palmte_irda_config = {
+       .transceiver_cap        = IR_SIRMODE,
+       .rx_channel             = OMAP_DMA_UART3_RX,
+       .tx_channel             = OMAP_DMA_UART3_TX,
+       .dest_start             = UART3_THR,
+       .src_start              = UART3_RHR,
+       .tx_trigger             = 0,
+       .rx_trigger             = 0,
+};
+
+static struct resource palmte_irda_resources[] = {
+       [0]     = {
+               .start  = INT_UART3,
+               .end    = INT_UART3,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device palmte_irda_device = {
+       .name           = "omapirda",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = &palmte_irda_config,
+       },
+       .num_resources  = ARRAY_SIZE(palmte_irda_resources),
+       .resource       = palmte_irda_resources,
+};
+
 static struct platform_device *devices[] __initdata = {
+       &palmte_rom_device,
+       &palmte_kp_device,
        &palmte_lcd_device,
+       &palmte_backlight_device,
+       &palmte_irda_device,
 };
 
 static struct omap_usb_config palmte_usb_config __initdata = {
-       .register_dev   = 1,
+       .register_dev   = 1,    /* Mini-B only receptacle */
        .hmc_mode       = 0,
-       .pins[0]        = 3,
+       .pins[0]        = 2,
 };
 
 static struct omap_mmc_config palmte_mmc_config __initdata = {
-       .mmc [0] = {
+       .mmc[0]         = {
                .enabled        = 1,
-               .wire4          = 1,
-               .wp_pin         = OMAP_MPUIO(3),
-               .power_pin      = -1,
-               .switch_pin     = -1,
+               .wp_pin         = PALMTE_MMC_WP_GPIO,
+               .power_pin      = PALMTE_MMC_POWER_GPIO,
+               .switch_pin     = PALMTE_MMC_SWITCH_GPIO,
        },
 };
 
@@ -67,21 +207,222 @@ static struct omap_lcd_config palmte_lcd_config __initdata = {
        .ctrl_name      = "internal",
 };
 
+static struct omap_uart_config palmte_uart_config __initdata = {
+       .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.
+ * May differ slightly from device to device but should be accurate
+ * enough to give basic idea of battery life left and trigger
+ * potential alerts.
+ */
+static const int palmte_battery_sample[] = {
+       2194, 2157, 2138, 2120,
+       2104, 2089, 2075, 2061,
+       2048, 2038, 2026, 2016,
+       2008, 1998, 1989, 1980,
+       1970, 1958, 1945, 1928,
+       1910, 1888, 1860, 1827,
+       1791, 1751, 1709, 1656,
+};
+
+#define INTERVAL               10
+#define BATTERY_HIGH_TRESHOLD  66
+#define BATTERY_LOW_TRESHOLD   33
+
+static void palmte_get_power_status(struct apm_power_info *info, int *battery)
+{
+       int charging, batt, hi, lo, mid;
+
+       charging = !omap_get_gpio_datain(PALMTE_DC_GPIO);
+       batt = battery[0];
+       if (charging)
+               batt -= 60;
+
+       hi = ARRAY_SIZE(palmte_battery_sample);
+       lo = 0;
+
+       info->battery_flag = 0;
+       info->units = APM_UNITS_MINS;
+
+       if (batt > palmte_battery_sample[lo]) {
+               info->battery_life = 100;
+               info->time = INTERVAL * ARRAY_SIZE(palmte_battery_sample);
+       } else if (batt <= palmte_battery_sample[hi - 1]) {
+               info->battery_life = 0;
+               info->time = 0;
+       } else {
+               while (hi > lo + 1) {
+                       mid = (hi + lo) >> 2;
+                       if (batt <= palmte_battery_sample[mid])
+                               lo = mid;
+                       else
+                               hi = mid;
+               }
+
+               mid = palmte_battery_sample[lo] - palmte_battery_sample[hi];
+               hi = palmte_battery_sample[lo] - batt;
+               info->battery_life = 100 - (100 * lo + 100 * hi / mid) /
+                       ARRAY_SIZE(palmte_battery_sample);
+               info->time = INTERVAL * (ARRAY_SIZE(palmte_battery_sample) -
+                               lo) - INTERVAL * hi / mid;
+       }
+
+       if (charging) {
+               info->ac_line_status = APM_AC_ONLINE;
+               info->battery_status = APM_BATTERY_STATUS_CHARGING;
+               info->battery_flag |= APM_BATTERY_FLAG_CHARGING;
+       } else {
+               info->ac_line_status = APM_AC_OFFLINE;
+               if (info->battery_life > BATTERY_HIGH_TRESHOLD)
+                       info->battery_status = APM_BATTERY_STATUS_HIGH;
+               else if (info->battery_life > BATTERY_LOW_TRESHOLD)
+                       info->battery_status = APM_BATTERY_STATUS_LOW;
+               else
+                       info->battery_status = APM_BATTERY_STATUS_CRITICAL;
+       }
+
+       if (info->battery_life > BATTERY_HIGH_TRESHOLD)
+               info->battery_flag |= APM_BATTERY_FLAG_HIGH;
+       else if (info->battery_life > BATTERY_LOW_TRESHOLD)
+               info->battery_flag |= APM_BATTERY_FLAG_LOW;
+       else
+               info->battery_flag |= APM_BATTERY_FLAG_CRITICAL;
+}
+#else
+#define palmte_get_power_status        NULL
+#endif
+
+static struct tsc2102_config palmte_tsc2102_config = {
+       .use_internal   = 0,
+       .monitor        = TSC_BAT1 | TSC_AUX | TSC_TEMP,
+       .temp_at25c     = { 2200, 2615 },
+       .apm_report     = palmte_get_power_status,
+       .alsa_config    = &palmte_alsa_config,
+};
+
 static struct omap_board_config_kernel palmte_config[] = {
-       { OMAP_TAG_USB, &palmte_usb_config },
-       { OMAP_TAG_MMC, &palmte_mmc_config },
-       { OMAP_TAG_LCD, &palmte_lcd_config },
+       { OMAP_TAG_USB,         &palmte_usb_config },
+       { OMAP_TAG_MMC,         &palmte_mmc_config },
+       { OMAP_TAG_LCD,         &palmte_lcd_config },
+       { OMAP_TAG_UART,        &palmte_uart_config },
 };
 
-static void __init omap_generic_init(void)
+static struct spi_board_info palmte_spi_info[] __initdata = {
+       {
+               .modalias       = "tsc2102",
+               .bus_num        = 2,    /* uWire (officially) */
+               .chip_select    = 0,    /* As opposed to 3 */
+               .irq            = OMAP_GPIO_IRQ(PALMTE_PINTDAV_GPIO),
+               .platform_data  = &palmte_tsc2102_config,
+               .max_speed_hz   = 8000000,
+       },
+};
+
+/* Periodically check for changes on important input pins */
+struct timer_list palmte_pin_timer;
+int prev_power, prev_headphones;
+
+static void palmte_pin_handler(unsigned long data) {
+       int power, headphones;
+
+       power = !omap_get_gpio_datain(PALMTE_DC_GPIO);
+       headphones = omap_get_gpio_datain(PALMTE_HEADPHONES_GPIO);
+
+       if (power && !prev_power)
+               printk(KERN_INFO "PM: cable connected\n");
+       else if (!power && prev_power)
+               printk(KERN_INFO "PM: cable disconnected\n");
+
+       if (headphones && !prev_headphones) {
+               /* Headphones connected, disable speaker */
+               omap_set_gpio_dataout(PALMTE_SPEAKER_GPIO, 0);
+               printk(KERN_INFO "PM: speaker off\n");
+       } else if (!headphones && prev_headphones) {
+               /* Headphones unplugged, re-enable speaker */
+               omap_set_gpio_dataout(PALMTE_SPEAKER_GPIO, 1);
+               printk(KERN_INFO "PM: speaker on\n");
+       }
+
+       prev_power = power;
+       prev_headphones = headphones;
+       mod_timer(&palmte_pin_timer, jiffies + msecs_to_jiffies(500));
+}
+
+static void __init palmte_gpio_setup(void)
+{
+       /* Set TSC2102 PINTDAV pin as input */
+       if (omap_request_gpio(PALMTE_PINTDAV_GPIO)) {
+               printk(KERN_ERR "Could not reserve PINTDAV GPIO!\n");
+               return;
+       }
+       omap_set_gpio_direction(PALMTE_PINTDAV_GPIO, 1);
+
+       /* Monitor cable-connected signals */
+       if (omap_request_gpio(PALMTE_DC_GPIO) ||
+                       omap_request_gpio(PALMTE_USB_OR_DC_GPIO) ||
+                       omap_request_gpio(PALMTE_USBDETECT_GPIO)) {
+               printk(KERN_ERR "Could not reserve cable signal GPIO!\n");
+               return;
+       }
+       omap_set_gpio_direction(PALMTE_DC_GPIO, 1);
+       omap_set_gpio_direction(PALMTE_USB_OR_DC_GPIO, 1);
+       omap_set_gpio_direction(PALMTE_USBDETECT_GPIO, 1);
+
+       /* Set speaker-enable pin as output */
+       if (omap_request_gpio(PALMTE_SPEAKER_GPIO)) {
+               printk(KERN_ERR "Could not reserve speaker GPIO!\n");
+               return;
+       }
+       omap_set_gpio_direction(PALMTE_SPEAKER_GPIO, 0);
+
+       /* Monitor the headphones-connected signal */
+       if (omap_request_gpio(PALMTE_HEADPHONES_GPIO)) {
+               printk(KERN_ERR "Could not reserve headphones signal GPIO!\n");
+               return;
+       }
+       omap_set_gpio_direction(PALMTE_HEADPHONES_GPIO, 1);
+
+       prev_power = omap_get_gpio_datain(PALMTE_DC_GPIO);
+       prev_headphones = !omap_get_gpio_datain(PALMTE_HEADPHONES_GPIO);
+       setup_timer(&palmte_pin_timer, palmte_pin_handler, 0);
+       palmte_pin_handler(0);
+}
+
+static void __init omap_palmte_init(void)
 {
        omap_board_config = palmte_config;
        omap_board_config_size = ARRAY_SIZE(palmte_config);
 
        platform_add_devices(devices, ARRAY_SIZE(devices));
+
+       spi_register_board_info(palmte_spi_info, ARRAY_SIZE(palmte_spi_info));
+
+       omap_serial_init();
+       palmte_gpio_setup();
 }
 
-static void __init omap_generic_map_io(void)
+static void __init omap_palmte_map_io(void)
 {
        omap1_map_common_io();
 }
@@ -90,8 +431,8 @@ MACHINE_START(OMAP_PALMTE, "OMAP310 based Palm Tungsten E")
        .phys_io        = 0xfff00000,
        .io_pg_offst    = ((0xfef00000) >> 18) & 0xfffc,
        .boot_params    = 0x10000100,
-       .map_io         = omap_generic_map_io,
-       .init_irq       = omap_generic_init_irq,
-       .init_machine   = omap_generic_init,
+       .map_io         = omap_palmte_map_io,
+       .init_irq       = omap_palmte_init_irq,
+       .init_machine   = omap_palmte_init,
        .timer          = &omap_timer,
 MACHINE_END
diff --git a/arch/arm/mach-omap1/board-palmtt.c b/arch/arm/mach-omap1/board-palmtt.c
new file mode 100644 (file)
index 0000000..e47010f
--- /dev/null
@@ -0,0 +1,357 @@
+/*
+ * linux/arch/arm/mach-omap1/board-palmtt.c
+ *
+ * Modified from board-palmtt2.c
+ *
+ * Modified and amended for Palm Tungsten|T
+ * by Marek Vasut <marek.vasut@gmail.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/delay.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/notifier.h>
+#include <linux/clk.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/leds.h>
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/flash.h>
+
+#include <asm/arch/led.h>
+#include <asm/arch/mcbsp.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/usb.h>
+#include <asm/arch/dma.h>
+#include <asm/arch/tc.h>
+#include <asm/arch/board.h>
+#include <asm/arch/irda.h>
+#include <asm/arch/keypad.h>
+#include <asm/arch/common.h>
+#include <asm/arch/omap-alsa.h>
+
+#include <linux/input.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/ads7846.h>
+
+static int palmtt_keymap[] = {
+       KEY(0, 0, KEY_ESC),
+       KEY(0, 1, KEY_SPACE),
+       KEY(0, 2, KEY_LEFTCTRL),
+       KEY(0, 3, KEY_TAB),
+       KEY(0, 4, KEY_ENTER),
+       KEY(1, 0, KEY_LEFT),
+       KEY(1, 1, KEY_DOWN),
+       KEY(1, 2, KEY_UP),
+       KEY(1, 3, KEY_RIGHT),
+       KEY(2, 0, KEY_SLEEP),
+       KEY(2, 4, KEY_Y),
+       0
+};
+
+static struct mtd_partition palmtt_partitions[] = {
+       {
+               .name           = "write8k",
+               .offset         = 0,
+               .size           = SZ_8K,
+               .mask_flags     = 0,
+       },
+       {
+               .name           = "PalmOS-BootLoader(ro)",
+               .offset         = SZ_8K,
+               .size           = 7 * SZ_8K,
+               .mask_flags     = MTD_WRITEABLE,
+       },
+       {
+               .name           = "u-boot",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = 8 * SZ_8K,
+               .mask_flags     = 0,
+       },
+       {
+               .name           = "PalmOS-FS(ro)",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = 7 * SZ_1M + 4 * SZ_64K - 16 * SZ_8K,
+               .mask_flags     = MTD_WRITEABLE,
+       },
+       {
+               .name           = "u-boot(rez)",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = SZ_128K,
+               .mask_flags     = 0
+       },
+       {
+               .name           = "empty",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = MTDPART_SIZ_FULL,
+               .mask_flags     = 0
+       }
+};
+
+static struct flash_platform_data palmtt_flash_data = {
+       .map_name       = "cfi_probe",
+       .width          = 2,
+       .parts          = palmtt_partitions,
+       .nr_parts       = ARRAY_SIZE(palmtt_partitions),
+};
+
+static struct resource palmtt_flash_resource = {
+       .start          = OMAP_CS0_PHYS,
+       .end            = OMAP_CS0_PHYS + SZ_8M - 1,
+       .flags          = IORESOURCE_MEM,
+};
+
+static struct platform_device palmtt_flash_device = {
+       .name           = "omapflash",
+       .id             = 0,
+       .dev            = {
+               .platform_data  = &palmtt_flash_data,
+       },
+       .num_resources  = 1,
+       .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,
+               .end    = INT_KEYBOARD,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct omap_kp_platform_data palmtt_kp_data = {
+       .rows   = 6,
+       .cols   = 3,
+       .keymap = palmtt_keymap,
+};
+
+static struct platform_device palmtt_kp_device = {
+       .name           = "omap-keypad",
+       .id             = -1,
+       .dev            = {
+               .platform_data = &palmtt_kp_data,
+       },
+       .num_resources  = ARRAY_SIZE(palmtt_kp_resources),
+       .resource       = palmtt_kp_resources,
+};
+
+static struct platform_device palmtt_lcd_device = {
+       .name           = "lcd_palmtt",
+       .id             = -1,
+};
+static struct omap_irda_config palmtt_irda_config = {
+       .transceiver_cap        = IR_SIRMODE,
+       .rx_channel             = OMAP_DMA_UART3_RX,
+       .tx_channel             = OMAP_DMA_UART3_TX,
+       .dest_start             = UART3_THR,
+       .src_start              = UART3_RHR,
+       .tx_trigger             = 0,
+       .rx_trigger             = 0,
+};
+
+static struct resource palmtt_irda_resources[] = {
+       [0]     = {
+               .start  = INT_UART3,
+               .end    = INT_UART3,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device palmtt_irda_device = {
+       .name           = "omapirda",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = &palmtt_irda_config,
+       },
+       .num_resources  = ARRAY_SIZE(palmtt_irda_resources),
+       .resource       = palmtt_irda_resources,
+};
+
+static struct platform_device palmtt_spi_device = {
+       .name           = "spi_palmtt",
+       .id             = -1,
+};
+
+static struct omap_backlight_config palmtt_backlight_config = {
+       .default_intensity      = 0xa0,
+};
+
+static struct platform_device palmtt_backlight_device = {
+       .name           = "omap-bl",
+       .id             = -1,
+       .dev            = {
+               .platform_data= &palmtt_backlight_config,
+       },
+};
+
+static struct omap_led_config palmtt_led_config[] = {
+       {
+               .cdev   = {
+                       .name   = "palmtt:led0",
+               },
+               .gpio   = PALMTT_LED_GPIO,
+       },
+};
+
+static struct omap_led_platform_data palmtt_led_data = {
+       .nr_leds        = ARRAY_SIZE(palmtt_led_config),
+       .leds           = palmtt_led_config,
+};
+
+static struct platform_device palmtt_led_device = {
+       .name   = "omap-led",
+       .id     = -1,
+       .dev    = {
+               .platform_data  = &palmtt_led_data,
+       },
+};
+
+static struct platform_device *palmtt_devices[] __initdata = {
+       &palmtt_flash_device,
+       &palmtt_mcbsp1_device,
+       &palmtt_kp_device,
+       &palmtt_lcd_device,
+       &palmtt_irda_device,
+       &palmtt_spi_device,
+       &palmtt_backlight_device,
+       &palmtt_led_device,
+};
+
+static int palmtt_get_pendown_state(void)
+{
+       return !omap_get_gpio_datain(6);
+}
+
+static const struct ads7846_platform_data palmtt_ts_info = {
+       .model                  = 7846,
+       .vref_delay_usecs       = 100,  /* internal, no capacitor */
+       .x_plate_ohms           = 419,
+       .y_plate_ohms           = 486,
+       .get_pendown_state      = palmtt_get_pendown_state,
+};
+
+static struct spi_board_info __initdata palmtt_boardinfo[] = {
+       {
+               /* MicroWire (bus 2) CS0 has an ads7846e */
+               .modalias       = "ads7846",
+               .platform_data  = &palmtt_ts_info,
+               .irq            = OMAP_GPIO_IRQ(6),
+               .max_speed_hz   = 120000        /* max sample rate at 3V */
+                                       * 26    /* command + data + overhead */,
+               .bus_num        = 2,
+               .chip_select    = 0,
+       }
+};
+
+static void __init omap_palmtt_init_irq(void)
+{
+       omap1_init_common_hw();
+       omap_init_irq();
+}
+
+static struct omap_usb_config palmtt_usb_config __initdata = {
+       .register_dev   = 1,
+       .hmc_mode       = 0,
+       .pins[0]        = 2,
+};
+
+static struct omap_lcd_config palmtt_lcd_config __initdata = {
+       .ctrl_name      = "internal",
+};
+
+static struct omap_uart_config palmtt_uart_config __initdata = {
+       .enabled_uarts = (1 << 0) | (1 << 1) | (0 << 2),
+};
+
+static struct omap_board_config_kernel palmtt_config[] = {
+       { OMAP_TAG_USB,         &palmtt_usb_config      },
+       { OMAP_TAG_LCD,         &palmtt_lcd_config      },
+       { OMAP_TAG_UART,        &palmtt_uart_config     },
+};
+
+static void __init omap_mpu_wdt_mode(int mode) {
+       if (mode)
+               omap_writew(0x8000, OMAP_WDT_TIMER_MODE);
+       else {
+               omap_writew(0x00f5, OMAP_WDT_TIMER_MODE);
+               omap_writew(0x00a0, OMAP_WDT_TIMER_MODE);
+       }
+}
+
+static void __init omap_palmtt_init(void)
+{
+       omap_mpu_wdt_mode(0);
+
+       omap_board_config = palmtt_config;
+       omap_board_config_size = ARRAY_SIZE(palmtt_config);
+
+       platform_add_devices(palmtt_devices, ARRAY_SIZE(palmtt_devices));
+
+       spi_register_board_info(palmtt_boardinfo,ARRAY_SIZE(palmtt_boardinfo));
+       omap_serial_init();
+}
+
+static void __init omap_palmtt_map_io(void)
+{
+       omap1_map_common_io();
+}
+
+MACHINE_START(OMAP_PALMTT, "OMAP1510 based Palm Tungsten|T")
+       .phys_io        = 0xfff00000,
+       .io_pg_offst    = ((0xfef00000) >> 18) & 0xfffc,
+       .boot_params    = 0x10000100,
+       .map_io         = omap_palmtt_map_io,
+       .init_irq       = omap_palmtt_init_irq,
+       .init_machine   = omap_palmtt_init,
+       .timer          = &omap_timer,
+MACHINE_END
diff --git a/arch/arm/mach-omap1/board-palmz71.c b/arch/arm/mach-omap1/board-palmz71.c
new file mode 100644 (file)
index 0000000..3936190
--- /dev/null
@@ -0,0 +1,383 @@
+/*
+ * linux/arch/arm/mach-omap1/board-palmz71.c
+ *
+ * Modified from board-generic.c
+ *
+ * Support for the Palm Zire71 PDA.
+ *
+ * Original version : Laurent Gonzalez
+ *
+ * Modified for zire71 : Marek Vasut
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/notifier.h>
+#include <linux/clk.h>
+#include <linux/irq.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/flash.h>
+
+#include <asm/arch/mcbsp.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/usb.h>
+#include <asm/arch/dma.h>
+#include <asm/arch/tc.h>
+#include <asm/arch/board.h>
+#include <asm/arch/irda.h>
+#include <asm/arch/keypad.h>
+#include <asm/arch/common.h>
+#include <asm/arch/omap-alsa.h>
+
+#include <linux/input.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/ads7846.h>
+
+static void __init
+omap_palmz71_init_irq(void)
+{
+       omap1_init_common_hw();
+       omap_init_irq();
+       omap_gpio_init();
+}
+
+static int palmz71_keymap[] = {
+       KEY(0, 0, KEY_F1),
+       KEY(0, 1, KEY_F2),
+       KEY(0, 2, KEY_F3),
+       KEY(0, 3, KEY_F4),
+       KEY(0, 4, KEY_POWER),
+       KEY(1, 0, KEY_LEFT),
+       KEY(1, 1, KEY_DOWN),
+       KEY(1, 2, KEY_UP),
+       KEY(1, 3, KEY_RIGHT),
+       KEY(1, 4, KEY_CENTER),
+       KEY(2, 0, KEY_CAMERA),
+       0,
+};
+
+static struct omap_kp_platform_data palmz71_kp_data = {
+       .rows   = 8,
+       .cols   = 8,
+       .keymap = palmz71_keymap,
+       .rep    = 1,
+       .delay  = 80,
+};
+
+static struct resource palmz71_kp_resources[] = {
+       [0] = {
+               .start  = INT_KEYBOARD,
+               .end    = INT_KEYBOARD,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device palmz71_kp_device = {
+       .name   = "omap-keypad",
+       .id     = -1,
+       .dev    = {
+               .platform_data = &palmz71_kp_data,
+       },
+       .num_resources  = ARRAY_SIZE(palmz71_kp_resources),
+       .resource       = palmz71_kp_resources,
+};
+
+static struct mtd_partition palmz71_rom_partitions[] = {
+       /* PalmOS "Small ROM", contains the bootloader and the debugger */
+       {
+               .name           = "smallrom",
+               .offset         = 0,
+               .size           = 0xa000,
+               .mask_flags     = MTD_WRITEABLE,
+       },
+       /* PalmOS "Big ROM", a filesystem with all the OS code and data */
+       {
+               .name   = "bigrom",
+               .offset = SZ_128K,
+               /*
+                * 0x5f0000 bytes big in the multi-language ("EFIGS") version,
+                * 0x7b0000 bytes in the English-only ("enUS") version.
+                */
+               .size           = 0x7b0000,
+               .mask_flags     = MTD_WRITEABLE,
+       },
+};
+
+static struct flash_platform_data palmz71_rom_data = {
+       .map_name       = "map_rom",
+       .name           = "onboardrom",
+       .width          = 2,
+       .parts          = palmz71_rom_partitions,
+       .nr_parts       = ARRAY_SIZE(palmz71_rom_partitions),
+};
+
+static struct resource palmz71_rom_resource = {
+       .start  = OMAP_CS0_PHYS,
+       .end    = OMAP_CS0_PHYS + SZ_8M - 1,
+       .flags  = IORESOURCE_MEM,
+};
+
+static struct platform_device palmz71_rom_device = {
+       .name   = "omapflash",
+       .id     = -1,
+       .dev = {
+               .platform_data = &palmz71_rom_data,
+       },
+       .num_resources  = 1,
+       .resource       = &palmz71_rom_resource,
+};
+
+static struct platform_device palmz71_lcd_device = {
+       .name   = "lcd_palmz71",
+       .id     = -1,
+};
+
+static struct omap_irda_config palmz71_irda_config = {
+       .transceiver_cap        = IR_SIRMODE,
+       .rx_channel             = OMAP_DMA_UART3_RX,
+       .tx_channel             = OMAP_DMA_UART3_TX,
+       .dest_start             = UART3_THR,
+       .src_start              = UART3_RHR,
+       .tx_trigger             = 0,
+       .rx_trigger             = 0,
+};
+
+static struct resource palmz71_irda_resources[] = {
+       [0] = {
+               .start  = INT_UART3,
+               .end    = INT_UART3,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device palmz71_irda_device = {
+       .name   = "omapirda",
+       .id     = -1,
+       .dev = {
+               .platform_data = &palmz71_irda_config,
+       },
+       .num_resources  = ARRAY_SIZE(palmz71_irda_resources),
+       .resource       = palmz71_irda_resources,
+};
+
+static struct platform_device palmz71_spi_device = {
+       .name   = "spi_palmz71",
+       .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 palmz71_backlight_device = {
+       .name   = "omap-bl",
+       .id     = -1,
+       .dev    = {
+               .platform_data = &palmz71_backlight_config,
+       },
+};
+
+static struct platform_device *devices[] __initdata = {
+       &palmz71_rom_device,
+       &palmz71_kp_device,
+       &palmz71_mcbsp1_device,
+       &palmz71_lcd_device,
+       &palmz71_irda_device,
+       &palmz71_spi_device,
+       &palmz71_backlight_device,
+};
+
+static int
+palmz71_get_pendown_state(void)
+{
+       return !omap_get_gpio_datain(PALMZ71_PENIRQ_GPIO);
+}
+
+static const struct ads7846_platform_data palmz71_ts_info = {
+       .model                  = 7846,
+       .vref_delay_usecs       = 100,  /* internal, no capacitor */
+       .x_plate_ohms           = 419,
+       .y_plate_ohms           = 486,
+       .get_pendown_state      = palmz71_get_pendown_state,
+};
+
+static struct spi_board_info __initdata palmz71_boardinfo[] = { {
+       /* MicroWire (bus 2) CS0 has an ads7846e */
+       .modalias       = "ads7846",
+       .platform_data  = &palmz71_ts_info,
+       .irq            = OMAP_GPIO_IRQ(PALMZ71_PENIRQ_GPIO),
+       .max_speed_hz   = 120000        /* max sample rate at 3V */
+                               * 26    /* command + data + overhead */,
+       .bus_num        = 2,
+       .chip_select    = 0,
+} };
+
+static struct omap_usb_config palmz71_usb_config __initdata = {
+       .register_dev   = 1,    /* Mini-B only receptacle */
+       .hmc_mode       = 0,
+       .pins[0]        = 2,
+};
+
+static struct omap_mmc_config palmz71_mmc_config __initdata = {
+       .mmc[0] = {
+               .enabled        = 1,
+               .wire4          = 0,
+               .wp_pin         = PALMZ71_MMC_WP_GPIO,
+               .power_pin      = -1,
+               .switch_pin     = PALMZ71_MMC_IN_GPIO,
+       },
+};
+
+static struct omap_lcd_config palmz71_lcd_config __initdata = {
+       .ctrl_name = "internal",
+};
+
+static struct omap_uart_config palmz71_uart_config __initdata = {
+       .enabled_uarts = (1 << 0) | (1 << 1) | (0 << 2),
+};
+
+static struct omap_board_config_kernel palmz71_config[] = {
+       {OMAP_TAG_USB,  &palmz71_usb_config},
+       {OMAP_TAG_MMC,  &palmz71_mmc_config},
+       {OMAP_TAG_LCD,  &palmz71_lcd_config},
+       {OMAP_TAG_UART, &palmz71_uart_config},
+};
+
+static irqreturn_t
+palmz71_powercable(int irq, void *dev_id)
+{
+       if (omap_get_gpio_datain(PALMZ71_USBDETECT_GPIO)) {
+               printk(KERN_INFO "PM: Power cable connected\n");
+               set_irq_type(OMAP_GPIO_IRQ(PALMZ71_USBDETECT_GPIO),
+                               IRQT_FALLING);
+       } else {
+               printk(KERN_INFO "PM: Power cable disconnected\n");
+               set_irq_type(OMAP_GPIO_IRQ(PALMZ71_USBDETECT_GPIO),
+                               IRQT_RISING);
+       }
+       return IRQ_HANDLED;
+}
+
+static void __init
+omap_mpu_wdt_mode(int mode)
+{
+       if (mode)
+               omap_writew(0x8000, OMAP_WDT_TIMER_MODE);
+       else {
+               omap_writew(0x00f5, OMAP_WDT_TIMER_MODE);
+               omap_writew(0x00a0, OMAP_WDT_TIMER_MODE);
+       }
+}
+
+static void __init
+palmz71_gpio_setup(int early)
+{
+       if (early) {
+               /* Only set GPIO1 so we have a working serial */
+               omap_set_gpio_dataout(1, 1);
+               omap_set_gpio_direction(1, 0);
+       } else {
+               /* Set MMC/SD host WP pin as input */
+               if (omap_request_gpio(PALMZ71_MMC_WP_GPIO)) {
+                       printk(KERN_ERR "Could not reserve WP GPIO!\n");
+                       return;
+               }
+               omap_set_gpio_direction(PALMZ71_MMC_WP_GPIO, 1);
+
+               /* Monitor the Power-cable-connected signal */
+               if (omap_request_gpio(PALMZ71_USBDETECT_GPIO)) {
+                       printk(KERN_ERR
+                               "Could not reserve cable signal GPIO!\n");
+                       return;
+               }
+               omap_set_gpio_direction(PALMZ71_USBDETECT_GPIO, 1);
+               if (request_irq(OMAP_GPIO_IRQ(PALMZ71_USBDETECT_GPIO),
+                               palmz71_powercable, IRQF_SAMPLE_RANDOM,
+                               "palmz71-cable", 0))
+                       printk(KERN_ERR
+                              "IRQ request for power cable failed!\n");
+               palmz71_powercable(OMAP_GPIO_IRQ(PALMZ71_USBDETECT_GPIO), 0);
+       }
+}
+
+static void __init
+omap_palmz71_init(void)
+{
+       palmz71_gpio_setup(1);
+       omap_mpu_wdt_mode(0);
+
+       omap_board_config = palmz71_config;
+       omap_board_config_size = ARRAY_SIZE(palmz71_config);
+
+       platform_add_devices(devices, ARRAY_SIZE(devices));
+
+       spi_register_board_info(palmz71_boardinfo,
+                               ARRAY_SIZE(palmz71_boardinfo));
+       omap_serial_init();
+       palmz71_gpio_setup(0);
+}
+
+static void __init
+omap_palmz71_map_io(void)
+{
+       omap1_map_common_io();
+}
+
+MACHINE_START(OMAP_PALMZ71, "OMAP310 based Palm Zire71")
+       .phys_io = 0xfff00000,
+       .io_pg_offst = ((0xfef00000) >> 18) & 0xfffc,
+       .boot_params = 0x10000100,.map_io = omap_palmz71_map_io,
+       .init_irq = omap_palmz71_init_irq,
+       .init_machine = omap_palmz71_init,
+       .timer = &omap_timer,
+MACHINE_END
index fa4be962df67b454c09afc2ea956f11251904825..1d5c8d5097222ad1289b4edf8664febb66434b61 100644 (file)
@@ -246,7 +246,7 @@ static void __init perseus2_init_smc91x(void)
        mdelay(50);
 }
 
-void omap_perseus2_init_irq(void)
+static void __init omap_perseus2_init_irq(void)
 {
        omap1_init_common_hw();
        omap_init_irq();
diff --git a/arch/arm/mach-omap1/board-sx1.c b/arch/arm/mach-omap1/board-sx1.c
new file mode 100644 (file)
index 0000000..2743d63
--- /dev/null
@@ -0,0 +1,494 @@
+/*
+* linux/arch/arm/mach-omap1/board-sx1.c
+*
+* Modified from board-generic.c
+*
+* Support for the Siemens SX1 mobile phone.
+*
+* Original version : Vladimir Ananiev (Vovan888-at-gmail com)
+*
+* Maintainters : Vladimir Ananiev (aka Vovan888), Sergge
+*              oslik.ru
+*
+* 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/input.h>
+#include <linux/platform_device.h>
+#include <linux/notifier.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/errno.h>
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/flash.h>
+#include <asm/mach/map.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/irda.h>
+#include <asm/arch/usb.h>
+#include <asm/arch/tc.h>
+#include <asm/arch/board.h>
+#include <asm/arch/common.h>
+#include <asm/arch/mcbsp.h>
+#include <asm/arch/omap-alsa.h>
+#include <asm/arch/keypad.h>
+
+/* Write to I2C device */
+int i2c_write_byte(u8 devaddr, u8 regoffset, u8 value)
+{
+       struct i2c_adapter *adap;
+       int err;
+       struct i2c_msg msg[1];
+       unsigned char data[2];
+
+       adap = i2c_get_adapter(0);
+       if (!adap)
+               return -ENODEV;
+       msg->addr = devaddr;    /* I2C address of chip */
+       msg->flags = 0;
+       msg->len = 2;
+       msg->buf = data;
+       data[0] = regoffset;    /* register num */
+       data[1] = value;                /* register data */
+       err = i2c_transfer(adap, msg, 1);
+       if (err >= 0)
+               return 0;
+       return err;
+}
+
+/* Read from I2C device */
+int i2c_read_byte(u8 devaddr, u8 regoffset, u8 * value)
+{
+       struct i2c_adapter *adap;
+       int err;
+       struct i2c_msg msg[1];
+       unsigned char data[2];
+
+       adap = i2c_get_adapter(0);
+       if (!adap)
+               return -ENODEV;
+
+       msg->addr = devaddr;    /* I2C address of chip */
+       msg->flags = 0;
+       msg->len = 1;
+       msg->buf = data;
+       data[0] = regoffset;    /* register num */
+       err = i2c_transfer(adap, msg, 1);
+
+       msg->addr = devaddr;    /* I2C address */
+       msg->flags = I2C_M_RD;
+       msg->len = 1;
+       msg->buf = data;
+       err = i2c_transfer(adap, msg, 1);
+       *value = data[0];
+
+       if (err >= 0)
+               return 0;
+       return err;
+}
+/* set keyboard backlight intensity */
+int sx1_setkeylight(u8 keylight)
+{
+       if (keylight > SOFIA_MAX_LIGHT_VAL)
+               keylight = SOFIA_MAX_LIGHT_VAL;
+       return i2c_write_byte(SOFIA_I2C_ADDR, SOFIA_KEYLIGHT_REG, keylight);
+}
+/* get current keylight intensity */
+int sx1_getkeylight(u8 * keylight)
+{
+       return i2c_read_byte(SOFIA_I2C_ADDR, SOFIA_KEYLIGHT_REG, keylight);
+}
+/* set LCD backlight intensity */
+int sx1_setbacklight(u8 backlight)
+{
+       if (backlight > SOFIA_MAX_LIGHT_VAL)
+               backlight = SOFIA_MAX_LIGHT_VAL;
+       return i2c_write_byte(SOFIA_I2C_ADDR, SOFIA_BACKLIGHT_REG, backlight);
+}
+/* get current LCD backlight intensity */
+int sx1_getbacklight (u8 * backlight)
+{
+       return i2c_read_byte(SOFIA_I2C_ADDR, SOFIA_BACKLIGHT_REG, backlight);
+}
+/* set LCD backlight power on/off */
+int sx1_setmmipower(u8 onoff)
+{
+       int err;
+       u8 dat = 0;
+       err = i2c_read_byte(SOFIA_I2C_ADDR, SOFIA_POWER1_REG, &dat);
+       if (err < 0)
+               return err;
+       if (onoff)
+               dat |= SOFIA_MMILIGHT_POWER;
+       else
+               dat &= ~SOFIA_MMILIGHT_POWER;
+       return i2c_write_byte(SOFIA_I2C_ADDR, SOFIA_POWER1_REG, dat);
+}
+/* set MMC power on/off */
+int sx1_setmmcpower(u8 onoff)
+{
+       int err;
+       u8 dat = 0;
+       err = i2c_read_byte(SOFIA_I2C_ADDR, SOFIA_POWER1_REG, &dat);
+       if (err < 0)
+               return err;
+       if (onoff)
+               dat |= SOFIA_MMC_POWER;
+       else
+               dat &= ~SOFIA_MMC_POWER;
+       return i2c_write_byte(SOFIA_I2C_ADDR, SOFIA_POWER1_REG, dat);
+}
+/* set USB power on/off */
+int sx1_setusbpower(u8 onoff)
+{
+       int err;
+       u8 dat = 0;
+       err = i2c_read_byte(SOFIA_I2C_ADDR, SOFIA_POWER1_REG, &dat);
+       if (err < 0)
+               return err;
+       if (onoff)
+               dat |= SOFIA_USB_POWER;
+       else
+               dat &= ~SOFIA_USB_POWER;
+       return i2c_write_byte(SOFIA_I2C_ADDR, SOFIA_POWER1_REG, dat);
+}
+
+EXPORT_SYMBOL(sx1_setkeylight);
+EXPORT_SYMBOL(sx1_getkeylight);
+EXPORT_SYMBOL(sx1_setbacklight);
+EXPORT_SYMBOL(sx1_getbacklight);
+EXPORT_SYMBOL(sx1_setmmipower);
+EXPORT_SYMBOL(sx1_setmmcpower);
+EXPORT_SYMBOL(sx1_setusbpower);
+
+/*----------- Keypad -------------------------*/
+
+static int sx1_keymap[] = {
+       KEY(5, 3, GROUP_0 | 117), /* camera Qt::Key_F17 */
+       KEY(0, 4, GROUP_0 | 114), /* voice memo Qt::Key_F14 */
+       KEY(1, 4, GROUP_2 | 114), /* voice memo */
+       KEY(2, 4, GROUP_3 | 114), /* voice memo */
+       KEY(0, 0, GROUP_1 | KEY_F12),   /* red button Qt::Key_Hangup */
+       KEY(4, 3, GROUP_1 | KEY_LEFT),
+       KEY(2, 3, GROUP_1 | KEY_DOWN),
+       KEY(1, 3, GROUP_1 | KEY_RIGHT),
+       KEY(0, 3, GROUP_1 | KEY_UP),
+       KEY(3, 3, GROUP_1 | KEY_POWER), /* joystick press or Qt::Key_Select */
+       KEY(5, 0, GROUP_1 | KEY_1),
+       KEY(4, 0, GROUP_1 | KEY_2),
+       KEY(3, 0, GROUP_1 | KEY_3),
+       KEY(3, 4, GROUP_1 | KEY_4),
+       KEY(4, 4, GROUP_1 | KEY_5),
+       KEY(5, 4, GROUP_1 | KEY_KPASTERISK),/* "*" */
+       KEY(4, 1, GROUP_1 | KEY_6),
+       KEY(5, 1, GROUP_1 | KEY_7),
+       KEY(3, 1, GROUP_1 | KEY_8),
+       KEY(3, 2, GROUP_1 | KEY_9),
+       KEY(5, 2, GROUP_1 | KEY_0),
+       KEY(4, 2, GROUP_1 | 113),       /* # F13 Toggle input method Qt::Key_F13 */
+       KEY(0, 1, GROUP_1 | KEY_F11),   /* green button Qt::Key_Call */
+       KEY(1, 2, GROUP_1 | KEY_YEN),   /* left soft Qt::Key_Context1 */
+       KEY(2, 2, GROUP_1 | KEY_F8),    /* right soft Qt::Key_Back */
+       KEY(2, 1, GROUP_1 | KEY_LEFTSHIFT), /* shift */
+       KEY(1, 1, GROUP_1 | KEY_BACKSPACE), /* C (clear) */
+       KEY(0, 2, GROUP_1 | KEY_F7),    /* menu Qt::Key_Menu */
+       0
+};
+
+static struct resource sx1_kp_resources[] = {
+       [0] = {
+               .start  = INT_KEYBOARD,
+               .end    = INT_KEYBOARD,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct omap_kp_platform_data sx1_kp_data = {
+       .rows           = 6,
+       .cols           = 6,
+       .keymap = sx1_keymap,
+       .keymapsize = ARRAY_SIZE(sx1_keymap),
+       .delay  = 80,
+};
+
+static struct platform_device sx1_kp_device = {
+       .name           = "omap-keypad",
+       .id             = -1,
+       .dev            = {
+               .platform_data = &sx1_kp_data,
+       },
+       .num_resources  = ARRAY_SIZE(sx1_kp_resources),
+       .resource       = sx1_kp_resources,
+};
+
+/*----------- IRDA -------------------------*/
+
+static struct omap_irda_config sx1_irda_data = {
+       .transceiver_cap        = IR_SIRMODE,
+       .rx_channel             = OMAP_DMA_UART3_RX,
+       .tx_channel             = OMAP_DMA_UART3_TX,
+       .dest_start             = UART3_THR,
+       .src_start              = UART3_RHR,
+       .tx_trigger             = 0,
+       .rx_trigger             = 0,
+};
+
+static struct resource sx1_irda_resources[] = {
+       [0] = {
+               .start  = INT_UART3,
+               .end    = INT_UART3,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static u64 irda_dmamask = 0xffffffff;
+
+static struct platform_device sx1_irda_device = {
+       .name           = "omapirda",
+       .id             = 0,
+       .dev            = {
+               .platform_data  = &sx1_irda_data,
+               .dma_mask       = &irda_dmamask,
+       },
+       .num_resources  = ARRAY_SIZE(sx1_irda_resources),
+       .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 */
+};
+
+/* TODO: PCM interface - McBSP2 */
+static struct omap_mcbsp_reg_cfg mcbsp2_regs = {
+       .spcr2  = FRST | GRST | XRST | XINTM(3),        /* SPCR2=F1 */
+       .spcr1  = RINTM(3) | RRST,      /* 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 */
+       /* mcbsp: slave */
+};
+
+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[] = {
+       /* bootloader (U-Boot, etc) in first sector */
+       {
+               .name           = "bootloader",
+               .offset         = 0x01800000,
+               .size           = SZ_128K,
+               .mask_flags     = MTD_WRITEABLE, /* force read-only */
+       },
+       /* bootloader params in the next sector */
+       {
+               .name           = "params",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = SZ_128K,
+               .mask_flags     = 0,
+       },
+       /* kernel */
+       {
+               .name           = "kernel",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = SZ_2M - 2 * SZ_128K,
+               .mask_flags     = 0
+       },
+       /* file system */
+       {
+               .name           = "filesystem",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = MTDPART_SIZ_FULL,
+               .mask_flags     = 0
+       }
+};
+
+static struct flash_platform_data sx1_flash_data = {
+       .map_name       = "cfi_probe",
+       .width          = 2,
+       .parts          = sx1_partitions,
+       .nr_parts       = ARRAY_SIZE(sx1_partitions),
+};
+
+#ifdef CONFIG_SX1_OLD_FLASH
+/* MTD Intel StrataFlash - old flashes */
+static struct resource sx1_old_flash_resource[] = {
+       [0] = {
+               .start  = OMAP_CS0_PHYS,        /* Physical */
+               .end    = OMAP_CS0_PHYS + SZ_16M - 1,,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = OMAP_CS1_PHYS,
+               .end    = OMAP_CS1_PHYS + SZ_8M - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device sx1_flash_device = {
+       .name           = "omapflash",
+       .id             = 0,
+       .dev            = {
+               .platform_data  = &sx1_flash_data,
+       },
+       .num_resources  = 2,
+       .resource       = &sx1_old_flash_resource,
+};
+#else
+/* MTD Intel 4000 flash - new flashes */
+static struct resource sx1_new_flash_resource = {
+       .start          = OMAP_CS0_PHYS,
+       .end            = OMAP_CS0_PHYS + SZ_32M - 1,
+       .flags          = IORESOURCE_MEM,
+};
+
+static struct platform_device sx1_flash_device = {
+       .name           = "omapflash",
+       .id             = 0,
+       .dev            = {
+               .platform_data  = &sx1_flash_data,
+       },
+       .num_resources  = 1,
+       .resource       = &sx1_new_flash_resource,
+};
+#endif
+
+/*----------- USB -------------------------*/
+
+static struct omap_usb_config sx1_usb_config __initdata = {
+       .otg            = 0,
+       .register_dev   = 1,
+       .register_host  = 0,
+       .hmc_mode       = 0,
+       .pins[0]        = 2,
+       .pins[1]        = 0,
+       .pins[2]        = 0,
+};
+
+/*----------- MMC -------------------------*/
+
+static struct omap_mmc_config sx1_mmc_config __initdata = {
+       .mmc [0] = {
+               .enabled        = 1,
+               .wire4          = 0,
+               .wp_pin         = -1,
+               .power_pin      = -1, /* power is in Sofia */
+               .switch_pin     = OMAP_MPUIO(3),
+       },
+};
+
+/*----------- LCD -------------------------*/
+
+static struct platform_device sx1_lcd_device = {
+       .name           = "lcd_sx1",
+       .id             = -1,
+};
+
+static struct omap_lcd_config sx1_lcd_config __initdata = {
+       .ctrl_name      = "internal",
+};
+
+/*-----------------------------------------*/
+static struct platform_device *sx1_devices[] __initdata = {
+       &sx1_flash_device,
+       &sx1_kp_device,
+       &sx1_lcd_device,
+       &sx1_mcbsp1_device,
+       &sx1_irda_device,
+};
+/*-----------------------------------------*/
+
+static struct omap_uart_config sx1_uart_config __initdata = {
+       .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
+};
+
+static struct omap_board_config_kernel sx1_config[] = {
+       { OMAP_TAG_USB, &sx1_usb_config },
+       { OMAP_TAG_MMC, &sx1_mmc_config },
+       { OMAP_TAG_LCD, &sx1_lcd_config },
+       { OMAP_TAG_UART,        &sx1_uart_config },
+};
+/*-----------------------------------------*/
+static void __init omap_sx1_init(void)
+{
+       platform_add_devices(sx1_devices, ARRAY_SIZE(sx1_devices));
+
+       omap_board_config = sx1_config;
+       omap_board_config_size = ARRAY_SIZE(sx1_config);
+       omap_serial_init();
+
+       /* 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 */
+       omap_set_gpio_direction(1, 0);/* gpio1 -> output */
+       omap_set_gpio_direction(11, 0);/* gpio11 -> output */
+       omap_set_gpio_direction(15, 0);/* gpio15 -> output */
+       /* set GPIO data */
+       omap_set_gpio_dataout(1, 1);/*A_IRDA_OFF = 1 */
+       omap_set_gpio_dataout(11, 0);/*A_SWITCH = 0 */
+       omap_set_gpio_dataout(15, 0);/*A_USB_ON = 0 */
+
+}
+/*----------------------------------------*/
+static void __init omap_sx1_init_irq(void)
+{
+       omap1_init_common_hw();
+       omap_init_irq();
+       omap_gpio_init();
+}
+/*----------------------------------------*/
+
+static void __init omap_sx1_map_io(void)
+{
+       omap1_map_common_io();
+}
+
+MACHINE_START(SX1, "OMAP310 based Siemens SX1")
+       .phys_io        = 0xfff00000,
+       .io_pg_offst    = ((0xfef00000) >> 18) & 0xfffc,
+       .boot_params    = 0x10000100,
+       .map_io         = omap_sx1_map_io,
+       .init_irq               = omap_sx1_init_irq,
+       .init_machine   = omap_sx1_init,
+       .timer          = &omap_timer,
+MACHINE_END
index 447a586eb33452c11b6891c618b8b3ac9033063b..214dd19889aca953922e77d6fc49efbb33c4daca 100644 (file)
@@ -235,7 +235,7 @@ static struct notifier_block panic_block = {
 static int __init voiceblue_setup(void)
 {
        /* Setup panic notifier */
-       notifier_chain_register(&panic_notifier_list, &panic_block);
+       atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
 
        return 0;
 }
index 638490e62d5f5ebb7e07a21f586c521b9b2f2fe2..7e3b24fccff13a0299293b403f9ca1875df9a8f8 100644 (file)
@@ -432,8 +432,7 @@ static int omap1_clk_enable(struct clk *clk)
                        }
 
                        if (clk->flags & CLOCK_NO_IDLE_PARENT)
-                               if (!cpu_is_omap24xx())
-                                       omap1_clk_deny_idle(clk->parent);
+                               omap1_clk_deny_idle(clk->parent);
                }
 
                ret = clk->enable(clk);
@@ -454,8 +453,7 @@ static void omap1_clk_disable(struct clk *clk)
                if (likely(clk->parent)) {
                        omap1_clk_disable(clk->parent);
                        if (clk->flags & CLOCK_NO_IDLE_PARENT)
-                               if (!cpu_is_omap24xx())
-                                       omap1_clk_allow_idle(clk->parent);
+                               omap1_clk_allow_idle(clk->parent);
                }
        }
 }
@@ -471,7 +469,7 @@ static int omap1_clk_enable_generic(struct clk *clk)
        if (unlikely(clk->enable_reg == 0)) {
                printk(KERN_ERR "clock.c: Enable for %s without enable code\n",
                       clk->name);
-               return 0;
+               return -EINVAL;
        }
 
        if (clk->flags & ENABLE_REG_32BIT) {
@@ -651,10 +649,18 @@ int __init omap1_clk_init(void)
        int crystal_type = 0; /* Default 12 MHz */
        u32 reg;
 
+#ifdef CONFIG_DEBUG_LL
+       /* Resets some clocks that may be left on from bootloader,
+        * but leaves serial clocks on.
+        */
+       omap_writel(0x3 << 29, MOD_CONF_CTRL_0);
+#endif
+
        /* USB_REQ_EN will be disabled later if necessary (usb_dc_ck) */
        reg = omap_readw(SOFT_REQ_REG) & (1 << 4);
        omap_writew(reg, SOFT_REQ_REG);
-       omap_writew(0, SOFT_REQ_REG2);
+       if (!cpu_is_omap15xx())
+               omap_writew(0, SOFT_REQ_REG2);
 
        clk_init(&omap1_clk_functions);
 
@@ -685,7 +691,7 @@ int __init omap1_clk_init(void)
 
        info = omap_get_config(OMAP_TAG_CLOCK, struct omap_clock_config);
        if (info != NULL) {
-               if (!cpu_is_omap1510())
+               if (!cpu_is_omap15xx())
                        crystal_type = info->system_clock_type;
        }
 
index f7df00205c4a6541827cb6e8331901b4c229e34b..4d6060c2facbae45ffe5257247e387642956b9d3 100644 (file)
@@ -282,7 +282,7 @@ static struct clk arminth_ck16xx = {
 static struct clk dsp_ck = {
        .name           = "dsp_ck",
        .parent         = &ck_dpll1,
-       .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+       .flags          = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
                          RATE_CKCTL,
        .enable_reg     = (void __iomem *)ARM_CKCTL,
        .enable_bit     = EN_DSPCK,
@@ -295,7 +295,7 @@ static struct clk dsp_ck = {
 static struct clk dspmmu_ck = {
        .name           = "dspmmu_ck",
        .parent         = &ck_dpll1,
-       .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+       .flags          = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
                          RATE_CKCTL | ALWAYS_ENABLED,
        .rate_offset    = CKCTL_DSPMMUDIV_OFFSET,
        .recalc         = &omap1_ckctl_recalc,
@@ -306,7 +306,7 @@ static struct clk dspmmu_ck = {
 static struct clk dspper_ck = {
        .name           = "dspper_ck",
        .parent         = &ck_dpll1,
-       .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+       .flags          = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
                          RATE_CKCTL | VIRTUAL_IO_ADDRESS,
        .enable_reg     = (void __iomem *)DSP_IDLECT2,
        .enable_bit     = EN_PERCK,
@@ -320,7 +320,7 @@ static struct clk dspper_ck = {
 static struct clk dspxor_ck = {
        .name           = "dspxor_ck",
        .parent         = &ck_ref,
-       .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+       .flags          = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
                          VIRTUAL_IO_ADDRESS,
        .enable_reg     = (void __iomem *)DSP_IDLECT2,
        .enable_bit     = EN_XORPCK,
@@ -332,7 +332,7 @@ static struct clk dspxor_ck = {
 static struct clk dsptim_ck = {
        .name           = "dsptim_ck",
        .parent         = &ck_ref,
-       .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+       .flags          = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
                          VIRTUAL_IO_ADDRESS,
        .enable_reg     = (void __iomem *)DSP_IDLECT2,
        .enable_bit     = EN_DSPTIMCK,
@@ -374,7 +374,7 @@ static struct clk arminth_ck1510 = {
 
 static struct clk tipb_ck = {
        /* No-idle controlled by "tc_ck" */
-       .name           = "tibp_ck",
+       .name           = "tipb_ck",
        .parent         = &tc_ck.clk,
        .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 |
                          ALWAYS_ENABLED,
@@ -733,7 +733,7 @@ remains active during MPU idle whenever this is enabled */
 static struct clk i2c_fck = {
        .name           = "i2c_fck",
        .id             = 1,
-       .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+       .flags          = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
                          VIRTUAL_CLOCK | CLOCK_NO_IDLE_PARENT |
                          ALWAYS_ENABLED,
        .parent         = &armxor_ck.clk,
index 6dcd10ab4496f765a7681731e85c1a8ee7c36f30..497c8bb5e69b5b47853672a47c4b3b21eb49d451 100644 (file)
 #include <asm/arch/mux.h>
 #include <asm/arch/gpio.h>
 
-#if    defined(CONFIG_OMAP1610_IR) || defined(CONFIG_OMAP161O_IR_MODULE)
-
-static u64 irda_dmamask = 0xffffffff;
-
-static struct platform_device omap1610ir_device = {
-       .name = "omap1610-ir",
-       .id = -1,
-       .dev = {
-               .dma_mask       = &irda_dmamask,
-       },
-};
-
-static void omap_init_irda(void)
-{
-       /* FIXME define and use a boot tag, members something like:
-        *  u8          uart;           // uart1, or uart3
-        * ... but driver only handles uart3 for now
-        *  s16         fir_sel;        // gpio for SIR vs FIR
-        * ... may prefer a callback for SIR/MIR/FIR mode select;
-        * while h2 uses a GPIO, H3 uses a gpio expander
-        */
-       if (machine_is_omap_h2()
-                       || machine_is_omap_h3())
-               (void) platform_device_register(&omap1610ir_device);
-}
-#else
-static inline void omap_init_irda(void) {}
-#endif
-
 /*-------------------------------------------------------------------------*/
 
-#if defined(CONFIG_RTC_DRV_OMAP) || defined(CONFIG_RTC_DRV_OMAP_MODULE)
+#if defined(CONFIG_OMAP_RTC) || defined(CONFIG_RTC_DRV_OMAP) || defined(CONFIG_RTC_DRV_OMAP_MODULE)
 
 #define        OMAP_RTC_BASE           0xfffb4800
 
@@ -90,6 +61,45 @@ static void omap_init_rtc(void)
 static inline void omap_init_rtc(void) {}
 #endif
 
+#if defined(CONFIG_OMAP_DSP) || defined(CONFIG_OMAP_DSP_MODULE)
+
+#if defined(CONFIG_ARCH_OMAP15XX)
+#  define OMAP1_MBOX_SIZE      0x23
+#  define INT_DSP_MAILBOX1     INT_1510_DSP_MAILBOX1
+#elif defined(CONFIG_ARCH_OMAP16XX)
+#  define OMAP1_MBOX_SIZE      0x2f
+#  define INT_DSP_MAILBOX1     INT_1610_DSP_MAILBOX1
+#endif
+
+#define OMAP1_MBOX_BASE                IO_ADDRESS(OMAP16XX_MAILBOX_BASE)
+
+static struct resource mbox_resources[] = {
+       {
+               .start          = OMAP1_MBOX_BASE,
+               .end            = OMAP1_MBOX_BASE + OMAP1_MBOX_SIZE,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = INT_DSP_MAILBOX1,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device mbox_device = {
+       .name           = "mailbox",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(mbox_resources),
+       .resource       = mbox_resources,
+};
+
+static inline void omap_init_mbox(void)
+{
+       platform_device_register(&mbox_device);
+}
+#else
+static inline void omap_init_mbox(void) { }
+#endif
+
 #if defined(CONFIG_OMAP_STI)
 
 #define OMAP1_STI_BASE         IO_ADDRESS(0xfffea000)
@@ -154,7 +164,8 @@ static int __init omap1_init_devices(void)
        /* please keep these calls, and their implementations above,
         * in alphabetical order so they're easier to sort through.
         */
-       omap_init_irda();
+
+       omap_init_mbox();
        omap_init_rtc();
        omap_init_sti();
 
index 6383a12ad970ffe275049d87237109ea80d13a5b..410d3e78dd0fd9911633c84657f23877792950c6 100644 (file)
@@ -238,7 +238,7 @@ void __init omap_init_irq(void)
 
        if (cpu_is_omap730())
                omap_unmask_irq(INT_730_IH2_IRQ);
-       else if (cpu_is_omap1510())
+       else if (cpu_is_omap15xx())
                omap_unmask_irq(INT_1510_IH2_IRQ);
        else if (cpu_is_omap16xx())
                omap_unmask_irq(INT_1610_IH2_IRQ);
diff --git a/arch/arm/mach-omap1/mailbox.c b/arch/arm/mach-omap1/mailbox.c
new file mode 100644 (file)
index 0000000..877b838
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * Mailbox reservation modules for DSP
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/resource.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <asm/arch/mailbox.h>
+#include <asm/arch/irqs.h>
+#include <asm/io.h>
+
+#define MAILBOX_ARM2DSP1               0x00
+#define MAILBOX_ARM2DSP1b              0x04
+#define MAILBOX_DSP2ARM1               0x08
+#define MAILBOX_DSP2ARM1b              0x0c
+#define MAILBOX_DSP2ARM2               0x10
+#define MAILBOX_DSP2ARM2b              0x14
+#define MAILBOX_ARM2DSP1_Flag          0x18
+#define MAILBOX_DSP2ARM1_Flag          0x1c
+#define MAILBOX_DSP2ARM2_Flag          0x20
+
+unsigned long mbox_base;
+
+struct omap_mbox1_fifo {
+       unsigned long cmd;
+       unsigned long data;
+       unsigned long flag;
+};
+
+struct omap_mbox1_priv {
+       struct omap_mbox1_fifo tx_fifo;
+       struct omap_mbox1_fifo rx_fifo;
+};
+
+static inline int mbox_read_reg(unsigned int reg)
+{
+       return __raw_readw(mbox_base + reg);
+}
+
+static inline void mbox_write_reg(unsigned int val, unsigned int reg)
+{
+       __raw_writew(val, mbox_base + reg);
+}
+
+/* msg */
+static inline mbox_msg_t omap1_mbox_fifo_read(struct omap_mbox *mbox)
+{
+       struct omap_mbox1_fifo *fifo =
+               &((struct omap_mbox1_priv *)mbox->priv)->rx_fifo;
+       mbox_msg_t msg;
+
+       msg = mbox_read_reg(fifo->data);
+       msg |= ((mbox_msg_t) mbox_read_reg(fifo->cmd)) << 16;
+
+       return msg;
+}
+
+static inline void
+omap1_mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg)
+{
+       struct omap_mbox1_fifo *fifo =
+               &((struct omap_mbox1_priv *)mbox->priv)->tx_fifo;
+
+       mbox_write_reg(msg & 0xffff, fifo->data);
+       mbox_write_reg(msg >> 16, fifo->cmd);
+}
+
+static inline int omap1_mbox_fifo_empty(struct omap_mbox *mbox)
+{
+       return 0;
+}
+
+static inline int omap1_mbox_fifo_full(struct omap_mbox *mbox)
+{
+       struct omap_mbox1_fifo *fifo =
+               &((struct omap_mbox1_priv *)mbox->priv)->rx_fifo;
+
+       return (mbox_read_reg(fifo->flag));
+}
+
+/* irq */
+static inline void
+omap1_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_type_t irq)
+{
+       if (irq == IRQ_RX)
+               enable_irq(mbox->irq);
+}
+
+static inline void
+omap1_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_type_t irq)
+{
+       if (irq == IRQ_RX)
+               disable_irq(mbox->irq);
+}
+
+static inline int
+omap1_mbox_is_irq(struct omap_mbox *mbox, omap_mbox_type_t irq)
+{
+       if (irq == IRQ_TX)
+               return 0;
+       return 1;
+}
+
+struct omap_mbox_ops omap1_mbox_ops = {
+       .type = OMAP_MBOX_TYPE1,
+       .fifo_read = omap1_mbox_fifo_read,
+       .fifo_write = omap1_mbox_fifo_write,
+       .fifo_empty = omap1_mbox_fifo_empty,
+       .fifo_full = omap1_mbox_fifo_full,
+       .enable_irq = omap1_mbox_enable_irq,
+       .disable_irq = omap1_mbox_disable_irq,
+       .is_irq = omap1_mbox_is_irq,
+};
+
+/* FIXME: the following struct should be created automatically by the user id  */
+
+/* DSP */
+static struct omap_mbox1_priv omap1_mbox_dsp_priv = {
+       .tx_fifo = {
+               .cmd  = MAILBOX_ARM2DSP1b,
+               .data = MAILBOX_ARM2DSP1,
+               .flag = MAILBOX_ARM2DSP1_Flag,
+       },
+       .rx_fifo = {
+               .cmd  = MAILBOX_DSP2ARM1b,
+               .data = MAILBOX_DSP2ARM1,
+               .flag = MAILBOX_DSP2ARM1_Flag,
+       },
+};
+
+struct omap_mbox mbox_dsp_info = {
+       .name = "dsp",
+       .ops  = &omap1_mbox_ops,
+       .priv = &omap1_mbox_dsp_priv,
+};
+EXPORT_SYMBOL(mbox_dsp_info);
+
+static int __init omap1_mbox_probe(struct platform_device *pdev)
+{
+       struct resource *res;
+       int ret = 0;
+
+       if (pdev->num_resources != 2) {
+               dev_err(&pdev->dev, "invalid number of resources: %d\n",
+                       pdev->num_resources);
+               return -ENODEV;
+       }
+
+       /* MBOX base */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (unlikely(!res)) {
+               dev_err(&pdev->dev, "invalid mem resource\n");
+               return -ENODEV;
+       }
+       mbox_base = res->start;
+
+       /* DSP IRQ */
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (unlikely(!res)) {
+               dev_err(&pdev->dev, "invalid irq resource\n");
+               return -ENODEV;
+       }
+       mbox_dsp_info.irq = res->start;
+
+       ret = omap_mbox_register(&mbox_dsp_info);
+
+       return ret;
+}
+
+static int omap1_mbox_remove(struct platform_device *pdev)
+{
+       omap_mbox_unregister(&mbox_dsp_info);
+
+       return 0;
+}
+
+static struct platform_driver omap1_mbox_driver = {
+       .probe  = omap1_mbox_probe,
+       .remove = omap1_mbox_remove,
+       .driver = {
+               .name = "mailbox",
+       },
+};
+
+static int __init omap1_mbox_init(void)
+{
+       return platform_driver_register(&omap1_mbox_driver);
+}
+
+static void __exit omap1_mbox_exit(void)
+{
+       platform_driver_unregister(&omap1_mbox_driver);
+}
+
+module_init(omap1_mbox_init);
+module_exit(omap1_mbox_exit);
+
+MODULE_LICENSE("GPL");
index 5432335bc493de0d65e44155909bd5ff413d7195..52c70e5fcf65ea459e6443be8ec5a221a627be99 100644 (file)
@@ -283,6 +283,30 @@ MUX_CFG("R11_1610_CF_IOIS16",       B,    0,    3,   2,   16,   1,   2,     1,  1)
 MUX_CFG("V10_1610_CF_IREQ",     A,   24,    3,   2,   14,   0,   2,     0,  1)
 MUX_CFG("W10_1610_CF_RESET",    A,   18,    3,   2,   12,   1,   2,     1,  1)
 MUX_CFG("W11_1610_CF_CD1",     10,   15,    3,   3,    8,   1,   3,     1,  1)
+
+/* parallel camera */
+MUX_CFG("J15_1610_CAM_LCLK",    4,   24,    0,   0,  18,   1,    0,     0,  0)
+MUX_CFG("J18_1610_CAM_D7",      4,   27,    0,   0,  19,   1,    0,     0,  0)
+MUX_CFG("J19_1610_CAM_D6",      5,    0,    0,   0,  20,   1,    0,     0,  0)
+MUX_CFG("J14_1610_CAM_D5",      5,    3,    0,   0,  21,   1,    0,     0,  0)
+MUX_CFG("K18_1610_CAM_D4",      5,    6,    0,   0,  22,   1,    0,     0,  0)
+MUX_CFG("K19_1610_CAM_D3",      5,    9,    0,   0,  23,   1,    0,     0,  0)
+MUX_CFG("K15_1610_CAM_D2",      5,   12,    0,   0,  24,   1,    0,     0,  0)
+MUX_CFG("K14_1610_CAM_D1",      5,   15,    0,   0,  25,   1,    0,     0,  0)
+MUX_CFG("L19_1610_CAM_D0",      5,   18,    0,   0,  26,   1,    0,     0,  0)
+MUX_CFG("L18_1610_CAM_VS",      5,   21,    0,   0,  27,   1,    0,     0,  0)
+MUX_CFG("L15_1610_CAM_HS",      5,   24,    0,   0,  28,   1,    0,     0,  0)
+MUX_CFG("M19_1610_CAM_RSTZ",    5,   27,    0,   0,  29,   0,    0,     0,  0)
+MUX_CFG("Y15_1610_CAM_OUTCLK",  A,    0,    6,   2,   6,   0,    2,     0,  0)
+
+/* serial camera */
+MUX_CFG("H19_1610_CAM_EXCLK",   4,   21,    0,   0,  17,   0,    0,     0,  0)
+       /* REVISIT 5912 spec sez CCP_* can't pullup or pulldown ... ? */
+MUX_CFG("Y12_1610_CCP_CLKP",    8,   18,    6,   1,  24,   1,    1,     0,  0)
+MUX_CFG("W13_1610_CCP_CLKM",    9,    0,    6,   1,  28,   1,    1,     0,  0)
+MUX_CFG("W14_1610_CCP_DATAP",   9,   24,    6,   2,   4,   1,    2,     0,  0)
+MUX_CFG("Y14_1610_CCP_DATAM",   9,   21,    6,   2,   3,   1,    2,     0,  0)
+
 };
 #endif /* CONFIG_ARCH_OMAP15XX || CONFIG_ARCH_OMAP16XX */
 
index 4834758d340c60a9bdec5b349a780443d9893e52..49efe903dacda7c98e8b1043b7b761fa62c73298 100644 (file)
@@ -256,7 +256,8 @@ void omap_pm_suspend(void)
                tps65010_set_led(LED1, OFF);
        }
 
-       omap_writew(0xffff, ULPD_SOFT_DISABLE_REQ_REG);
+       if (!cpu_is_omap15xx())
+               omap_writew(0xffff, ULPD_SOFT_DISABLE_REQ_REG);
 
        /*
         * Step 1: turn off interrupts (FIXME: NOTE: already disabled)
@@ -434,7 +435,8 @@ void omap_pm_suspend(void)
                MPUI1610_RESTORE(OMAP_IH2_3_MIR);
        }
 
-       omap_writew(0, ULPD_SOFT_DISABLE_REQ_REG);
+       if (!cpu_is_omap15xx())
+               omap_writew(0, ULPD_SOFT_DISABLE_REQ_REG);
 
        /*
         * Reenable interrupts
@@ -704,6 +706,8 @@ static struct pm_ops omap_pm_ops ={
 
 static int __init omap_pm_init(void)
 {
+       int error;
+
        printk("Power Management for TI OMAP.\n");
 
        /*
@@ -760,7 +764,9 @@ static int __init omap_pm_init(void)
        omap_pm_init_proc();
 #endif
 
-       subsys_create_file(&power_subsys, &sleep_while_idle_attr);
+       error = subsys_create_file(&power_subsys, &sleep_while_idle_attr);
+       if (error)
+               printk(KERN_ERR "subsys_create_file failed: %d\n", error);
 
        if (cpu_is_omap16xx()) {
                /* configure LOW_PWR pin */
index 4cc98a578e4bf5ed98ac048f702f2c519ae7a22d..10a4fe88b2fd5993a9b8d262f63f9aea4dca5381 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * linux/arch/arm/mach-omap1/serial.c
  *
- * OMAP1 CPU identification code
+ * OMAP1 serial support.
  *
  * 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
@@ -59,7 +59,7 @@ static void __init omap_serial_reset(struct plat_serial8250_port *p)
        omap_serial_outp(p, UART_OMAP_SCR, 0x08);       /* TX watermark */
        omap_serial_outp(p, UART_OMAP_MDR1, 0x00);      /* enable UART */
 
-       if (!cpu_is_omap1510()) {
+       if (!cpu_is_omap15xx()) {
                omap_serial_outp(p, UART_OMAP_SYSC, 0x01);
                while (!(omap_serial_in(p, UART_OMAP_SYSC) & 0x01));
        }
@@ -121,7 +121,7 @@ void __init omap_serial_init(void)
                serial_platform_data[1].irq = INT_730_UART_MODEM_IRDA_2;
        }
 
-       if (cpu_is_omap1510()) {
+       if (cpu_is_omap15xx()) {
                serial_platform_data[0].uartclk = OMAP1510_BASE_BAUD * 16;
                serial_platform_data[1].uartclk = OMAP1510_BASE_BAUD * 16;
                serial_platform_data[2].uartclk = OMAP1510_BASE_BAUD * 16;
@@ -147,10 +147,10 @@ void __init omap_serial_init(void)
                                printk("Could not get uart1_ck\n");
                        else {
                                clk_enable(uart1_ck);
-                               if (cpu_is_omap1510())
+                               if (cpu_is_omap15xx())
                                        clk_set_rate(uart1_ck, 12000000);
                        }
-                       if (cpu_is_omap1510()) {
+                       if (cpu_is_omap15xx()) {
                                omap_cfg_reg(UART1_TX);
                                omap_cfg_reg(UART1_RTS);
                                if (machine_is_omap_innovator()) {
@@ -167,12 +167,12 @@ void __init omap_serial_init(void)
                                printk("Could not get uart2_ck\n");
                        else {
                                clk_enable(uart2_ck);
-                               if (cpu_is_omap1510())
+                               if (cpu_is_omap15xx())
                                        clk_set_rate(uart2_ck, 12000000);
                                else
                                        clk_set_rate(uart2_ck, 48000000);
                        }
-                       if (cpu_is_omap1510()) {
+                       if (cpu_is_omap15xx()) {
                                omap_cfg_reg(UART2_TX);
                                omap_cfg_reg(UART2_RTS);
                                if (machine_is_omap_innovator()) {
@@ -189,10 +189,10 @@ void __init omap_serial_init(void)
                                printk("Could not get uart3_ck\n");
                        else {
                                clk_enable(uart3_ck);
-                               if (cpu_is_omap1510())
+                               if (cpu_is_omap15xx())
                                        clk_set_rate(uart3_ck, 12000000);
                        }
-                       if (cpu_is_omap1510()) {
+                       if (cpu_is_omap15xx()) {
                                omap_cfg_reg(UART3_TX);
                                omap_cfg_reg(UART3_RX);
                        }
index 1b7e4a506c2646e66788aaa47f8056147ba4da4a..64fefff5d99f61ac5348526df6e304f926d1ae08 100644 (file)
@@ -39,6 +39,9 @@
 #include <linux/interrupt.h>
 #include <linux/sched.h>
 #include <linux/spinlock.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/clocksource.h>
 
 #include <asm/system.h>
 #include <asm/hardware.h>
 #include <asm/mach/irq.h>
 #include <asm/mach/time.h>
 
-struct sys_timer omap_timer;
 
-/*
- * ---------------------------------------------------------------------------
- * MPU timer
- * ---------------------------------------------------------------------------
- */
 #define OMAP_MPU_TIMER_BASE            OMAP_MPU_TIMER1_BASE
 #define OMAP_MPU_TIMER_OFFSET          0x100
 
@@ -88,21 +85,6 @@ static inline unsigned long long cycles_2_ns(unsigned long long cyc)
        return (cyc * cyc2ns_scale) >> CYC2NS_SCALE_FACTOR;
 }
 
-/*
- * MPU_TICKS_PER_SEC must be an even number, otherwise machinecycles_to_usecs
- * will break. On P2, the timer count rate is 6.5 MHz after programming PTV
- * with 0. This divides the 13MHz input by 2, and is undocumented.
- */
-#if defined(CONFIG_MACH_OMAP_PERSEUS2) || defined(CONFIG_MACH_OMAP_FSAMPLE)
-/* REVISIT: This ifdef construct should be replaced by a query to clock
- * framework to see if timer base frequency is 12.0, 13.0 or 19.2 MHz.
- */
-#define MPU_TICKS_PER_SEC              (13000000 / 2)
-#else
-#define MPU_TICKS_PER_SEC              (12000000 / 2)
-#endif
-
-#define MPU_TIMER_TICK_PERIOD          ((MPU_TICKS_PER_SEC / HZ) - 1)
 
 typedef struct {
        u32 cntl;                       /* CNTL_TIMER, R/W */
@@ -131,87 +113,94 @@ static inline void omap_mpu_timer_start(int nr, unsigned long load_val)
        timer->cntl = (MPU_TIMER_CLOCK_ENABLE | MPU_TIMER_AR | MPU_TIMER_ST);
 }
 
-unsigned long omap_mpu_timer_ticks_to_usecs(unsigned long nr_ticks)
+/*
+ * ---------------------------------------------------------------------------
+ * MPU timer 1 ... count down to zero, interrupt, reload
+ * ---------------------------------------------------------------------------
+ */
+static irqreturn_t omap_mpu_timer1_interrupt(int irq, void *dev_id)
 {
-       unsigned long long nsec;
+       write_seqlock(&xtime_lock);
+       /* NOTE:  no lost-tick detection/handling! */
+       timer_tick();
+       write_sequnlock(&xtime_lock);
 
-       nsec = cycles_2_ns((unsigned long long)nr_ticks);
-       return (unsigned long)nsec / 1000;
+       return IRQ_HANDLED;
 }
 
-/*
- * Last processed system timer interrupt
- */
-static unsigned long omap_mpu_timer_last = 0;
+static struct irqaction omap_mpu_timer1_irq = {
+       .name           = "mpu_timer1",
+       .flags          = IRQF_DISABLED | IRQF_TIMER,
+       .handler        = omap_mpu_timer1_interrupt,
+};
 
-/*
- * Returns elapsed usecs since last system timer interrupt
- */
-static unsigned long omap_mpu_timer_gettimeoffset(void)
+static __init void omap_init_mpu_timer(unsigned long rate)
 {
-       unsigned long now = 0 - omap_mpu_timer_read(0);
-       unsigned long elapsed = now - omap_mpu_timer_last;
+       set_cyc2ns_scale(rate / 1000);
 
-       return omap_mpu_timer_ticks_to_usecs(elapsed);
+       setup_irq(INT_TIMER1, &omap_mpu_timer1_irq);
+       omap_mpu_timer_start(0, (rate / HZ) - 1);
 }
 
 /*
- * Elapsed time between interrupts is calculated using timer0.
- * Latency during the interrupt is calculated using timer1.
- * Both timer0 and timer1 are counting at 6MHz (P2 6.5MHz).
+ * ---------------------------------------------------------------------------
+ * MPU timer 2 ... free running 32-bit clock source and scheduler clock
+ * ---------------------------------------------------------------------------
  */
-static irqreturn_t omap_mpu_timer_interrupt(int irq, void *dev_id)
-{
-       unsigned long now, latency;
 
-       write_seqlock(&xtime_lock);
-       now = 0 - omap_mpu_timer_read(0);
-       latency = MPU_TICKS_PER_SEC / HZ - omap_mpu_timer_read(1);
-       omap_mpu_timer_last = now - latency;
-       timer_tick();
-       write_sequnlock(&xtime_lock);
+static unsigned long omap_mpu_timer2_overflows;
 
+static irqreturn_t omap_mpu_timer2_interrupt(int irq, void *dev_id)
+{
+       omap_mpu_timer2_overflows++;
        return IRQ_HANDLED;
 }
 
-static struct irqaction omap_mpu_timer_irq = {
-       .name           = "mpu timer",
-       .flags          = IRQF_DISABLED | IRQF_TIMER,
-       .handler        = omap_mpu_timer_interrupt,
+static struct irqaction omap_mpu_timer2_irq = {
+       .name           = "mpu_timer2",
+       .flags          = IRQF_DISABLED,
+       .handler        = omap_mpu_timer2_interrupt,
 };
 
-static unsigned long omap_mpu_timer1_overflows;
-static irqreturn_t omap_mpu_timer1_interrupt(int irq, void *dev_id)
+static cycle_t mpu_read(void)
 {
-       omap_mpu_timer1_overflows++;
-       return IRQ_HANDLED;
+       return ~omap_mpu_timer_read(1);
 }
 
-static struct irqaction omap_mpu_timer1_irq = {
-       .name           = "mpu timer1 overflow",
-       .flags          = IRQF_DISABLED,
-       .handler        = omap_mpu_timer1_interrupt,
+static struct clocksource clocksource_mpu = {
+       .name           = "mpu_timer2",
+       .rating         = 300,
+       .read           = mpu_read,
+       .mask           = CLOCKSOURCE_MASK(32),
+       .shift          = 24,
+       .is_continuous  = 1,
 };
 
-static __init void omap_init_mpu_timer(void)
+static void __init omap_init_clocksource(unsigned long rate)
 {
-       set_cyc2ns_scale(MPU_TICKS_PER_SEC / 1000);
-       omap_timer.offset = omap_mpu_timer_gettimeoffset;
-       setup_irq(INT_TIMER1, &omap_mpu_timer1_irq);
-       setup_irq(INT_TIMER2, &omap_mpu_timer_irq);
-       omap_mpu_timer_start(0, 0xffffffff);
-       omap_mpu_timer_start(1, MPU_TIMER_TICK_PERIOD);
+       static char err[] __initdata = KERN_ERR
+                       "%s: can't register clocksource!\n";
+
+       clocksource_mpu.mult
+               = clocksource_khz2mult(rate/1000, clocksource_mpu.shift);
+
+       setup_irq(INT_TIMER2, &omap_mpu_timer2_irq);
+       omap_mpu_timer_start(1, ~0);
+
+       if (clocksource_register(&clocksource_mpu))
+               printk(err, clocksource_mpu.name);
 }
 
+
 /*
  * Scheduler clock - returns current time in nanosec units.
  */
 unsigned long long sched_clock(void)
 {
-       unsigned long ticks = 0 - omap_mpu_timer_read(0);
+       unsigned long ticks = 0 - omap_mpu_timer_read(1);
        unsigned long long ticks64;
 
-       ticks64 = omap_mpu_timer1_overflows;
+       ticks64 = omap_mpu_timer2_overflows;
        ticks64 <<= 32;
        ticks64 |= ticks;
 
@@ -225,10 +214,21 @@ unsigned long long sched_clock(void)
  */
 static void __init omap_timer_init(void)
 {
-       omap_init_mpu_timer();
+       struct clk      *ck_ref = clk_get(NULL, "ck_ref");
+       unsigned long   rate;
+
+       BUG_ON(IS_ERR(ck_ref));
+
+       rate = clk_get_rate(ck_ref);
+       clk_put(ck_ref);
+
+       /* PTV = 0 */
+       rate /= 2;
+
+       omap_init_mpu_timer(rate);
+       omap_init_clocksource(rate);
 }
 
 struct sys_timer omap_timer = {
        .init           = omap_timer_init,
-       .offset         = NULL,         /* Initialized later */
 };
index aab97ccf1e63648889ddb515abd9c35ff85fd826..845daa6f6635b89a6c858c0e9b96d4670a1d146f 100644 (file)
@@ -9,6 +9,11 @@ config ARCH_OMAP2420
        bool "OMAP2420 support"
        depends on ARCH_OMAP24XX
        select OMAP_DM_TIMER
+       select ARCH_OMAP_OTG
+
+config ARCH_OMAP2430
+       bool "OMAP2430 support"
+       depends on ARCH_OMAP24XX
 
 comment "OMAP Board Type"
        depends on ARCH_OMAP2
@@ -17,9 +22,58 @@ config MACH_OMAP_GENERIC
        bool "Generic OMAP board"
        depends on ARCH_OMAP2 && ARCH_OMAP24XX
 
+config MACH_NOKIA_N800
+       bool "Nokia N800"
+       depends on ARCH_OMAP24XX
+
+config MACH_OMAP2_TUSB6010
+       bool
+       depends on ARCH_OMAP2 && ARCH_OMAP2420
+       default y if MACH_NOKIA_N800
+
 config MACH_OMAP_H4
        bool "OMAP 2420 H4 board"
        depends on ARCH_OMAP2 && ARCH_OMAP24XX
+       select OMAP_DEBUG_DEVICES
+       select GPIOEXPANDER_OMAP
+
+config MACH_OMAP_2430SDP
+       bool "OMAP 2430 SDP board"
+       depends on ARCH_OMAP2 && ARCH_OMAP24XX
+
+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"
index 266d88e77bdc7b29da1c2c7db6b6240dddd50c08..60373f596c013998f78c082b6eb87b30bd6fd80b 100644 (file)
@@ -9,10 +9,22 @@ obj-y := irq.o id.o io.o sram-fn.o memory.o prcm.o clock.o mux.o devices.o \
 obj-$(CONFIG_OMAP_MPU_TIMER)           += timer-gp.o
 
 # Power Management
-obj-$(CONFIG_PM) += pm.o pm-domain.o sleep.o
+obj-$(CONFIG_PM) += pm.o sleep.o
+
+# DSP
+obj-$(CONFIG_OMAP_DSP) += mailbox_mach.o
+mailbox_mach-objs      := mailbox.o
 
 # Specific board support
 obj-$(CONFIG_MACH_OMAP_GENERIC)                += board-generic.o
 obj-$(CONFIG_MACH_OMAP_H4)             += board-h4.o
+obj-$(CONFIG_MACH_OMAP_2430SDP)                += board-2430sdp.o
 obj-$(CONFIG_MACH_OMAP_APOLLON)                += board-apollon.o
+obj-$(CONFIG_MACH_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-pm.o
+
+# TUSB 6010 chips
+obj-$(CONFIG_MACH_OMAP2_TUSB6010)      += usb-tusb6010.o
 
diff --git a/arch/arm/mach-omap2/board-2430sdp.c b/arch/arm/mach-omap2/board-2430sdp.c
new file mode 100644 (file)
index 0000000..9b262e0
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * linux/arch/arm/mach-omap2/board-2430sdp.c
+ *
+ * Copyright (C) 2006 Texas Instruments
+ *
+ * Modified from mach-omap2/board-generic.c
+ *
+ * Initial Code : Based on a patch from Komal Shah and Richard Woodruff
+ * Updated the Code for 2430 SDP : 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/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/flash.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/board.h>
+#include <asm/arch/common.h>
+#include <asm/arch/gpmc.h>
+#include "prcm-regs.h"
+
+#include <asm/io.h>
+#include <asm/delay.h>
+
+#define        SDP2430_FLASH_CS        0
+#define        SDP2430_SMC91X_CS       5
+
+static struct mtd_partition sdp2430_partitions[] = {
+       /* bootloader (U-Boot, etc) in first sector */
+       {
+               .name           = "bootloader",
+               .offset         = 0,
+               .size           = SZ_256K,
+               .mask_flags     = MTD_WRITEABLE,        /* force read-only */
+        },
+       /* bootloader params in the next sector */
+       {
+               .name           = "params",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = SZ_128K,
+               .mask_flags     = 0,
+        },
+       /* kernel */
+       {
+               .name           = "kernel",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = SZ_2M,
+               .mask_flags     = 0
+       },
+       /* file system */
+       {
+               .name           = "filesystem",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = MTDPART_SIZ_FULL,
+               .mask_flags     = 0
+       }
+};
+
+static struct flash_platform_data sdp2430_flash_data = {
+       .map_name       = "cfi_probe",
+       .width          = 2,
+       .parts          = sdp2430_partitions,
+       .nr_parts       = ARRAY_SIZE(sdp2430_partitions),
+};
+
+static struct resource sdp2430_flash_resource = {
+       .start          = SDP2430_CS0_BASE,
+       .end            = SDP2430_CS0_BASE + SZ_64M - 1,
+       .flags          = IORESOURCE_MEM,
+};
+
+static struct platform_device sdp2430_flash_device = {
+       .name           = "omapflash",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &sdp2430_flash_data,
+       },
+       .num_resources  = 1,
+       .resource       = &sdp2430_flash_resource,
+};
+
+static struct resource sdp2430_smc91x_resources[] = {
+       [0] = {
+               .start  = SDP2430_CS0_BASE,
+               .end    = SDP2430_CS0_BASE + SZ_64M - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = OMAP_GPIO_IRQ(OMAP24XX_ETHR_GPIO_IRQ),
+               .end    = OMAP_GPIO_IRQ(OMAP24XX_ETHR_GPIO_IRQ),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device sdp2430_smc91x_device = {
+       .name           = "smc91x",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(sdp2430_smc91x_resources),
+       .resource       = sdp2430_smc91x_resources,
+};
+
+static struct platform_device *sdp2430_devices[] __initdata = {
+       &sdp2430_smc91x_device,
+       &sdp2430_flash_device,
+};
+
+static inline void __init sdp2430_init_smc91x(void)
+{
+       int eth_cs;
+       unsigned long cs_mem_base;
+       unsigned int rate;
+       struct clk *l3ck;
+
+       eth_cs = SDP2430_SMC91X_CS;
+
+       l3ck = clk_get(NULL, "core_l3_ck");
+       if (IS_ERR(l3ck))
+               rate = 100000000;
+       else
+               rate = clk_get_rate(l3ck);
+
+       /* Make sure CS1 timings are correct, for 2430 always muxed */
+       gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG1, 0x00011200);
+
+       if (rate >= 160000000) {
+               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG2, 0x001f1f01);
+               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG3, 0x00080803);
+               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG4, 0x1c0b1c0a);
+               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG5, 0x041f1F1F);
+               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG6, 0x000004C4);
+       } else if (rate >= 130000000) {
+               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG2, 0x001f1f00);
+               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG3, 0x00080802);
+               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG4, 0x1C091C09);
+               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG5, 0x041f1F1F);
+               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG6, 0x000004C4);
+       } else { /* rate = 100000000 */
+               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG2, 0x001f1f00);
+               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG3, 0x00080802);
+               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG4, 0x1C091C09);
+               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG5, 0x031A1F1F);
+               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG6, 0x000003C2);
+       }
+
+       if (gpmc_cs_request(eth_cs, SZ_16M, &cs_mem_base) < 0) {
+               printk(KERN_ERR "Failed to request GPMC mem for smc91x\n");
+               return;
+       }
+
+       sdp2430_smc91x_resources[0].start = cs_mem_base + 0x300;
+       sdp2430_smc91x_resources[0].end = cs_mem_base + 0x30f;
+       udelay(100);
+
+       if (omap_request_gpio(OMAP24XX_ETHR_GPIO_IRQ) < 0) {
+               printk(KERN_ERR "Failed to request GPIO%d for smc91x IRQ\n",
+                       OMAP24XX_ETHR_GPIO_IRQ);
+               gpmc_cs_free(eth_cs);
+               return;
+       }
+       omap_set_gpio_direction(OMAP24XX_ETHR_GPIO_IRQ, 1);
+
+}
+
+static void __init omap_2430sdp_init_irq(void)
+{
+       omap2_init_common_hw();
+       omap_init_irq();
+       omap_gpio_init();
+       sdp2430_init_smc91x();
+}
+
+static struct omap_uart_config sdp2430_uart_config __initdata = {
+       .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
+};
+
+static struct omap_board_config_kernel sdp2430_config[] = {
+       {OMAP_TAG_UART, &sdp2430_uart_config},
+};
+
+static void __init omap_2430sdp_init(void)
+{
+       platform_add_devices(sdp2430_devices, ARRAY_SIZE(sdp2430_devices));
+       omap_board_config = sdp2430_config;
+       omap_board_config_size = ARRAY_SIZE(sdp2430_config);
+       omap_serial_init();
+}
+
+static void __init omap_2430sdp_map_io(void)
+{
+       omap2_map_common_io();
+}
+
+MACHINE_START(OMAP_2430SDP, "OMAP2430 sdp2430 board")
+       /* Maintainer: Syed Khasim - Texas Instruments Inc */
+       .phys_io        = 0x48000000,
+       .io_pg_offst    = ((0xd8000000) >> 18) & 0xfffc,
+       .boot_params    = 0x80000100,
+       .map_io         = omap_2430sdp_map_io,
+       .init_irq       = omap_2430sdp_init_irq,
+       .init_machine   = omap_2430sdp_init,
+       .timer          = &omap_timer,
+MACHINE_END
index 878ff9181d0e5159477f5560e571da9cedecf91d..5e1cada561d80dfadb90620638a03568d88c99fd 100644 (file)
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
+#include <linux/leds.h>
+#include <linux/irq.h>
+#include <linux/err.h>
+#include <linux/clk.h>
 
 #include <asm/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/flash.h>
 
 #include <asm/arch/gpio.h>
+#include <asm/arch/led.h>
 #include <asm/arch/mux.h>
 #include <asm/arch/usb.h>
 #include <asm/arch/board.h>
 #include <asm/arch/common.h>
+#include <asm/arch/gpmc.h>
 #include "prcm-regs.h"
 
 /* LED & Switch macros */
@@ -46,6 +52,9 @@
 #define SW_UP_GPIO17           17
 #define SW_DOWN_GPIO58         58
 
+#define APOLLON_FLASH_CS       0
+#define APOLLON_ETH_CS         1
+
 static struct mtd_partition apollon_partitions[] = {
        {
                .name           = "X-Loader + U-Boot",
@@ -85,10 +94,10 @@ static struct flash_platform_data apollon_flash_data = {
        .nr_parts       = ARRAY_SIZE(apollon_partitions),
 };
 
-static struct resource apollon_flash_resource = {
-       .start          = APOLLON_CS0_BASE,
-       .end            = APOLLON_CS0_BASE + SZ_128K,
-       .flags          = IORESOURCE_MEM,
+static struct resource apollon_flash_resource[] = {
+       [0] = {
+               .flags          = IORESOURCE_MEM,
+       },
 };
 
 static struct platform_device apollon_onenand_device = {
@@ -97,14 +106,24 @@ static struct platform_device apollon_onenand_device = {
        .dev            = {
                .platform_data  = &apollon_flash_data,
        },
-       .num_resources  = ARRAY_SIZE(&apollon_flash_resource),
-       .resource       = &apollon_flash_resource,
+       .num_resources  = ARRAY_SIZE(apollon_flash_resource),
+       .resource       = apollon_flash_resource,
 };
 
+static void __init apollon_flash_init(void)
+{
+       unsigned long base;
+
+       if (gpmc_cs_request(APOLLON_FLASH_CS, SZ_128K, &base) < 0) {
+               printk(KERN_ERR "Cannot request OneNAND GPMC CS\n");
+               return;
+       }
+       apollon_flash_resource[0].start = base;
+       apollon_flash_resource[0].end   = base + SZ_128K - 1;
+}
+
 static struct resource apollon_smc91x_resources[] = {
        [0] = {
-               .start  = APOLLON_ETHR_START,           /* Physical */
-               .end    = APOLLON_ETHR_START + 0xf,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
@@ -126,28 +145,98 @@ static struct platform_device apollon_lcd_device = {
        .id             = -1,
 };
 
+static struct omap_led_config apollon_led_config[] = {
+       {
+               .cdev   = {
+                       .name   = "apollon:led0",
+               },
+               .gpio   = LED0_GPIO13,
+       },
+       {
+               .cdev   = {
+                       .name   = "apollon:led1",
+               },
+               .gpio   = LED1_GPIO14,
+       },
+       {
+               .cdev   = {
+                       .name   = "apollon:led2",
+               },
+               .gpio   = LED2_GPIO15,
+       },
+};
+
+static struct omap_led_platform_data apollon_led_data = {
+       .nr_leds        = ARRAY_SIZE(apollon_led_config),
+       .leds           = apollon_led_config,
+};
+
+static struct platform_device apollon_led_device = {
+       .name           = "omap-led",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = &apollon_led_data,
+       },
+};
+
 static struct platform_device *apollon_devices[] __initdata = {
        &apollon_onenand_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 *l3ck;
+       int eth_cs;
+
+       l3ck = clk_get(NULL, "core_l3_ck");
+       if (IS_ERR(l3ck))
+               rate = 100000000;
+       else
+               rate = clk_get_rate(l3ck);
+
+       eth_cs = APOLLON_ETH_CS;
+
        /* Make sure CS1 timings are correct */
-       GPMC_CONFIG1_1 = 0x00011203;
-       GPMC_CONFIG2_1 = 0x001f1f01;
-       GPMC_CONFIG3_1 = 0x00080803;
-       GPMC_CONFIG4_1 = 0x1c091c09;
-       GPMC_CONFIG5_1 = 0x041f1f1f;
-       GPMC_CONFIG6_1 = 0x000004c4;
-       GPMC_CONFIG7_1 = 0x00000f40 | (APOLLON_CS1_BASE >> 24);
+       gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG1, 0x00011200);
+
+       if (rate >= 160000000) {
+               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG2, 0x001f1f01);
+               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG3, 0x00080803);
+               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG4, 0x1c0b1c0a);
+               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG5, 0x041f1F1F);
+               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG6, 0x000004C4);
+       } else if (rate >= 130000000) {
+               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG2, 0x001f1f00);
+               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG3, 0x00080802);
+               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG4, 0x1C091C09);
+               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG5, 0x041f1F1F);
+               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG6, 0x000004C4);
+       } else {/* rate = 100000000 */
+               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG2, 0x001f1f00);
+               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG3, 0x00080802);
+               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG4, 0x1C091C09);
+               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG5, 0x031A1F1F);
+               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG6, 0x000003C2);
+       }
+
+       if (gpmc_cs_request(eth_cs, SZ_16M, &base) < 0) {
+               printk(KERN_ERR "Failed to request GPMC CS for smc91x\n");
+               return;
+       }
+       apollon_smc91x_resources[0].start = base + 0x300;
+       apollon_smc91x_resources[0].end   = base + 0x30f;
        udelay(100);
 
        omap_cfg_reg(W4__24XX_GPIO74);
        if (omap_request_gpio(APOLLON_ETHR_GPIO_IRQ) < 0) {
                printk(KERN_ERR "Failed to request GPIO%d for smc91x IRQ\n",
                        APOLLON_ETHR_GPIO_IRQ);
+               gpmc_cs_free(eth_cs);
                return;
        }
        omap_set_gpio_direction(APOLLON_ETHR_GPIO_IRQ, 1);
@@ -171,10 +260,18 @@ static struct omap_mmc_config apollon_mmc_config __initdata = {
                .wire4          = 1,
                .wp_pin         = -1,
                .power_pin      = -1,
+       /* Note: If you want to detect card feature, please assign 37 */
                .switch_pin     = -1,
        },
 };
 
+static struct omap_usb_config apollon_usb_config __initdata = {
+       .register_dev   = 1,
+       .hmc_mode       = 0x14, /* 0:dev 1:host1 2:disable */
+
+       .pins[0]        = 6,
+};
+
 static struct omap_lcd_config apollon_lcd_config __initdata = {
        .ctrl_name      = "internal",
 };
@@ -182,6 +279,7 @@ static struct omap_lcd_config apollon_lcd_config __initdata = {
 static struct omap_board_config_kernel apollon_config[] = {
        { OMAP_TAG_UART,        &apollon_uart_config },
        { OMAP_TAG_MMC,         &apollon_mmc_config },
+       { OMAP_TAG_USB,         &apollon_usb_config },
        { OMAP_TAG_LCD,         &apollon_lcd_config },
 };
 
@@ -250,13 +348,22 @@ static void __init apollon_sw_init(void)
                return;
 }
 
+static void __init apollon_usb_init(void)
+{
+       /* USB device */
+       /* DEVICE_SUSPEND */
+       omap_cfg_reg(P21_242X_GPIO12);
+       omap_request_gpio(12);
+       omap_set_gpio_direction(12, 0);         /* OUT */
+       omap_set_gpio_dataout(12, 0);
+}
+
 static void __init omap_apollon_init(void)
 {
        apollon_led_init();
        apollon_sw_init();
-
-       /* REVISIT: where's the correct place */
-       omap_cfg_reg(W19_24XX_SYS_NIRQ);
+       apollon_flash_init();
+       apollon_usb_init();
 
        /* Use Interal loop-back in MMC/SDIO Module Input Clock selection */
        CONTROL_DEVCONF |= (1 << 24);
index 3b1ad1d981a359288dc67c84c6f5416e5b1042c7..1787d878895f9c1e9bb67c75831a89e668c72f0c 100644 (file)
@@ -19,6 +19,8 @@
 #include <linux/delay.h>
 #include <linux/workqueue.h>
 #include <linux/input.h>
+#include <linux/err.h>
+#include <linux/clk.h>
 
 #include <asm/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/arch/keypad.h>
 #include <asm/arch/menelaus.h>
 #include <asm/arch/dma.h>
+#include <asm/arch/gpmc.h>
 #include "prcm-regs.h"
 
 #include <asm/io.h>
 #include <asm/delay.h>
 
+#define H4_FLASH_CS    0
+#define H4_SMC91X_CS   1
+
 static unsigned int row_gpios[6] = { 88, 89, 124, 11, 6, 96 };
 static unsigned int col_gpios[7] = { 90, 91, 100, 36, 12, 97, 98 };
 
@@ -117,8 +123,6 @@ static struct flash_platform_data h4_flash_data = {
 };
 
 static struct resource h4_flash_resource = {
-       .start          = H4_CS0_BASE,
-       .end            = H4_CS0_BASE + SZ_64M - 1,
        .flags          = IORESOURCE_MEM,
 };
 
@@ -132,28 +136,9 @@ static struct platform_device h4_flash_device = {
        .resource       = &h4_flash_resource,
 };
 
-static struct resource h4_smc91x_resources[] = {
-       [0] = {
-               .start  = OMAP24XX_ETHR_START,          /* Physical */
-               .end    = OMAP24XX_ETHR_START + 0xf,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = OMAP_GPIO_IRQ(OMAP24XX_ETHR_GPIO_IRQ),
-               .end    = OMAP_GPIO_IRQ(OMAP24XX_ETHR_GPIO_IRQ),
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device h4_smc91x_device = {
-       .name           = "smc91x",
-       .id             = -1,
-       .num_resources  = ARRAY_SIZE(h4_smc91x_resources),
-       .resource       = h4_smc91x_resources,
-};
-
 /* Select between the IrDA and aGPS module
  */
+#if defined(CONFIG_OMAP_IR) || defined(CONFIG_OMAP_IR_MODULE)
 static int h4_select_irda(struct device *dev, int state)
 {
        unsigned char expa;
@@ -179,9 +164,11 @@ static int h4_select_irda(struct device *dev, int state)
        return err;
 }
 
-static void set_trans_mode(void *data)
+static void set_trans_mode(struct work_struct *work)
 {
-       int *mode = data;
+       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;
 
@@ -191,7 +178,7 @@ static void set_trans_mode(void *data)
 
        expa &= ~0x01;
 
-       if (!(*mode & IR_SIRMODE)) { /* MIR/FIR */
+       if (!(mode & IR_SIRMODE)) { /* MIR/FIR */
                expa |= 0x01;
        }
 
@@ -204,13 +191,17 @@ static int h4_transceiver_mode(struct device *dev, int mode)
 {
        struct omap_irda_config *irda_config = dev->platform_data;
 
+       irda_config->mode = mode;
        cancel_delayed_work(&irda_config->gpio_expa);
-       PREPARE_WORK(&irda_config->gpio_expa, set_trans_mode, &mode);
-#error this is not permitted - mode is an argument variable
+       PREPARE_DELAYED_WORK(&irda_config->gpio_expa, set_trans_mode);
        schedule_delayed_work(&irda_config->gpio_expa, 0);
 
        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,
@@ -266,32 +257,103 @@ static struct platform_device h4_lcd_device = {
 };
 
 static struct platform_device *h4_devices[] __initdata = {
-       &h4_smc91x_device,
        &h4_flash_device,
        &h4_irda_device,
        &h4_kp_device,
        &h4_lcd_device,
 };
 
-static inline void __init h4_init_smc91x(void)
+/* 2420 Sysboot setup (2430 is different) */
+static u32 get_sysboot_value(void)
+{
+       return (omap_readl(OMAP242X_CONTROL_STATUS) & 0xFFF);
+}
+
+/* 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
+ *  correctly.  The macro needs to look at production_id not just hawkeye.
+ */
+static u32 is_gpmc_muxed(void)
+{
+       u32 mux;
+       mux = get_sysboot_value();
+       if ((mux & 0xF) == 0xd)
+               return 1;       /* NAND config (could be either) */
+       if (mux & 0x2)          /* if mux'ed */
+               return 1;
+       else
+               return 0;
+}
+
+static inline void __init h4_init_debug(void)
 {
+       int eth_cs;
+       unsigned long cs_mem_base;
+       unsigned int muxed, rate;
+       struct clk *l3ck;
+
+       eth_cs  = H4_SMC91X_CS;
+
+       l3ck = clk_get(NULL, "core_l3_ck");
+       if (IS_ERR(l3ck))
+               rate = 100000000;
+       else
+               rate = clk_get_rate(l3ck);
+
+       if (is_gpmc_muxed())
+               muxed = 0x200;
+       else
+               muxed = 0;
+
        /* Make sure CS1 timings are correct */
-       GPMC_CONFIG1_1 = 0x00011200;
-       GPMC_CONFIG2_1 = 0x001f1f01;
-       GPMC_CONFIG3_1 = 0x00080803;
-       GPMC_CONFIG4_1 = 0x1c091c09;
-       GPMC_CONFIG5_1 = 0x041f1f1f;
-       GPMC_CONFIG6_1 = 0x000004c4;
-       GPMC_CONFIG7_1 = 0x00000f40 | (0x08000000 >> 24);
+       gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG1,
+                         0x00011000 | muxed);
+
+       if (rate >= 160000000) {
+               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG2, 0x001f1f01);
+               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG3, 0x00080803);
+               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG4, 0x1c0b1c0a);
+               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG5, 0x041f1F1F);
+               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG6, 0x000004C4);
+       } else if (rate >= 130000000) {
+               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG2, 0x001f1f00);
+               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG3, 0x00080802);
+               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG4, 0x1C091C09);
+               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG5, 0x041f1F1F);
+               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG6, 0x000004C4);
+       } else {/* rate = 100000000 */
+               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG2, 0x001f1f00);
+               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG3, 0x00080802);
+               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG4, 0x1C091C09);
+               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG5, 0x031A1F1F);
+               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG6, 0x000003C2);
+       }
+
+       if (gpmc_cs_request(eth_cs, SZ_16M, &cs_mem_base) < 0) {
+               printk(KERN_ERR "Failed to request GPMC mem for smc91x\n");
+               return;
+       }
+
        udelay(100);
 
        omap_cfg_reg(M15_24XX_GPIO92);
-       if (omap_request_gpio(OMAP24XX_ETHR_GPIO_IRQ) < 0) {
-               printk(KERN_ERR "Failed to request GPIO%d for smc91x IRQ\n",
-                       OMAP24XX_ETHR_GPIO_IRQ);
+       if (debug_card_init(cs_mem_base, OMAP24XX_ETHR_GPIO_IRQ) < 0)
+               gpmc_cs_free(eth_cs);
+}
+
+static void __init h4_init_flash(void)
+{
+       unsigned long base;
+
+       if (gpmc_cs_request(H4_FLASH_CS, SZ_64M, &base) < 0) {
+               printk("Can't request GPMC CS for flash\n");
                return;
        }
-       omap_set_gpio_direction(OMAP24XX_ETHR_GPIO_IRQ, 1);
+       h4_flash_resource.start = base;
+       h4_flash_resource.end   = base + SZ_64M - 1;
 }
 
 static void __init omap_h4_init_irq(void)
@@ -299,11 +361,15 @@ static void __init omap_h4_init_irq(void)
        omap2_init_common_hw();
        omap_init_irq();
        omap_gpio_init();
-       h4_init_smc91x();
+       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_mmc_config h4_mmc_config __initdata = {
@@ -320,12 +386,113 @@ static struct omap_lcd_config h4_lcd_config __initdata = {
        .ctrl_name      = "internal",
 };
 
+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 omap_board_config_kernel h4_config[] = {
        { OMAP_TAG_UART,        &h4_uart_config },
        { OMAP_TAG_MMC,         &h4_mmc_config },
        { OMAP_TAG_LCD,         &h4_lcd_config },
+       { OMAP_TAG_USB,         &h4_usb_config },
+};
+
+#ifdef CONFIG_MACH_OMAP_H4_TUSB
+
+#include <linux/usb/musb.h>
+
+static struct musb_hdrc_platform_data tusb_data = {
+       .mode           = MUSB_OTG,
+       .min_power      = 25,   /* x2 = 50 mA drawn from VBUS as peripheral */
+
+       /* 1.8V supplied by Menelaus, other voltages supplied by VBAT;
+        * so no switching.
+        */
 };
 
+static void __init tusb_evm_setup(void)
+{
+       static char     announce[] __initdata =
+                               KERN_INFO "TUSB 6010 EVM\n";
+       int             irq;
+       unsigned        dmachan = 0;
+
+       /* There are at least 32 different combinations of boards that
+        * are loosely called "H4", with a 2420 ... different OMAP chip
+        * revisions (with pin mux changes for DMAREQ, GPMC errata, etc),
+        * modifications of the CPU board, mainboard, EVM, TUSB etc.
+        * Plus omap2422, omap2423, etc.
+        *
+        * So you might need to tweak this setup to make the TUSB EVM
+        * behave on your particular setup ...
+        */
+
+       /* Already set up:  GPMC AD[0..15], CLK, nOE, nWE, nADV_ALE */
+       omap_cfg_reg(E2_GPMC_NCS2);
+       omap_cfg_reg(L2_GPMC_NCS7);
+       omap_cfg_reg(M1_GPMC_WAIT2);
+
+       switch ((system_rev >> 8) & 0x0f) {
+       case 0:         /* ES 1.0 */
+       case 1:         /* ES 2.0 */
+               /* Assume early board revision without optional ES2.0
+                * rework to swap J15 & AA10 so DMAREQ0 works
+                */
+               omap_cfg_reg(AA10_242X_GPIO13);
+               irq = 13;
+               // omap_cfg_reg(J15_24XX_DMAREQ0);
+               break;
+       default:
+               /* Later Menelaus boards can support all 6 DMA request
+                * lines, at the price of boot flash A23-A26.
+                */
+               omap_cfg_reg(J15_24XX_GPIO99);
+               irq = 99;
+               dmachan = (1 << 1) | (1 << 0);
+#if !(defined(CONFIG_MTD_OMAP_NOR) || defined(CONFIG_MTD_OMAP_NOR_MODULE))
+               dmachan |= (1 << 5) | (1 << 4) (1 << 3) | (1 << 2);
+#endif
+               break;
+       }
+
+       if (tusb6010_setup_interface(&tusb_data,
+                       TUSB6010_REFCLK_24, /* waitpin */ 2,
+                       /* async cs */ 2, /* sync cs */ 7,
+                       irq, dmachan) == 0)
+               printk(announce);
+}
+
+#endif
+
 static void __init omap_h4_init(void)
 {
        /*
@@ -346,10 +513,26 @@ static void __init omap_h4_init(void)
        }
 #endif
 
+#ifdef CONFIG_MACH_OMAP2_H4_USB1
+       /* S3.3 controls whether these pins are for UART2 or USB1 */
+       omap_cfg_reg(N14_24XX_USB1_SE0);
+       omap_cfg_reg(P15_24XX_USB1_DAT);
+       omap_cfg_reg(W20_24XX_USB1_TXEN);
+       omap_cfg_reg(V19_24XX_USB1_RCV);
+#endif
+
        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();
+
+       /* smc91x, debug leds, ps/2, extra uarts */
+       h4_init_debug();
+
+#ifdef CONFIG_MACH_OMAP_H4_TUSB
+       tusb_evm_setup();
+#endif
+
 }
 
 static void __init omap_h4_map_io(void)
diff --git a/arch/arm/mach-omap2/board-n800-audio.c b/arch/arm/mach-omap2/board-n800-audio.c
new file mode 100644 (file)
index 0000000..1608d3d
--- /dev/null
@@ -0,0 +1,357 @@
+/*
+ * linux/arch/arm/mach-omap/omap2/board-n800-audio.c
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Contact: Juha Yrj?l?
+ *          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/delay.h>
+#include <linux/platform_device.h>
+#include <linux/spi/tsc2301.h>
+
+#include <asm/io.h>
+#include <asm/arch/eac.h>
+
+#include "../plat-omap/dsp/dsp_common.h"
+
+#if defined(CONFIG_SPI_TSC2301_AUDIO) && defined(CONFIG_SND_OMAP24XX_EAC)
+#define AUDIO_ENABLED
+
+static struct clk *sys_clkout2;
+static struct clk *func96m_clk;
+static struct device *eac_device;
+static struct device *tsc2301_device;
+
+static int enable_audio;
+static int audio_ok;
+static spinlock_t audio_lock;
+
+
+/*
+ * Leaving EAC pins multiplexed to EAC functionality results
+ * in about 2 mA extra current leaked. The workaround is to
+ * multiplex the EAC pins to protected mode (with pull-ups enabled)
+ * whenever audio is not being used.
+ */
+static int mux_disabled;
+static u32 saved_mux[2];
+
+static void n800_enable_eac_mux(void)
+{
+       if (!mux_disabled)
+               return;
+       __raw_writel(saved_mux[0], IO_ADDRESS(0x480000e8));
+       __raw_writel(saved_mux[1], IO_ADDRESS(0x48000124));
+       mux_disabled = 0;
+}
+
+static void n800_disable_eac_mux(void)
+{
+       u32 l;
+
+       if (mux_disabled) {
+               WARN_ON(mux_disabled);
+               return;
+       }
+       saved_mux[0] = __raw_readl(IO_ADDRESS(0x480000e8));
+       saved_mux[1] = __raw_readl(IO_ADDRESS(0x48000124));
+       l = saved_mux[0] & ~0xff;
+       l |= 0x1f;
+       __raw_writel(l, IO_ADDRESS(0x480000e8));
+       __raw_writel(0x1f1f1f1f, IO_ADDRESS(0x48000124));
+       mux_disabled = 1;
+}
+
+static int n800_eac_enable_ext_clocks(struct device *dev)
+{
+       BUG_ON(tsc2301_device == NULL);
+       n800_enable_eac_mux();
+       tsc2301_enable_mclk(tsc2301_device);
+
+       return 0;
+}
+
+static void n800_eac_disable_ext_clocks(struct device *dev)
+{
+       BUG_ON(tsc2301_device == NULL);
+       n800_disable_eac_mux();
+       tsc2301_disable_mclk(tsc2301_device);
+}
+
+static int n800_audio_set_power(void *pdata, int dac, int adc)
+{
+       BUG_ON(pdata != tsc2301_device);
+       tsc2301_mixer_set_power(tsc2301_device, dac, adc);
+
+       return 0;
+}
+
+static int n800_audio_register_controls(void *pdata, struct snd_card *card)
+{
+       BUG_ON(pdata != tsc2301_device);
+       return tsc2301_mixer_register_controls(tsc2301_device, card);
+}
+
+static struct eac_codec n800_eac_codec = {
+       .mclk_src = EAC_MCLK_EXT_2x12288000,
+       .codec_mode = EAC_CODEC_I2S,
+       .codec_conf.i2s.polarity_changed_mode = 0,
+       .codec_conf.i2s.sync_delay_enable = 0,
+       .default_rate = 48000,
+       .set_power = n800_audio_set_power,
+       .register_controls = n800_audio_register_controls,
+       .short_name = "TSC2301",
+};
+
+static int n800_register_codec(void)
+{
+       int r, do_enable = 0;
+       unsigned long flags;
+
+       n800_eac_codec.private_data = tsc2301_device;
+       r = eac_register_codec(eac_device, &n800_eac_codec);
+       if (r < 0)
+               return r;
+       spin_lock_irqsave(&audio_lock, flags);
+       audio_ok = 1;
+       if (enable_audio)
+               do_enable = 1;
+       spin_unlock_irqrestore(&audio_lock, flags);
+       if (do_enable)
+               eac_set_mode(eac_device, 1, 1);
+       return 0;
+}
+
+static void n800_unregister_codec(void)
+{
+       audio_ok = 0;
+       eac_unregister_codec(eac_device);
+       eac_set_mode(eac_device, 0, 0);
+}
+
+static int n800_eac_init(struct device *dev)
+{
+       int r;
+
+       BUG_ON(eac_device != NULL);
+       eac_device = dev;
+       if (tsc2301_device != NULL) {
+               r = n800_register_codec();
+               if (r < 0)
+                       return r;
+       }
+
+       return 0;
+}
+
+static void n800_eac_cleanup(struct device *dev)
+{
+       eac_device = NULL;
+       if (tsc2301_device != NULL)
+               n800_unregister_codec();
+}
+
+static int n800_codec_get_clocks(struct device *dev)
+{
+       sys_clkout2 = clk_get(dev, "sys_clkout2");
+       if (IS_ERR(sys_clkout2)) {
+               printk(KERN_ERR "Could not get sys_clkout2\n");
+               return -ENODEV;
+       }
+       /* configure 12 MHz output on SYS_CLKOUT2. Therefore we must use
+        * 96 MHz as its parent in order to get 12 MHz */
+       func96m_clk = clk_get(dev, "func_96m_ck");
+       if (IS_ERR(func96m_clk)) {
+               printk(KERN_ERR "could not get func 96M clock\n");
+               clk_put(sys_clkout2);
+               return -ENODEV;
+       }
+
+       clk_set_parent(sys_clkout2, func96m_clk);
+       clk_set_rate(sys_clkout2, 12000000);
+
+       return 0;
+}
+
+static void n800_codec_put_clocks(struct device *dev)
+{
+       clk_put(func96m_clk);
+       clk_put(sys_clkout2);
+}
+
+static int n800_codec_enable_clock(struct device *dev)
+{
+       int err;
+
+       err = clk_enable(sys_clkout2);
+       if (err)
+               return err;
+       /* TODO: 'educated' guess for audio codec's PLL startup delay */
+       mdelay(1);
+
+       return 0;
+}
+
+static void n800_codec_disable_clock(struct device *dev)
+{
+       clk_disable(sys_clkout2);
+}
+
+static int n800_codec_init(struct device *dev)
+{
+       int r;
+
+       BUG_ON(tsc2301_device != NULL);
+       tsc2301_device = dev;
+       if ((r = n800_codec_get_clocks(dev)) < 0)
+               return r;
+       if (eac_device != NULL) {
+               r = n800_register_codec();
+               if (r < 0) {
+                       n800_codec_put_clocks(dev);
+                       return r;
+               }
+       }
+       return 0;
+}
+
+static void n800_codec_cleanup(struct device *dev)
+{
+       tsc2301_device = NULL;
+       if (eac_device != NULL)
+               n800_unregister_codec();
+       n800_codec_put_clocks(dev);
+}
+
+static struct eac_platform_data n800_eac_data = {
+       .init = n800_eac_init,
+       .cleanup = n800_eac_cleanup,
+       .enable_ext_clocks = n800_eac_enable_ext_clocks,
+       .disable_ext_clocks = n800_eac_disable_ext_clocks,
+};
+
+static const struct tsc2301_mixer_gpio n800_mixer_gpios[] = {
+       {
+               .name                   = "Headset Amplifier",
+               .gpio                   = 1,
+               .deactivate_on_pd       = 1,
+       }, {
+               .name                   = "Speaker Amplifier",
+               .gpio                   = 2,
+               .def_enable             = 1,
+               .deactivate_on_pd       = 1,
+       }, {
+               .name                   = "Headset Mic Select",
+               .gpio                   = 3,
+       }
+};
+
+static struct platform_device retu_headset_device = {
+       .name           = "retu-headset",
+       .id             = -1,
+       .dev            = {
+               .release        = NULL,
+       },
+};
+
+void __init n800_audio_init(struct tsc2301_platform_data *tc)
+{
+       spin_lock_init(&audio_lock);
+
+       if (platform_device_register(&retu_headset_device) < 0)
+               return;
+       omap_init_eac(&n800_eac_data);
+
+       tc->pll_pdc = 7;
+       tc->pll_a = 7;
+       tc->pll_n = 9;
+       tc->pll_output = 1;
+       tc->mclk_ratio = TSC2301_MCLK_256xFS;
+       tc->i2s_sample_rate = TSC2301_I2S_SR_48000;
+       tc->i2s_format = TSC2301_I2S_FORMAT0;
+       tc->power_down_blocks = TSC2301_REG_PD_MISC_MOPD;
+       tc->mixer_gpios = n800_mixer_gpios;
+       tc->n_mixer_gpios = ARRAY_SIZE(n800_mixer_gpios);
+       tc->codec_init = n800_codec_init;
+       tc->codec_cleanup = n800_codec_cleanup;
+       tc->enable_clock = n800_codec_enable_clock;
+       tc->disable_clock = n800_codec_disable_clock;
+}
+
+#else
+
+void __init n800_audio_init(void)
+{
+}
+
+#endif
+
+#ifdef CONFIG_OMAP_DSP
+
+int n800_audio_enable(struct dsp_kfunc_device *kdev, int stage)
+{
+#ifdef AUDIO_ENABLED
+       unsigned long flags;
+       int do_enable = 0;
+
+       spin_lock_irqsave(&audio_lock, flags);
+
+       pr_debug("DSP power up request (audio codec %sinitialized)\n",
+                audio_ok ? "" : "not ");
+
+       if (enable_audio)
+               goto out;
+       enable_audio = 1;
+       if (audio_ok)
+               do_enable = 1;
+out:
+       spin_unlock_irqrestore(&audio_lock, flags);
+       if (do_enable)
+               eac_set_mode(eac_device, 1, 1);
+#endif
+       return 0;
+}
+
+int n800_audio_disable(struct dsp_kfunc_device *kdev, int stage)
+{
+#ifdef AUDIO_ENABLED
+       unsigned long flags;
+       int do_disable = 0;
+
+       spin_lock_irqsave(&audio_lock, flags);
+
+       pr_debug("DSP power down request (audio codec %sinitialized)\n",
+               audio_ok ? "" : "not ");
+
+       if (!enable_audio)
+               goto out;
+       enable_audio = 0;
+       if (audio_ok)
+               do_disable = 1;
+out:
+       spin_unlock_irqrestore(&audio_lock, flags);
+       if (do_disable)
+               eac_set_mode(eac_device, 0, 0);
+#endif
+       return 0;
+}
+
+#endif /* CONFIG_OMAP_DSP */
diff --git a/arch/arm/mach-omap2/board-n800-bt.c b/arch/arm/mach-omap2/board-n800-bt.c
new file mode 100644 (file)
index 0000000..4ea19cc
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Nokia N800 platform-specific data for Bluetooth
+ *
+ * Copyright (C) 2005, 2006 Nokia Corporation
+ * Contact: Ville Tervo <ville.tervo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <asm/arch/board.h>
+
+static struct platform_device n800_bt_device = {
+       .name           = "hci_h4p",
+       .id             = -1,
+       .num_resources  = 0,
+};
+
+void __init n800_bt_init(void)
+{
+       const struct omap_bluetooth_config *bt_config;
+
+       bt_config = (void *) omap_get_config(OMAP_TAG_NOKIA_BT,
+                                            struct omap_bluetooth_config);
+       n800_bt_device.dev.platform_data = (void *) bt_config;
+       if (platform_device_register(&n800_bt_device) < 0)
+               BUG();
+}
+
diff --git a/arch/arm/mach-omap2/board-n800-dsp.c b/arch/arm/mach-omap2/board-n800-dsp.c
new file mode 100644 (file)
index 0000000..cb01363
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * linux/arch/arm/mach-omap2/board-n800-dsp.c
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+
+#include "../plat-omap/dsp/dsp_common.h"
+
+extern int n800_audio_enable(struct dsp_kfunc_device *kdev, int stage);
+extern int n800_audio_disable(struct dsp_kfunc_device *kdev, int stage);
+
+#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)
+{
+       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)
+{
+       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);
+
+       mutex_lock(&kdev->lock);
+
+       if (kdev->enabled)
+               goto out;
+       kdev->enabled = 1;
+
+       clk_enable(kdev->fck);
+       clk_enable(kdev->ick);
+ out:
+       mutex_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);
+
+       mutex_lock(&kdev->lock);
+
+       if (kdev->enabled == 0)
+               goto out;
+       kdev->enabled = 0;
+
+       clk_disable(kdev->ick);
+       clk_disable(kdev->fck);
+ out:
+       mutex_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 */
diff --git a/arch/arm/mach-omap2/board-n800-flash.c b/arch/arm/mach-omap2/board-n800-flash.c
new file mode 100644 (file)
index 0000000..3a4c52a
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * linux/arch/arm/mach-omap/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 <asm/arch/onenand.h>
+#include <asm/arch/board.h>
+
+static struct mtd_partition n800_partitions[8];
+
+static struct omap_onenand_platform_data n800_onenand_data = {
+       .cs = 0,
+       .gpio_irq = 26,
+       .parts = n800_partitions,
+       .nr_parts = 0 /* filled later */
+};
+
+static struct platform_device n800_onenand_device = {
+       .name           = "omap2-onenand",
+       .id             = -1,
+       .dev = {
+               .platform_data = &n800_onenand_data,
+       },
+};
+
+
+void __init n800_flash_init(void)
+{
+       const struct omap_partition_config *part;
+       int i = 0;
+
+       while ((part = omap_get_nr_config(OMAP_TAG_PARTITION,
+                                         struct omap_partition_config, i)) != NULL) {
+               struct mtd_partition *mpart;
+
+               mpart = n800_partitions + i;
+               mpart->name = (char *) part->name;
+               mpart->size = part->size;
+               mpart->offset = part->offset;
+               mpart->mask_flags = part->mask_flags;
+               i++;
+               if (i == ARRAY_SIZE(n800_partitions)) {
+                       printk(KERN_ERR "Too many partitions supplied\n");
+                       return;
+               }
+       }
+       n800_onenand_data.nr_parts = i;
+       if (platform_device_register(&n800_onenand_device) < 0) {
+               printk(KERN_ERR "Unable to register OneNAND device\n");
+               return;
+       }
+}
diff --git a/arch/arm/mach-omap2/board-n800-mmc.c b/arch/arm/mach-omap2/board-n800-mmc.c
new file mode 100644 (file)
index 0000000..b20f1ad
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ * linux/arch/arm/mach-omap2/board-n800-mmc.c
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Author: Juha Yrj?l?
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <asm/arch/mmc.h>
+#include <asm/arch/menelaus.h>
+#include <asm/arch/gpio.h>
+
+#ifdef CONFIG_MMC_OMAP
+
+static const int slot_switch_gpio = 96;
+static const int slot1_wp_gpio = 23;
+static const int slot2_wp_gpio = 8;
+static int slot1_cover_closed;
+static int slot2_cover_closed;
+static struct device *mmc_device;
+
+/*
+ * VMMC --> slot 1
+ * VDCDC3_APE, VMCS2_APE --> slot 2
+ * GPIO96 --> Menelaus GPIO2
+ */
+
+static int n800_mmc_switch_slot(struct device *dev, int slot)
+{
+#ifdef CONFIG_MMC_DEBUG
+       printk("Choose slot %d\n", slot + 1);
+#endif
+       if (slot == 0)
+               omap_set_gpio_dataout(slot_switch_gpio, 0);
+       else
+               omap_set_gpio_dataout(slot_switch_gpio, 1);
+       return 0;
+}
+
+static int n800_mmc_set_power(struct device *dev, int slot, int power_on, int vdd)
+{
+       int mV;
+
+#ifdef CONFIG_MMC_DEBUG
+       printk("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_18_19:
+                       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:
+               case MMC_VDD_19_20:
+                       mV = 2000;
+                       break;
+               case MMC_VDD_18_19:
+               case MMC_VDD_17_18:
+                       mV = 1800;
+                       break;
+               case MMC_VDD_150_155:
+               case MMC_VDD_145_150:
+                       mV = 1500;
+                       break;
+               default:
+                       BUG();
+               }
+               return menelaus_set_vdcdc(3, mV);
+       }
+       return 0;
+}
+
+static int n800_mmc_set_bus_mode(struct device *dev, int slot, int bus_mode)
+{
+       int r;
+
+#ifdef CONFIG_MMC_DEBUG
+       printk("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())
+               printk(KERN_ERR "MMC: unable to set bus mode for slot %d\n", slot);
+       return r;
+}
+
+#if 0
+static int n800_mmc_get_ro(struct device *dev, int slot)
+{
+       int ro;
+
+       slot++;
+       if (slot == 1)
+               ro = omap_get_gpio_datain(slot1_wp_gpio);
+       else
+               ro = omap_get_gpio_datain(slot2_wp_gpio);
+#ifdef CONFIG_MMC_DEBUG
+       printk("Get RO slot %d: %s\n", slot, ro ? "read-only" : "read-write");
+#endif
+       return ro;
+}
+#endif
+
+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_closed;
+       else
+               return slot2_cover_closed;
+}
+
+static void n800_mmc_callback(void *data, u8 card_mask)
+{
+       if (card_mask & (1 << 1))
+               slot2_cover_closed = 0;
+       else
+               slot2_cover_closed = 1;
+        omap_mmc_notify_cover_event(mmc_device, 1, slot2_cover_closed);
+}
+
+void n800_mmc_slot1_cover_handler(void *arg, int state)
+{
+       if (mmc_device == NULL)
+               return;
+
+       slot1_cover_closed = state;
+       omap_mmc_notify_cover_event(mmc_device, 0, state);
+}
+
+static int n800_mmc_late_init(struct device *dev)
+{
+       int r;
+
+       mmc_device = dev;
+
+       r = menelaus_set_slot_sel(1);
+       if (r < 0)
+               return r;
+
+       r = menelaus_set_mmc_slot(1, 1, 0, 1);
+       if (r < 0)
+               return r;
+       r = menelaus_set_mmc_slot(2, 1, 0, 1);
+       if (r < 0)
+               return r;
+
+       r = menelaus_get_slot_pin_states();
+       if (r < 0)
+               return r;
+
+       if (r & (1 << 1))
+               slot2_cover_closed = 1;
+       else
+               slot2_cover_closed = 0;
+
+       r = menelaus_register_mmc_callback(n800_mmc_callback, NULL);
+
+       return r;
+}
+
+static void n800_mmc_cleanup(struct device *dev)
+{
+       menelaus_unregister_mmc_callback();
+}
+
+static struct omap_mmc_platform_data n800_mmc_data = {
+       .enabled                = 1,
+       .nr_slots               = 2,
+       .wire4                  = 1,
+       .switch_slot            = n800_mmc_switch_slot,
+       .init                   = n800_mmc_late_init,
+       .cleanup                = n800_mmc_cleanup,
+       .slots[0] = {
+               .set_power      = n800_mmc_set_power,
+               .set_bus_mode   = n800_mmc_set_bus_mode,
+               .get_ro         = NULL,
+               .get_cover_state= n800_mmc_get_cover_state,
+               .ocr_mask       = MMC_VDD_18_19 | MMC_VDD_28_29 | MMC_VDD_30_31 |
+                                 MMC_VDD_32_33 | MMC_VDD_33_34,
+               .name           = "internal",
+       },
+       .slots[1] = {
+               .set_power      = n800_mmc_set_power,
+               .set_bus_mode   = n800_mmc_set_bus_mode,
+               .get_ro         = NULL,
+               .get_cover_state= n800_mmc_get_cover_state,
+               .ocr_mask       = MMC_VDD_150_155 | MMC_VDD_145_150 | MMC_VDD_17_18 |
+                                 MMC_VDD_18_19 | MMC_VDD_19_20 | MMC_VDD_20_21 |
+                                 MMC_VDD_21_22 | MMC_VDD_22_23 | MMC_VDD_23_24 |
+                                 MMC_VDD_24_25 | MMC_VDD_27_28 | MMC_VDD_28_29 |
+                                 MMC_VDD_29_30 | MMC_VDD_30_31 | MMC_VDD_32_33 |
+                                 MMC_VDD_33_34,
+               .name           = "external",
+       },
+};
+
+void __init n800_mmc_init(void)
+{
+       omap_set_mmc_info(1, &n800_mmc_data);
+       if (omap_request_gpio(slot_switch_gpio) < 0)
+               BUG();
+       omap_set_gpio_dataout(slot_switch_gpio, 0);
+       omap_set_gpio_direction(slot_switch_gpio, 0);
+       if (omap_request_gpio(slot1_wp_gpio) < 0)
+               BUG();
+       if (omap_request_gpio(slot2_wp_gpio) < 0)
+               BUG();
+       omap_set_gpio_direction(slot1_wp_gpio, 1);
+       omap_set_gpio_direction(slot2_wp_gpio, 1);
+}
+
+#else
+
+void __init n800_mmc_init(void)
+{
+}
+
+void n800_mmc_slot1_cover_handler(void *arg, int state)
+{
+}
+
+#endif
diff --git a/arch/arm/mach-omap2/board-n800-pm.c b/arch/arm/mach-omap2/board-n800-pm.c
new file mode 100644 (file)
index 0000000..fb2873e
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Nokia N800 PM code
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Author: Amit Kucheria <amit.kucheria@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/kernel.h>
+#include <linux/module.h>
+#include <asm/arch/menelaus.h>
+
+#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,
+};
+
+void __init n800_pm_init(void)
+{
+       menelaus_set_platform_data(&n800_menelaus_platform_data);
+}
+
+#else
+
+void __init n800_pm_init(void)
+{
+}
+
+#endif
+
diff --git a/arch/arm/mach-omap2/board-n800-usb.c b/arch/arm/mach-omap2/board-n800-usb.c
new file mode 100644 (file)
index 0000000..75243ac
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * linux/arch/arm/mach-omap/omap2/board-n800-usb.c
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Author: Juha Yrj?l?
+ *
+ * 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/usb/musb.h>
+#include <asm/arch/gpmc.h>
+#include <asm/arch/gpio.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);
+
+#if    defined(CONFIG_USB_MUSB_OTG)
+#      define BOARD_MODE       MUSB_OTG
+#elif  defined(CONFIG_USB_MUSB_PERIPHERAL)
+#      define BOARD_MODE       MUSB_PERIPHERAL
+#else  /* defined(CONFIG_USB_MUSB_HOST) */
+#      define BOARD_MODE       MUSB_HOST
+#endif
+
+static struct musb_hdrc_platform_data tusb_data = {
+       .mode           = BOARD_MODE,
+       .multipoint     = 1,
+       .set_power      = tusb_set_power,
+       .min_power      = 25,   /* x2 = 50 mA drawn from VBUS as peripheral */
+};
+
+/*
+ * Enable or disable power to TUSB6010. When enabling, turn on 3.3 V and
+ * 1.5 V voltage regulators of PM companion chip. Companion chip will then
+ * provide then PGOOD signal to TUSB6010 which will release it from reset.
+ */
+static int tusb_set_power(int state)
+{
+       int i, retval = 0;
+
+       if (state) {
+               omap_set_gpio_dataout(GPIO_TUSB_ENABLE, 1);
+               msleep(1);
+
+               /* Wait until TUSB6010 pulls INT pin down */
+               i = 100;
+               while (i && omap_get_gpio_datain(GPIO_TUSB_INT)) {
+                       msleep(1);
+                       i--;
+               }
+
+               if (!i) {
+                       printk(KERN_ERR "tusb: powerup failed\n");
+                       retval = -ENODEV;
+               }
+       } else {
+               omap_set_gpio_dataout(GPIO_TUSB_ENABLE, 0);
+               msleep(10);
+       }
+
+       return retval;
+}
+
+void __init n800_usb_init(void)
+{
+       int ret = 0;
+       static char     announce[] __initdata = KERN_INFO "TUSB 6010\n";
+
+       /* PM companion chip power control pin */
+       ret = omap_request_gpio(GPIO_TUSB_ENABLE);
+       if (ret != 0) {
+               printk(KERN_ERR "Could not get TUSB power GPIO%i\n",
+                      GPIO_TUSB_ENABLE);
+               return;
+       }
+       omap_set_gpio_direction(GPIO_TUSB_ENABLE, 0);
+
+       tusb_set_power(0);
+
+       ret = tusb6010_setup_interface(&tusb_data, TUSB6010_REFCLK_19, 2,
+                                       TUSB_ASYNC_CS, TUSB_SYNC_CS,
+                                       GPIO_TUSB_INT, 0x3f);
+       if (ret != 0)
+               goto err;
+
+       printk(announce);
+
+       return;
+
+err:
+       omap_free_gpio(GPIO_TUSB_ENABLE);
+}
diff --git a/arch/arm/mach-omap2/board-n800.c b/arch/arm/mach-omap2/board-n800.c
new file mode 100644 (file)
index 0000000..2188294
--- /dev/null
@@ -0,0 +1,525 @@
+/*
+ * linux/arch/arm/mach-omap/omap2/board-n800.c
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ * Author: Juha Yrj?l? <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/input.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/usb.h>
+#include <asm/arch/board.h>
+#include <asm/arch/common.h>
+#include <asm/arch/mcspi.h>
+#include <asm/arch/menelaus.h>
+#include <asm/arch/lcd_mipid.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/gpio-switch.h>
+#include <asm/arch/omapfb.h>
+#include <asm/arch/blizzard.h>
+
+#include <../drivers/cbus/tahvo.h>
+
+#define N800_BLIZZARD_POWERDOWN_GPIO 15
+#define N800_STI_GPIO          62
+#define N800_CAM_SENSOR_RESET_GPIO     53
+#define N800_KEYB_IRQ_GPIO             109
+
+static void __init nokia_n800_init_irq(void)
+{
+       omap2_init_common_hw();
+       omap_init_irq();
+       omap_gpio_init();
+
+#ifdef CONFIG_OMAP_STI
+       if (omap_request_gpio(N800_STI_GPIO) < 0) {
+               printk(KERN_ERR "Failed to request GPIO %d for STI\n",
+                      N800_STI_GPIO);
+               return;
+       }
+
+       omap_set_gpio_direction(N800_STI_GPIO, 0);
+       omap_set_gpio_dataout(N800_STI_GPIO, 0);
+#endif
+}
+
+#if defined(CONFIG_MENELAUS) && defined(CONFIG_SENSORS_TMP105)
+
+static int n800_tmp105_set_power(int enable)
+{
+       return menelaus_set_vaux(enable ? 2800 : 0);
+}
+
+#else
+
+#define n800_tmp105_set_power NULL
+
+#endif
+
+static struct omap_uart_config n800_uart_config __initdata = {
+       .enabled_uarts = (1 << 0) | (1 << 2),
+};
+
+#include "../../../drivers/cbus/retu.h"
+
+static struct omap_fbmem_config n800_fbmem0_config __initdata = {
+       .size = 752 * 1024,
+};
+
+static struct omap_fbmem_config n800_fbmem1_config __initdata = {
+       .size = 752 * 1024,
+};
+
+static struct omap_fbmem_config n800_fbmem2_config __initdata = {
+       .size = 752 * 1024,
+};
+
+static struct omap_tmp105_config n800_tmp105_config __initdata = {
+       .tmp105_irq_pin = 125,
+       .set_power = n800_tmp105_set_power,
+};
+
+static void mipid_shutdown(struct mipid_platform_data *pdata)
+{
+       if (pdata->nreset_gpio != -1) {
+               pr_info("shutdown LCD\n");
+               omap_set_gpio_dataout(pdata->nreset_gpio, 0);
+               msleep(120);
+       }
+}
+
+static struct mipid_platform_data n800_mipid_platform_data = {
+       .shutdown = mipid_shutdown,
+};
+
+static void __init mipid_dev_init(void)
+{
+       const struct omap_lcd_config *conf;
+
+       conf = omap_get_config(OMAP_TAG_LCD, struct omap_lcd_config);
+       if (conf != NULL) {
+               n800_mipid_platform_data.nreset_gpio = conf->nreset_gpio;
+               n800_mipid_platform_data.data_lines = conf->data_lines;
+       }
+}
+
+static struct {
+       struct clk *sys_ck;
+} blizzard;
+
+static int blizzard_get_clocks(void)
+{
+       blizzard.sys_ck = clk_get(0, "osc_ck");
+       if (IS_ERR(blizzard.sys_ck)) {
+               printk(KERN_ERR "can't get Blizzard clock\n");
+               return PTR_ERR(blizzard.sys_ck);
+       }
+       return 0;
+}
+
+static unsigned long blizzard_get_clock_rate(struct device *dev)
+{
+       return clk_get_rate(blizzard.sys_ck);
+}
+
+static void blizzard_enable_clocks(int enable)
+{
+       if (enable)
+               clk_enable(blizzard.sys_ck);
+       else
+               clk_disable(blizzard.sys_ck);
+}
+
+static void blizzard_power_up(struct device *dev)
+{
+       /* Vcore to 1.475V */
+       tahvo_set_clear_reg_bits(0x07, 0, 0xf);
+       msleep(10);
+
+       blizzard_enable_clocks(1);
+       omap_set_gpio_dataout(N800_BLIZZARD_POWERDOWN_GPIO, 1);
+}
+
+static void blizzard_power_down(struct device *dev)
+{
+       omap_set_gpio_dataout(N800_BLIZZARD_POWERDOWN_GPIO, 0);
+       blizzard_enable_clocks(0);
+
+       /* Vcore to 1.005V */
+       tahvo_set_clear_reg_bits(0x07, 0xf, 0);
+}
+
+static struct blizzard_platform_data n800_blizzard_data = {
+       .power_up       = blizzard_power_up,
+       .power_down     = blizzard_power_down,
+       .get_clock_rate = blizzard_get_clock_rate,
+       .te_connected   = 1,
+};
+
+static void __init blizzard_dev_init(void)
+{
+       int r;
+
+       r = omap_request_gpio(N800_BLIZZARD_POWERDOWN_GPIO);
+       if (r < 0)
+               return;
+       omap_set_gpio_direction(N800_BLIZZARD_POWERDOWN_GPIO, 0);
+       omap_set_gpio_dataout(N800_BLIZZARD_POWERDOWN_GPIO, 1);
+
+       blizzard_get_clocks();
+       omapfb_set_ctrl_platform_data(&n800_blizzard_data);
+}
+
+#if defined(CONFIG_CBUS_RETU) && defined(CONFIG_VIDEO_CAMERA_SENSOR_TCM825X) && \
+       defined(CONFIG_MENELAUS)
+#define SUPPORT_SENSOR
+#endif
+
+#ifdef SUPPORT_SENSOR
+
+static int sensor_okay;
+
+/*
+ * VSIM1       --> CAM_IOVDD   --> IOVDD (1.8 V)
+ */
+static int tcm825x_sensor_power_on(void *data)
+{
+       int ret;
+
+       if (!sensor_okay)
+               return -ENODEV;
+
+       /* 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(100);
+
+       omap_set_gpio_dataout(N800_CAM_SENSOR_RESET_GPIO, 1);
+       msleep(1);
+
+       return 0;
+}
+
+static int tcm825x_sensor_power_off(void * data)
+{
+       int ret;
+
+       omap_set_gpio_dataout(N800_CAM_SENSOR_RESET_GPIO, 0);
+       msleep(1);
+
+       /* Set VSim1 off */
+       retu_write_reg(RETU_REG_CTRL_CLR, 0x0080);
+       msleep(1);
+
+       /* Set VIO_MODE to off */
+       ret = menelaus_set_vio(0);
+       if (ret < 0)
+               return ret;
+       msleep(1);
+
+       /* Set VMEM_MODE to off */
+       ret = menelaus_set_vmem(0);
+       if (ret < 0)
+               return ret;
+       msleep(1);
+
+       return 0;
+}
+
+static struct omap_camera_sensor_config n800_sensor_config = {
+       .power_on   = tcm825x_sensor_power_on,
+       .power_off  = tcm825x_sensor_power_off,
+};
+
+static void __init n800_cam_init(void)
+{
+       int r;
+
+       r = omap_request_gpio(N800_CAM_SENSOR_RESET_GPIO);
+       if (r < 0)
+               return;
+
+       omap_set_gpio_dataout(N800_CAM_SENSOR_RESET_GPIO, 0);
+       omap_set_gpio_direction(N800_CAM_SENSOR_RESET_GPIO, 0);
+
+       sensor_okay = 1;
+}
+
+#else
+
+static inline void n800_cam_init(void) {}
+
+#endif
+
+static struct omap_board_config_kernel n800_config[] = {
+       { OMAP_TAG_UART,                        &n800_uart_config },
+#ifdef SUPPORT_SENSOR
+       { OMAP_TAG_CAMERA_SENSOR,               &n800_sensor_config },
+#endif
+       { 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 int n800_get_keyb_irq_state(struct device *dev)
+{
+       return !omap_get_gpio_datain(N800_KEYB_IRQ_GPIO);
+}
+
+static struct tsc2301_platform_data tsc2301_config = {
+       .reset_gpio     = 118,
+       .dav_gpio       = 103,
+       .pen_int_gpio   = 106,
+       .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,
+       .get_keyb_irq_state = n800_get_keyb_irq_state,
+};
+
+static void tsc2301_dev_init(void)
+{
+       int gpio = N800_KEYB_IRQ_GPIO;
+
+       if (omap_request_gpio(gpio) < 0) {
+               printk("can't get KBIRQ GPIO\n");
+               return;
+       }
+       omap_set_gpio_direction(gpio, 1);
+       tsc2301_config.keyb_int = OMAP_GPIO_IRQ(gpio);
+}
+
+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,
+};
+
+static struct spi_board_info n800_spi_board_info[] __initdata = {
+       [0] = {
+               .modalias       = "lcd_mipid",
+               .bus_num        = 1,
+               .chip_select    = 1,
+               .max_speed_hz   = 4000000,
+               .controller_data= &mipid_mcspi_config,
+               .platform_data  = &n800_mipid_platform_data,
+       }, [1] = {
+               .modalias       = "cx3110x",
+               .bus_num        = 2,
+               .chip_select    = 0,
+               .max_speed_hz   = 48000000,
+               .controller_data= &cx3110x_mcspi_config,
+       }, [2] = {
+               .modalias       = "tsc2301",
+               .bus_num        = 1,
+               .chip_select    = 0,
+               .max_speed_hz   = 6000000,
+               .controller_data= &tsc2301_mcspi_config,
+               .platform_data  = &tsc2301_config,
+       },
+};
+
+#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_SPI_TSC2301_TOUCHSCREEN)
+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        = 4;
+                       tsc2301_config.ts_ignore_last   = 1;
+                       tsc2301_config.ts_max_pressure  = 255;
+                       tsc2301_config.ts_stab_time     = 100;
+               } else if (strcmp(conf->panel_name, "ls041y3") == 0) {
+                       tsc2301_config.ts_x_plate_ohm   = 280;
+                       tsc2301_config.ts_hw_avg        = 16;
+                       tsc2301_config.ts_touch_pressure= 215;
+                       tsc2301_config.ts_max_pressure  = 255;
+                       tsc2301_config.ts_ignore_last   = 1;
+               } 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
+
+extern void n800_mmc_slot1_cover_handler(void *arg, int state);
+
+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
+};
+
+extern void __init n800_flash_init(void);
+extern void __init n800_mmc_init(void);
+extern void __init n800_bt_init(void);
+extern void __init n800_audio_init(struct tsc2301_platform_data *);
+extern void __init n800_dsp_init(void);
+extern void __init n800_usb_init(void);
+extern void __init n800_pm_init(void);
+
+static void __init nokia_n800_init(void)
+{
+       platform_add_devices(n800_devices, ARRAY_SIZE(n800_devices));
+       n800_flash_init();
+       n800_mmc_init();
+       n800_bt_init();
+       n800_audio_init(&tsc2301_config);
+       n800_dsp_init();
+       n800_usb_init();
+       n800_cam_init();
+       n800_ts_set_config();
+       spi_register_board_info(n800_spi_board_info,
+                               ARRAY_SIZE(n800_spi_board_info));
+       omap_serial_init();
+       mipid_dev_init();
+       blizzard_dev_init();
+       tsc2301_dev_init();
+       omap_register_gpio_switches(n800_gpio_switches,
+                                   ARRAY_SIZE(n800_gpio_switches));
+       n800_pm_init();
+}
+
+static void __init nokia_n800_map_io(void)
+{
+       omap_board_config = n800_config;
+       omap_board_config_size = ARRAY_SIZE(n800_config);
+
+       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
index 0de201c3d50b4a09d488109338d90a1df12597a9..03065074f8084373852a8e1faff97b2b363656ee 100644 (file)
@@ -27,6 +27,7 @@
 
 #include <asm/arch/clock.h>
 #include <asm/arch/sram.h>
+#include <asm/div64.h>
 
 #include "prcm-regs.h"
 #include "memory.h"
@@ -1159,8 +1160,8 @@ int __init omap2_clk_init(void)
        clk_enable(&sync_32k_ick);
        clk_enable(&omapctrl_ick);
 
-       /* Force the APLLs active during bootup to avoid disabling and
-        * enabling them unnecessarily. */
+       /* Force the APLLs always active. The clocks are idled
+        * automatically by hardware. */
        clk_enable(&apll96_ck);
        clk_enable(&apll54_ck);
 
@@ -1173,12 +1174,3 @@ int __init omap2_clk_init(void)
 
        return 0;
 }
-
-static int __init omap2_disable_aplls(void)
-{
-       clk_disable(&apll96_ck);
-       clk_disable(&apll54_ck);
-
-       return 0;
-}
-late_initcall(omap2_disable_aplls);
index 8816f5a33a289b12aa59669d291c1a5d20dc7fde..162978fd535943e7fdffcbdaec41866586955d1e 100644 (file)
@@ -1013,7 +1013,8 @@ static struct clk dss2_fck = {            /* Alt clk used in power management */
        .name           = "dss2_fck",
        .parent         = &sys_ck,              /* fixed at sys_ck or 48MHz */
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
-                               RATE_CKCTL | CM_CORE_SEL1 | RATE_FIXED,
+                               RATE_CKCTL | CM_CORE_SEL1 | RATE_FIXED |
+                               DELAYED_APP,
        .enable_reg     = (void __iomem *)&CM_FCLKEN1_CORE,
        .enable_bit     = 1,
        .src_offset     = 13,
index aa4322451e8b5dbe10cfd76cf58fff09b9384abf..b603bc5f8e5bad9f30314cad01ec92e77126ca60 100644 (file)
@@ -24,7 +24,7 @@
 #include <asm/arch/mux.h>
 #include <asm/arch/gpio.h>
 
-#if    defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE)
+#if    defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE)
 
 #define OMAP2_I2C_BASE2                0x48072000
 #define OMAP2_I2C_INT2         57
@@ -42,8 +42,8 @@ static struct resource i2c_resources2[] = {
 };
 
 static struct platform_device omap_i2c_device2 = {
-        .name           = "i2c_omap",
-        .id             = 2,
+       .name           = "i2c_omap",
+       .id             = 2,
        .num_resources  = ARRAY_SIZE(i2c_resources2),
        .resource       = i2c_resources2,
 };
@@ -55,8 +55,10 @@ static void omap_init_i2c(void)
        if (machine_is_omap_h4())
                return;
 
-       omap_cfg_reg(J15_24XX_I2C2_SCL);
-       omap_cfg_reg(H19_24XX_I2C2_SDA);
+       if (!cpu_is_omap2430()) {
+               omap_cfg_reg(J15_24XX_I2C2_SCL);
+               omap_cfg_reg(H19_24XX_I2C2_SDA);
+       }
        (void) platform_device_register(&omap_i2c_device2);
 }
 
@@ -66,6 +68,40 @@ static void omap_init_i2c(void) {}
 
 #endif
 
+#if defined(CONFIG_OMAP_DSP) || defined(CONFIG_OMAP_DSP_MODULE)
+#define OMAP2_MBOX_BASE                IO_ADDRESS(OMAP24XX_MAILBOX_BASE)
+
+static struct resource mbox_resources[] = {
+       {
+               .start          = OMAP2_MBOX_BASE,
+               .end            = OMAP2_MBOX_BASE + 0x11f,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = INT_24XX_MAIL_U0_MPU,
+               .flags          = IORESOURCE_IRQ,
+       },
+       {
+               .start          = INT_24XX_MAIL_U3_MPU,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device mbox_device = {
+       .name           = "mailbox",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(mbox_resources),
+       .resource       = mbox_resources,
+};
+
+static inline void omap_init_mbox(void)
+{
+       platform_device_register(&mbox_device);
+}
+#else
+static inline void omap_init_mbox(void) { }
+#endif
+
 #if defined(CONFIG_OMAP_STI)
 
 #define OMAP2_STI_BASE         IO_ADDRESS(0x48068000)
@@ -111,29 +147,45 @@ static inline void omap_init_sti(void) {}
 #define OMAP2_MCSPI1_BASE              0x48098000
 #define OMAP2_MCSPI2_BASE              0x4809a000
 
-/* FIXME: use resources instead */
-
 static struct omap2_mcspi_platform_config omap2_mcspi1_config = {
-       .base           = io_p2v(OMAP2_MCSPI1_BASE),
        .num_cs         = 4,
 };
 
+static struct resource omap2_mcspi1_resources[] = {
+       {
+               .start          = OMAP2_MCSPI1_BASE,
+               .end            = OMAP2_MCSPI1_BASE + 0xff,
+               .flags          = IORESOURCE_MEM,
+       },
+};
+
 struct platform_device omap2_mcspi1 = {
        .name           = "omap2_mcspi",
        .id             = 1,
+       .num_resources  = ARRAY_SIZE(omap2_mcspi1_resources),
+       .resource       = omap2_mcspi1_resources,
        .dev            = {
                .platform_data = &omap2_mcspi1_config,
        },
 };
 
 static struct omap2_mcspi_platform_config omap2_mcspi2_config = {
-       .base           = io_p2v(OMAP2_MCSPI2_BASE),
        .num_cs         = 2,
 };
 
+static struct resource omap2_mcspi2_resources[] = {
+       {
+               .start          = OMAP2_MCSPI2_BASE,
+               .end            = OMAP2_MCSPI2_BASE + 0xff,
+               .flags          = IORESOURCE_MEM,
+       },
+};
+
 struct platform_device omap2_mcspi2 = {
        .name           = "omap2_mcspi",
        .id             = 2,
+       .num_resources  = ARRAY_SIZE(omap2_mcspi2_resources),
+       .resource       = omap2_mcspi2_resources,
        .dev            = {
                .platform_data = &omap2_mcspi2_config,
        },
@@ -157,10 +209,10 @@ static int __init omap2_init_devices(void)
         * in alphabetical order so they're easier to sort through.
         */
        omap_init_i2c();
+       omap_init_mbox();
        omap_init_mcspi();
        omap_init_sti();
 
        return 0;
 }
 arch_initcall(omap2_init_devices);
-
index d8f57824423f63708ca42a5b6a118c5470fb6406..b6b47f2a4ae307e85d050fc25f1b264087f94b25 100644 (file)
 
 #undef DEBUG
 
+#ifdef CONFIG_ARCH_OMAP2420
 #define GPMC_BASE              0x6800a000
+#endif
+
+#ifdef CONFIG_ARCH_OMAP2430
+#define GPMC_BASE              0x6E000000
+#endif
+
 #define GPMC_REVISION          0x00
 #define GPMC_SYSCONFIG         0x10
 #define GPMC_SYSSTATUS         0x14
@@ -88,7 +95,7 @@ u32 gpmc_cs_read_reg(int cs, int idx)
 }
 
 /* TODO: Add support for gpmc_fck to clock framework and use it */
-static unsigned long gpmc_get_fclk_period(void)
+unsigned long gpmc_get_fclk_period(void)
 {
        /* In picoseconds */
        return 1000000000 / ((clk_get_rate(gpmc_l3_clk)) / 1000);
@@ -104,6 +111,13 @@ unsigned int gpmc_ns_to_ticks(unsigned int time_ns)
        return (time_ns * 1000 + tick_ps - 1) / tick_ps;
 }
 
+unsigned int gpmc_round_ns_to_ticks(unsigned int time_ns)
+{
+       unsigned long ticks = gpmc_ns_to_ticks(time_ns);
+
+       return ticks * gpmc_get_fclk_period() / 1000;
+}
+
 #ifdef DEBUG
 static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
                               int time, const char *name)
@@ -120,15 +134,21 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
        else
                ticks = gpmc_ns_to_ticks(time);
        nr_bits = end_bit - st_bit + 1;
-       if (ticks >= 1 << nr_bits)
+       if (ticks >= 1 << nr_bits) {
+#ifdef DEBUG
+               printk(KERN_INFO "GPMC CS%d: %-10s* %3d ns, %3d ticks >= %d\n",
+                               cs, name, time, ticks, 1 << nr_bits);
+#endif
                return -1;
+       }
 
        mask = (1 << nr_bits) - 1;
        l = gpmc_cs_read_reg(cs, reg);
 #ifdef DEBUG
-       printk(KERN_INFO "GPMC CS%d: %-10s: %d ticks, %3lu ns (was %i ticks)\n",
+       printk(KERN_INFO
+               "GPMC CS%d: %-10s: %3d ticks, %3lu ns (was %3i ticks) %3d ns\n",
               cs, name, ticks, gpmc_get_fclk_period() * ticks / 1000,
-              (l >> st_bit) & mask);
+                       (l >> st_bit) & mask, time);
 #endif
        l &= ~(mask << st_bit);
        l |= ticks << st_bit;
@@ -157,7 +177,7 @@ int gpmc_cs_calc_divider(int cs, unsigned int sync_clk)
        div = l / gpmc_get_fclk_period();
        if (div > 4)
                return -1;
-       if (div < 0)
+       if (div <= 0)
                div = 1;
 
        return div;
@@ -191,14 +211,19 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t)
 
        GPMC_SET_ONE(GPMC_CS_CONFIG5, 24, 27, page_burst_access);
 
+       /* caller is expected to have initialized CONFIG1 to cover
+        * at least sync vs async
+        */
+       l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
+       if (l & (GPMC_CONFIG1_READTYPE_SYNC | GPMC_CONFIG1_WRITETYPE_SYNC)) {
 #ifdef DEBUG
-       printk(KERN_INFO "GPMC CS%d CLK period is %lu (div %d)\n",
-              cs, gpmc_get_fclk_period(), div);
+               printk(KERN_INFO "GPMC CS%d CLK period is %lu ns (div %d)\n",
+                               cs, (div * gpmc_get_fclk_period()) / 1000, div);
 #endif
-
-       l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
-       l &= ~0x03;
-       l |= (div - 1);
+               l &= ~0x03;
+               l |= (div - 1);
+               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, l);
+       }
 
        return 0;
 }
@@ -246,14 +271,22 @@ static int gpmc_cs_mem_enabled(int cs)
        return l & (1 << 6);
 }
 
-static void gpmc_cs_set_reserved(int cs, int reserved)
+int gpmc_cs_set_reserved(int cs, int reserved)
 {
+       if (cs > GPMC_CS_NUM)
+               return -ENODEV;
+
        gpmc_cs_map &= ~(1 << cs);
        gpmc_cs_map |= (reserved ? 1 : 0) << cs;
+
+       return 0;
 }
 
-static int gpmc_cs_reserved(int cs)
+int gpmc_cs_reserved(int cs)
 {
+       if (cs > GPMC_CS_NUM)
+               return -ENODEV;
+
        return gpmc_cs_map & (1 << cs);
 }
 
index 871ace4fccb879a186cf135f87a0dcbfaafa4343..4dfd878d796841e43cd8e16cad6bb793aeabeb4c 100644 (file)
 
 #include <asm/io.h>
 
+#if defined(CONFIG_ARCH_OMAP2420)
 #define OMAP24XX_TAP_BASE      io_p2v(0x48014000)
+#endif
+
+#if defined(CONFIG_ARCH_OMAP2430)
+#define OMAP24XX_TAP_BASE      io_p2v(0x4900A000)
+#endif
 
 #define OMAP_TAP_IDCODE                0x0204
 #define OMAP_TAP_PROD_ID       0x0208
index a0728c33e5d9e60de43b6f867b1efcfd61c1561f..4640d9abacbf4321b5b09d9ffb05162bd90ee873 100644 (file)
@@ -5,6 +5,7 @@
  *
  * Copyright (C) 2005 Nokia Corporation
  * Author: Juha Yrjölä <juha.yrjola@nokia.com>
+ * Updated map desc to add 2430 support : <x0khasim@ti.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -26,6 +27,7 @@
 extern void omap_sram_init(void);
 extern int omap2_clk_init(void);
 extern void omap2_check_revision(void);
+extern void omap2_init_memory(void);
 extern void gpmc_init(void);
 
 /*
@@ -44,6 +46,38 @@ static struct map_desc omap2_io_desc[] __initdata = {
                .pfn            = __phys_to_pfn(L4_24XX_PHYS),
                .length         = L4_24XX_SIZE,
                .type           = MT_DEVICE
+       },
+#ifdef CONFIG_ARCH_OMAP2430
+       {
+               .virtual        = L4_WK_243X_VIRT,
+               .pfn            = __phys_to_pfn(L4_WK_243X_PHYS),
+               .length         = L4_WK_243X_SIZE,
+               .type           = MT_DEVICE
+       },
+       {
+               .virtual        = OMAP243X_GPMC_VIRT,
+               .pfn            = __phys_to_pfn(OMAP243X_GPMC_PHYS),
+               .length         = OMAP243X_GPMC_SIZE,
+               .type           = MT_DEVICE
+       },
+#endif
+       {
+               .virtual        = DSP_MEM_24XX_VIRT,
+               .pfn            = __phys_to_pfn(DSP_MEM_24XX_PHYS),
+               .length         = DSP_MEM_24XX_SIZE,
+               .type           = MT_DEVICE
+       },
+       {
+               .virtual        = DSP_IPI_24XX_VIRT,
+               .pfn            = __phys_to_pfn(DSP_IPI_24XX_PHYS),
+               .length         = DSP_IPI_24XX_SIZE,
+               .type           = MT_DEVICE
+       },
+       {
+               .virtual        = DSP_MMU_24XX_VIRT,
+               .pfn            = __phys_to_pfn(DSP_MMU_24XX_PHYS),
+               .length         = DSP_MMU_24XX_SIZE,
+               .type           = MT_DEVICE
        }
 };
 
@@ -67,5 +101,11 @@ void __init omap2_init_common_hw(void)
 {
        omap2_mux_init();
        omap2_clk_init();
+/*
+ * Need to Fix this for 2430
+ */
+#ifndef CONFIG_ARCH_OMAP2430
+       omap2_init_memory();
+#endif
        gpmc_init();
 }
index a39d306803002448d86357fa3bd7535be73e0e7f..f064f725e724aed9394178820167c54d2eb29b56 100644 (file)
@@ -37,7 +37,7 @@ static struct omap_irq_bank {
 } __attribute__ ((aligned(4))) irq_banks[] = {
        {
                /* MPU INTC */
-               .base_reg       = OMAP24XX_IC_BASE,
+               .base_reg       = IO_ADDRESS(OMAP24XX_IC_BASE),
                .nr_irqs        = 96,
        }, {
                /* XXX: DSP INTC */
@@ -47,7 +47,7 @@ static struct omap_irq_bank {
 /* XXX: FIQ and additional INTC support (only MPU at the moment) */
 static void omap_ack_irq(unsigned int irq)
 {
-       omap_writel(0x1, irq_banks[0].base_reg + INTC_CONTROL);
+       __raw_writel(0x1, irq_banks[0].base_reg + INTC_CONTROL);
 }
 
 static void omap_mask_irq(unsigned int irq)
@@ -60,7 +60,7 @@ static void omap_mask_irq(unsigned int irq)
                irq %= 32;
        }
 
-       omap_writel(1 << irq, irq_banks[0].base_reg + INTC_MIR_SET0 + offset);
+       __raw_writel(1 << irq, irq_banks[0].base_reg + INTC_MIR_SET0 + offset);
 }
 
 static void omap_unmask_irq(unsigned int irq)
@@ -73,7 +73,7 @@ static void omap_unmask_irq(unsigned int irq)
                irq %= 32;
        }
 
-       omap_writel(1 << irq, irq_banks[0].base_reg + INTC_MIR_CLEAR0 + offset);
+       __raw_writel(1 << irq, irq_banks[0].base_reg + INTC_MIR_CLEAR0 + offset);
 }
 
 static void omap_mask_ack_irq(unsigned int irq)
@@ -93,17 +93,20 @@ static void __init omap_irq_bank_init_one(struct omap_irq_bank *bank)
 {
        unsigned long tmp;
 
-       tmp = omap_readl(bank->base_reg + INTC_REVISION) & 0xff;
+       tmp = __raw_readl(bank->base_reg + INTC_REVISION) & 0xff;
        printk(KERN_INFO "IRQ: Found an INTC at 0x%08lx "
                         "(revision %ld.%ld) with %d interrupts\n",
                         bank->base_reg, tmp >> 4, tmp & 0xf, bank->nr_irqs);
 
-       tmp = omap_readl(bank->base_reg + INTC_SYSCONFIG);
+       tmp = __raw_readl(bank->base_reg + INTC_SYSCONFIG);
        tmp |= 1 << 1;  /* soft reset */
-       omap_writel(tmp, bank->base_reg + INTC_SYSCONFIG);
+       __raw_writel(tmp, bank->base_reg + INTC_SYSCONFIG);
 
-       while (!(omap_readl(bank->base_reg + INTC_SYSSTATUS) & 0x1))
+       while (!(__raw_readl(bank->base_reg + INTC_SYSSTATUS) & 0x1))
                /* Wait for reset to complete */;
+
+       /* Enable autoidle */
+       __raw_writel(1 << 0, bank->base_reg + INTC_SYSCONFIG);
 }
 
 void __init omap_init_irq(void)
diff --git a/arch/arm/mach-omap2/mailbox.c b/arch/arm/mach-omap2/mailbox.c
new file mode 100644 (file)
index 0000000..e541e95
--- /dev/null
@@ -0,0 +1,310 @@
+/*
+ * Mailbox reservation modules for OMAP2
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Written by: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
+ *        and  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/kernel.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <asm/arch/mailbox.h>
+#include <asm/arch/irqs.h>
+#include <asm/io.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
+
+unsigned long mbox_base;
+
+#define MAILBOX_IRQ_NOTFULL(n)         (1 << (2 * (n) + 1))
+#define MAILBOX_IRQ_NEWMSG(n)          (1 << (2 * (n)))
+
+struct omap_mbox2_fifo {
+       unsigned long msg;
+       unsigned long fifo_stat;
+       unsigned long msg_stat;
+};
+
+struct omap_mbox2_priv {
+       struct omap_mbox2_fifo tx_fifo;
+       struct omap_mbox2_fifo rx_fifo;
+       unsigned long irqenable;
+       unsigned long irqstatus;
+       u32 newmsg_bit;
+       u32 notfull_bit;
+};
+
+struct clk *mbox_ick_handle;
+
+static inline unsigned int mbox_read_reg(unsigned int reg)
+{
+       return __raw_readl(mbox_base + reg);
+}
+
+static inline void mbox_write_reg(unsigned int val, unsigned int reg)
+{
+       __raw_writel(val, mbox_base + reg);
+}
+
+/* Mailbox H/W preparations */
+static inline int omap2_mbox_startup(struct omap_mbox *mbox)
+{
+       unsigned int l;
+
+       mbox_ick_handle = clk_get(NULL, "mailboxes_ick");
+       if (IS_ERR(mbox_ick_handle)) {
+               printk("Could not get mailboxes_ick\n");
+               return -ENODEV;
+       }
+       clk_enable(mbox_ick_handle);
+
+       /* set smart-idle & autoidle */
+       l = mbox_read_reg(MAILBOX_SYSCONFIG);
+       l |= 0x00000011;
+       mbox_write_reg(l, MAILBOX_SYSCONFIG);
+
+       return 0;
+}
+
+static inline void omap2_mbox_shutdown(struct omap_mbox *mbox)
+{
+       clk_disable(mbox_ick_handle);
+       clk_put(mbox_ick_handle);
+}
+
+/* Mailbox FIFO handle functions */
+static inline mbox_msg_t omap2_mbox_fifo_read(struct omap_mbox *mbox)
+{
+       struct omap_mbox2_fifo *fifo = &((struct omap_mbox2_priv *)mbox->priv)->rx_fifo;
+       return (mbox_msg_t) mbox_read_reg(fifo->msg);
+}
+
+static inline void omap2_mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg)
+{
+       struct omap_mbox2_fifo *fifo = &((struct omap_mbox2_priv *)mbox->priv)->tx_fifo;
+       mbox_write_reg(msg, fifo->msg);
+}
+
+static inline int omap2_mbox_fifo_empty(struct omap_mbox *mbox)
+{
+       struct omap_mbox2_fifo *fifo = &((struct omap_mbox2_priv *)mbox->priv)->rx_fifo;
+       return (mbox_read_reg(fifo->msg_stat) == 0);
+}
+
+static inline int omap2_mbox_fifo_full(struct omap_mbox *mbox)
+{
+       struct omap_mbox2_fifo *fifo = &((struct omap_mbox2_priv *)mbox->priv)->tx_fifo;
+       return (mbox_read_reg(fifo->fifo_stat));
+}
+
+/* Mailbox IRQ handle functions */
+static inline void omap2_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_type_t irq)
+{
+       struct omap_mbox2_priv *p = (struct omap_mbox2_priv *)mbox->priv;
+       u32 l, bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
+
+       l = mbox_read_reg(p->irqenable);
+       l |= bit;
+       mbox_write_reg(l, p->irqenable);
+}
+
+static inline void omap2_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_type_t irq)
+{
+       struct omap_mbox2_priv *p = (struct omap_mbox2_priv *)mbox->priv;
+       u32 l, bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
+
+       l = mbox_read_reg(p->irqenable);
+       l &= ~bit;
+       mbox_write_reg(l, p->irqenable);
+}
+
+static inline void omap2_mbox_ack_irq(struct omap_mbox *mbox, omap_mbox_type_t irq)
+{
+       struct omap_mbox2_priv *p = (struct omap_mbox2_priv *)mbox->priv;
+       u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
+
+       mbox_write_reg(bit, p->irqstatus);
+}
+
+static inline int omap2_mbox_is_irq(struct omap_mbox *mbox, omap_mbox_type_t irq)
+{
+       struct omap_mbox2_priv *p = (struct omap_mbox2_priv *)mbox->priv;
+       u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
+       u32 enable = mbox_read_reg(p->irqenable);
+       u32 status = mbox_read_reg(p->irqstatus);
+
+       return (enable & status & bit);
+}
+
+struct omap_mbox_ops omap2_mbox_ops = {
+       .type = OMAP_MBOX_TYPE2,
+       .startup = omap2_mbox_startup,
+       .shutdown = omap2_mbox_shutdown,
+       .fifo_read = omap2_mbox_fifo_read,
+       .fifo_write = omap2_mbox_fifo_write,
+       .fifo_empty = omap2_mbox_fifo_empty,
+       .fifo_full = omap2_mbox_fifo_full,
+       .enable_irq = omap2_mbox_enable_irq,
+       .disable_irq = omap2_mbox_disable_irq,
+       .ack_irq = omap2_mbox_ack_irq,
+       .is_irq = omap2_mbox_is_irq,
+};
+
+/*
+ * MAILBOX 0: ARM -> DSP,
+ * MAILBOX 1: ARM <- DSP.
+ * MAILBOX 2: ARM -> IVA,
+ * MAILBOX 3: ARM <- IVA.
+ */
+
+/* FIXME: the following structs should be filled automatically by the user id */
+
+/* DSP */
+static struct omap_mbox2_priv omap2_mbox_dsp_priv = {
+       .tx_fifo = {
+               .msg = MAILBOX_MESSAGE_0,
+               .fifo_stat = MAILBOX_FIFOSTATUS_0,
+       },
+       .rx_fifo = {
+               .msg = MAILBOX_MESSAGE_1,
+               .msg_stat = MAILBOX_MSGSTATUS_1,
+       },
+       .irqenable = MAILBOX_IRQENABLE_0,
+       .irqstatus = MAILBOX_IRQSTATUS_0,
+       .notfull_bit = MAILBOX_IRQ_NOTFULL(0),
+       .newmsg_bit = MAILBOX_IRQ_NEWMSG(1),
+};
+
+struct omap_mbox mbox_dsp_info = {
+       .name = "dsp",
+       .ops = &omap2_mbox_ops,
+       .priv = &omap2_mbox_dsp_priv,
+};
+EXPORT_SYMBOL(mbox_dsp_info);
+
+/* IVA */
+static struct omap_mbox2_priv omap2_mbox_iva_priv = {
+       .tx_fifo = {
+               .msg = MAILBOX_MESSAGE_2,
+               .fifo_stat = MAILBOX_FIFOSTATUS_2,
+       },
+       .rx_fifo = {
+               .msg = MAILBOX_MESSAGE_3,
+               .msg_stat = MAILBOX_MSGSTATUS_3,
+       },
+       .irqenable = MAILBOX_IRQENABLE_3,
+       .irqstatus = MAILBOX_IRQSTATUS_3,
+       .notfull_bit = MAILBOX_IRQ_NOTFULL(2),
+       .newmsg_bit = MAILBOX_IRQ_NEWMSG(3),
+};
+
+static struct omap_mbox mbox_iva_info = {
+       .name = "iva",
+       .ops = &omap2_mbox_ops,
+       .priv = &omap2_mbox_iva_priv,
+};
+
+static int __init 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;
+       }
+
+       /* MBOX base */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (unlikely(!res)) {
+               dev_err(&pdev->dev, "invalid mem resource\n");
+               return -ENODEV;
+       }
+       mbox_base = res->start;
+
+       /* DSP IRQ */
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (unlikely(!res)) {
+               dev_err(&pdev->dev, "invalid irq resource\n");
+               return -ENODEV;
+       }
+       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;
+       }
+       mbox_iva_info.irq = res->start;
+
+       ret = omap_mbox_register(&mbox_iva_info);
+
+       return ret;
+}
+
+static int omap2_mbox_remove(struct platform_device *pdev)
+{
+       omap_mbox_unregister(&mbox_dsp_info);
+       return 0;
+}
+
+static struct platform_driver omap2_mbox_driver = {
+       .probe = omap2_mbox_probe,
+       .remove = omap2_mbox_remove,
+       .driver = {
+               .name = "mailbox",
+       },
+};
+
+int __init omap2_mbox_init(void)
+{
+       return platform_driver_register(&omap2_mbox_driver);
+}
+
+static void __exit omap2_mbox_exit(void)
+{
+       platform_driver_unregister(&omap2_mbox_driver);
+}
+
+module_init(omap2_mbox_init);
+module_exit(omap2_mbox_exit);
+
+MODULE_LICENSE("GPL");
index 85cbc2a2e6639bf573ff399203a62df5c616085f..3e5d8cd4ea4f9ed6fb08737e03661d4af6899291 100644 (file)
@@ -30,6 +30,7 @@
 #include "prcm-regs.h"
 #include "memory.h"
 
+
 static struct memory_timings mem_timings;
 
 u32 omap2_memory_get_slow_dll_ctrl(void)
@@ -99,3 +100,20 @@ void omap2_init_memory_params(u32 force_lock_to_unlock_mode)
        /* 90 degree phase for anything below 133Mhz + disable DLL filter */
        mem_timings.slow_dll_ctrl |= ((1 << 1) | (3 << 8));
 }
+
+/* turn on smart idle modes for SDRAM scheduler and controller */
+void __init omap2_init_memory(void)
+{
+       u32 l;
+
+       l = SMS_SYSCONFIG;
+       l &= ~(0x3 << 3);
+       l |= (0x2 << 3);
+       SMS_SYSCONFIG = l;
+
+       l = SDRC_SYSCONFIG;
+       l &= ~(0x3 << 3);
+       l |= (0x2 << 3);
+       SDRC_SYSCONFIG = l;
+
+}
index f538d0fdb13c35a47ec2bca1c3996f1b8e44c9c0..05750975d7463ebde347f3f08c14d56651e0bf25 100644 (file)
@@ -43,7 +43,7 @@ struct pin_config __initdata_or_module omap24xx_pins[] = {
 /* 24xx I2C */
 MUX_CFG_24XX("M19_24XX_I2C1_SCL",      0x111,  0,      0,      0,      1)
 MUX_CFG_24XX("L15_24XX_I2C1_SDA",      0x112,  0,      0,      0,      1)
-MUX_CFG_24XX("J15_24XX_I2C2_SCL",      0x113,  0,      0,      0,      1)
+MUX_CFG_24XX("J15_24XX_I2C2_SCL",      0x113,  0,      0,      1,      1)
 MUX_CFG_24XX("H19_24XX_I2C2_SDA",      0x114,  0,      0,      0,      1)
 
 /* Menelaus interrupt */
@@ -52,7 +52,9 @@ MUX_CFG_24XX("W19_24XX_SYS_NIRQ",     0x12c,  0,      1,      1,      1)
 /* 24xx clocks */
 MUX_CFG_24XX("W14_24XX_SYS_CLKOUT",    0x137,  0,      1,      1,      1)
 
-/* 24xx GPMC wait pin monitoring */
+/* 24xx GPMC chipselects, wait pin monitoring */
+MUX_CFG_24XX("E2_GPMC_NCS2",           0x08e,  0,      1,      1,      1)
+MUX_CFG_24XX("L2_GPMC_NCS7",           0x093,  0,      1,      1,      1)
 MUX_CFG_24XX("L3_GPMC_WAIT0",          0x09a,  0,      1,      1,      1)
 MUX_CFG_24XX("N7_GPMC_WAIT1",          0x09b,  0,      1,      1,      1)
 MUX_CFG_24XX("M1_GPMC_WAIT2",          0x09c,  0,      1,      1,      1)
@@ -65,17 +67,20 @@ MUX_CFG_24XX("W15_24XX_MCBSP2_DR",  0x126,  1,      1,      0,      1)
 MUX_CFG_24XX("V15_24XX_MCBSP2_DX",     0x127,  1,      1,      0,      1)
 
 /* 24xx GPIO */
-MUX_CFG_24XX("M21_242X_GPIO11",                0x0c9,  3,      1,      1,      1)
-MUX_CFG_24XX("AA10_242X_GPIO13",       0x0e5,  3,      0,      0,      1)
-MUX_CFG_24XX("AA6_242X_GPIO14",                0x0e6,  3,      0,      0,      1)
-MUX_CFG_24XX("AA4_242X_GPIO15",                0x0e7,  3,      0,      0,      1)
-MUX_CFG_24XX("Y11_242X_GPIO16",                0x0e8,  3,      0,      0,      1)
-MUX_CFG_24XX("AA12_242X_GPIO17",       0x0e9,  3,      0,      0,      1)
-MUX_CFG_24XX("AA8_242X_GPIO58",                0x0ea,  3,      0,      0,      1)
+MUX_CFG_24XX("M21_242X_GPIO11",                0x0c9,  3,      1,      1,      1)
+MUX_CFG_24XX("P21_242X_GPIO12",                0x0ca,  3,      0,      0,      1)
+MUX_CFG_24XX("AA10_242X_GPIO13",       0x0e5,  3,      0,      0,      1)
+MUX_CFG_24XX("AA6_242X_GPIO14",                0x0e6,  3,      0,      0,      1)
+MUX_CFG_24XX("AA4_242X_GPIO15",                0x0e7,  3,      0,      0,      1)
+MUX_CFG_24XX("Y11_242X_GPIO16",                0x0e8,  3,      0,      0,      1)
+MUX_CFG_24XX("AA12_242X_GPIO17",       0x0e9,  3,      0,      0,      1)
+MUX_CFG_24XX("AA8_242X_GPIO58",                0x0ea,  3,      0,      0,      1)
 MUX_CFG_24XX("Y20_24XX_GPIO60",                0x12c,  3,      0,      0,      1)
-MUX_CFG_24XX("W4__24XX_GPIO74",                0x0f2,  3,      0,      0,      1)
+MUX_CFG_24XX("W4__24XX_GPIO74",                0x0f2,  3,      0,      0,      1)
 MUX_CFG_24XX("M15_24XX_GPIO92",                0x10a,  3,      0,      0,      1)
+MUX_CFG_24XX("J15_24XX_GPIO99",                0x113,  3,      1,      1,      1)
 MUX_CFG_24XX("V14_24XX_GPIO117",       0x128,  3,      1,      0,      1)
+MUX_CFG_24XX("P14_24XX_GPIO125",       0x140,  3,      1,      1,      1)
 
 /* 242x DBG GPIO */
 MUX_CFG_24XX("V4_242X_GPIO49",         0xd3,   3,      0,      0,      1)
@@ -90,17 +95,17 @@ MUX_CFG_24XX("T3_242X_GPIO55",              0xd9,   3,      0,      0,      1)
 MUX_CFG_24XX("U2_242X_GPIO56",         0xda,   3,      0,      0,      1)
 
 /* 24xx external DMA requests */
-MUX_CFG_24XX("AA10_242X_DMAREQ0",      0x0e5,  2,      0,      0,      1)
-MUX_CFG_24XX("AA6_242X_DMAREQ1",       0x0e6,  2,      0,      0,      1)
-MUX_CFG_24XX("E4_242X_DMAREQ2",                0x074,  2,      0,      0,      1)
-MUX_CFG_24XX("G4_242X_DMAREQ3",                0x073,  2,      0,      0,      1)
-MUX_CFG_24XX("D3_242X_DMAREQ4",                0x072,  2,      0,      0,      1)
-MUX_CFG_24XX("E3_242X_DMAREQ5",                0x071,  2,      0,      0,      1)
+MUX_CFG_24XX("AA10_242X_DMAREQ0",      0x0e5,  2,      0,      0,      1)
+MUX_CFG_24XX("AA6_242X_DMAREQ1",       0x0e6,  2,      0,      0,      1)
+MUX_CFG_24XX("E4_242X_DMAREQ2",                0x074,  2,      0,      0,      1)
+MUX_CFG_24XX("G4_242X_DMAREQ3",                0x073,  2,      0,      0,      1)
+MUX_CFG_24XX("D3_242X_DMAREQ4",                0x072,  2,      0,      0,      1)
+MUX_CFG_24XX("E3_242X_DMAREQ5",                0x071,  2,      0,      0,      1)
 
 /* TSC IRQ */
 MUX_CFG_24XX("P20_24XX_TSC_IRQ",       0x108,  0,      0,      0,      1)
 
-/* UART3  */
+/* UART3 */
 MUX_CFG_24XX("K15_24XX_UART3_TX",      0x118,  0,      0,      0,      1)
 MUX_CFG_24XX("K14_24XX_UART3_RX",      0x119,  0,      0,      0,      1)
 
@@ -118,6 +123,30 @@ MUX_CFG_24XX("E18_24XX_MMC_DAT_DIR3",      0x0fc,  0,      0,      0,      1)
 MUX_CFG_24XX("G18_24XX_MMC_CMD_DIR",   0x0fd,  0,      0,      0,      1)
 MUX_CFG_24XX("H15_24XX_MMC_CLKI",      0x0fe,  0,      0,      0,      1)
 
+/* Full speed USB */
+MUX_CFG_24XX("J20_24XX_USB0_PUEN",     0x11d,  0,      0,      0,      1)
+MUX_CFG_24XX("J19_24XX_USB0_VP",       0x11e,  0,      0,      0,      1)
+MUX_CFG_24XX("K20_24XX_USB0_VM",       0x11f,  0,      0,      0,      1)
+MUX_CFG_24XX("J18_24XX_USB0_RCV",      0x120,  0,      0,      0,      1)
+MUX_CFG_24XX("K19_24XX_USB0_TXEN",     0x121,  0,      0,      0,      1)
+MUX_CFG_24XX("J14_24XX_USB0_SE0",      0x122,  0,      0,      0,      1)
+MUX_CFG_24XX("K18_24XX_USB0_DAT",      0x123,  0,      0,      0,      1)
+
+MUX_CFG_24XX("N14_24XX_USB1_SE0",      0x0ed,  2,      0,      0,      1)
+MUX_CFG_24XX("W12_24XX_USB1_SE0",      0x0dd,  3,      0,      0,      1)
+MUX_CFG_24XX("P15_24XX_USB1_DAT",      0x0ee,  2,      0,      0,      1)
+MUX_CFG_24XX("R13_24XX_USB1_DAT",      0x0e0,  3,      0,      0,      1)
+MUX_CFG_24XX("W20_24XX_USB1_TXEN",     0x0ec,  2,      0,      0,      1)
+MUX_CFG_24XX("P13_24XX_USB1_TXEN",     0x0df,  3,      0,      0,      1)
+MUX_CFG_24XX("V19_24XX_USB1_RCV",      0x0eb,  2,      0,      0,      1)
+MUX_CFG_24XX("V12_24XX_USB1_RCV",      0x0de,  3,      0,      0,      1)
+
+MUX_CFG_24XX("AA10_24XX_USB2_SE0",     0x0e5,  2,      0,      0,      1)
+MUX_CFG_24XX("Y11_24XX_USB2_DAT",      0x0e8,  2,      0,      0,      1)
+MUX_CFG_24XX("AA12_24XX_USB2_TXEN",    0x0e9,  2,      0,      0,      1)
+MUX_CFG_24XX("AA6_24XX_USB2_RCV",      0x0e6,  2,      0,      0,      1)
+MUX_CFG_24XX("AA4_24XX_USB2_TLLSE0",   0x0e7,  2,      0,      0,      1)
+
 /* Keypad GPIO*/
 MUX_CFG_24XX("T19_24XX_KBR0",          0x106,  3,      1,      1,      1)
 MUX_CFG_24XX("R19_24XX_KBR1",          0x107,  3,      1,      1,      1)
diff --git a/arch/arm/mach-omap2/pm-domain.c b/arch/arm/mach-omap2/pm-domain.c
deleted file mode 100644 (file)
index 2494091..0000000
+++ /dev/null
@@ -1,299 +0,0 @@
-/*
- * linux/arch/arm/mach-omap2/pm-domain.c
- *
- * Power domain functions for OMAP2
- *
- * Copyright (C) 2006 Nokia Corporation
- * Tony Lindgren <tony@atomide.com>
- *
- * Some code based on earlier OMAP2 sample PM code
- * Copyright (C) 2005 Texas Instruments, Inc.
- * 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.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/clk.h>
-
-#include <asm/io.h>
-
-#include "prcm-regs.h"
-
-/* Power domain offsets */
-#define PM_MPU_OFFSET                  0x100
-#define PM_CORE_OFFSET                 0x200
-#define PM_GFX_OFFSET                  0x300
-#define PM_WKUP_OFFSET                 0x400           /* Autoidle only */
-#define PM_PLL_OFFSET                  0x500           /* Autoidle only */
-#define PM_DSP_OFFSET                  0x800
-#define PM_MDM_OFFSET                  0xc00
-
-/* Power domain wake-up dependency control register */
-#define PM_WKDEP_OFFSET                        0xc8
-#define                EN_MDM                  (1 << 5)
-#define                EN_WKUP                 (1 << 4)
-#define                EN_GFX                  (1 << 3)
-#define                EN_DSP                  (1 << 2)
-#define                EN_MPU                  (1 << 1)
-#define                EN_CORE                 (1 << 0)
-
-/* Core power domain state transition control register */
-#define PM_PWSTCTRL_OFFSET             0xe0
-#define                FORCESTATE              (1 << 18)       /* Only for DSP & GFX */
-#define                MEM4RETSTATE            (1 << 6)
-#define                MEM3RETSTATE            (1 << 5)
-#define                MEM2RETSTATE            (1 << 4)
-#define                MEM1RETSTATE            (1 << 3)
-#define                LOGICRETSTATE           (1 << 2)        /* Logic is retained */
-#define                POWERSTATE_OFF          0x3
-#define                POWERSTATE_RETENTION    0x1
-#define                POWERSTATE_ON           0x0
-
-/* Power domain state register */
-#define PM_PWSTST_OFFSET               0xe4
-
-/* Hardware supervised state transition control register */
-#define CM_CLKSTCTRL_OFFSET            0x48
-#define                AUTOSTAT_MPU            (1 << 0)        /* MPU */
-#define                AUTOSTAT_DSS            (1 << 2)        /* Core */
-#define                AUTOSTAT_L4             (1 << 1)        /* Core */
-#define                AUTOSTAT_L3             (1 << 0)        /* Core */
-#define                AUTOSTAT_GFX            (1 << 0)        /* GFX */
-#define                AUTOSTAT_IVA            (1 << 8)        /* 2420 IVA in DSP domain */
-#define                AUTOSTAT_DSP            (1 << 0)        /* DSP */
-#define                AUTOSTAT_MDM            (1 << 0)        /* MDM */
-
-/* Automatic control of interface clock idling */
-#define CM_AUTOIDLE1_OFFSET            0x30
-#define CM_AUTOIDLE2_OFFSET            0x34            /* Core only */
-#define CM_AUTOIDLE3_OFFSET            0x38            /* Core only */
-#define CM_AUTOIDLE4_OFFSET            0x3c            /* Core only */
-#define                AUTO_54M(x)             (((x) & 0x3) << 6)
-#define                AUTO_96M(x)             (((x) & 0x3) << 2)
-#define                AUTO_DPLL(x)            (((x) & 0x3) << 0)
-#define                AUTO_STOPPED            0x3
-#define                AUTO_BYPASS_FAST        0x2             /* DPLL only */
-#define                AUTO_BYPASS_LOW_POWER   0x1             /* DPLL only */
-#define                AUTO_DISABLED           0x0
-
-/* Voltage control PRCM_VOLTCTRL bits */
-#define                AUTO_EXTVOLT            (1 << 15)
-#define                FORCE_EXTVOLT           (1 << 14)
-#define                SETOFF_LEVEL(x)         (((x) & 0x3) << 12)
-#define                MEMRETCTRL              (1 << 8)
-#define                SETRET_LEVEL(x)         (((x) & 0x3) << 6)
-#define                VOLT_LEVEL(x)           (((x) & 0x3) << 0)
-
-#define OMAP24XX_PRCM_VBASE    IO_ADDRESS(OMAP24XX_PRCM_BASE)
-#define prcm_readl(r)          __raw_readl(OMAP24XX_PRCM_VBASE + (r))
-#define prcm_writel(v, r)      __raw_writel((v), OMAP24XX_PRCM_VBASE + (r))
-
-static u32 pmdomain_get_wakeup_dependencies(int domain_offset)
-{
-       return prcm_readl(domain_offset + PM_WKDEP_OFFSET);
-}
-
-static void pmdomain_set_wakeup_dependencies(u32 state, int domain_offset)
-{
-       prcm_writel(state, domain_offset + PM_WKDEP_OFFSET);
-}
-
-static u32 pmdomain_get_powerstate(int domain_offset)
-{
-       return prcm_readl(domain_offset + PM_PWSTCTRL_OFFSET);
-}
-
-static void pmdomain_set_powerstate(u32 state, int domain_offset)
-{
-       prcm_writel(state, domain_offset + PM_PWSTCTRL_OFFSET);
-}
-
-static u32 pmdomain_get_clock_autocontrol(int domain_offset)
-{
-       return prcm_readl(domain_offset + CM_CLKSTCTRL_OFFSET);
-}
-
-static void pmdomain_set_clock_autocontrol(u32 state, int domain_offset)
-{
-       prcm_writel(state, domain_offset + CM_CLKSTCTRL_OFFSET);
-}
-
-static u32 pmdomain_get_clock_autoidle1(int domain_offset)
-{
-       return prcm_readl(domain_offset + CM_AUTOIDLE1_OFFSET);
-}
-
-/* Core domain only */
-static u32 pmdomain_get_clock_autoidle2(int domain_offset)
-{
-       return prcm_readl(domain_offset + CM_AUTOIDLE2_OFFSET);
-}
-
-/* Core domain only */
-static u32 pmdomain_get_clock_autoidle3(int domain_offset)
-{
-       return prcm_readl(domain_offset + CM_AUTOIDLE3_OFFSET);
-}
-
-/* Core domain only */
-static u32 pmdomain_get_clock_autoidle4(int domain_offset)
-{
-       return prcm_readl(domain_offset + CM_AUTOIDLE4_OFFSET);
-}
-
-static void pmdomain_set_clock_autoidle1(u32 state, int domain_offset)
-{
-       prcm_writel(state, CM_AUTOIDLE1_OFFSET + domain_offset);
-}
-
-/* Core domain only */
-static void pmdomain_set_clock_autoidle2(u32 state, int domain_offset)
-{
-       prcm_writel(state, CM_AUTOIDLE2_OFFSET + domain_offset);
-}
-
-/* Core domain only */
-static void pmdomain_set_clock_autoidle3(u32 state, int domain_offset)
-{
-       prcm_writel(state, CM_AUTOIDLE3_OFFSET + domain_offset);
-}
-
-/* Core domain only */
-static void pmdomain_set_clock_autoidle4(u32 state, int domain_offset)
-{
-       prcm_writel(state, CM_AUTOIDLE4_OFFSET + domain_offset);
-}
-
-/*
- * Configures power management domains to idle clocks automatically.
- */
-void pmdomain_set_autoidle(void)
-{
-       u32 val;
-
-       /* Set PLL auto stop for 54M, 96M & DPLL */
-       pmdomain_set_clock_autoidle1(AUTO_54M(AUTO_STOPPED) |
-                                    AUTO_96M(AUTO_STOPPED) |
-                                    AUTO_DPLL(AUTO_STOPPED), PM_PLL_OFFSET);
-
-       /* External clock input control
-        * REVISIT: Should this be in clock framework?
-        */
-       PRCM_CLKSRC_CTRL |= (0x3 << 3);
-
-       /* Configure number of 32KHz clock cycles for sys_clk */
-       PRCM_CLKSSETUP = 0x00ff;
-
-       /* Configure automatic voltage transition */
-       PRCM_VOLTSETUP = 0;
-       val = PRCM_VOLTCTRL;
-       val &= ~(SETOFF_LEVEL(0x3) | VOLT_LEVEL(0x3));
-       val |= SETOFF_LEVEL(1) | VOLT_LEVEL(1) | AUTO_EXTVOLT;
-       PRCM_VOLTCTRL = val;
-
-       /* Disable emulation tools functional clock */
-       PRCM_CLKEMUL_CTRL = 0x0;
-
-       /* Set core memory retention state */
-       val = pmdomain_get_powerstate(PM_CORE_OFFSET);
-       if (cpu_is_omap2420()) {
-               val &= ~(0x7 << 3);
-               val |= (MEM3RETSTATE | MEM2RETSTATE | MEM1RETSTATE);
-       } else {
-               val &= ~(0xf << 3);
-               val |= (MEM4RETSTATE | MEM3RETSTATE | MEM2RETSTATE |
-                       MEM1RETSTATE);
-       }
-       pmdomain_set_powerstate(val, PM_CORE_OFFSET);
-
-       /* OCP interface smart idle. REVISIT: Enable autoidle bit0 ? */
-       val = SMS_SYSCONFIG;
-       val &= ~(0x3 << 3);
-       val |= (0x2 << 3) | (1 << 0);
-       SMS_SYSCONFIG |= val;
-
-       val = SDRC_SYSCONFIG;
-       val &= ~(0x3 << 3);
-       val |= (0x2 << 3);
-       SDRC_SYSCONFIG = val;
-
-       /* Configure L3 interface for smart idle.
-        * REVISIT: Enable autoidle bit0 ?
-        */
-       val = GPMC_SYSCONFIG;
-       val &= ~(0x3 << 3);
-       val |= (0x2 << 3) | (1 << 0);
-       GPMC_SYSCONFIG = val;
-
-       pmdomain_set_powerstate(LOGICRETSTATE | POWERSTATE_RETENTION,
-                               PM_MPU_OFFSET);
-       pmdomain_set_powerstate(POWERSTATE_RETENTION, PM_CORE_OFFSET);
-       if (!cpu_is_omap2420())
-               pmdomain_set_powerstate(POWERSTATE_RETENTION, PM_MDM_OFFSET);
-
-       /* Assume suspend function has saved the state for DSP and GFX */
-       pmdomain_set_powerstate(FORCESTATE | POWERSTATE_OFF, PM_DSP_OFFSET);
-       pmdomain_set_powerstate(FORCESTATE | POWERSTATE_OFF, PM_GFX_OFFSET);
-
-#if 0
-       /* REVISIT: Internal USB needs special handling */
-       force_standby_usb();
-       if (cpu_is_omap2430())
-               force_hsmmc();
-       sdram_self_refresh_on_idle_req(1);
-#endif
-
-       /* Enable clock auto control for all domains.
-        * Note that CORE domain includes also DSS, L4 & L3.
-        */
-       pmdomain_set_clock_autocontrol(AUTOSTAT_MPU, PM_MPU_OFFSET);
-       pmdomain_set_clock_autocontrol(AUTOSTAT_GFX, PM_GFX_OFFSET);
-       pmdomain_set_clock_autocontrol(AUTOSTAT_DSS | AUTOSTAT_L4 | AUTOSTAT_L3,
-                                      PM_CORE_OFFSET);
-       if (cpu_is_omap2420())
-               pmdomain_set_clock_autocontrol(AUTOSTAT_IVA | AUTOSTAT_DSP,
-                                              PM_DSP_OFFSET);
-       else {
-               pmdomain_set_clock_autocontrol(AUTOSTAT_DSP, PM_DSP_OFFSET);
-               pmdomain_set_clock_autocontrol(AUTOSTAT_MDM, PM_MDM_OFFSET);
-       }
-
-       /* Enable clock autoidle for all domains */
-       pmdomain_set_clock_autoidle1(0x2, PM_DSP_OFFSET);
-       if (cpu_is_omap2420()) {
-               pmdomain_set_clock_autoidle1(0xfffffff9, PM_CORE_OFFSET);
-               pmdomain_set_clock_autoidle2(0x7, PM_CORE_OFFSET);
-               pmdomain_set_clock_autoidle1(0x3f, PM_WKUP_OFFSET);
-       } else {
-               pmdomain_set_clock_autoidle1(0xeafffff1, PM_CORE_OFFSET);
-               pmdomain_set_clock_autoidle2(0xfff, PM_CORE_OFFSET);
-               pmdomain_set_clock_autoidle1(0x7f, PM_WKUP_OFFSET);
-               pmdomain_set_clock_autoidle1(0x3, PM_MDM_OFFSET);
-       }
-       pmdomain_set_clock_autoidle3(0x7, PM_CORE_OFFSET);
-       pmdomain_set_clock_autoidle4(0x1f, PM_CORE_OFFSET);
-}
-
-/*
- * Initializes power domains by removing wake-up dependencies and powering
- * down DSP and GFX. Gets called from PM init. Note that DSP and IVA code
- * must re-enable DSP and GFX when used.
- */
-void __init pmdomain_init(void)
-{
-       /* Remove all domain wakeup dependencies */
-       pmdomain_set_wakeup_dependencies(EN_WKUP | EN_CORE, PM_MPU_OFFSET);
-       pmdomain_set_wakeup_dependencies(0, PM_DSP_OFFSET);
-       pmdomain_set_wakeup_dependencies(0, PM_GFX_OFFSET);
-       pmdomain_set_wakeup_dependencies(EN_WKUP | EN_MPU, PM_CORE_OFFSET);
-       if (cpu_is_omap2430())
-               pmdomain_set_wakeup_dependencies(0, PM_MDM_OFFSET);
-
-       /* Power down DSP and GFX */
-       pmdomain_set_powerstate(POWERSTATE_OFF | FORCESTATE, PM_DSP_OFFSET);
-       pmdomain_set_powerstate(POWERSTATE_OFF | FORCESTATE, PM_GFX_OFFSET);
-}
index d7eee99b7e3fef12029d700f9550e6e0a96a3df7..27d7f85425b37c14cc50baa3176c5b2aa736a975 100644 (file)
@@ -6,6 +6,16 @@
  * Copyright (C) 2006 Nokia Corporation
  * Tony Lindgren <tony@atomide.com>
  *
+ * Fixed suspend-resume/dynamic-idle to get OMAP to retention
+ * Amit Kucheria <amit.kucheria@nokia.com>
+ * Igor Stoppa <igor.stoppa@nokia.com>
+ *
+ * Fixed MPU sleep to get ARM idle
+ * Igor Stoppa <igor.stoppa@nokia.com>
+ *
+ * Fixed MPU sleep some more
+ * Juha Yrjola
+ *
  * Copyright (C) 2005 Texas Instruments, Inc.
  * Richard Woodruff <r-woodruff2@ti.com>
  *
@@ -24,6 +34,7 @@
 #include <linux/sysfs.h>
 #include <linux/module.h>
 #include <linux/delay.h>
+#include <linux/clk.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/arch/clock.h>
 #include <asm/arch/sram.h>
 #include <asm/arch/pm.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/dma.h>
+#include <asm/arch/board.h>
+
+#define PRCM_BASE              0x48008000
+#define PRCM_REVISION          0x000
+#define PRCM_SYSCONFIG         0x010
+#define PRCM_IRQSTATUS_MPU     0x018
+#define PRCM_IRQENABLE_MPU     0x01c
+#define PRCM_VOLTCTRL          0x050
+#define                AUTO_EXTVOLT    (1 << 15)
+#define                FORCE_EXTVOLT   (1 << 14)
+#define                SETOFF_LEVEL(x) (((x) & 0x3) << 12)
+#define                MEMRETCTRL      (1 << 8)
+#define                SETRET_LEVEL(x) (((x) & 0x3) << 6)
+#define                VOLT_LEVEL(x)   (((x) & 0x3) << 0)
+#define PRCM_CLKSRC_CTRL       0x060
+#define PRCM_CLKOUT_CTRL       0x070
+#define PRCM_CLKEMUL_CTRL      0x078
+#define PRCM_CLKCFG_CTRL       0x080
+#define PRCM_VOLTSETUP         0x090
+#define PRCM_CLKSSETUP         0x094
+
+
+#define CM_CLKSEL_MPU          0x140
+#define CM_CLKSTCTRL_MPU       0x148
+#define                AUTOSTAT_MPU    (1 << 0)
+#define PM_WKDEP_MPU           0x1c8
+#define        EN_WKUP         (1 << 4)
+#define        EN_GFX          (1 << 3)
+#define        EN_DSP          (1 << 2)
+#define        EN_MPU          (1 << 1)
+#define        EN_CORE         (1 << 0)
+#define PM_PWSTCTRL_MPU                0x1e0
+#define PM_PWSTST_MPU          0x1e4
+
+
+#define CM_FCLKEN1_CORE                0x200
+#define CM_FCLKEN2_CORE                0x204
+#define CM_ICLKEN1_CORE                0x210
+#define CM_ICLKEN2_CORE                0x214
+#define CM_ICLKEN4_CORE                0x21c
+#define CM_IDLEST1_CORE                0x220
+#define CM_IDLEST2_CORE                0x224
+#define CM_AUTOIDLE1_CORE      0x230
+#define CM_AUTOIDLE2_CORE      0x234
+#define CM_AUTOIDLE3_CORE      0x238
+#define CM_AUTOIDLE4_CORE      0x23c
+#define CM_CLKSEL1_CORE                0x240
+#define CM_CLKSEL2_CORE                0x244
+#define CM_CLKSTCTRL_CORE      0x248
+#define                AUTOSTAT_DSS    (1 << 2)
+#define                AUTOSTAT_L4     (1 << 1)
+#define                AUTOSTAT_L3     (1 << 0)
+#define PM_WKEN1_CORE          0x2a0
+#define PM_WKEN2_CORE          0x2a4
+#define PM_WKST1_CORE          0x2b0
+#define PM_WKST2_CORE          0x2b4
+#define PM_WKDEP_CORE          0x2c8
+#define PM_PWSTCTRL_CORE       0x2e0
+#define PM_PWSTST_CORE         0x2e4
+
+
+#define CM_CLKSTCTRL_GFX       0x348
+#define                AUTOSTAT_GFX    (1 << 0)
+#define PM_WKDEP_GFX           0x3c8
+#define PM_PWSTCTRL_GFX                0x3e0
+
+
+#define CM_FCLKEN_WKUP         0x400
+#define CM_ICLKEN_WKUP         0x410
+#define CM_AUTOIDLE_WKUP       0x430
+#define PM_WKEN_WKUP           0x4a0
+#define        EN_GPIOS        (1 << 2)
+#define        EN_GPT1         (1 << 0)
+#define PM_WKST_WKUP           0x4b0
+
+
+#define CM_CLKEN_PLL           0x500
+#define CM_IDLEST_CKGEN                0x520
+#define CM_AUTOIDLE_PLL                0x530
+#define CM_CLKSEL1_PLL         0x540
+#define CM_CLKSEL2_PLL         0x544
+
+
+#define CM_FCLKEN_DSP          0x800
+#define CM_ICLKEN_DSP          0x810
+#define CM_IDLEST_DSP          0x820
+#define CM_AUTOIDLE_DSP                0x830
+#define CM_CLKSEL_DSP          0x840
+#define CM_CLKSTCTRL_DSP       0x848
+#define                AUTOSTAT_IVA    (1 << 8)
+#define                AUTOSTAT_DSP    (1 << 0)
+#define RM_RSTCTRL_DSP         0x850
+#define RM_RSTST_DSP           0x858
+#define PM_WKDEP_DSP           0x8c8
+#define PM_PWSTCTRL_DSP                0x8e0
+#define PM_PWSTST_DSP          0x8e4
 
-#include "prcm-regs.h"
-
-static struct clk *vclk;
 static void (*omap2_sram_idle)(void);
-static void (*omap2_sram_suspend)(int dllctrl, int cpu_rev);
+static void (*omap2_sram_suspend)(int dllctrl);
 static void (*saved_idle)(void);
 
-extern void __init pmdomain_init(void);
-extern void pmdomain_set_autoidle(void);
+static u32 prcm_base = IO_ADDRESS(PRCM_BASE);
 
-static unsigned int omap24xx_sleep_save[OMAP24XX_SLEEP_SAVE_SIZE];
+static inline void prcm_write_reg(int idx, u32 val)
+{
+       __raw_writel(val, prcm_base + idx);
+}
 
-void omap2_pm_idle(void)
+static inline u32 prcm_read_reg(int idx)
 {
-       local_irq_disable();
-       local_fiq_disable();
-       if (need_resched()) {
-               local_fiq_enable();
-               local_irq_enable();
-               return;
-       }
+       return __raw_readl(prcm_base + idx);
+}
 
-       /*
-        * Since an interrupt may set up a timer, we don't want to
-        * reprogram the hardware timer with interrupts enabled.
-        * Re-enable interrupts only after returning from idle.
-        */
-       timer_dyn_reprogram();
+static u32 omap2_read_32k_sync_counter(void)
+{
+        return omap_readl(0x48004010);
+}
 
-       omap2_sram_idle();
-       local_fiq_enable();
-       local_irq_enable();
+#ifdef CONFIG_PM_DEBUG
+int omap2_pm_debug = 0;
+
+static int serial_console_clock_disabled;
+static int serial_console_uart;
+static unsigned int serial_console_next_disable;
+
+static struct clk *console_iclk, *console_fclk;
+
+static void serial_console_kick(void)
+{
+       serial_console_next_disable = omap2_read_32k_sync_counter();
+       /* Keep the clocks on for 4 secs */
+       serial_console_next_disable += 4 * 32768;
 }
 
-static int omap2_pm_prepare(suspend_state_t state)
+static void serial_wait_tx(void)
 {
-       int error = 0;
+       static const unsigned long uart_bases[3] = {
+               0x4806a000, 0x4806c000, 0x4806e000
+       };
+       unsigned long lsr_reg;
+       int looped = 0;
+
+       /* Wait for TX FIFO and THR to get empty */
+       lsr_reg = IO_ADDRESS(uart_bases[serial_console_uart - 1] + (5 << 2));
+       while ((__raw_readb(lsr_reg) & 0x60) != 0x60)
+               looped = 1;
+       if (looped)
+               serial_console_kick();
+}
 
-       /* We cannot sleep in idle until we have resumed */
-       saved_idle = pm_idle;
-       pm_idle = NULL;
+static void serial_console_fclk_mask(u32 *f1, u32 *f2)
+{
+       switch (serial_console_uart)  {
+       case 1:
+               *f1 &= ~(1 << 21);
+               break;
+       case 2:
+               *f1 &= ~(1 << 22);
+               break;
+       case 3:
+               *f2 &= ~(1 << 2);
+               break;
+       }
+}
 
-       switch (state)
-       {
-       case PM_SUSPEND_STANDBY:
-       case PM_SUSPEND_MEM:
+static void serial_console_sleep(int enable)
+{
+       if (console_iclk == NULL || console_fclk == NULL)
+               return;
+
+       if (enable) {
+               BUG_ON(serial_console_clock_disabled);
+               if (clk_get_usecount(console_fclk) == 0)
+                       return;
+               if ((int) serial_console_next_disable - (int) omap2_read_32k_sync_counter() >= 0)
+                       return;
+               serial_wait_tx();
+               clk_disable(console_iclk);
+               clk_disable(console_fclk);
+               serial_console_clock_disabled = 1;
+       } else {
+               int serial_wakeup = 0;
+               u32 l;
+
+               switch (serial_console_uart)  {
+               case 1:
+                       l = prcm_read_reg(PM_WKST1_CORE);
+                       if (l & (1 << 21))
+                               serial_wakeup = 1;
+                       break;
+               case 2:
+                       l = prcm_read_reg(PM_WKST1_CORE);
+                       if (l & (1 << 22))
+                               serial_wakeup = 1;
+                       break;
+               case 3:
+                       l = prcm_read_reg(PM_WKST2_CORE);
+                       if (l & (1 << 2))
+                               serial_wakeup = 1;
+                       break;
+               }
+               if (serial_wakeup)
+                       serial_console_kick();
+               if (!serial_console_clock_disabled)
+                       return;
+               clk_enable(console_iclk);
+               clk_enable(console_fclk);
+               serial_console_clock_disabled = 0;
+       }
+}
+
+static void pm_init_serial_console(void)
+{
+       const struct omap_serial_console_config *conf;
+       char name[16];
+       u32 l;
+
+       conf = omap_get_config(OMAP_TAG_SERIAL_CONSOLE,
+                              struct omap_serial_console_config);
+       if (conf == NULL)
+               return;
+       if (conf->console_uart > 3 || conf->console_uart < 1)
+               return;
+       serial_console_uart = conf->console_uart;
+       sprintf(name, "uart%d_fck", conf->console_uart);
+       console_fclk = clk_get(NULL, name);
+       if (IS_ERR(console_fclk))
+               console_fclk = NULL;
+       name[6] = 'i';
+       console_iclk = clk_get(NULL, name);
+       if (IS_ERR(console_fclk))
+               console_iclk = NULL;
+       if (console_fclk == NULL || console_iclk == NULL) {
+               serial_console_uart = 0;
+               return;
+       }
+       switch (serial_console_uart) {
+       case 1:
+               l = prcm_read_reg(PM_WKEN1_CORE);
+               l |= 1 << 21;
+               prcm_write_reg(PM_WKEN1_CORE, l);
+               break;
+       case 2:
+               l = prcm_read_reg(PM_WKEN1_CORE);
+               l |= 1 << 22;
+               prcm_write_reg(PM_WKEN1_CORE, l);
+               break;
+       case 3:
+               l = prcm_read_reg(PM_WKEN2_CORE);
+               l |= 1 << 2;
+               prcm_write_reg(PM_WKEN2_CORE, l);
                break;
+       }
+}
 
-       case PM_SUSPEND_DISK:
-               return -ENOTSUPP;
+#define DUMP_REG(reg) \
+       regs[reg_count].name = #reg; \
+       regs[reg_count++].val = prcm_read_reg(reg)
+#define DUMP_INTC_REG(reg, off) \
+       regs[reg_count].name = #reg; \
+       regs[reg_count++].val = __raw_readl(IO_ADDRESS(0x480fe000 + (off)))
 
-       default:
-               return -EINVAL;
+static void omap2_pm_dump(int mode, int resume, unsigned int us)
+{
+       struct reg {
+               const char *name;
+               u32 val;
+       } regs[32];
+       int reg_count = 0, i;
+       const char *s1 = NULL, *s2 = NULL;
+
+       if (!resume) {
+#if 0
+               /* MPU */
+               DUMP_REG(PRCM_IRQENABLE_MPU);
+               DUMP_REG(CM_CLKSTCTRL_MPU);
+               DUMP_REG(PM_PWSTCTRL_MPU);
+               DUMP_REG(PM_PWSTST_MPU);
+               DUMP_REG(PM_WKDEP_MPU);
+#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_REG(CM_FCLKEN1_CORE);
+               DUMP_REG(CM_FCLKEN2_CORE);
+               DUMP_REG(CM_FCLKEN_WKUP);
+               DUMP_REG(CM_ICLKEN1_CORE);
+               DUMP_REG(CM_ICLKEN2_CORE);
+               DUMP_REG(CM_ICLKEN_WKUP);
+               DUMP_REG(CM_CLKEN_PLL);
+               DUMP_REG(PRCM_CLKEMUL_CTRL);
+               DUMP_REG(CM_AUTOIDLE_PLL);
+               DUMP_REG(PM_PWSTST_CORE);
+               DUMP_REG(PRCM_CLKSRC_CTRL);
+#endif
+#if 0
+               /* DSP */
+               DUMP_REG(CM_FCLKEN_DSP);
+               DUMP_REG(CM_ICLKEN_DSP);
+               DUMP_REG(CM_IDLEST_DSP);
+               DUMP_REG(CM_AUTOIDLE_DSP);
+               DUMP_REG(CM_CLKSEL_DSP);
+               DUMP_REG(CM_CLKSTCTRL_DSP);
+               DUMP_REG(RM_RSTCTRL_DSP);
+               DUMP_REG(RM_RSTST_DSP);
+               DUMP_REG(PM_PWSTCTRL_DSP);
+               DUMP_REG(PM_PWSTST_DSP);
+#endif
+       } else {
+               DUMP_REG(PM_WKST1_CORE);
+               DUMP_REG(PM_WKST2_CORE);
+               DUMP_REG(PM_WKST_WKUP);
+               DUMP_REG(PRCM_IRQSTATUS_MPU);
+#if 1
+               DUMP_INTC_REG(INTC_PENDING_IRQ0, 0x0098);
+               DUMP_INTC_REG(INTC_PENDING_IRQ1, 0x00b8);
+               DUMP_INTC_REG(INTC_PENDING_IRQ2, 0x00d8);
+#endif
        }
 
-       return error;
+       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)
+               printk("--- Going to %s %s (next timer after %u ms)\n", s1, s2,
+                      jiffies_to_msecs(next_timer_interrupt() - jiffies));
+       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);
 }
 
-#define INT0_WAKE_MASK (OMAP_IRQ_BIT(INT_24XX_GPIO_BANK1) |    \
-                       OMAP_IRQ_BIT(INT_24XX_GPIO_BANK2) |     \
-                       OMAP_IRQ_BIT(INT_24XX_GPIO_BANK3))
+#else
+static inline void serial_console_sleep(int enable) {}
+static inline void pm_init_serial_console(void) {}
+static inline void omap2_pm_dump(int mode, int resume, unsigned int us) {}
+static inline void serial_console_fclk_mask(u32 *f1, u32 *f2) {}
 
-#define INT1_WAKE_MASK (OMAP_IRQ_BIT(INT_24XX_GPIO_BANK4))
+#define omap2_pm_debug 0
 
-#define INT2_WAKE_MASK (OMAP_IRQ_BIT(INT_24XX_UART1_IRQ) |     \
-                       OMAP_IRQ_BIT(INT_24XX_UART2_IRQ) |      \
-                       OMAP_IRQ_BIT(INT_24XX_UART3_IRQ))
+#endif
 
-#define preg(reg)      printk("%s\t(0x%p):\t0x%08x\n", #reg, &reg, reg);
+static unsigned short enable_dyn_sleep = 0; /* disabled till drivers are fixed */
 
-static void omap2_pm_debug(char * desc)
+static ssize_t omap_pm_sleep_while_idle_show(struct subsystem * subsys, char *buf)
 {
-       printk("%s:\n", desc);
-
-       preg(CM_CLKSTCTRL_MPU);
-       preg(CM_CLKSTCTRL_CORE);
-       preg(CM_CLKSTCTRL_GFX);
-       preg(CM_CLKSTCTRL_DSP);
-       preg(CM_CLKSTCTRL_MDM);
-
-       preg(PM_PWSTCTRL_MPU);
-       preg(PM_PWSTCTRL_CORE);
-       preg(PM_PWSTCTRL_GFX);
-       preg(PM_PWSTCTRL_DSP);
-       preg(PM_PWSTCTRL_MDM);
-
-       preg(PM_PWSTST_MPU);
-       preg(PM_PWSTST_CORE);
-       preg(PM_PWSTST_GFX);
-       preg(PM_PWSTST_DSP);
-       preg(PM_PWSTST_MDM);
-
-       preg(CM_AUTOIDLE1_CORE);
-       preg(CM_AUTOIDLE2_CORE);
-       preg(CM_AUTOIDLE3_CORE);
-       preg(CM_AUTOIDLE4_CORE);
-       preg(CM_AUTOIDLE_WKUP);
-       preg(CM_AUTOIDLE_PLL);
-       preg(CM_AUTOIDLE_DSP);
-       preg(CM_AUTOIDLE_MDM);
-
-       preg(CM_ICLKEN1_CORE);
-       preg(CM_ICLKEN2_CORE);
-       preg(CM_ICLKEN3_CORE);
-       preg(CM_ICLKEN4_CORE);
-       preg(CM_ICLKEN_GFX);
-       preg(CM_ICLKEN_WKUP);
-       preg(CM_ICLKEN_DSP);
-       preg(CM_ICLKEN_MDM);
-
-       preg(CM_IDLEST1_CORE);
-       preg(CM_IDLEST2_CORE);
-       preg(CM_IDLEST3_CORE);
-       preg(CM_IDLEST4_CORE);
-       preg(CM_IDLEST_GFX);
-       preg(CM_IDLEST_WKUP);
-       preg(CM_IDLEST_CKGEN);
-       preg(CM_IDLEST_DSP);
-       preg(CM_IDLEST_MDM);
-
-       preg(RM_RSTST_MPU);
-       preg(RM_RSTST_GFX);
-       preg(RM_RSTST_WKUP);
-       preg(RM_RSTST_DSP);
-       preg(RM_RSTST_MDM);
-
-       preg(PM_WKDEP_MPU);
-       preg(PM_WKDEP_CORE);
-       preg(PM_WKDEP_GFX);
-       preg(PM_WKDEP_DSP);
-       preg(PM_WKDEP_MDM);
-
-       preg(CM_FCLKEN_WKUP);
-       preg(CM_ICLKEN_WKUP);
-       preg(CM_IDLEST_WKUP);
-       preg(CM_AUTOIDLE_WKUP);
-       preg(CM_CLKSEL_WKUP);
-
-       preg(PM_WKEN_WKUP);
-       preg(PM_WKST_WKUP);
+       return sprintf(buf, "%hu\n", enable_dyn_sleep);
 }
 
-static inline void omap2_pm_save_registers(void)
+static ssize_t omap_pm_sleep_while_idle_store(struct subsystem * subsys,
+                                             const char * buf,
+                                             size_t n)
 {
-       /* Save interrupt registers */
-       OMAP24XX_SAVE(INTC_MIR0);
-       OMAP24XX_SAVE(INTC_MIR1);
-       OMAP24XX_SAVE(INTC_MIR2);
-
-       /* Save power control registers */
-       OMAP24XX_SAVE(CM_CLKSTCTRL_MPU);
-       OMAP24XX_SAVE(CM_CLKSTCTRL_CORE);
-       OMAP24XX_SAVE(CM_CLKSTCTRL_GFX);
-       OMAP24XX_SAVE(CM_CLKSTCTRL_DSP);
-       OMAP24XX_SAVE(CM_CLKSTCTRL_MDM);
-
-       /* Save power state registers */
-       OMAP24XX_SAVE(PM_PWSTCTRL_MPU);
-       OMAP24XX_SAVE(PM_PWSTCTRL_CORE);
-       OMAP24XX_SAVE(PM_PWSTCTRL_GFX);
-       OMAP24XX_SAVE(PM_PWSTCTRL_DSP);
-       OMAP24XX_SAVE(PM_PWSTCTRL_MDM);
-
-       /* Save autoidle registers */
-       OMAP24XX_SAVE(CM_AUTOIDLE1_CORE);
-       OMAP24XX_SAVE(CM_AUTOIDLE2_CORE);
-       OMAP24XX_SAVE(CM_AUTOIDLE3_CORE);
-       OMAP24XX_SAVE(CM_AUTOIDLE4_CORE);
-       OMAP24XX_SAVE(CM_AUTOIDLE_WKUP);
-       OMAP24XX_SAVE(CM_AUTOIDLE_PLL);
-       OMAP24XX_SAVE(CM_AUTOIDLE_DSP);
-       OMAP24XX_SAVE(CM_AUTOIDLE_MDM);
-
-       /* Save idle state registers */
-       OMAP24XX_SAVE(CM_IDLEST1_CORE);
-       OMAP24XX_SAVE(CM_IDLEST2_CORE);
-       OMAP24XX_SAVE(CM_IDLEST3_CORE);
-       OMAP24XX_SAVE(CM_IDLEST4_CORE);
-       OMAP24XX_SAVE(CM_IDLEST_GFX);
-       OMAP24XX_SAVE(CM_IDLEST_WKUP);
-       OMAP24XX_SAVE(CM_IDLEST_CKGEN);
-       OMAP24XX_SAVE(CM_IDLEST_DSP);
-       OMAP24XX_SAVE(CM_IDLEST_MDM);
-
-       /* Save clock registers */
-       OMAP24XX_SAVE(CM_FCLKEN1_CORE);
-       OMAP24XX_SAVE(CM_FCLKEN2_CORE);
-       OMAP24XX_SAVE(CM_ICLKEN1_CORE);
-       OMAP24XX_SAVE(CM_ICLKEN2_CORE);
-       OMAP24XX_SAVE(CM_ICLKEN3_CORE);
-       OMAP24XX_SAVE(CM_ICLKEN4_CORE);
+       unsigned short value;
+       if (sscanf(buf, "%hu", &value) != 1 ||
+           (value != 0 && value != 1)) {
+               printk(KERN_ERR "idle_sleep_store: Invalid value\n");
+               return -EINVAL;
+       }
+       enable_dyn_sleep = value;
+       return n;
 }
 
-static inline void omap2_pm_restore_registers(void)
+static struct subsys_attribute sleep_while_idle_attr = {
+       .attr   = {
+               .name = __stringify(sleep_while_idle),
+               .mode = 0644,
+       },
+       .show   = omap_pm_sleep_while_idle_show,
+       .store  = omap_pm_sleep_while_idle_store,
+};
+
+extern struct subsystem power_subsys;
+
+static struct clk *osc_ck, *emul_ck;
+
+#define CONTROL_DEVCONF                __REG32(0x48000274)
+#define SDRC_DLLA_CTRL         __REG32(0x68009060)
+
+static int omap2_fclks_active(void)
 {
-       /* Restore clock state registers */
-       OMAP24XX_RESTORE(CM_CLKSTCTRL_MPU);
-       OMAP24XX_RESTORE(CM_CLKSTCTRL_CORE);
-       OMAP24XX_RESTORE(CM_CLKSTCTRL_GFX);
-       OMAP24XX_RESTORE(CM_CLKSTCTRL_DSP);
-       OMAP24XX_RESTORE(CM_CLKSTCTRL_MDM);
-
-       /* Restore power state registers */
-       OMAP24XX_RESTORE(PM_PWSTCTRL_MPU);
-       OMAP24XX_RESTORE(PM_PWSTCTRL_CORE);
-       OMAP24XX_RESTORE(PM_PWSTCTRL_GFX);
-       OMAP24XX_RESTORE(PM_PWSTCTRL_DSP);
-       OMAP24XX_RESTORE(PM_PWSTCTRL_MDM);
-
-       /* Restore idle state registers */
-       OMAP24XX_RESTORE(CM_IDLEST1_CORE);
-       OMAP24XX_RESTORE(CM_IDLEST2_CORE);
-       OMAP24XX_RESTORE(CM_IDLEST3_CORE);
-       OMAP24XX_RESTORE(CM_IDLEST4_CORE);
-       OMAP24XX_RESTORE(CM_IDLEST_GFX);
-       OMAP24XX_RESTORE(CM_IDLEST_WKUP);
-       OMAP24XX_RESTORE(CM_IDLEST_CKGEN);
-       OMAP24XX_RESTORE(CM_IDLEST_DSP);
-       OMAP24XX_RESTORE(CM_IDLEST_MDM);
-
-       /* Restore autoidle registers */
-       OMAP24XX_RESTORE(CM_AUTOIDLE1_CORE);
-       OMAP24XX_RESTORE(CM_AUTOIDLE2_CORE);
-       OMAP24XX_RESTORE(CM_AUTOIDLE3_CORE);
-       OMAP24XX_RESTORE(CM_AUTOIDLE4_CORE);
-       OMAP24XX_RESTORE(CM_AUTOIDLE_WKUP);
-       OMAP24XX_RESTORE(CM_AUTOIDLE_PLL);
-       OMAP24XX_RESTORE(CM_AUTOIDLE_DSP);
-       OMAP24XX_RESTORE(CM_AUTOIDLE_MDM);
-
-       /* Restore clock registers */
-       OMAP24XX_RESTORE(CM_FCLKEN1_CORE);
-       OMAP24XX_RESTORE(CM_FCLKEN2_CORE);
-       OMAP24XX_RESTORE(CM_ICLKEN1_CORE);
-       OMAP24XX_RESTORE(CM_ICLKEN2_CORE);
-       OMAP24XX_RESTORE(CM_ICLKEN3_CORE);
-       OMAP24XX_RESTORE(CM_ICLKEN4_CORE);
-
-       /* REVISIT: Clear interrupts here */
-
-       /* Restore interrupt registers */
-       OMAP24XX_RESTORE(INTC_MIR0);
-       OMAP24XX_RESTORE(INTC_MIR1);
-       OMAP24XX_RESTORE(INTC_MIR2);
+       u32 f1, f2;
+
+       f1 = prcm_read_reg(CM_FCLKEN1_CORE);
+       f2 = prcm_read_reg(CM_FCLKEN2_CORE);
+       serial_console_fclk_mask(&f1, &f2);
+       if (f1 | f2)
+               return 1;
+       return 0;
 }
 
-static int omap2_pm_suspend(void)
+static int omap2_irq_pending(void)
 {
-       int processor_type = 0;
+       u32 pending_reg = IO_ADDRESS(0x480fe098);
+       int i;
 
-       /* REVISIT: 0x21 or 0x26? */
-       if (cpu_is_omap2420())
-               processor_type = 0x21;
+       for (i = 0; i < 4; i++) {
+               if (__raw_readl(pending_reg))
+                       return 1;
+               pending_reg += 0x20;
+       }
+       return 0;
+}
 
-       if (!processor_type)
-               return -ENOTSUPP;
+static atomic_t sleep_block = ATOMIC_INIT(0);
 
-       local_irq_disable();
-       local_fiq_disable();
+void omap2_block_sleep(void)
+{
+       atomic_inc(&sleep_block);
+}
+
+void omap2_allow_sleep(void)
+{
+       int i;
 
-       omap2_pm_save_registers();
+       i = atomic_dec_return(&sleep_block);
+       BUG_ON(i < 0);
+}
+
+extern void omap2_gpio_prepare_for_retention(void);
+extern void omap2_gpio_resume_after_retention(void);
 
-       /* Disable interrupts except for the wake events */
-       INTC_MIR_SET0 = 0xffffffff & ~INT0_WAKE_MASK;
-       INTC_MIR_SET1 = 0xffffffff & ~INT1_WAKE_MASK;
-       INTC_MIR_SET2 = 0xffffffff & ~INT2_WAKE_MASK;
+static void omap2_enter_full_retention(void)
+{
+       u32 sleep_time = 0;
 
-       pmdomain_set_autoidle();
+       /* 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 */
-       PM_WKST1_CORE = 0;
-       PM_WKST2_CORE = 0;
-       PM_WKST_WKUP = 0;
+       prcm_write_reg(PM_WKST1_CORE, 0xffffffff);
+       prcm_write_reg(PM_WKST2_CORE, 0xffffffff);
+       prcm_write_reg(PM_WKST_WKUP, 0xffffffff);
 
-       /* Enable wake-up events */
-       PM_WKEN1_CORE = (1 << 22) | (1 << 21);  /* UART1 & 2 */
-       PM_WKEN2_CORE = (1 << 2);               /* UART3 */
-       PM_WKEN_WKUP = (1 << 2) | (1 << 0);     /* GPIO & GPT1 */
+       /* Try to enter retention */
+       prcm_write_reg(PM_PWSTCTRL_MPU, (0x01 << 0) | (1 << 2));
+
+       /* Workaround to kill USB */
+       CONTROL_DEVCONF |= 0x00008000;
+
+       omap2_gpio_prepare_for_retention();
+
+       if (omap2_pm_debug) {
+               omap2_pm_dump(0, 0, 0);
+               sleep_time = omap2_read_32k_sync_counter();
+       }
 
-       /* Disable clocks except for CM_ICLKEN2_CORE. It gets disabled
-        * in the SRAM suspend code */
-       CM_FCLKEN1_CORE = 0;
-       CM_FCLKEN2_CORE = 0;
-       CM_ICLKEN1_CORE = 0;
-       CM_ICLKEN3_CORE = 0;
-       CM_ICLKEN4_CORE = 0;
+       /* One last check for pending IRQs to avoid extra latency due
+        * to sleeping unnecessarily. */
+       if (omap2_irq_pending())
+               goto no_sleep;
+
+       serial_console_sleep(1);
+       /* Jump to SRAM suspend code */
+       omap2_sram_suspend(SDRC_DLLA_CTRL);
+no_sleep:
+       serial_console_sleep(0);
+
+       if (omap2_pm_debug) {
+               unsigned long long tmp;
+               u32 resume_time;
+
+               resume_time = omap2_read_32k_sync_counter();
+               tmp = resume_time - sleep_time;
+               tmp *= 1000000;
+               omap2_pm_dump(0, 1, tmp / 32768);
+       }
+       omap2_gpio_resume_after_retention();
+
+       clk_enable(osc_ck);
+
+}
 
-       omap2_pm_debug("Status before suspend");
+static int omap2_i2c_active(void)
+{
+       u32 l;
+
+       l = prcm_read_reg(CM_FCLKEN1_CORE);
+       return l & ((1 << 19) | (1 << 20));
+}
 
-       /* Must wait for serial buffers to clear */
-       mdelay(200);
+static int sti_console_enabled;
+
+static int omap2_allow_mpu_retention(void)
+{
+       u32 l;
+
+       if (atomic_read(&sleep_block))
+               return 0;
+
+       /* Check for UART2, UART1, McSPI2, McSPI1 and DSS1. */
+       l = prcm_read_reg(CM_FCLKEN1_CORE);
+       if (l & 0x04660001)
+               return 0;
+       /* Check for UART3. */
+       l = prcm_read_reg(CM_FCLKEN2_CORE);
+       if (l & (1 << 2))
+               return 0;
+       if (sti_console_enabled)
+               return 0;
+
+       /* FIXME: Enable soon */
+       return 0;
+}
+
+static void omap2_enter_mpu_retention(void)
+{
+       u32 sleep_time = 0;
+       int only_idle = 0;
+
+       /* Putting MPU into the WFI state while a transfer is active
+        * seems to cause the I2C block to timeout. Why? Good question. */
+       if (omap2_i2c_active())
+               return;
+
+       /* The peripherals seem not to be able to wake up the MPU when
+        * it is in retention mode. */
+       if (omap2_allow_mpu_retention()) {
+               prcm_write_reg(PM_WKST1_CORE, 0xffffffff);
+               prcm_write_reg(PM_WKST2_CORE, 0xffffffff);
+               prcm_write_reg(PM_WKST_WKUP, 0xffffffff);
+
+               /* Try to enter MPU retention */
+               prcm_write_reg(PM_PWSTCTRL_MPU, (0x01 << 0) | (1 << 2));
+       } else {
+               /* Block MPU retention */
+               prcm_write_reg(PM_PWSTCTRL_MPU, 1 << 2);
+               only_idle = 1;
+       }
+
+       if (omap2_pm_debug) {
+               omap2_pm_dump(only_idle ? 2 : 1, 0, 0);
+               sleep_time = omap2_read_32k_sync_counter();
+       }
+
+       omap2_sram_idle();
+
+       if (omap2_pm_debug) {
+               unsigned long long tmp;
+               u32 resume_time;
+
+               resume_time = omap2_read_32k_sync_counter();
+               tmp = resume_time - sleep_time;
+               tmp *= 1000000;
+               omap2_pm_dump(only_idle ? 2 : 1, 1, tmp / 32768);
+       }
+}
 
-       /* Jump to SRAM suspend code
-        * REVISIT: When is this SDRC_DLLB_CTRL?
+static int omap2_can_sleep(void)
+{
+       if (!enable_dyn_sleep)
+               return 0;
+       if (omap2_fclks_active())
+               return 0;
+       if (atomic_read(&sleep_block) > 0)
+               return 0;
+       if (clk_get_usecount(osc_ck) > 1)
+               return 0;
+       if (omap_dma_running())
+               return 0;
+
+       return 1;
+}
+
+static void omap2_pm_idle(void)
+{
+       local_irq_disable();
+       local_fiq_disable();
+
+       if (!omap2_can_sleep()) {
+               /* timer_dyn_reprogram() takes about 100-200 us to complete.
+                * In some contexts (e.g. when waiting for a GPMC-SDRAM DMA
+                * transfer to complete), the increased latency is too much.
+                *
+                * omap2_block_sleep() and omap2_allow_sleep() can be used
+                * to indicate this.
+                */
+               if (atomic_read(&sleep_block) == 0) {
+                       timer_dyn_reprogram();
+                       if (omap2_irq_pending())
+                               goto out;
+               }
+               omap2_enter_mpu_retention();
+               goto out;
+       }
+
+       /*
+        * Since an interrupt may set up a timer, we don't want to
+        * reprogram the hardware timer with interrupts enabled.
+        * Re-enable interrupts only after returning from idle.
         */
-       omap2_sram_suspend(SDRC_DLLA_CTRL, processor_type);
+       timer_dyn_reprogram();
+
+       if (omap2_irq_pending())
+               goto out;
 
-       /* Back from sleep */
-       omap2_pm_restore_registers();
+       omap2_enter_full_retention();
 
+out:
        local_fiq_enable();
        local_irq_enable();
+}
+
+static int omap2_pm_prepare(suspend_state_t state)
+{
+       int error = 0;
+
+       /* We cannot sleep in idle until we have resumed */
+       saved_idle = pm_idle;
+       pm_idle = NULL;
+
+       switch (state) {
+       case PM_SUSPEND_STANDBY:
+       case PM_SUSPEND_MEM:
+               break;
+       case PM_SUSPEND_DISK:
+               return -ENOTSUPP;
+       default:
+               return -EINVAL;
+       }
+
+       return error;
+}
+
+static int omap2_pm_suspend(void)
+{
+       u32 wken_wkup, mir1;
+
+       wken_wkup = prcm_read_reg(PM_WKEN_WKUP);
+       prcm_write_reg(PM_WKEN_WKUP, wken_wkup & ~EN_GPT1);
+
+       /* Mask GPT1 */
+       mir1 = omap_readl(0x480fe0a4);
+       omap_writel(1 << 5, 0x480fe0ac);
+
+       omap2_enter_full_retention();
+
+       omap_writel(mir1, 0x480fe0a4);
+       prcm_write_reg(PM_WKEN_WKUP, wken_wkup);
 
        return 0;
 }
@@ -347,8 +716,7 @@ static int omap2_pm_enter(suspend_state_t state)
 {
        int ret = 0;
 
-       switch (state)
-       {
+       switch (state) {
        case PM_SUSPEND_STANDBY:
        case PM_SUSPEND_MEM:
                ret = omap2_pm_suspend();
@@ -376,16 +744,100 @@ static struct pm_ops omap_pm_ops = {
        .finish         = omap2_pm_finish,
 };
 
+static void __init prcm_setup_regs(void)
+{
+       u32 l;
+
+       /* Enable autoidle */
+       prcm_write_reg(PRCM_SYSCONFIG, 1 << 0);
+
+       /* Set all domain wakeup dependencies */
+       prcm_write_reg(PM_WKDEP_MPU, EN_WKUP);
+       prcm_write_reg(PM_WKDEP_DSP, 0);
+       prcm_write_reg(PM_WKDEP_GFX, 0);
+
+       l = prcm_read_reg(PM_PWSTCTRL_CORE);
+       /* Enable retention for all memory blocks */
+       l |= (1 << 3) | (1 << 4) | (1 << 5);
+       /* Set power state to RETENTION */
+       l &= ~0x03;
+       l |= 0x01 << 0;
+       prcm_write_reg(PM_PWSTCTRL_CORE, l);
+
+       prcm_write_reg(PM_PWSTCTRL_MPU, (0x01 << 0) | (1 << 2));
+
+       /* Power down DSP and GFX */
+       prcm_write_reg(PM_PWSTCTRL_DSP, (1 << 18) | 0x03);
+       prcm_write_reg(PM_PWSTCTRL_GFX, (1 << 18) | 0x03);
+
+       /* Enable clock auto control for all domains */
+       prcm_write_reg(CM_CLKSTCTRL_MPU, AUTOSTAT_MPU);
+       prcm_write_reg(CM_CLKSTCTRL_CORE, AUTOSTAT_DSS | AUTOSTAT_L4 | AUTOSTAT_L3);
+       prcm_write_reg(CM_CLKSTCTRL_GFX, AUTOSTAT_GFX);
+       prcm_write_reg(CM_CLKSTCTRL_DSP, AUTOSTAT_IVA | AUTOSTAT_DSP);
+
+       /* Enable clock autoidle for all domains */
+       prcm_write_reg(CM_AUTOIDLE1_CORE, 0xfffffff9);
+       prcm_write_reg(CM_AUTOIDLE2_CORE, 0x07);
+       prcm_write_reg(CM_AUTOIDLE3_CORE, 0x07);
+       prcm_write_reg(CM_AUTOIDLE4_CORE, 0x1f);
+
+       prcm_write_reg(CM_AUTOIDLE_DSP, 0x02);
+
+       /* Put DPLL and both APLLs into autoidle mode */
+       prcm_write_reg(CM_AUTOIDLE_PLL, (0x03 << 0) | (0x03 << 2) | (0x03 << 6));
+
+       prcm_write_reg(CM_AUTOIDLE_WKUP, 0x3f);
+
+       /* REVISIT: Configure number of 32 kHz clock cycles for sys_clk
+        * stabilisation */
+       prcm_write_reg(PRCM_CLKSSETUP, 15);
+
+       /* Configure automatic voltage transition */
+       prcm_write_reg(PRCM_VOLTSETUP, 2);
+       l = AUTO_EXTVOLT | SETOFF_LEVEL(1) | MEMRETCTRL | \
+               SETRET_LEVEL(1) | VOLT_LEVEL(0);
+       prcm_write_reg(PRCM_VOLTCTRL, l);
+
+       /* Enable wake-up events */
+       prcm_write_reg(PM_WKEN_WKUP, EN_GPIOS | EN_GPT1);
+}
+
 int __init omap2_pm_init(void)
 {
-       printk("Power Management for TI OMAP.\n");
+       u32 l;
+
+       printk(KERN_INFO "Power Management for OMAP2 initializing\n");
+       l = prcm_read_reg(PRCM_REVISION);
+       printk(KERN_INFO "PRCM revision %d.%d\n", (l >> 4) & 0x0f, l & 0x0f);
+
+       osc_ck = clk_get(NULL, "osc_ck");
+       if (IS_ERR(osc_ck)) {
+               printk(KERN_ERR "could not get osc_ck\n");
+               return -ENODEV;
+       }
 
-       vclk = clk_get(NULL, "virt_prcm_set");
-       if (IS_ERR(vclk)) {
-               printk(KERN_ERR "Could not get PM vclk\n");
+       emul_ck = clk_get(NULL, "emul_ck");
+       if (IS_ERR(emul_ck)) {
+               printk(KERN_ERR "could not get emul_ck\n");
+               clk_put(osc_ck);
                return -ENODEV;
        }
 
+       prcm_setup_regs();
+
+       pm_init_serial_console();
+
+       /* Hack to prevent MPU retention when STI console is enabled. */
+       {
+               const struct omap_sti_console_config *sti;
+
+               sti = omap_get_config(OMAP_TAG_STI_CONSOLE,
+                                     struct omap_sti_console_config);
+               if (sti != NULL && sti->enable)
+                       sti_console_enabled = 1;
+       }
+
        /*
         * We copy the assembler sleep/wakeup routines to SRAM.
         * These routines need to be in SRAM as that's the only
@@ -393,16 +845,17 @@ int __init omap2_pm_init(void)
         */
        omap2_sram_idle = omap_sram_push(omap24xx_idle_loop_suspend,
                                         omap24xx_idle_loop_suspend_sz);
-
        omap2_sram_suspend = omap_sram_push(omap24xx_cpu_suspend,
                                            omap24xx_cpu_suspend_sz);
 
        pm_set_ops(&omap_pm_ops);
        pm_idle = omap2_pm_idle;
 
-       pmdomain_init();
+       l = subsys_create_file(&power_subsys, &sleep_while_idle_attr);
+       if (l)
+               printk(KERN_ERR "subsys_create_file failed: %d\n", l);
 
        return 0;
 }
 
-__initcall(omap2_pm_init);
+late_initcall(omap2_pm_init);
index aaa5589e8169845e97e0d63f7d6db2b65dee2e1b..e9c367fc9f613c96723820cc7e0fd10d7fde421f 100644 (file)
@@ -84,7 +84,7 @@ static inline void __init omap_serial_reset(struct plat_serial8250_port *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, 0x01);
+       serial_write_reg(p, UART_OMAP_SYSC, (0x02 << 3) | (1 << 2) | (1 << 0));
 }
 
 void __init omap_serial_init()
index 16247d557853fbb146a4319c1b60442f2a59b744..a67bc1863f90785fe36381f92a110f17ec664e60 100644 (file)
@@ -5,6 +5,10 @@
  * Texas Instruments, <www.ti.com>
  * Richard Woodruff <r-woodruff2@ti.com>
  *
+ * (C) Copyright 2006 Nokia Corporation
+ * Fixed idle loop sleep
+ * Igor Stoppa <igor.stoppa@nokia.com>
+ *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of
 #include <asm/arch/io.h>
 #include <asm/arch/pm.h>
 
-#define A_32KSYNC_CR_V         IO_ADDRESS(OMAP_TIMER32K_BASE+0x10)
-#define A_PRCM_VOLTCTRL_V      IO_ADDRESS(OMAP24XX_PRCM_BASE+0x50)
-#define A_PRCM_CLKCFG_CTRL_V   IO_ADDRESS(OMAP24XX_PRCM_BASE+0x80)
-#define A_CM_CLKEN_PLL_V       IO_ADDRESS(OMAP24XX_PRCM_BASE+0x500)
-#define A_CM_IDLEST_CKGEN_V    IO_ADDRESS(OMAP24XX_PRCM_BASE+0x520)
-#define A_CM_CLKSEL1_PLL_V     IO_ADDRESS(OMAP24XX_PRCM_BASE+0x540)
-#define A_CM_CLKSEL2_PLL_V     IO_ADDRESS(OMAP24XX_PRCM_BASE+0x544)
-
 #define A_SDRC_DLLA_CTRL_V     IO_ADDRESS(OMAP24XX_SDRC_BASE+0x60)
 #define        A_SDRC_POWER_V          IO_ADDRESS(OMAP24XX_SDRC_BASE+0x70)
 #define A_SDRC_RFR_CTRL_V      IO_ADDRESS(OMAP24XX_SDRC_BASE+0xA4)
@@ -53,7 +49,7 @@
  */
 ENTRY(omap24xx_idle_loop_suspend)
        stmfd   sp!, {r0, lr}           @ save registers on stack
-       mov     r0, #0                  @ clear for mcr setup
+       mov     r0, #0x0                @ clear for mrc call
        mcr     p15, 0, r0, c7, c0, 4   @ wait for interrupt
        ldmfd   sp!, {r0, pc}           @ restore regs and return
 
@@ -67,9 +63,6 @@ ENTRY(omap24xx_idle_loop_suspend_sz)
  *
  * Input:
  * R0 :        DLL ctrl value pre-Sleep
- * R1 : Processor+Revision
- *     2420: 0x21 = 242xES1, 0x26 = 242xES2.2
- *     2430: 0x31 = 2430ES1, 0x32 = 2430ES2
  *
  * The if the DPLL is going to AutoIdle. It seems like the DPLL may be back on
  * when we get called, but the DLL probably isn't.  We will wait a bit more in
@@ -129,14 +122,8 @@ A_SDRC_POWER:
        .word A_SDRC_POWER_V
 A_SDRC0:
        .word A_SDRC0_V
-A_CM_CLKSEL2_PLL_S:
-       .word A_CM_CLKSEL2_PLL_V
-A_CM_CLKEN_PLL:
-       .word A_CM_CLKEN_PLL_V
 A_SDRC_DLLA_CTRL_S:
        .word A_SDRC_DLLA_CTRL_V
-A_SDRC_MANUAL_S:
-       .word A_SDRC_MANUAL_V
 
 ENTRY(omap24xx_cpu_suspend_sz)
        .word   . - omap24xx_cpu_suspend
index 973189cd97665c7aee22f2a51439e5745eb4a630..45d1aaa51b576d47a3610d6c04c1d8b90691cee3 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/err.h>
 #include <linux/clk.h>
 #include <linux/delay.h>
+#include <linux/irq.h>
 
 #include <asm/mach/time.h>
 #include <asm/arch/dmtimer.h>
@@ -64,7 +65,7 @@ static void __init omap2_gp_timer_init(void)
        BUG_ON(gptimer == NULL);
 
        omap_dm_timer_set_source(gptimer, OMAP_TIMER_SRC_SYS_CLK);
-       tick_period = clk_get_rate(omap_dm_timer_get_fclk(gptimer)) / 100;
+       tick_period = clk_get_rate(omap_dm_timer_get_fclk(gptimer)) / HZ;
        tick_period -= 1;
 
        setup_irq(omap_dm_timer_get_irq(gptimer), &omap2_gp_timer_irq);
diff --git a/arch/arm/mach-omap2/usb-tusb6010.c b/arch/arm/mach-omap2/usb-tusb6010.c
new file mode 100644 (file)
index 0000000..497f733
--- /dev/null
@@ -0,0 +1,349 @@
+/*
+ * linux/arch/arm/mach-omap/omap2/usb-tusb6010.c
+ *
+ * Copyright (C) 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 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/usb/musb.h>
+
+#include <asm/arch/gpmc.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/mux.h>
+
+
+static u8              async_cs, sync_cs;
+static unsigned                refclk_psec;
+
+
+/* t2_ps, when quantized to fclk units, must happen no earlier than
+ * the clock after after t1_NS.
+ *
+ * Return a possibly updated value of t2_ps, converted to nsec.
+ */
+static unsigned
+next_clk(unsigned t1_NS, unsigned t2_ps, unsigned fclk_ps)
+{
+       unsigned        t1_ps = t1_NS * 1000;
+       unsigned        t1_f, t2_f;
+
+       if ((t1_ps + fclk_ps) < t2_ps)
+               return t2_ps / 1000;
+
+       t1_f = (t1_ps + fclk_ps - 1) / fclk_ps;
+       t2_f = (t2_ps + fclk_ps - 1) / fclk_ps;
+
+       if (t1_f >= t2_f)
+               t2_f = t1_f + 1;
+
+       return (t2_f * fclk_ps) / 1000;
+}
+
+/* NOTE:  timings are from tusb 6010 datasheet Rev 1.8, 12-Sept 2006 */
+
+static int tusb_set_async_mode(unsigned sysclk_ps, unsigned fclk_ps)
+{
+       struct gpmc_timings     t;
+       unsigned                t_acsnh_advnh = sysclk_ps + 3000;
+       unsigned                tmp;
+
+       memset(&t, 0, sizeof(t));
+
+       /* CS_ON = t_acsnh_acsnl */
+       t.cs_on = 8;
+       /* ADV_ON = t_acsnh_advnh - t_advn */
+       t.adv_on = next_clk(t.cs_on, t_acsnh_advnh - 7000, fclk_ps);
+
+       /*
+        * READ ... from omap2420 TRM fig 12-13
+        */
+
+       /* ADV_RD_OFF = t_acsnh_advnh */
+       t.adv_rd_off = next_clk(t.adv_on, t_acsnh_advnh, fclk_ps);
+
+       /* OE_ON = t_acsnh_advnh + t_advn_oen (then wait for nRDY) */
+       t.oe_on = next_clk(t.adv_on, t_acsnh_advnh + 1000, fclk_ps);
+
+       /* ACCESS = counters continue only after nRDY */
+       tmp = t.oe_on * 1000 + 300;
+       t.access = next_clk(t.oe_on, tmp, fclk_ps);
+
+       /* OE_OFF = after data gets sampled */
+       tmp = t.access * 1000;
+       t.oe_off = next_clk(t.access, tmp, fclk_ps);
+
+       t.cs_rd_off = t.oe_off;
+
+       tmp = t.cs_rd_off * 1000 + 7000 /* t_acsn_rdy_z */;
+       t.rd_cycle = next_clk(t.cs_rd_off, tmp, fclk_ps);
+
+       /*
+        * WRITE ... from omap2420 TRM fig 12-15
+        */
+
+       /* ADV_WR_OFF = t_acsnh_advnh */
+       t.adv_wr_off = t.adv_rd_off;
+
+       /* WE_ON = t_acsnh_advnh + t_advn_wen (then wait for nRDY) */
+       t.we_on = next_clk(t.adv_wr_off, t_acsnh_advnh + 1000, fclk_ps);
+
+       /* WE_OFF = after data gets sampled */
+       tmp = t.we_on * 1000 + 300;
+       t.we_off = next_clk(t.we_on, tmp, fclk_ps);
+
+       t.cs_wr_off = t.we_off;
+
+       tmp = t.cs_wr_off * 1000 + 7000 /* t_acsn_rdy_z */;
+       t.wr_cycle = next_clk(t.cs_wr_off, tmp, fclk_ps);
+
+       return gpmc_cs_set_timings(async_cs, &t);
+}
+
+static int tusb_set_sync_mode(unsigned sysclk_ps, unsigned fclk_ps)
+{
+       struct gpmc_timings     t;
+       unsigned                t_scsnh_advnh = sysclk_ps + 3000;
+       unsigned                tmp;
+
+       memset(&t, 0, sizeof(t));
+       t.cs_on = 8;
+
+       /* ADV_ON = t_acsnh_advnh - t_advn */
+       t.adv_on = next_clk(t.cs_on, t_scsnh_advnh - 7000, fclk_ps);
+
+       /* GPMC_CLK rate = fclk rate / div */
+       t.sync_clk = 12 /* 11.1 nsec */;
+       tmp = (t.sync_clk * 1000 + fclk_ps - 1) / fclk_ps;
+       if (tmp > 4)
+               return -ERANGE;
+       if (tmp <= 0)
+               tmp = 1;
+       t.page_burst_access = (fclk_ps * tmp) / 1000;
+
+       /*
+        * READ ... based on omap2420 TRM fig 12-19, 12-20
+        */
+
+       /* ADV_RD_OFF = t_scsnh_advnh */
+       t.adv_rd_off = next_clk(t.adv_on, t_scsnh_advnh, fclk_ps);
+
+       /* OE_ON = t_scsnh_advnh + t_advn_oen * fclk_ps (then wait for nRDY) */
+       tmp = (t.adv_rd_off * 1000) + (3 * fclk_ps);
+       t.oe_on = next_clk(t.adv_on, tmp, fclk_ps);
+
+       /* ACCESS = number of clock cycles after t_adv_eon */
+       tmp = (t.oe_on * 1000) + (5 * fclk_ps);
+       t.access = next_clk(t.oe_on, tmp, fclk_ps);
+
+       /* OE_OFF = after data gets sampled */
+       tmp = (t.access * 1000) + (1 * fclk_ps);
+       t.oe_off = next_clk(t.access, tmp, fclk_ps);
+
+       t.cs_rd_off = t.oe_off;
+
+       tmp = t.cs_rd_off * 1000 + 7000 /* t_scsn_rdy_z */;
+       t.rd_cycle = next_clk(t.cs_rd_off, tmp, fclk_ps);
+
+       /*
+        * WRITE ... based on omap2420 TRM fig 12-21
+        */
+
+       /* ADV_WR_OFF = t_scsnh_advnh */
+       t.adv_wr_off = t.adv_rd_off;
+
+       /* WE_ON = t_scsnh_advnh + t_advn_wen * fclk_ps (then wait for nRDY) */
+       tmp = (t.adv_wr_off * 1000) + (3 * fclk_ps);
+       t.we_on = next_clk(t.adv_wr_off, tmp, fclk_ps);
+
+       /* WE_OFF = number of clock cycles after t_adv_wen */
+       tmp = (t.we_on * 1000) + (6 * fclk_ps);
+       t.we_off = next_clk(t.we_on, tmp, fclk_ps);
+
+       t.cs_wr_off = t.we_off;
+
+       tmp = t.cs_wr_off * 1000 + 7000 /* t_scsn_rdy_z */;
+       t.wr_cycle = next_clk(t.cs_wr_off, tmp, fclk_ps);
+
+       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)
+{
+       static const char       error[] =
+               KERN_ERR "tusb6010 %s retime error %d\n";
+
+       unsigned        fclk_ps = gpmc_get_fclk_period();
+       unsigned        sysclk_ps;
+       int             status;
+
+       if (!refclk_psec)
+               return -ENODEV;
+
+       sysclk_ps = is_refclk ? refclk_psec : TUSB6010_OSCCLK_60;
+
+       status = tusb_set_async_mode(sysclk_ps, fclk_ps);
+       if (status < 0) {
+               printk(error, "async", status);
+               goto done;
+       }
+       status = tusb_set_sync_mode(sysclk_ps, fclk_ps);
+       if (status < 0)
+               printk(error, "sync", status);
+done:
+       return status;
+}
+EXPORT_SYMBOL_GPL(tusb6010_platform_retime);
+
+static struct resource tusb_resources[] = {
+       /* Order is significant!  The start/end fields
+        * are updated during setup..
+        */
+       { /* Asynchronous access */
+               .flags  = IORESOURCE_MEM,
+       },
+       { /* Synchronous access */
+               .flags  = IORESOURCE_MEM,
+       },
+       { /* IRQ */
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static u64 tusb_dmamask = ~(u32)0;
+
+static struct platform_device tusb_device = {
+       .name           = "musb_hdrc",
+       .id             = -1,
+       .dev = {
+               .dma_mask               = &tusb_dmamask,
+               .coherent_dma_mask      = 0xffffffff,
+       },
+       .num_resources  = ARRAY_SIZE(tusb_resources),
+       .resource       = tusb_resources,
+};
+
+
+/* this may be called only from board-*.c setup code */
+int __init
+tusb6010_setup_interface(struct musb_hdrc_platform_data *data,
+               unsigned ps_refclk, unsigned waitpin,
+               unsigned async, unsigned sync,
+               unsigned irq, unsigned dmachan)
+{
+       int             status;
+       static char     error[] __initdata =
+               KERN_ERR "tusb6010 init error %d, %d\n";
+
+       /* ASYNC region, primarily for PIO */
+       status = gpmc_cs_request(async, SZ_16M, (unsigned long *)
+                               &tusb_resources[0].start);
+       if (status < 0) {
+               printk(error, 1, status);
+               return status;
+       }
+       tusb_resources[0].end = tusb_resources[0].start + 0x9ff;
+       async_cs = async;
+       gpmc_cs_write_reg(async, GPMC_CS_CONFIG1,
+                         GPMC_CONFIG1_PAGE_LEN(2)
+                       | GPMC_CONFIG1_WAIT_READ_MON
+                       | GPMC_CONFIG1_WAIT_WRITE_MON
+                       | GPMC_CONFIG1_WAIT_PIN_SEL(waitpin)
+                       | GPMC_CONFIG1_READTYPE_ASYNC
+                       | GPMC_CONFIG1_WRITETYPE_ASYNC
+                       | GPMC_CONFIG1_DEVICESIZE_16
+                       | GPMC_CONFIG1_DEVICETYPE_NOR
+                       | GPMC_CONFIG1_MUXADDDATA);
+
+
+       /* SYNC region, primarily for DMA */
+       status = gpmc_cs_request(sync, SZ_16M, (unsigned long *)
+                               &tusb_resources[1].start);
+       if (status < 0) {
+               printk(error, 2, status);
+               return status;
+       }
+       tusb_resources[1].end = tusb_resources[1].start + 0x9ff;
+       sync_cs = sync;
+       gpmc_cs_write_reg(sync, GPMC_CS_CONFIG1,
+                         GPMC_CONFIG1_READMULTIPLE_SUPP
+                       | GPMC_CONFIG1_READTYPE_SYNC
+                       | GPMC_CONFIG1_WRITEMULTIPLE_SUPP
+                       | GPMC_CONFIG1_WRITETYPE_SYNC
+                       | GPMC_CONFIG1_CLKACTIVATIONTIME(1)
+                       | GPMC_CONFIG1_PAGE_LEN(2)
+                       | GPMC_CONFIG1_WAIT_READ_MON
+                       | GPMC_CONFIG1_WAIT_WRITE_MON
+                       | GPMC_CONFIG1_WAIT_PIN_SEL(waitpin)
+                       | GPMC_CONFIG1_DEVICESIZE_16
+                       | GPMC_CONFIG1_DEVICETYPE_NOR
+                       | GPMC_CONFIG1_MUXADDDATA
+                       /* fclk divider gets set later */
+                       );
+
+       /* IRQ */
+       status = omap_request_gpio(irq);
+       if (status < 0) {
+               printk(error, 3, status);
+               return status;
+       }
+       omap_set_gpio_direction(irq, 1);
+       tusb_resources[2].start = irq + IH_GPIO_BASE;
+
+       /* set up memory timings ... can speed them up later */
+       if (!ps_refclk) {
+               printk(error, 4, status);
+               return -ENODEV;
+       }
+       refclk_psec = ps_refclk;
+       status = tusb6010_platform_retime(1);
+       if (status < 0) {
+               printk(error, 5, status);
+               return status;
+       }
+
+       /* finish device setup ... */
+       if (!data) {
+               printk(error, 6, status);
+               return -ENODEV;
+       }
+       data->multipoint = 1;
+       tusb_device.dev.platform_data = data;
+
+       /* REVISIT let the driver know what DMA channels work */
+       if (!dmachan)
+               tusb_device.dev.dma_mask = NULL;
+       else {
+               /* assume OMAP 2420 ES2.0 and later */
+               if (dmachan & (1 << 0))
+                       omap_cfg_reg(AA10_242X_DMAREQ0);
+               if (dmachan & (1 << 1))
+                       omap_cfg_reg(AA6_242X_DMAREQ1);
+               if (dmachan & (1 << 2))
+                       omap_cfg_reg(E4_242X_DMAREQ2);
+               if (dmachan & (1 << 3))
+                       omap_cfg_reg(G4_242X_DMAREQ3);
+               if (dmachan & (1 << 4))
+                       omap_cfg_reg(D3_242X_DMAREQ4);
+               if (dmachan & (1 << 5))
+                       omap_cfg_reg(E3_242X_DMAREQ5);
+       }
+
+       /* so far so good ... register the device */
+       status = platform_device_register(&tusb_device);
+       if (status < 0) {
+               printk(error, 7, status);
+               return status;
+       }
+       return 0;
+}
index 6a94e54848fd7a965294c1be8fc72e350878aaee..b20411139401ff110b136a3a2cb5199dbe91978e 100644 (file)
@@ -8,4 +8,5 @@ DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
 
 oprofile-y                             := $(DRIVER_OBJS) common.o backtrace.o
 oprofile-$(CONFIG_CPU_XSCALE)          += op_model_xscale.o
+oprofile-$(CONFIG_CPU_V6)              += op_model_v6.o
 
index 6f833358cd0612c4c13e5d59619e86ccee2749e5..f4661725b48d787169fcefcdde552f576e28c56a 100644 (file)
@@ -135,6 +135,10 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
        spec = &op_xscale_spec;
 #endif
 
+#ifdef CONFIG_CPU_V6
+       spec = &op_arm11_spec;
+#endif
+
        if (spec) {
                ret = spec->init();
                if (ret < 0)
index 38c6ad158547e2e615620888c59848be57784f46..b45efa5299453f904fabf91885d8829a90b4178e 100644 (file)
@@ -24,6 +24,10 @@ struct op_arm_model_spec {
 extern struct op_arm_model_spec op_xscale_spec;
 #endif
 
+#ifdef CONFIG_CPU_V6
+extern struct op_arm_model_spec op_arm11_spec;
+#endif
+
 extern void arm_backtrace(struct pt_regs * const regs, unsigned int depth);
 
 extern int __init op_arm_init(struct oprofile_operations *ops, struct op_arm_model_spec *spec);
diff --git a/arch/arm/oprofile/op_model_v6.c b/arch/arm/oprofile/op_model_v6.c
new file mode 100644 (file)
index 0000000..63f3818
--- /dev/null
@@ -0,0 +1,280 @@
+/**
+ * @file op_model_v6.c
+ * ARM11 Performance Monitor Driver
+ *
+ * Based on op_model_xscale.c
+ *
+ * @remark Copyright 2000-2004 Deepak Saxena <dsaxena@mvista.com>
+ * @remark Copyright 2000-2004 MontaVista Software Inc
+ * @remark Copyright 2004 Dave Jiang <dave.jiang@intel.com>
+ * @remark Copyright 2004 Intel Corporation
+ * @remark Copyright 2004 Zwane Mwaikambo <zwane@arm.linux.org.uk>
+ * @remark Copyright 2004 OProfile Authors
+ *
+ * @remark Read the file COPYING
+ *
+ * @author Tony Lindgren <tony@atomide.com>
+ */
+
+/* #define DEBUG */
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/oprofile.h>
+#include <linux/interrupt.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+
+#include "op_counter.h"
+#include "op_arm_model.h"
+
+#define        PMU_ENABLE      0x001   /* Enable counters */
+#define PMN_RESET      0x002   /* Reset event counters */
+#define        CCNT_RESET      0x004   /* Reset clock counter */
+#define        PMU_RESET       (CCNT_RESET | PMN_RESET)
+#define PMU_CNT64      0x008   /* Make CCNT count every 64th cycle */
+
+/*
+ * Different types of events that can be counted by the XScale PMU
+ * as used by Oprofile userspace. Here primarily for documentation
+ * purposes.
+ */
+
+#define EVT_ICACHE_MISS                        0x00
+#define        EVT_ICACHE_NO_DELIVER           0x01
+#define        EVT_DATA_STALL                  0x02
+#define        EVT_ITLB_MISS                   0x03
+#define        EVT_DTLB_MISS                   0x04
+#define        EVT_BRANCH                      0x05
+#define        EVT_BRANCH_MISS                 0x06
+#define        EVT_INSTRUCTION                 0x07
+#define        EVT_DCACHE_FULL_STALL           0x08
+#define        EVT_DCACHE_FULL_STALL_CONTIG    0x09
+#define        EVT_DCACHE_ACCESS               0x0A
+#define        EVT_DCACHE_MISS                 0x0B
+#define        EVT_DCACE_WRITE_BACK            0x0C
+#define        EVT_PC_CHANGED                  0x0D
+#define        EVT_BCU_REQUEST                 0x10
+#define        EVT_BCU_FULL                    0x11
+#define        EVT_BCU_DRAIN                   0x12
+#define        EVT_BCU_ECC_NO_ELOG             0x14
+#define        EVT_BCU_1_BIT_ERR               0x15
+#define        EVT_RMW                         0x16
+/* EVT_CCNT is not hardware defined */
+#define EVT_CCNT                       0xFE
+#define EVT_UNUSED                     0xFF
+
+struct pmu_counter {
+       volatile unsigned long ovf;
+       unsigned long reset_counter;
+};
+
+enum { CCNT, PMN0, PMN1, PMN2, PMN3, MAX_COUNTERS };
+
+static struct pmu_counter results[MAX_COUNTERS];
+
+enum { PMU_ARM11 };
+
+struct pmu_type {
+       int id;
+       char *name;
+       int num_counters;
+       int interrupt;
+       unsigned int int_enable;
+       unsigned int cnt_ovf[MAX_COUNTERS];
+       unsigned int int_mask[MAX_COUNTERS];
+};
+
+static struct pmu_type pmu_parms[] = {
+       {
+               .id             = PMU_ARM11,
+               .name           = "arm/arm11",
+               .num_counters   = 3,
+#ifdef CONFIG_ARCH_OMAP2
+               .interrupt      = 3,
+#else
+               .interrupt      = -1,
+#endif
+               .int_mask       = { [PMN0] = 0x10, [PMN1] = 0x20,
+                                       [CCNT] = 0x40 },
+               .cnt_ovf        = { [CCNT] = 0x400, [PMN0] = 0x100,
+                                       [PMN1] = 0x200},
+       },
+};
+
+static struct pmu_type *pmu;
+
+static void write_pmnc(u32 val)
+{
+       __asm__ __volatile__ ("mcr p15, 0, %0, c15, c12, 0" : : "r" (val));
+}
+
+static u32 read_pmnc(void)
+{
+       u32 val;
+
+       __asm__ __volatile__ ("mrc p15, 0, %0, c15, c12, 0" : "=r" (val));
+
+       return val;
+}
+
+static u32 read_counter(int counter)
+{
+       u32 val = 0;
+
+       switch (counter) {
+       case CCNT:
+               __asm__ __volatile__ ("mrc p15, 0, %0, c15, c12, 1" : "=r" (val));
+               break;
+       case PMN0:
+               __asm__ __volatile__ ("mrc p15, 0, %0, c15, c12, 2" : "=r" (val));
+               break;
+       case PMN1:
+               __asm__ __volatile__ ("mrc p15, 0, %0, c15, c12, 3" : "=r" (val));
+               break;
+       }
+
+       return val;
+}
+
+static void write_counter(int counter, u32 val)
+{
+       switch (counter) {
+       case CCNT:
+               __asm__ __volatile__ ("mcr p15, 0, %0, c15, c12, 1" : : "r" (val));
+               break;
+       case PMN0:
+               __asm__ __volatile__ ("mcr p15, 0, %0, c15, c12, 2" : : "r" (val));
+               break;
+       case PMN1:
+               __asm__ __volatile__ ("mcr p15, 0, %0, c15, c12, 3" : : "r" (val));
+               break;
+       }
+}
+
+static int arm11_setup_ctrs(void)
+{
+       u32 pmnc;
+       int i;
+
+       for (i = CCNT; i < MAX_COUNTERS; i++) {
+               if (counter_config[i].enabled)
+                       continue;
+
+               counter_config[i].event = EVT_UNUSED;
+       }
+
+       pmnc = (counter_config[PMN1].event << 20)
+                       | (counter_config[PMN0].event << 12);
+       pr_debug("arm11_setup_ctrs: pmnc: %#08x\n", pmnc);
+       write_pmnc(pmnc);
+
+       for (i = CCNT; i < MAX_COUNTERS; i++) {
+               if (counter_config[i].event == EVT_UNUSED) {
+                       counter_config[i].event = 0;
+                       pmu->int_enable &= ~pmu->int_mask[i];
+                       continue;
+               }
+
+               results[i].reset_counter = counter_config[i].count;
+               write_counter(i, -(u32)counter_config[i].count);
+               pmu->int_enable |= pmu->int_mask[i];
+               pr_debug("arm11_setup_ctrs: counter%d %#08x from %#08lx\n", i,
+                       read_counter(i), counter_config[i].count);
+       }
+
+       return 0;
+}
+
+static void inline __arm11_check_ctrs(void)
+{
+       int i;
+       u32 pmnc = read_pmnc();
+
+       /* Write the value back to clear the overflow flags. Overflow */
+       /* flags remain in pmnc for use below */
+       write_pmnc(pmnc & ~PMU_ENABLE);
+
+       for (i = CCNT; i <= PMN1; i++) {
+               if (!(pmu->int_mask[i] & pmu->int_enable))
+                       continue;
+
+               if (pmnc & pmu->cnt_ovf[i])
+                       results[i].ovf++;
+       }
+}
+
+static irqreturn_t arm11_pmu_interrupt(int irq, void *arg, struct pt_regs *regs)
+{
+       int i;
+       u32 pmnc;
+
+       __arm11_check_ctrs();
+
+       for (i = CCNT; i < MAX_COUNTERS; i++) {
+               if (!results[i].ovf)
+                       continue;
+
+               write_counter(i, -(u32)results[i].reset_counter);
+               oprofile_add_sample(regs, i);
+               results[i].ovf--;
+       }
+
+       pmnc = read_pmnc() | PMU_ENABLE;
+       write_pmnc(pmnc);
+
+       return IRQ_HANDLED;
+}
+
+static void arm11_pmu_stop(void)
+{
+       u32 pmnc = read_pmnc();
+
+       pmnc &= ~PMU_ENABLE;
+       write_pmnc(pmnc);
+
+       if (pmu->interrupt >= 0)
+               free_irq(pmu->interrupt, results);
+}
+
+static int arm11_pmu_start(void)
+{
+       int ret;
+       u32 pmnc = read_pmnc();
+
+       if (pmu->interrupt >= 0) {
+               ret = request_irq(pmu->interrupt, arm11_pmu_interrupt,
+                       IRQF_DISABLED, "ARM11 PMU", (void *)results);
+               if (ret < 0) {
+                       printk(KERN_ERR "oprofile: unable to request IRQ%d "
+                               "for ARM11 PMU\n", pmu->interrupt);
+                       return ret;
+               }
+
+               pmnc |= pmu->int_enable;
+       }
+
+       pmnc |= PMU_ENABLE;
+       write_pmnc(pmnc);
+       pr_debug("arm11_pmu_start: pmnc: %#08x mask: %08x\n",
+                       pmnc, pmu->int_enable);
+       return 0;
+}
+
+static int arm11_detect_pmu(void)
+{
+       pmu = &pmu_parms[PMU_ARM11];
+
+       op_arm11_spec.name = pmu->name;
+       op_arm11_spec.num_counters = pmu->num_counters;
+       pr_debug("arm11_detect_pmu: detected %s PMU\n", pmu->name);
+
+       return 0;
+}
+
+struct op_arm_model_spec op_arm11_spec = {
+       .init           = arm11_detect_pmu,
+       .setup_ctrs     = arm11_setup_ctrs,
+       .start          = arm11_pmu_start,
+       .stop           = arm11_pmu_stop,
+};
index f2dc363de66b782db4c109bd229d815ab20e5ee9..3114d8271b55a305a1464d81a267e79c90923c0c 100644 (file)
@@ -19,6 +19,16 @@ endchoice
 
 comment "OMAP Feature Selections"
 
+config OMAP_DEBUG_DEVICES
+       bool
+       help
+         For debug cards on TI reference boards.
+
+config OMAP_DEBUG_LEDS
+       bool
+       depends on OMAP_DEBUG_DEVICES
+       default y if LEDS || LEDS_OMAP_DEBUG
+
 config OMAP_RESET_CLOCKS
        bool "Reset unused clocks during boot"
        depends on ARCH_OMAP
@@ -31,6 +41,39 @@ config OMAP_RESET_CLOCKS
          probably do not want this option enabled until your
          device drivers work properly.
 
+config OMAP_BOOT_TAG
+       bool "OMAP bootloader information passing"
+        depends on ARCH_OMAP
+        default n
+        help
+          Say Y, if you have a bootloader which passes information
+          about your board and its peripheral configuration.
+
+config OMAP_BOOT_REASON
+       bool "Support for boot reason"
+        depends on OMAP_BOOT_TAG
+        default n
+        help
+          Say Y, if you want to have a procfs entry for reading the boot
+          reason in user-space.
+
+config OMAP_COMPONENT_VERSION
+       bool "Support for component version display"
+       depends on OMAP_BOOT_TAG && PROC_FS
+       default n
+       help
+         Say Y, if you want to have a procfs entry for reading component
+         versions (supplied by the bootloader) in user-space.
+
+config OMAP_GPIO_SWITCH
+       bool "GPIO switch support"
+        default n
+        help
+          Say Y, if you want to have support for reporting of GPIO
+          switches (e.g. cover switches) via sysfs. Your bootloader has
+          to provide information about the switches to the kernel via the
+          ATAG_BOARD mechanism if they're not defined by the board config.
+
 config OMAP_MUX
        bool "OMAP multiplexing support"
         depends on ARCH_OMAP
@@ -57,6 +100,25 @@ config OMAP_MUX_WARNINGS
          to change the pin multiplexing setup.  When there are no warnings
          printed, it's safe to deselect OMAP_MUX for your product.
 
+config OMAP_STI
+       bool "STI/XTI support"
+       depends on ARCH_OMAP16XX || ARCH_OMAP24XX
+       default n
+
+config OMAP_STI_CONSOLE
+       bool "STI console support"
+       depends on OMAP_STI
+       help
+         This enables a console driver by way of STI/XTI.
+
+config OMAP_MCBSP
+       bool "McBSP support"
+       depends on ARCH_OMAP
+       default y
+       help
+         Say Y here if you want support for the OMAP Multichannel
+         Buffered Serial Port.
+
 choice
         prompt "System timer"
        default OMAP_MPU_TIMER
@@ -120,6 +182,8 @@ config OMAP_SERIAL_WAKE
          to data on the serial RX line. This allows you to wake the
          system from serial console.
 
+source "arch/arm/plat-omap/dsp/Kconfig"
+
 endmenu
 
 endif
index 2896b4546411c3237bc7374435958276916f4a36..112708729ef4c5fc8cf0967c42ccf383b5c6be1c 100644 (file)
@@ -3,7 +3,8 @@
 #
 
 # Common support
-obj-y := common.o sram.o sram-fn.o clock.o devices.o dma.o mux.o gpio.o mcbsp.o usb.o fb.o
+obj-y := common.o sram.o sram-fn.o clock.o devices.o dma.o mux.o gpio.o \
+        usb.o fb.o
 obj-m :=
 obj-n :=
 obj-  :=
@@ -13,7 +14,19 @@ obj-$(CONFIG_OMAP_32K_TIMER) += timer32k.o
 # OCPI interconnect support for 1710, 1610 and 5912
 obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o
 
+# STI support
+obj-$(CONFIG_OMAP_STI) += sti/
+
+obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o
 
 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
 
+# DSP subsystem
+obj-y += dsp/
+obj-$(CONFIG_OMAP_DSP) += mailbox.o
diff --git a/arch/arm/plat-omap/bootreason.c b/arch/arm/plat-omap/bootreason.c
new file mode 100644 (file)
index 0000000..253dfcf
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * linux/arch/arm/plat-omap/bootreason.c
+ *
+ * OMAP Bootreason passing
+ *
+ * Copyright (c) 2004 Nokia
+ *
+ * Written by David Weinehall <david.weinehall@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/proc_fs.h>
+#include <linux/errno.h>
+#include <asm/arch/board.h>
+
+static char boot_reason[16];
+
+static int omap_bootreason_read_proc(char *page, char **start, off_t off,
+                                        int count, int *eof, void *data)
+{
+       int len = 0;
+
+       len += sprintf(page + len, "%s\n", boot_reason);
+
+       *start = page + off;
+
+       if (len > off)
+               len -= off;
+       else
+               len = 0;
+
+       return len < count ? len  : count;
+}
+
+static int __init bootreason_init(void)
+{
+       const struct omap_boot_reason_config *cfg;
+       int reason_valid = 0;
+
+       cfg = omap_get_config(OMAP_TAG_BOOT_REASON, struct omap_boot_reason_config);
+       if (cfg != NULL) {
+               strncpy(boot_reason, cfg->reason_str, sizeof(cfg->reason_str));
+               boot_reason[sizeof(cfg->reason_str)] = 0;
+               reason_valid = 1;
+       } else {
+               /* Read the boot reason from the OMAP registers */
+       }
+
+       if (!reason_valid)
+               return -ENOENT;
+
+       printk(KERN_INFO "Bootup reason: %s\n", boot_reason);
+
+       if (!create_proc_read_entry("bootreason", S_IRUGO, NULL,
+                                       omap_bootreason_read_proc, NULL))
+               return -ENOMEM;
+
+       return 0;
+}
+
+late_initcall(bootreason_init);
index f1179ad4be1bb0f63e3d95059c8e3188b5bcc1e4..a463fa2f7d375667b463b2adf8fbbc14c95d8b67 100644 (file)
@@ -33,6 +33,41 @@ static DEFINE_SPINLOCK(clockfw_lock);
 
 static struct clk_functions *arch_clock;
 
+#ifdef CONFIG_PM_DEBUG
+
+static void print_parents(struct clk *clk)
+{
+       struct clk *p;
+       int printed = 0;
+
+       list_for_each_entry(p, &clocks, node) {
+               if (p->parent == clk && p->usecount) {
+                       if (!clk->usecount && !printed) {
+                               printk("MISMATCH: %s\n", clk->name);
+                               printed = 1;
+                       }
+                       printk("\t%-15s\n", p->name);
+               }
+       }
+}
+
+void clk_print_usecounts(void)
+{
+       unsigned long flags;
+       struct clk *p;
+
+       spin_lock_irqsave(&clockfw_lock, flags);
+       list_for_each_entry(p, &clocks, node) {
+               if (p->usecount)
+                       printk("%-15s: %d\n", p->name, p->usecount);
+               print_parents(p);
+
+       }
+       spin_unlock_irqrestore(&clockfw_lock, flags);
+}
+
+#endif
+
 /*-------------------------------------------------------------------------
  * Standard clock functions defined in include/linux/clk.h
  *-------------------------------------------------------------------------*/
@@ -359,3 +394,65 @@ int __init clk_init(struct clk_functions * custom_clocks)
 
        return 0;
 }
+
+#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_PROC_FS)
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
+static void *omap_ck_start(struct seq_file *m, loff_t *pos)
+{
+       return *pos < 1 ? (void *)1 : NULL;
+}
+
+static void *omap_ck_next(struct seq_file *m, void *v, loff_t *pos)
+{
+       ++*pos;
+       return NULL;
+}
+
+static void omap_ck_stop(struct seq_file *m, void *v)
+{
+}
+
+int omap_ck_show(struct seq_file *m, void *v)
+{
+       struct clk *cp;
+
+       list_for_each_entry(cp, &clocks, node)
+               seq_printf(m,"%s %ld %d\n", cp->name, cp->rate, cp->usecount);
+
+       return 0;
+}
+
+static struct seq_operations omap_ck_op = {
+       .start =        omap_ck_start,
+       .next =         omap_ck_next,
+       .stop =         omap_ck_stop,
+       .show =         omap_ck_show
+};
+
+static int omap_ck_open(struct inode *inode, struct file *file)
+{
+       return seq_open(file, &omap_ck_op);
+}
+
+static struct file_operations proc_omap_ck_operations = {
+       .open           = omap_ck_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = seq_release,
+};
+
+int __init omap_ck_init(void)
+{
+    struct proc_dir_entry *entry;
+
+       entry = create_proc_entry("omap_clocks", 0, NULL);
+       if (entry)
+               entry->proc_fops = &proc_omap_ck_operations;
+       return 0;
+
+}
+__initcall(omap_ck_init);
+#endif
+
index 57b7b93674a486218bb4e35ca9840bd1b90d7c6f..2a72b9a4401937902ef14121c4fc1d92a666138f 100644 (file)
@@ -40,6 +40,26 @@ int omap_bootloader_tag_len;
 struct omap_board_config_kernel *omap_board_config;
 int omap_board_config_size;
 
+#ifdef CONFIG_OMAP_BOOT_TAG
+
+static int __init parse_tag_omap(const struct tag *tag)
+{
+       u32 size = tag->hdr.size - (sizeof(tag->hdr) >> 2);
+
+        size <<= 2;
+       if (size > sizeof(omap_bootloader_tag))
+               return -1;
+
+       memcpy(omap_bootloader_tag, tag->u.omap.data, size);
+       omap_bootloader_tag_len = size;
+
+        return 0;
+}
+
+__tagtable(ATAG_BOARD, parse_tag_omap);
+
+#endif
+
 static const void *get_config(u16 tag, size_t len, int skip, size_t *len_out)
 {
        struct omap_board_config_kernel *kinfo = NULL;
@@ -93,8 +113,12 @@ static const void *get_config(u16 tag, size_t len, int skip, size_t *len_out)
         * in the kernel. */
        for (i = 0; i < omap_board_config_size; i++) {
                if (omap_board_config[i].tag == tag) {
-                       kinfo = &omap_board_config[i];
-                       break;
+                       if (skip == 0) {
+                               kinfo = &omap_board_config[i];
+                               break;
+                       } else {
+                               skip--;
+                       }
                }
        }
        if (kinfo == NULL)
@@ -156,3 +180,55 @@ static int __init omap_add_serial_console(void)
        return add_preferred_console("ttyS", line, opt);
 }
 console_initcall(omap_add_serial_console);
+
+
+/*
+ * 32KHz clocksource ... always available, on pretty most chips except
+ * OMAP 730 and 1510.  Other timers could be used as clocksources, with
+ * higher resolution in free-running counter modes (e.g. 12 MHz xtal),
+ * but systems won't necessarily want to spend resources that way.
+ */
+
+#if defined(CONFIG_ARCH_OMAP16XX)
+#define TIMER_32K_SYNCHRONIZED         0xfffbc410
+#elif defined(CONFIG_ARCH_OMAP2420)
+#define TIMER_32K_SYNCHRONIZED         0x48004010
+#elif defined(CONFIG_ARCH_OMAP2430)
+#define TIMER_32K_SYNCHRONIZED         0x49020010
+#endif
+
+#ifdef TIMER_32K_SYNCHRONIZED
+
+#include <linux/clocksource.h>
+
+static cycle_t omap_32k_read(void)
+{
+       return omap_readl(TIMER_32K_SYNCHRONIZED);
+}
+
+static struct clocksource clocksource_32k = {
+       .name           = "32k_counter",
+       .rating         = 250,
+       .read           = omap_32k_read,
+       .mask           = CLOCKSOURCE_MASK(32),
+       .shift          = 10,
+       .is_continuous  = 1,
+};
+
+static int __init omap_init_clocksource_32k(void)
+{
+       static char err[] __initdata = KERN_ERR
+                       "%s: can't register clocksource!\n";
+
+       if (cpu_is_omap16xx() || cpu_is_omap24xx()) {
+               clocksource_32k.mult = clocksource_hz2mult(32768,
+                                           clocksource_32k.shift);
+
+               if (clocksource_register(&clocksource_32k))
+                       printk(err, clocksource_32k.name);
+       }
+       return 0;
+}
+arch_initcall(omap_init_clocksource_32k);
+
+#endif /* TIMER_32K_SYNCHRONIZED */
diff --git a/arch/arm/plat-omap/component-version.c b/arch/arm/plat-omap/component-version.c
new file mode 100644 (file)
index 0000000..a9fe63d
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ *  linux/arch/arm/plat-omap/component-version.c
+ *
+ *  Copyright (C) 2005 Nokia Corporation
+ *  Written by Juha Yrjölä <juha.yrjola@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/proc_fs.h>
+#include <asm/arch/board.h>
+#include <asm/arch/board-nokia.h>
+
+static int component_version_read_proc(char *page, char **start, off_t off,
+                                      int count, int *eof, void *data)
+{
+       int len, i;
+       const struct omap_version_config *ver;
+       char *p;
+
+       i = 0;
+       p = page;
+       while ((ver = omap_get_nr_config(OMAP_TAG_VERSION_STR,
+                                        struct omap_version_config, i)) != NULL) {
+               p += sprintf(p, "%-12s%s\n", ver->component, ver->version);
+               i++;
+       }
+
+       len = (p - page) - off;
+       if (len < 0)
+               len = 0;
+
+       *eof = (len <= count) ? 1 : 0;
+       *start = page + off;
+
+       return len;
+}
+
+static int __init component_version_init(void)
+{
+       if (omap_get_config(OMAP_TAG_VERSION_STR, struct omap_version_config) == NULL)
+               return -ENODEV;
+       if (!create_proc_read_entry("component_version", S_IRUGO, NULL,
+                                   component_version_read_proc, NULL))
+               return -ENOMEM;
+
+       return 0;
+}
+
+static void __exit component_version_exit(void)
+{
+       remove_proc_entry("component_version", NULL);
+}
+
+late_initcall(component_version_init);
+module_exit(component_version_exit);
+
+MODULE_AUTHOR("Juha Yrjölä <juha.yrjola@nokia.com>");
+MODULE_DESCRIPTION("Component version driver");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/plat-omap/debug-devices.c b/arch/arm/plat-omap/debug-devices.c
new file mode 100644 (file)
index 0000000..83a5f8b
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * linux/arch/arm/plat-omap/debug-devices.c
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ * Modified from mach-omap2/board-h4.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 <asm/hardware.h>
+#include <asm/io.h>
+
+#include <asm/arch/board.h>
+#include <asm/arch/gpio.h>
+
+
+/* Many OMAP development platforms reuse the same "debug board"; these
+ * platforms include H2, H3, H4, and Perseus2.
+ */
+
+static struct resource smc91x_resources[] = {
+       [0] = {
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device smc91x_device = {
+       .name           = "smc91x",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(smc91x_resources),
+       .resource       = smc91x_resources,
+};
+
+static struct resource led_resources[] = {
+       [0] = {
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device led_device = {
+       .name           = "omap_dbg_led",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(led_resources),
+       .resource       = led_resources,
+};
+
+static struct platform_device *debug_devices[] __initdata = {
+       &smc91x_device,
+       &led_device,
+       /* ps2 kbd + mouse ports */
+       /* 4 extra uarts */
+       /* 6 input dip switches */
+       /* 8 output pins */
+};
+
+int __init debug_card_init(u32 addr, unsigned gpio)
+{
+       int     status;
+
+       smc91x_resources[0].start = addr + 0x300;
+       smc91x_resources[0].end   = addr + 0x30f;
+
+       smc91x_resources[1].start = OMAP_GPIO_IRQ(gpio);
+       smc91x_resources[1].end   = OMAP_GPIO_IRQ(gpio);
+
+       status = omap_request_gpio(gpio);
+       if (status < 0) {
+               printk(KERN_ERR "GPIO%d unavailable for smc91x IRQ\n", gpio);
+               return status;
+       }
+       omap_set_gpio_direction(gpio, 1);
+
+       led_resources[0].start = addr;
+       led_resources[0].end   = addr + SZ_4K - 1;
+
+       return platform_add_devices(debug_devices, ARRAY_SIZE(debug_devices));
+}
diff --git a/arch/arm/plat-omap/debug-leds.c b/arch/arm/plat-omap/debug-leds.c
new file mode 100644 (file)
index 0000000..511d6a5
--- /dev/null
@@ -0,0 +1,319 @@
+/*
+ * linux/arch/arm/plat-omap/debug-leds.c
+ *
+ * Copyright 2003 by Texas Instruments Incorporated
+ *
+ * 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/platform_device.h>
+#include <linux/leds.h>
+
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/leds.h>
+#include <asm/system.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/fpga.h>
+#include <asm/arch/gpio.h>
+
+
+/* Many OMAP development platforms reuse the same "debug board"; these
+ * platforms include H2, H3, H4, and Perseus2.  There are 16 LEDs on the
+ * debug board (all green), accessed through FPGA registers.
+ *
+ * The "surfer" expansion board and H2 sample board also have two-color
+ * green+red LEDs (in parallel), used here for timer and idle indicators
+ * in preference to the ones on the debug board, for a "Disco LED" effect.
+ *
+ * This driver exports either the original ARM LED API, the new generic
+ * one, or both.
+ */
+
+static spinlock_t                      lock;
+static struct h2p2_dbg_fpga __iomem    *fpga;
+static u16                             led_state, hw_led_state;
+
+
+#ifdef CONFIG_LEDS
+#define old_led_api()  1
+#else
+#define old_led_api()  0
+#endif
+
+#ifdef CONFIG_LEDS_OMAP_DEBUG
+#define new_led_api()  1
+#else
+#define new_led_api()  0
+#endif
+
+
+/*-------------------------------------------------------------------------*/
+
+/* original ARM debug LED API:
+ *  - timer and idle leds (some boards use non-FPGA leds here);
+ *  - up to 4 generic leds, easily accessed in-kernel (any context)
+ */
+
+#define GPIO_LED_RED           3
+#define GPIO_LED_GREEN         OMAP_MPUIO(4)
+
+#define LED_STATE_ENABLED      0x01
+#define LED_STATE_CLAIMED      0x02
+#define LED_TIMER_ON           0x04
+
+#define GPIO_IDLE              GPIO_LED_GREEN
+#define GPIO_TIMER             GPIO_LED_RED
+
+static void h2p2_dbg_leds_event(led_event_t evt)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&lock, flags);
+
+       if (!(led_state & LED_STATE_ENABLED) && evt != led_start)
+               goto done;
+
+       switch (evt) {
+       case led_start:
+               if (fpga)
+                       led_state |= LED_STATE_ENABLED;
+               break;
+
+       case led_stop:
+       case led_halted:
+               /* all leds off during suspend or shutdown */
+
+               if (!(machine_is_omap_perseus2() || machine_is_omap_h4())) {
+                       omap_set_gpio_dataout(GPIO_TIMER, 0);
+                       omap_set_gpio_dataout(GPIO_IDLE, 0);
+               }
+
+               __raw_writew(~0, &fpga->leds);
+               led_state &= ~LED_STATE_ENABLED;
+               goto done;
+
+       case led_claim:
+               led_state |= LED_STATE_CLAIMED;
+               hw_led_state = 0;
+               break;
+
+       case led_release:
+               led_state &= ~LED_STATE_CLAIMED;
+               break;
+
+#ifdef CONFIG_LEDS_TIMER
+       case led_timer:
+               led_state ^= LED_TIMER_ON;
+
+               if (machine_is_omap_perseus2() || machine_is_omap_h4())
+                       hw_led_state ^= H2P2_DBG_FPGA_P2_LED_TIMER;
+               else {
+                       omap_set_gpio_dataout(GPIO_TIMER,
+                                       led_state & LED_TIMER_ON);
+                       goto done;
+               }
+
+               break;
+#endif
+
+#ifdef CONFIG_LEDS_CPU
+       /* LED lit iff busy */
+       case led_idle_start:
+               if (machine_is_omap_perseus2() || machine_is_omap_h4())
+                       hw_led_state &= ~H2P2_DBG_FPGA_P2_LED_IDLE;
+               else {
+                       omap_set_gpio_dataout(GPIO_IDLE, 1);
+                       goto done;
+               }
+
+               break;
+
+       case led_idle_end:
+               if (machine_is_omap_perseus2() || machine_is_omap_h4())
+                       hw_led_state |= H2P2_DBG_FPGA_P2_LED_IDLE;
+               else {
+                       omap_set_gpio_dataout(GPIO_IDLE, 0);
+                       goto done;
+               }
+
+               break;
+#endif
+
+       case led_green_on:
+               hw_led_state |= H2P2_DBG_FPGA_LED_GREEN;
+               break;
+       case led_green_off:
+               hw_led_state &= ~H2P2_DBG_FPGA_LED_GREEN;
+               break;
+
+       case led_amber_on:
+               hw_led_state |= H2P2_DBG_FPGA_LED_AMBER;
+               break;
+       case led_amber_off:
+               hw_led_state &= ~H2P2_DBG_FPGA_LED_AMBER;
+               break;
+
+       case led_red_on:
+               hw_led_state |= H2P2_DBG_FPGA_LED_RED;
+               break;
+       case led_red_off:
+               hw_led_state &= ~H2P2_DBG_FPGA_LED_RED;
+               break;
+
+       case led_blue_on:
+               hw_led_state |= H2P2_DBG_FPGA_LED_BLUE;
+               break;
+       case led_blue_off:
+               hw_led_state &= ~H2P2_DBG_FPGA_LED_BLUE;
+               break;
+
+       default:
+               break;
+       }
+
+
+       /*
+        *  Actually burn the LEDs
+        */
+       if (led_state & LED_STATE_ENABLED)
+               __raw_writew(~hw_led_state, &fpga->leds);
+
+done:
+       spin_unlock_irqrestore(&lock, flags);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* "new" LED API
+ *  - with syfs access and generic triggering
+ *  - not readily accessible to in-kernel drivers
+ */
+
+struct dbg_led {
+       struct led_classdev     cdev;
+       u16                     mask;
+};
+
+static struct dbg_led dbg_leds[] = {
+       /* REVISIT at least H2 uses different timer & cpu leds... */
+#ifndef CONFIG_LEDS_TIMER
+       { .mask = 1 << 0,  .cdev.name =  "d4:green", },         /* timer */
+#endif
+#ifndef CONFIG_LEDS_CPU
+       { .mask = 1 << 1,  .cdev.name =  "d5:green", },         /* !idle */
+#endif
+       { .mask = 1 << 2,  .cdev.name =  "d6:green", },
+       { .mask = 1 << 3,  .cdev.name =  "d7:green", },
+
+       { .mask = 1 << 4,  .cdev.name =  "d8:green", },
+       { .mask = 1 << 5,  .cdev.name =  "d9:green", },
+       { .mask = 1 << 6,  .cdev.name = "d10:green", },
+       { .mask = 1 << 7,  .cdev.name = "d11:green", },
+
+       { .mask = 1 << 8,  .cdev.name = "d12:green", },
+       { .mask = 1 << 9,  .cdev.name = "d13:green", },
+       { .mask = 1 << 10, .cdev.name = "d14:green", },
+       { .mask = 1 << 11, .cdev.name = "d15:green", },
+
+#ifndef        CONFIG_LEDS
+       { .mask = 1 << 12, .cdev.name = "d16:green", },
+       { .mask = 1 << 13, .cdev.name = "d17:green", },
+       { .mask = 1 << 14, .cdev.name = "d18:green", },
+       { .mask = 1 << 15, .cdev.name = "d19:green", },
+#endif
+};
+
+static void
+fpga_led_set(struct led_classdev *cdev, enum led_brightness value)
+{
+       struct dbg_led  *led = container_of(cdev, struct dbg_led, cdev);
+       unsigned long   flags;
+
+       spin_lock_irqsave(&lock, flags);
+       if (value == LED_OFF)
+               hw_led_state &= ~led->mask;
+       else
+               hw_led_state |= led->mask;
+       __raw_writew(~hw_led_state, &fpga->leds);
+       spin_unlock_irqrestore(&lock, flags);
+}
+
+static void __init newled_init(struct device *dev)
+{
+       unsigned        i;
+       struct dbg_led  *led;
+       int             status;
+
+       for (i = 0, led = dbg_leds; i < ARRAY_SIZE(dbg_leds); i++, led++) {
+               led->cdev.brightness_set = fpga_led_set;
+               status = led_classdev_register(dev, &led->cdev);
+               if (status < 0)
+                       break;
+       }
+       return;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int /* __init */ fpga_probe(struct platform_device *pdev)
+{
+       struct resource *iomem;
+
+       spin_lock_init(&lock);
+
+       iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!iomem)
+               return -ENODEV;
+
+       fpga = ioremap(iomem->start, H2P2_DBG_FPGA_SIZE);
+       __raw_writew(~0, &fpga->leds);
+
+       if (old_led_api()) {
+               leds_event = h2p2_dbg_leds_event;
+               leds_event(led_start);
+       }
+
+       if (new_led_api()) {
+               newled_init(&pdev->dev);
+       }
+
+       return 0;
+}
+
+static int fpga_suspend_late(struct platform_device *pdev, pm_message_t mesg)
+{
+       __raw_writew(~0, &fpga->leds);
+       return 0;
+}
+
+static int fpga_resume_early(struct platform_device *pdev)
+{
+       __raw_writew(~hw_led_state, &fpga->leds);
+       return 0;
+}
+
+
+static struct platform_driver led_driver = {
+       .driver.name    = "omap_dbg_led",
+       .probe          = fpga_probe,
+       .suspend_late   = fpga_suspend_late,
+       .resume_early   = fpga_resume_early,
+};
+
+static int __init fpga_init(void)
+{
+       if (machine_is_omap_h4()
+                       || machine_is_omap_h3()
+                       || machine_is_omap_h2()
+                       || machine_is_omap_perseus2()
+                       )
+               return platform_driver_register(&led_driver);
+       return 0;
+}
+fs_initcall(fpga_init);
index dbc3f44e07a603f8b891c2901e1223a846dc34f1..93bf7c767542ac324cc85d3e97633decf2672e03 100644 (file)
 #include <asm/arch/gpio.h>
 #include <asm/arch/menelaus.h>
 
-#if    defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE)
+#if    defined(CONFIG_OMAP_DSP) || defined(CONFIG_OMAP_DSP_MODULE)
+
+#include "../plat-omap/dsp/dsp_common.h"
+
+static struct dsp_platform_data dsp_pdata = {
+       .kdev_list = LIST_HEAD_INIT(dsp_pdata.kdev_list),
+};
+
+static struct resource omap_dsp_resources[] = {
+       {
+               .name   = "dsp_mmu",
+               .start  = -1,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device omap_dsp_device = {
+       .name           = "dsp",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(omap_dsp_resources),
+       .resource       = omap_dsp_resources,
+       .dev = {
+               .platform_data = &dsp_pdata,
+       },
+};
+
+static inline void omap_init_dsp(void)
+{
+       struct resource *res;
+       int irq;
+
+       if (cpu_is_omap15xx())
+               irq = INT_1510_DSP_MMU;
+       else if (cpu_is_omap16xx())
+               irq = INT_1610_DSP_MMU;
+       else if (cpu_is_omap24xx())
+               irq = INT_24XX_DSP_MMU;
+
+       res = platform_get_resource_byname(&omap_dsp_device,
+                                          IORESOURCE_IRQ, "dsp_mmu");
+       res->start = irq;
+
+       platform_device_register(&omap_dsp_device);
+}
+
+int dsp_kfunc_device_register(struct dsp_kfunc_device *kdev)
+{
+       static DEFINE_MUTEX(dsp_pdata_lock);
+
+       mutex_init(&kdev->lock);
+
+       mutex_lock(&dsp_pdata_lock);
+       list_add_tail(&kdev->entry, &dsp_pdata.kdev_list);
+       mutex_unlock(&dsp_pdata_lock);
+
+       return 0;
+}
+EXPORT_SYMBOL(dsp_kfunc_device_register);
+
+#else
+static inline void omap_init_dsp(void) { }
+#endif /* CONFIG_OMAP_DSP */
+
+/*-------------------------------------------------------------------------*/
+#if    defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE)
 
 #define        OMAP1_I2C_BASE          0xfffb3800
 #define OMAP2_I2C_BASE1                0x48070000
@@ -48,8 +112,8 @@ static struct resource i2c_resources1[] = {
 /* DMA not used; works around erratum writing to non-empty i2c fifo */
 
 static struct platform_device omap_i2c_device1 = {
-        .name           = "i2c_omap",
-        .id             = 1,
+       .name           = "i2c_omap",
+       .id             = 1,
        .num_resources  = ARRAY_SIZE(i2c_resources1),
        .resource       = i2c_resources1,
 };
@@ -72,8 +136,10 @@ static void omap_init_i2c(void)
         * it can include clocking and address info, maybe more.
         */
        if (cpu_is_omap24xx()) {
-               omap_cfg_reg(M19_24XX_I2C1_SCL);
-               omap_cfg_reg(L15_24XX_I2C1_SDA);
+               if (machine_is_omap_h4()) {
+                       omap_cfg_reg(M19_24XX_I2C1_SCL);
+                       omap_cfg_reg(L15_24XX_I2C1_SDA);
+               }
        } else {
                omap_cfg_reg(I2C_SCL);
                omap_cfg_reg(I2C_SDA);
@@ -376,7 +442,7 @@ static inline void omap_init_wdt(void) {}
 
 /*-------------------------------------------------------------------------*/
 
-#if    defined(CONFIG_OMAP_RNG) || defined(CONFIG_OMAP_RNG_MODULE)
+#if defined(CONFIG_HW_RANDOM_OMAP) || defined(CONFIG_HW_RANDOM_OMAP_MODULE)
 
 #ifdef CONFIG_ARCH_OMAP24XX
 #define        OMAP_RNG_BASE           0x480A0000
@@ -429,17 +495,21 @@ static inline void omap_init_rng(void) {}
  */
 static int __init omap_init_devices(void)
 {
+/*
+ * Need to enable relevant once for 2430 SDP
+ */
+#ifndef CONFIG_MACH_OMAP_2430SDP
        /* please keep these calls, and their implementations above,
         * in alphabetical order so they're easier to sort through.
         */
-       omap_init_i2c();
+       omap_init_dsp();
        omap_init_kp();
        omap_init_mmc();
        omap_init_uwire();
        omap_init_wdt();
        omap_init_rng();
-
+#endif
+       omap_init_i2c();
        return 0;
 }
 arch_initcall(omap_init_devices);
-
index bb045e5ddbd837e3906a90415e5800b383c6dd08..2d86b106ff3e06b0dbc9ffe3a8e84b0945fb96b0 100644 (file)
@@ -557,7 +557,7 @@ int omap_request_dma(int dev_id, const char *dev_name,
                omap_enable_channel_irq(free_ch);
                /* Clear the CSR register and IRQ status register */
                OMAP_DMA_CSR_REG(free_ch) = OMAP2_DMA_CSR_CLEAR_MASK;
-               omap_writel(~0x0, OMAP_DMA4_IRQSTATUS_L0);
+               omap_writel(1 << free_ch, OMAP_DMA4_IRQSTATUS_L0);
        }
 
        *dma_ch_out = free_ch;
@@ -597,10 +597,7 @@ void omap_free_dma(int lch)
 
                /* Clear the CSR register and IRQ status register */
                OMAP_DMA_CSR_REG(lch) = OMAP2_DMA_CSR_CLEAR_MASK;
-
-               val = omap_readl(OMAP_DMA4_IRQSTATUS_L0);
-               val |= 1 << lch;
-               omap_writel(val, OMAP_DMA4_IRQSTATUS_L0);
+               omap_writel(1 << lch, OMAP_DMA4_IRQSTATUS_L0);
 
                /* Disable all DMA interrupts for the channel. */
                OMAP_DMA_CICR_REG(lch) = 0;
@@ -927,12 +924,18 @@ static irqreturn_t omap1_dma_irq_handler(int irq, void *dev_id)
 static int omap2_dma_handle_ch(int ch)
 {
        u32 status = OMAP_DMA_CSR_REG(ch);
-       u32 val;
 
-       if (!status)
+       if (!status) {
+               if (printk_ratelimit())
+                       printk(KERN_WARNING "Spurious DMA IRQ for lch %d\n", ch);
                return 0;
-       if (unlikely(dma_chan[ch].dev_id == -1))
+       }
+       if (unlikely(dma_chan[ch].dev_id == -1)) {
+               if (printk_ratelimit())
+                       printk(KERN_WARNING "IRQ %04x for non-allocated DMA"
+                                       "channel %d\n", status, ch);
                return 0;
+       }
        if (unlikely(status & OMAP_DMA_DROP_IRQ))
                printk(KERN_INFO
                       "DMA synchronization event drop occurred with device "
@@ -948,11 +951,7 @@ static int omap2_dma_handle_ch(int ch)
                       dma_chan[ch].dev_id);
 
        OMAP_DMA_CSR_REG(ch) = OMAP2_DMA_CSR_CLEAR_MASK;
-
-       val = omap_readl(OMAP_DMA4_IRQSTATUS_L0);
-       /* ch in this function is from 0-31 while in register it is 1-32 */
-       val = 1 << (ch);
-       omap_writel(val, OMAP_DMA4_IRQSTATUS_L0);
+       omap_writel(1 << ch, OMAP_DMA4_IRQSTATUS_L0);
 
        if (likely(dma_chan[ch].callback != NULL))
                dma_chan[ch].callback(ch, status, dma_chan[ch].data);
@@ -967,11 +966,15 @@ static irqreturn_t omap2_dma_irq_handler(int irq, void *dev_id)
        int i;
 
        val = omap_readl(OMAP_DMA4_IRQSTATUS_L0);
-
-       for (i = 1; i <= OMAP_LOGICAL_DMA_CH_COUNT; i++) {
-               int active = val & (1 << (i - 1));
-               if (active)
-                       omap2_dma_handle_ch(i - 1);
+       if (val == 0) {
+               if (printk_ratelimit())
+                       printk(KERN_WARNING "Spurious DMA IRQ\n");
+               return IRQ_HANDLED;
+       }
+       for (i = 0; i < OMAP_LOGICAL_DMA_CH_COUNT && val != 0; i++) {
+               if (val & 1)
+                       omap2_dma_handle_ch(i);
+               val >>= 1;
        }
 
        return IRQ_HANDLED;
index bcbb8d7392be6d5b5ca729b29a32439a1ba5331a..36073dfaa4db57810c96f1674c39f5889c13fc93 100644 (file)
@@ -90,8 +90,8 @@ static struct omap_dm_timer dm_timers[] = {
        { .phys_base = 0xfffb2c00, .irq = INT_1610_GPTIMER4 },
        { .phys_base = 0xfffb3400, .irq = INT_1610_GPTIMER5 },
        { .phys_base = 0xfffb3c00, .irq = INT_1610_GPTIMER6 },
-       { .phys_base = 0xfffb4400, .irq = INT_1610_GPTIMER7 },
-       { .phys_base = 0xfffb4c00, .irq = INT_1610_GPTIMER8 },
+       { .phys_base = 0xfffb7400, .irq = INT_1610_GPTIMER7 },
+       { .phys_base = 0xfffbd400, .irq = INT_1610_GPTIMER8 },
 };
 
 #elif defined(CONFIG_ARCH_OMAP2)
@@ -314,6 +314,8 @@ struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer)
 __u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
 {
        BUG();
+
+       return 0;
 }
 
 #endif
@@ -370,7 +372,7 @@ void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
 
        /* When the functional clock disappears, too quick writes seem to
         * cause an abort. */
-       __delay(15000);
+       __delay(150000);
 }
 
 #endif
@@ -504,6 +506,8 @@ int omap_dm_timer_init(void)
                BUG_ON(dm_source_clocks[i] == NULL);
        }
 #endif
+       if (cpu_is_omap243x())
+               dm_timers[0].phys_base = 0x49018000;
 
        for (i = 0; i < dm_timer_count; i++) {
 #ifdef CONFIG_ARCH_OMAP2
diff --git a/arch/arm/plat-omap/dsp/Kconfig b/arch/arm/plat-omap/dsp/Kconfig
new file mode 100644 (file)
index 0000000..71da40b
--- /dev/null
@@ -0,0 +1,29 @@
+
+config OMAP_DSP
+       tristate "OMAP DSP driver (DSP Gateway)"
+       depends on ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP24XX
+       help
+         This enables OMAP DSP driver, DSP Gateway.
+
+config OMAP_DSP_MBCMD_VERBOSE
+       bool "Mailbox Command Verbose LOG"
+       depends on OMAP_DSP
+       help
+          This enables kernel log output in the Mailbox command exchanges
+         in the DSP Gateway driver.
+
+config OMAP_DSP_TASK_MULTIOPEN
+       bool "DSP Task Multiopen Capability"
+       depends on OMAP_DSP
+       help
+          This enables DSP tasks to be opened by multiple times at a time.
+         Otherwise, they can be opened only once at a time.
+
+config OMAP_DSP_FBEXPORT
+       bool "Framebuffer export to DSP"
+       depends on OMAP_DSP
+       help
+          This enables to map the frame buffer to DSP.
+         By doing this, DSP can access the frame buffer directly without
+         bothering ARM.
+
diff --git a/arch/arm/plat-omap/dsp/Makefile b/arch/arm/plat-omap/dsp/Makefile
new file mode 100644 (file)
index 0000000..c7d86f3
--- /dev/null
@@ -0,0 +1,15 @@
+#
+# 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
diff --git a/arch/arm/plat-omap/dsp/dsp.h b/arch/arm/plat-omap/dsp/dsp.h
new file mode 100644 (file)
index 0000000..3535659
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "hardware_dsp.h"
+#include "dsp_common.h"
+
+/*
+ * MAJOR device number: !! allocated arbitrary !!
+ */
+#define OMAP_DSP_CTL_MAJOR             96
+#define OMAP_DSP_TASK_MAJOR            97
+
+#define OLD_BINARY_SUPPORT     y
+
+#ifdef OLD_BINARY_SUPPORT
+#define MBREV_3_0      0x0017
+#define MBREV_3_2      0x0018
+#endif
+
+#define DSP_INIT_PAGE  0xfff000
+
+#ifdef CONFIG_ARCH_OMAP1
+/* idle program will be placed at IDLEPG_BASE. */
+#define IDLEPG_BASE    0xfffe00
+#define IDLEPG_SIZE    0x100
+#endif /* CONFIG_ARCH_OMAP1 */
+
+/* timeout value for DSP response */
+#define DSP_TIMEOUT    (10 * HZ)
+
+enum dsp_mem_type_e {
+       MEM_TYPE_CROSSING = -1,
+       MEM_TYPE_NONE = 0,
+       MEM_TYPE_DARAM,
+       MEM_TYPE_SARAM,
+       MEM_TYPE_EXTERN,
+};
+
+
+typedef int __bitwise arm_dsp_dir_t;
+#define DIR_A2D        ((__force arm_dsp_dir_t) 1)
+#define DIR_D2A        ((__force arm_dsp_dir_t) 2)
+
+enum cfgstat_e {
+       CFGSTAT_CLEAN = 0,
+       CFGSTAT_READY,
+       CFGSTAT_SUSPEND,
+       CFGSTAT_RESUME, /* request only */
+       CFGSTAT_MAX
+};
+
+enum errcode_e {
+       ERRCODE_WDT = 0,
+       ERRCODE_MMU,
+       ERRCODE_MAX
+};
+
+/* keep 2 entries for TID_FREE and TID_ANON */
+#define TASKDEV_MAX    254
+
+#define MK32(uw,lw)    (((u32)(uw)) << 16 | (lw))
+#define MKLONG(uw,lw)  (((unsigned long)(uw)) << 16 | (lw))
+#define MKVIRT(uw,lw)  dspword_to_virt(MKLONG((uw), (lw)));
+
+struct sync_seq {
+       u16 da_dsp;
+       u16 da_arm;
+       u16 ad_dsp;
+       u16 ad_arm;
+};
+
+struct mem_sync_struct {
+       struct sync_seq *DARAM;
+       struct sync_seq *SARAM;
+       struct sync_seq *SDRAM;
+};
+
+/* struct mbcmd and union mbcmd_hw must be compatible */
+struct mbcmd {
+       u32 data:16;
+       u32 cmd_l:8;
+       u32 cmd_h:7;
+       u32 seq:1;
+};
+
+#define MBCMD_INIT(h, l, d) { \
+               .cmd_h = (h), \
+               .cmd_l = (l), \
+               .data  = (d), \
+       }
+
+struct mb_exarg {
+       u8 tid;
+       int argc;
+       u16 *argv;
+};
+
+extern void dsp_mbox_start(void);
+extern void dsp_mbox_stop(void);
+extern int dsp_mbox_config(void *p);
+extern int sync_with_dsp(u16 *syncwd, u16 tid, int try_cnt);
+extern int __dsp_mbcmd_send_exarg(struct mbcmd *mb, struct mb_exarg *arg,
+                                 int recovery_flag);
+#define dsp_mbcmd_send(mb)             __dsp_mbcmd_send_exarg((mb), NULL, 0)
+#define dsp_mbcmd_send_exarg(mb, arg)  __dsp_mbcmd_send_exarg((mb), (arg), 0)
+extern int dsp_mbcmd_send_and_wait_exarg(struct mbcmd *mb, struct mb_exarg *arg,
+                                        wait_queue_head_t *q);
+#define dsp_mbcmd_send_and_wait(mb, q) \
+       dsp_mbcmd_send_and_wait_exarg((mb), NULL, (q))
+
+static __inline__ int __mbcompose_send_exarg(u8 cmd_h, u8 cmd_l, u16 data,
+                                            struct mb_exarg *arg,
+                                            int recovery_flag)
+{
+       struct mbcmd mb = MBCMD_INIT(cmd_h, cmd_l, data);
+       return __dsp_mbcmd_send_exarg(&mb, arg, recovery_flag);
+}
+#define mbcompose_send(cmd_h, cmd_l, data) \
+       __mbcompose_send_exarg(MBOX_CMD_DSP_##cmd_h, (cmd_l), (data), NULL, 0)
+#define mbcompose_send_exarg(cmd_h, cmd_l, data, arg) \
+       __mbcompose_send_exarg(MBOX_CMD_DSP_##cmd_h, (cmd_l), (data), arg, 0)
+#define mbcompose_send_recovery(cmd_h, cmd_l, data) \
+       __mbcompose_send_exarg(MBOX_CMD_DSP_##cmd_h, (cmd_l), (data), NULL, 1)
+
+static __inline__ int __mbcompose_send_and_wait_exarg(u8 cmd_h, u8 cmd_l,
+                                                     u16 data,
+                                                     struct mb_exarg *arg,
+                                                     wait_queue_head_t *q)
+{
+       struct mbcmd mb = MBCMD_INIT(cmd_h, cmd_l, data);
+       return dsp_mbcmd_send_and_wait_exarg(&mb, arg, q);
+}
+#define mbcompose_send_and_wait(cmd_h, cmd_l, data, q) \
+       __mbcompose_send_and_wait_exarg(MBOX_CMD_DSP_##cmd_h, (cmd_l), (data), \
+                                       NULL, (q))
+#define mbcompose_send_and_wait_exarg(cmd_h, cmd_l, data, arg, q) \
+       __mbcompose_send_and_wait_exarg(MBOX_CMD_DSP_##cmd_h, (cmd_l), (data), \
+                                       (arg), (q))
+
+extern struct ipbuf_head *bid_to_ipbuf(u16 bid);
+extern void ipbuf_start(void);
+extern void ipbuf_stop(void);
+extern int ipbuf_config(u16 ln, u16 lsz, void *base);
+extern int ipbuf_sys_config(void *p, arm_dsp_dir_t dir);
+extern int ipbuf_p_validate(void *p, arm_dsp_dir_t dir);
+extern struct ipbuf_head *get_free_ipbuf(u8 tid);
+extern void release_ipbuf(struct ipbuf_head *ipb_h);
+extern void balance_ipbuf(void);
+extern void unuse_ipbuf(struct ipbuf_head *ipb_h);
+extern void unuse_ipbuf_nowait(struct ipbuf_head *ipb_h);
+
+#define release_ipbuf_pvt(ipbuf_pvt) \
+       do { \
+               (ipbuf_pvt)->s = TID_FREE; \
+       } while(0)
+
+extern int mbox_revision;
+
+extern int dsp_cfgstat_request(enum cfgstat_e st);
+extern enum cfgstat_e dsp_cfgstat_get_stat(void);
+extern int dsp_set_runlevel(u8 level);
+
+extern int dsp_task_config_all(u8 n);
+extern void dsp_task_unconfig_all(void);
+extern u8 dsp_task_count(void);
+extern int dsp_taskmod_busy(void);
+extern int dsp_mkdev(char *name);
+extern int dsp_rmdev(char *name);
+extern int dsp_tadd_minor(unsigned char minor, dsp_long_t adr);
+extern int dsp_tdel_minor(unsigned char minor);
+extern int dsp_tkill_minor(unsigned char minor);
+extern long taskdev_state_stale(unsigned char minor);
+extern int dsp_dbg_config(u16 *buf, u16 sz, u16 lsz);
+extern void dsp_dbg_stop(void);
+
+extern int ipbuf_is_held(u8 tid, u16 bid);
+
+extern int dsp_mem_sync_inc(void);
+extern int dsp_mem_sync_config(struct mem_sync_struct *sync);
+extern enum dsp_mem_type_e dsp_mem_type(void *vadr, size_t len);
+extern int dsp_address_validate(void *p, size_t len, char *fmt, ...);
+extern int dsp_mem_enable(void *adr);
+extern void dsp_mem_disable(void *adr);
+#ifdef CONFIG_ARCH_OMAP1
+extern void dsp_mem_usecount_clear(void);
+#endif
+extern void exmap_use(void *vadr, size_t len);
+extern void exmap_unuse(void *vadr, size_t len);
+extern unsigned long dsp_virt_to_phys(void *vadr, size_t *len);
+extern void dsp_mem_start(void);
+extern void dsp_mem_stop(void);
+
+extern void dsp_twch_start(void);
+extern void dsp_twch_stop(void);
+extern void dsp_twch_touch(void);
+
+extern void dsp_err_start(void);
+extern void dsp_err_stop(void);
+extern void dsp_err_set(enum errcode_e code, unsigned long arg);
+extern void dsp_err_clear(enum errcode_e code);
+extern int dsp_err_isset(enum errcode_e code);
+
+enum cmd_l_type_e {
+       CMD_L_TYPE_NULL,
+       CMD_L_TYPE_TID,
+       CMD_L_TYPE_SUBCMD,
+};
+
+struct cmdinfo {
+       char *name;
+       enum cmd_l_type_e cmd_l_type;
+       void (*handler)(struct mbcmd *mb);
+};
+
+extern const struct cmdinfo *cmdinfo[];
+
+#define cmd_name(mb)   (cmdinfo[(mb).cmd_h]->name)
+extern char *subcmd_name(struct mbcmd *mb);
+
+extern void mblog_add(struct mbcmd *mb, arm_dsp_dir_t dir);
diff --git a/arch/arm/plat-omap/dsp/dsp_common.c b/arch/arm/plat-omap/dsp/dsp_common.c
new file mode 100644 (file)
index 0000000..b998509
--- /dev/null
@@ -0,0 +1,615 @@
+/*
+ * 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/clk.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <asm/io.h>
+#include <asm/tlbflush.h>
+#include <asm/irq.h>
+#ifdef CONFIG_ARCH_OMAP1
+#include <asm/arch/tc.h>
+#endif
+#include "dsp_common.h"
+
+#if defined(CONFIG_ARCH_OMAP1)
+#define dsp_boot_config(mode)  omap_writew((mode), MPUI_DSP_BOOT_CONFIG)
+#elif defined(CONFIG_ARCH_OMAP2)
+#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;
+
+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;
+}
+
+#endif /* CONFIG_ARCH_OMAP1 */
+
+static int init_done;
+
+static int __init 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
+       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");
+               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);
+       }
+
+       dsp_ick_handle = clk_get(NULL, "dsp_ick");
+       if (IS_ERR(dsp_ick_handle)) {
+               printk(KERN_ERR "omapdsp: could not acquire dsp_ick handle.\n");
+               return PTR_ERR(dsp_ick_handle);
+       }
+#endif
+
+       init_done = 1;
+       printk(KERN_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;
+                       if (omap_dsp != NULL)
+                               enable_irq(omap_dsp->mmu_irq);
+               }
+               return;
+       }
+
+       /* cpustat.req < CPUSTAT_RUN */
+
+       if (cpustat.stat == CPUSTAT_RUN) {
+               if (omap_dsp != NULL)
+                       disable_irq(omap_dsp->mmu_irq);
+#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);
+}
+
+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;
+}
+
+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);
+}
+#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);
+EXPORT_SYMBOL(omap_dsp_request_mem);
+EXPORT_SYMBOL(omap_dsp_release_mem);
+#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);
+#ifdef CONFIG_ARCH_OMAP1
+EXPORT_SYMBOL(dsp_register_mem_cb);
+EXPORT_SYMBOL(dsp_unregister_mem_cb);
+#endif /* CONFIG_ARCH_OMAP1 */
+
+EXPORT_SYMBOL(__cpu_flush_kern_tlb_range);
+EXPORT_SYMBOL(cpu_architecture);
+EXPORT_SYMBOL(pmd_clear_bad);
+#endif
diff --git a/arch/arm/plat-omap/dsp/dsp_common.h b/arch/arm/plat-omap/dsp/dsp_common.h
new file mode 100644 (file)
index 0000000..872d838
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * 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 DRIVER_DSP_COMMON_H
+#define DRIVER_DSP_COMMON_H
+
+#include "hardware_dsp.h"
+
+#define DSPSPACE_SIZE  0x1000000
+
+#define omap_set_bit_regw(b,r) \
+       do { omap_writew(omap_readw(r) | (b), (r)); } while(0)
+#define omap_clr_bit_regw(b,r) \
+       do { omap_writew(omap_readw(r) & ~(b), (r)); } while(0)
+#define omap_set_bit_regl(b,r) \
+       do { omap_writel(omap_readl(r) | (b), (r)); } while(0)
+#define omap_clr_bit_regl(b,r) \
+       do { omap_writel(omap_readl(r) & ~(b), (r)); } while(0)
+#define 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
+ */
+#define RSTCTRL_RST1_DSP       0x00000001
+#define RSTCTRL_RST2_DSP       0x00000002
+#define __dsp_core_enable() \
+       do { RM_RSTCTRL_DSP &= ~RSTCTRL_RST1_DSP; } while (0)
+#define __dsp_core_disable() \
+       do { RM_RSTCTRL_DSP |= RSTCTRL_RST1_DSP; } while (0)
+#define __dsp_per_enable() \
+       do { RM_RSTCTRL_DSP &= ~RSTCTRL_RST2_DSP; } while (0)
+#define __dsp_per_disable() \
+       do { RM_RSTCTRL_DSP |= RSTCTRL_RST2_DSP; } while (0)
+#endif /* CONFIG_ARCH_OMAP2 */
+
+typedef u32 dsp_long_t;        /* must have ability to carry TADD_ABORTADR */
+
+#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);
+#ifdef CONFIG_ARCH_OMAP1
+void dsp_set_idle_boot_base(dsp_long_t adr, size_t size);
+void dsp_reset_idle_boot_base(void);
+#endif
+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);
+#ifdef CONFIG_ARCH_OMAP1
+void dsp_register_mem_cb(int (*req_cb)(void), void (*rel_cb)(void));
+void dsp_unregister_mem_cb(void);
+#endif
+
+#if defined(CONFIG_ARCH_OMAP1)
+static inline void dsp_clk_autoidle(void) {}
+#elif defined(CONFIG_ARCH_OMAP2)
+static inline void dsp_clk_autoidle(void)
+{
+       /*XXX should be handled in mach-omap[1,2] XXX*/
+       PM_PWSTCTRL_DSP = (1 << 18) | (1 << 0);
+       CM_AUTOIDLE_DSP |= (1 << 1);
+       CM_CLKSTCTRL_DSP |= (1 << 0);
+}
+#endif
+
+struct dsp_kfunc_device {
+       char            *name;
+       struct clk      *fck;
+       struct clk      *ick;;
+       struct mutex     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     (*remove)(struct dsp_kfunc_device *);
+       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 */
+       int                     mmu_irq;
+       struct omap_mbox        *mbox;
+       struct device           *dev;
+       struct list_head        *kdev_list;
+       int                     initialized;
+};
+
+#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 /* DRIVER_DSP_COMMON_H */
diff --git a/arch/arm/plat-omap/dsp/dsp_core.c b/arch/arm/plat-omap/dsp/dsp_core.c
new file mode 100644 (file)
index 0000000..2da959b
--- /dev/null
@@ -0,0 +1,685 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/mutex.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <asm/delay.h>
+#include <asm/arch/mailbox.h>
+#include <asm/arch/dsp_common.h>
+#include "dsp_mbcmd.h"
+#include "dsp.h"
+#include "ipbuf.h"
+#include "dsp_common.h"
+
+MODULE_AUTHOR("Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>");
+MODULE_DESCRIPTION("OMAP DSP driver module");
+MODULE_LICENSE("GPL");
+
+static struct sync_seq *mbseq;
+static u16 mbseq_expect_tmp;
+static u16 *mbseq_expect = &mbseq_expect_tmp;
+
+extern void dsp_mem_late_init(void);
+
+/*
+ * mailbox commands
+ */
+extern void mbox_wdsnd(struct mbcmd *mb);
+extern void mbox_wdreq(struct mbcmd *mb);
+extern void mbox_bksnd(struct mbcmd *mb);
+extern void mbox_bkreq(struct mbcmd *mb);
+extern void mbox_bkyld(struct mbcmd *mb);
+extern void mbox_bksndp(struct mbcmd *mb);
+extern void mbox_bkreqp(struct mbcmd *mb);
+extern void mbox_tctl(struct mbcmd *mb);
+extern void mbox_poll(struct mbcmd *mb);
+#ifdef OLD_BINARY_SUPPORT
+/* v3.3 obsolete */
+extern void mbox_wdt(struct mbcmd *mb);
+#endif
+extern void mbox_suspend(struct mbcmd *mb);
+static void mbox_kfunc(struct mbcmd *mb);
+extern void mbox_tcfg(struct mbcmd *mb);
+extern void mbox_tadd(struct mbcmd *mb);
+extern void mbox_tdel(struct mbcmd *mb);
+extern void mbox_dspcfg(struct mbcmd *mb);
+extern void mbox_regrw(struct mbcmd *mb);
+extern void mbox_getvar(struct mbcmd *mb);
+extern void mbox_err(struct mbcmd *mb);
+extern void mbox_dbg(struct mbcmd *mb);
+
+static const struct cmdinfo
+       cif_wdsnd    = { "WDSND",    CMD_L_TYPE_TID,    mbox_wdsnd   },
+       cif_wdreq    = { "WDREQ",    CMD_L_TYPE_TID,    mbox_wdreq   },
+       cif_bksnd    = { "BKSND",    CMD_L_TYPE_TID,    mbox_bksnd   },
+       cif_bkreq    = { "BKREQ",    CMD_L_TYPE_TID,    mbox_bkreq   },
+       cif_bkyld    = { "BKYLD",    CMD_L_TYPE_NULL,   mbox_bkyld   },
+       cif_bksndp   = { "BKSNDP",   CMD_L_TYPE_TID,    mbox_bksndp  },
+       cif_bkreqp   = { "BKREQP",   CMD_L_TYPE_TID,    mbox_bkreqp  },
+       cif_tctl     = { "TCTL",     CMD_L_TYPE_TID,    mbox_tctl    },
+       cif_poll     = { "POLL",     CMD_L_TYPE_NULL,   mbox_poll    },
+#ifdef OLD_BINARY_SUPPORT
+       /* v3.3 obsolete */
+       cif_wdt      = { "WDT",      CMD_L_TYPE_NULL,   mbox_wdt     },
+#endif
+       cif_runlevel = { "RUNLEVEL", CMD_L_TYPE_SUBCMD, NULL        },
+       cif_pm       = { "PM",       CMD_L_TYPE_SUBCMD, NULL        },
+       cif_suspend  = { "SUSPEND",  CMD_L_TYPE_NULL,   mbox_suspend },
+       cif_kfunc    = { "KFUNC",    CMD_L_TYPE_SUBCMD, mbox_kfunc   },
+       cif_tcfg     = { "TCFG",     CMD_L_TYPE_TID,    mbox_tcfg    },
+       cif_tadd     = { "TADD",     CMD_L_TYPE_TID,    mbox_tadd    },
+       cif_tdel     = { "TDEL",     CMD_L_TYPE_TID,    mbox_tdel    },
+       cif_tstop    = { "TSTOP",    CMD_L_TYPE_TID,    NULL        },
+       cif_dspcfg   = { "DSPCFG",   CMD_L_TYPE_SUBCMD, mbox_dspcfg  },
+       cif_regrw    = { "REGRW",    CMD_L_TYPE_SUBCMD, mbox_regrw   },
+       cif_getvar   = { "GETVAR",   CMD_L_TYPE_SUBCMD, mbox_getvar  },
+       cif_setvar   = { "SETVAR",   CMD_L_TYPE_SUBCMD, NULL        },
+       cif_err      = { "ERR",      CMD_L_TYPE_SUBCMD, mbox_err     },
+       cif_dbg      = { "DBG",      CMD_L_TYPE_NULL,   mbox_dbg     };
+
+#define MBOX_CMD_MAX   0x80
+const struct cmdinfo *cmdinfo[MBOX_CMD_MAX] = {
+       [MBOX_CMD_DSP_WDSND]    = &cif_wdsnd,
+       [MBOX_CMD_DSP_WDREQ]    = &cif_wdreq,
+       [MBOX_CMD_DSP_BKSND]    = &cif_bksnd,
+       [MBOX_CMD_DSP_BKREQ]    = &cif_bkreq,
+       [MBOX_CMD_DSP_BKYLD]    = &cif_bkyld,
+       [MBOX_CMD_DSP_BKSNDP]   = &cif_bksndp,
+       [MBOX_CMD_DSP_BKREQP]   = &cif_bkreqp,
+       [MBOX_CMD_DSP_TCTL]     = &cif_tctl,
+       [MBOX_CMD_DSP_POLL]     = &cif_poll,
+#ifdef OLD_BINARY_SUPPORT
+       [MBOX_CMD_DSP_WDT]      = &cif_wdt, /* v3.3 obsolete */
+#endif
+       [MBOX_CMD_DSP_RUNLEVEL] = &cif_runlevel,
+       [MBOX_CMD_DSP_PM]       = &cif_pm,
+       [MBOX_CMD_DSP_SUSPEND]  = &cif_suspend,
+       [MBOX_CMD_DSP_KFUNC]    = &cif_kfunc,
+       [MBOX_CMD_DSP_TCFG]     = &cif_tcfg,
+       [MBOX_CMD_DSP_TADD]     = &cif_tadd,
+       [MBOX_CMD_DSP_TDEL]     = &cif_tdel,
+       [MBOX_CMD_DSP_TSTOP]    = &cif_tstop,
+       [MBOX_CMD_DSP_DSPCFG]   = &cif_dspcfg,
+       [MBOX_CMD_DSP_REGRW]    = &cif_regrw,
+       [MBOX_CMD_DSP_GETVAR]   = &cif_getvar,
+       [MBOX_CMD_DSP_SETVAR]   = &cif_setvar,
+       [MBOX_CMD_DSP_ERR]      = &cif_err,
+       [MBOX_CMD_DSP_DBG]      = &cif_dbg,
+};
+
+static int dsp_kfunc_probe_devices(struct omap_dsp *dsp)
+{
+       struct dsp_kfunc_device *p;
+       int ret, fail = 0;
+
+       mutex_lock(&dsp->lock);
+       list_for_each_entry(p, dsp->kdev_list, entry) {
+               if (p->probe == NULL)
+                       continue;
+               ret = p->probe(p);
+               if (ret) {
+                       printk(KERN_ERR
+                              "probing %s failed\n", p->name);
+                       fail++;
+               }
+       }
+       mutex_unlock(&dsp->lock);
+
+       pr_debug("%s() fail:%d\n", __FUNCTION__, fail);
+
+       return fail;
+}
+
+static int dsp_kfunc_remove_devices(struct omap_dsp *dsp)
+{
+       struct dsp_kfunc_device *p;
+       int ret, fail = 0;
+
+       mutex_lock(&dsp->lock);
+       list_for_each_entry_reverse(p, dsp->kdev_list, entry) {
+               if (p->remove == NULL)
+                       continue;
+               ret = p->remove(p);
+               if (ret) {
+                       printk(KERN_ERR
+                              "removing %s failed\n", p->name);
+                       fail++;
+               }
+       }
+       mutex_unlock(&dsp->lock);
+
+       pr_debug("%s() fail:%d\n", __FUNCTION__, fail);
+
+       return fail;
+}
+
+static int dsp_kfunc_enable_devices(struct omap_dsp *dsp, int type, int stage)
+{
+       struct dsp_kfunc_device *p;
+       int ret, fail = 0;
+
+       mutex_lock(&dsp->lock);
+       list_for_each_entry(p, dsp->kdev_list, entry) {
+               if ((p->type != type) || (p->enable == NULL))
+                       continue;
+               ret = p->enable(p, stage);
+               if (ret) {
+                       printk(KERN_ERR
+                              "enabling %s failed\n", p->name);
+                       fail++;
+               }
+       }
+       mutex_unlock(&dsp->lock);
+
+       pr_debug("%s(%d) fail:%d\n", __FUNCTION__, type, fail);
+
+       return fail;
+}
+
+static int dsp_kfunc_disable_devices(struct omap_dsp *dsp, int type, int stage)
+{
+       struct dsp_kfunc_device *p;
+       int ret, fail = 0;
+
+       mutex_lock(&dsp->lock);
+       list_for_each_entry_reverse(p, omap_dsp->kdev_list, entry) {
+               if ((p->type != type) || (p->disable == NULL))
+                       continue;
+               ret = p->disable(p, stage);
+               if (ret) {
+                       printk(KERN_ERR
+                              "disabling %s failed\n", p->name);
+                       fail++;
+               }
+       }
+       mutex_unlock(&dsp->lock);
+
+       pr_debug("%s(%d) fail:%d\n", __FUNCTION__, type, fail);
+
+       return fail;
+}
+
+int sync_with_dsp(u16 *adr, u16 val, int try_cnt)
+{
+       int try;
+
+       if (*(volatile u16 *)adr == val)
+               return 0;
+
+       for (try = 0; try < try_cnt; try++) {
+               udelay(1);
+               if (*(volatile u16 *)adr == val) {
+                       /* success! */
+                       pr_info("omapdsp: sync_with_dsp(): try = %d\n", try);
+                       return 0;
+               }
+       }
+
+       /* fail! */
+       return -1;
+}
+
+static int mbcmd_sender_prepare(void *data)
+{
+       struct mb_exarg *arg = data;
+       int i, ret = 0;
+       /*
+        * even if ipbuf_sys_ad is in DSP internal memory,
+        * dsp_mem_enable() never cause to call PM mailbox command
+        * because in that case DSP memory should be always enabled.
+        * (see ipbuf_sys_hold_mem_active in ipbuf.c)
+        *
+        * Therefore, we can call this function here safely.
+        */
+       if (sync_with_dsp(&ipbuf_sys_ad->s, TID_FREE, 10) < 0) {
+               printk(KERN_ERR "omapdsp: ipbuf_sys_ad is busy.\n");
+               ret = -EBUSY;
+               goto out;
+       }
+
+       for (i = 0; i < arg->argc; i++) {
+               ipbuf_sys_ad->d[i] = arg->argv[i];
+       }
+       ipbuf_sys_ad->s = arg->tid;
+ out:
+       return ret;
+}
+
+/*
+ * __dsp_mbcmd_send_exarg(): mailbox dispatcher
+ */
+int __dsp_mbcmd_send_exarg(struct mbcmd *mb, struct mb_exarg *arg,
+                          int recovery_flag)
+{
+       int ret = 0;
+
+       if (unlikely(omap_dsp->enabled == 0)) {
+               ret = dsp_kfunc_enable_devices(omap_dsp,
+                                              DSP_KFUNC_DEV_TYPE_COMMON, 0);
+               if (ret == 0)
+                       omap_dsp->enabled = 1;
+       }
+
+       /*
+        * while MMU fault is set,
+        * only recovery command can be executed
+        */
+       if (dsp_err_isset(ERRCODE_MMU) && !recovery_flag) {
+               printk(KERN_ERR
+                      "mbox: mmu interrupt is set. %s is aborting.\n",
+                      cmd_name(*mb));
+               goto out;
+       }
+
+       if (arg)
+               dsp_mem_enable(ipbuf_sys_ad);
+
+       ret = omap_mbox_msg_send(omap_dsp->mbox,
+                                *(mbox_msg_t *)mb, (void*)arg);
+       if (ret)
+               goto out;
+
+       if (mbseq)
+               mbseq->ad_arm++;
+
+       mblog_add(mb, DIR_A2D);
+ out:
+       if (arg)
+               dsp_mem_disable(ipbuf_sys_ad);
+
+       return ret;
+}
+
+int dsp_mbcmd_send_and_wait_exarg(struct mbcmd *mb, struct mb_exarg *arg,
+                                 wait_queue_head_t *q)
+{
+       long current_state;
+       DECLARE_WAITQUEUE(wait, current);
+
+       add_wait_queue(q, &wait);
+       current_state = current->state;
+       set_current_state(TASK_INTERRUPTIBLE);
+       if (dsp_mbcmd_send_exarg(mb, arg) < 0) {
+               set_current_state(current_state);
+               remove_wait_queue(q, &wait);
+               return -1;
+       }
+       schedule_timeout(DSP_TIMEOUT);
+       set_current_state(current_state);
+       remove_wait_queue(q, &wait);
+
+       return 0;
+}
+
+/*
+ * mbcmd receiver
+ */
+static void mbcmd_receiver(mbox_msg_t msg)
+{
+       struct mbcmd *mb = (struct mbcmd *)&msg;
+
+       if (cmdinfo[mb->cmd_h] == NULL) {
+               printk(KERN_ERR
+                      "invalid message (%08x) for mbcmd_receiver().\n", msg);
+               return;
+       }
+
+       (*mbseq_expect)++;
+
+       mblog_add(mb, DIR_D2A);
+
+       /* call handler for the command */
+       if (cmdinfo[mb->cmd_h]->handler)
+               cmdinfo[mb->cmd_h]->handler(mb);
+       else
+               printk(KERN_ERR "mbox: %s is not allowed from DSP.\n",
+                      cmd_name(*mb));
+}
+
+static int mbsync_hold_mem_active;
+
+void dsp_mbox_start(void)
+{
+       omap_mbox_init_seq(omap_dsp->mbox);
+       mbseq_expect_tmp = 0;
+}
+
+void dsp_mbox_stop(void)
+{
+       mbseq = NULL;
+       mbseq_expect = &mbseq_expect_tmp;
+}
+
+int dsp_mbox_config(void *p)
+{
+       unsigned long flags;
+
+       if (dsp_address_validate(p, sizeof(struct sync_seq), "mbseq") < 0)
+               return -1;
+       if (dsp_mem_type(p, sizeof(struct sync_seq)) != MEM_TYPE_EXTERN) {
+               printk(KERN_WARNING
+                      "omapdsp: mbseq is placed in DSP internal memory.\n"
+                      "         It will prevent DSP from idling.\n");
+               mbsync_hold_mem_active = 1;
+               /*
+                * dsp_mem_enable() never fails because
+                * it has been already enabled in dspcfg process and
+                * this will just increment the usecount.
+                */
+               dsp_mem_enable((void *)daram_base);
+       }
+
+       local_irq_save(flags);
+       mbseq = p;
+       mbseq->da_arm = mbseq_expect_tmp;
+       mbseq_expect = &mbseq->da_arm;
+       local_irq_restore(flags);
+
+       return 0;
+}
+
+static int __init dsp_mbox_init(void)
+{
+       omap_dsp->mbox = omap_mbox_get("dsp");
+       if (omap_dsp->mbox == NULL) {
+               printk(KERN_ERR "failed to get mailbox handler for DSP.\n");
+               return -ENODEV;
+       }
+
+       omap_dsp->mbox->msg_receive_cb = mbcmd_receiver;
+       omap_dsp->mbox->msg_sender_cb = mbcmd_sender_prepare;
+
+       return 0;
+}
+
+static void dsp_mbox_exit(void)
+{
+       omap_dsp->mbox->msg_sender_cb = NULL;
+       omap_dsp->mbox->msg_receive_cb = NULL;
+
+       if (mbsync_hold_mem_active) {
+               dsp_mem_disable((void *)daram_base);
+               mbsync_hold_mem_active = 0;
+       }
+}
+
+/*
+ * kernel function dispatcher
+ */
+extern void mbox_fbctl_upd(void);
+extern void mbox_fbctl_disable(struct mbcmd *mb);
+
+static void mbox_kfunc_fbctl(struct mbcmd *mb)
+{
+       switch (mb->data) {
+       case FBCTL_UPD:
+               mbox_fbctl_upd();
+               break;
+       case FBCTL_DISABLE:
+               mbox_fbctl_disable(mb);
+               break;
+       default:
+               printk(KERN_ERR
+                      "mbox: Unknown FBCTL from DSP: 0x%04x\n", mb->data);
+       }
+}
+
+/*
+ * dspgw: KFUNC message handler
+ */
+static void mbox_kfunc_power(unsigned short data)
+{
+       int ret = -1;
+
+       switch (data) {
+       case DVFS_START: /* ACK from DSP */
+               /* TBD */
+               break;
+       case AUDIO_PWR_UP:
+               ret = dsp_kfunc_enable_devices(omap_dsp,
+                                              DSP_KFUNC_DEV_TYPE_AUDIO, 0);
+               if (ret == 0)
+                       ret++;
+               break;
+       case AUDIO_PWR_DOWN: /* == AUDIO_PWR_DOWN1 */
+               ret = dsp_kfunc_disable_devices(omap_dsp,
+                                               DSP_KFUNC_DEV_TYPE_AUDIO, 1);
+               break;
+       case AUDIO_PWR_DOWN2:
+               ret = dsp_kfunc_disable_devices(omap_dsp,
+                                               DSP_KFUNC_DEV_TYPE_AUDIO, 2);
+               break;
+       case DSP_PWR_DOWN:
+               ret = dsp_kfunc_disable_devices(omap_dsp,
+                                               DSP_KFUNC_DEV_TYPE_COMMON, 0);
+               if (ret == 0)
+                       omap_dsp->enabled = 0;
+               break;
+       default:
+               printk(KERN_ERR
+                      "mailbox: Unknown PWR from DSP: 0x%04x\n", data);
+               break;
+       }
+
+       if (unlikely(ret < 0)) {
+               printk(KERN_ERR "mailbox: PWR(0x%04x) failed\n", data);
+               return;
+       }
+
+       if (likely(ret == 0))
+               return;
+
+       mbcompose_send(KFUNC, KFUNC_POWER, data);
+}
+
+static void mbox_kfunc(struct mbcmd *mb)
+{
+       switch (mb->cmd_l) {
+       case KFUNC_FBCTL:
+               mbox_kfunc_fbctl(mb);
+               break;
+       case KFUNC_POWER:
+               mbox_kfunc_power(mb->data);
+               break;
+       default:
+               printk(KERN_ERR
+                      "mbox: Unknown KFUNC from DSP: 0x%02x\n", mb->cmd_l);
+       }
+}
+
+int dsp_late_init(void)
+{
+       int ret;
+
+       dsp_clk_autoidle();
+
+#ifdef CONFIG_ARCH_OMAP2
+       clk_enable(dsp_fck_handle);
+       clk_enable(dsp_ick_handle);
+       __dsp_per_enable();
+#endif
+       dsp_mem_late_init();
+
+#ifdef CONFIG_ARCH_OMAP1
+       dsp_set_idle_boot_base(IDLEPG_BASE, IDLEPG_SIZE);
+#endif
+       ret = dsp_kfunc_enable_devices(omap_dsp,
+                                      DSP_KFUNC_DEV_TYPE_COMMON, 0);
+       if (ret == 0)
+               omap_dsp->enabled = 0;
+
+       return 0;
+}
+
+extern int  dsp_ctl_core_init(void);
+extern void dsp_ctl_core_exit(void);
+extern void dsp_ctl_init(void);
+extern void dsp_ctl_exit(void);
+extern int  dsp_mem_init(void);
+extern void dsp_mem_exit(void);
+extern void mblog_init(void);
+extern void mblog_exit(void);
+extern int  dsp_taskmod_init(void);
+extern void dsp_taskmod_exit(void);
+
+/*
+ * driver functions
+ */
+static int __init dsp_drv_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct omap_dsp *info;
+       struct dsp_platform_data *pdata = pdev->dev.platform_data;
+
+       dev_info(&pdev->dev, "OMAP DSP driver initialization\n");
+
+       info = kzalloc(sizeof(struct omap_dsp), GFP_KERNEL);
+       if (unlikely(info == NULL)) {
+               dev_dbg(&pdev->dev, "no memory for info\n");
+               return -ENOMEM;
+       }
+       platform_set_drvdata(pdev, info);
+       omap_dsp = info;
+
+       mutex_init(&info->lock);
+       info->dev = &pdev->dev;
+       info->kdev_list = &pdata->kdev_list;
+
+       ret = dsp_kfunc_probe_devices(info);
+       if (ret) {
+               ret = -ENXIO;
+               goto fail0;
+       }
+
+       info->mmu_irq = platform_get_irq_byname(pdev, "dsp_mmu");
+       if (unlikely(info->mmu_irq) < 0) {
+               ret = -ENXIO;
+               goto fail1;
+       }
+
+       if ((ret = dsp_ctl_core_init()) < 0)
+               goto fail2;
+       if ((ret = dsp_mem_init()) < 0)
+               goto fail3;
+       dsp_ctl_init();
+       mblog_init();
+       if ((ret = dsp_taskmod_init()) < 0)
+               goto fail4;
+       if ((ret = dsp_mbox_init()) < 0)
+               goto fail5;
+
+       return 0;
+
+ fail5:
+       dsp_taskmod_exit();
+ fail4:
+       mblog_exit();
+       dsp_ctl_exit();
+       dsp_mem_exit();
+ fail3:
+       dsp_ctl_core_exit();
+ fail2:
+ fail1:
+       dsp_kfunc_remove_devices(info);
+ fail0:
+       kfree(info);
+
+       return ret;
+}
+
+static int dsp_drv_remove(struct platform_device *pdev)
+{
+       struct omap_dsp *info = platform_get_drvdata(pdev);
+
+       dsp_cpustat_request(CPUSTAT_RESET);
+
+       dsp_cfgstat_request(CFGSTAT_CLEAN);
+       dsp_mbox_exit();
+       dsp_taskmod_exit();
+       mblog_exit();
+       dsp_ctl_exit();
+       dsp_mem_exit();
+
+       dsp_ctl_core_exit();
+
+#ifdef CONFIG_ARCH_OMAP2
+       __dsp_per_disable();
+       clk_disable(dsp_ick_handle);
+       clk_disable(dsp_fck_handle);
+#endif
+       dsp_kfunc_remove_devices(info);
+       kfree(info);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int dsp_drv_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       dsp_cfgstat_request(CFGSTAT_SUSPEND);
+
+       return 0;
+}
+
+static int dsp_drv_resume(struct platform_device *pdev)
+{
+       dsp_cfgstat_request(CFGSTAT_RESUME);
+
+       return 0;
+}
+#else
+#define dsp_drv_suspend                NULL
+#define dsp_drv_resume         NULL
+#endif /* CONFIG_PM */
+
+static struct platform_driver dsp_driver = {
+       .probe          = dsp_drv_probe,
+       .remove         = dsp_drv_remove,
+       .suspend        = dsp_drv_suspend,
+       .resume         = dsp_drv_resume,
+       .driver         = {
+               .name   = "dsp",
+       },
+};
+
+static int __init omap_dsp_mod_init(void)
+{
+       return platform_driver_register(&dsp_driver);
+}
+
+static void __exit omap_dsp_mod_exit(void)
+{
+       platform_driver_unregister(&dsp_driver);
+}
+
+/* module dependency: need mailbox module that have mbox_dsp_info */
+extern struct omap_mbox mbox_dsp_info;
+struct omap_mbox *mbox_dep = &mbox_dsp_info;
+
+module_init(omap_dsp_mod_init);
+module_exit(omap_dsp_mod_exit);
diff --git a/arch/arm/plat-omap/dsp/dsp_ctl.c b/arch/arm/plat-omap/dsp/dsp_ctl.c
new file mode 100644 (file)
index 0000000..91be986
--- /dev/null
@@ -0,0 +1,1057 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/ioctls.h>
+#include <asm/arch/mailbox.h>
+#include "hardware_dsp.h"
+#include "dsp_mbcmd.h"
+#include "dsp.h"
+#include "ipbuf.h"
+#include "ioctl.h"
+
+enum dsp_space_e {
+       SPACE_MEM,
+       SPACE_IO,
+};
+
+#ifdef CONFIG_OMAP_DSP_FBEXPORT
+static enum fbstat_e {
+       FBSTAT_DISABLED = 0,
+       FBSTAT_ENABLED,
+       FBSTAT_MAX,
+} fbstat = FBSTAT_ENABLED;
+#endif
+
+static enum cfgstat_e cfgstat;
+int mbox_revision;
+static u8 n_stask;
+
+static ssize_t ifver_show(struct device *dev, struct device_attribute *attr,
+                         char *buf);
+static ssize_t cpustat_show(struct device *dev, struct device_attribute *attr,
+                           char *buf);
+static ssize_t icrmask_show(struct device *dev, struct device_attribute *attr,
+                           char *buf);
+static ssize_t icrmask_store(struct device *dev, struct device_attribute *attr,
+                            const char *buf, size_t count);
+static ssize_t loadinfo_show(struct device *dev, struct device_attribute *attr,
+                            char *buf);
+
+#define __ATTR_RW(_name, _mode) { \
+       .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE },     \
+       .show   = _name##_show,                                 \
+       .store  = _name##_store,                                        \
+}
+
+static struct device_attribute dev_attr_ifver     = __ATTR_RO(ifver);
+static struct device_attribute dev_attr_cpustat   = __ATTR_RO(cpustat);
+static struct device_attribute dev_attr_icrmask   = __ATTR_RW(icrmask, 0644);
+static struct device_attribute dev_attr_loadinfo  = __ATTR_RO(loadinfo);
+
+/*
+ * misc interactive mailbox command operations
+ */
+static struct misc_mb_wait_struct {
+       struct mutex lock;
+       wait_queue_head_t wait_q;
+       u8 cmd_h;
+       u8 cmd_l;
+       u16 *retvp;
+} misc_mb_wait = {
+       .lock = __MUTEX_INITIALIZER(misc_mb_wait.lock),
+       .wait_q = __WAIT_QUEUE_HEAD_INITIALIZER(misc_mb_wait.wait_q),
+};
+
+static int __misc_mbcompose_send_and_wait(u8 cmd_h, u8 cmd_l, u16 data,
+                                         u16 *retvp)
+{
+       struct mbcmd mb = MBCMD_INIT(cmd_h, cmd_l, data);
+       int ret = 0;
+
+       if (mutex_lock_interruptible(&misc_mb_wait.lock))
+               return -EINTR;
+
+       misc_mb_wait.cmd_h = mb.cmd_h;
+       misc_mb_wait.cmd_l = mb.cmd_l;
+       misc_mb_wait.retvp = retvp;
+       dsp_mbcmd_send_and_wait(&mb, &misc_mb_wait.wait_q);
+
+       if (misc_mb_wait.cmd_h != 0)
+               ret = -EINVAL;
+
+       mutex_unlock(&misc_mb_wait.lock);
+       return ret;
+}
+
+#define misc_mbcompose_send_and_wait(cmd_h, cmd_l, data, retvp) \
+               __misc_mbcompose_send_and_wait(MBOX_CMD_DSP_##cmd_h, (cmd_l), \
+                                              (data), (retvp));
+
+static int misc_mbcmd_response(struct mbcmd *mb, int argc, int match_cmd_l_flag)
+{
+       volatile u16 *buf;
+       int i;
+
+       /* if match_cmd_l_v flag is set, cmd_l needs to be matched as well. */
+       if (!waitqueue_active(&misc_mb_wait.wait_q) ||
+           (misc_mb_wait.cmd_h != mb->cmd_h) ||
+           (match_cmd_l_flag && (misc_mb_wait.cmd_l != mb->cmd_l))) {
+               const struct cmdinfo *ci = cmdinfo[mb->cmd_h];
+               char cmdstr[32];
+
+               if (ci->cmd_l_type == CMD_L_TYPE_SUBCMD)
+                       sprintf(cmdstr, "%s:%s", ci->name, subcmd_name(mb));
+               else
+                       strcpy(cmdstr, ci->name);
+               printk(KERN_WARNING
+                      "mbox: unexpected command %s received!\n", cmdstr);
+               return -1;
+       }
+
+       /*
+        * if argc == 1, receive data through mbox:data register.
+        * if argc > 1, receive through ipbuf_sys.
+        */
+       if (argc == 1)
+               misc_mb_wait.retvp[0] = mb->data;
+       else if (argc > 1) {
+               if (dsp_mem_enable(ipbuf_sys_da) < 0) {
+                       printk(KERN_ERR "mbox: %s - ipbuf_sys_da read failed!\n",
+                              cmdinfo[mb->cmd_h]->name);
+                       return -1;
+               }
+               if (sync_with_dsp(&ipbuf_sys_da->s, TID_ANON, 10) < 0) {
+                       printk(KERN_ERR "mbox: %s - IPBUF sync failed!\n",
+                              cmdinfo[mb->cmd_h]->name);
+                       dsp_mem_disable(ipbuf_sys_da);
+                       return -1;
+               }
+               /* need word access. do not use memcpy. */
+               buf = ipbuf_sys_da->d;
+               for (i = 0; i < argc; i++)
+                       misc_mb_wait.retvp[i] = buf[i];
+               release_ipbuf_pvt(ipbuf_sys_da);
+               dsp_mem_disable(ipbuf_sys_da);
+       }
+
+       misc_mb_wait.cmd_h = 0;
+       wake_up_interruptible(&misc_mb_wait.wait_q);
+       return 0;
+}
+
+static int dsp_regread(enum dsp_space_e space, u16 adr, u16 *val)
+{
+       u8 cmd_l = (space == SPACE_MEM) ? REGRW_MEMR : REGRW_IOR;
+       int ret;
+
+       ret = misc_mbcompose_send_and_wait(REGRW, cmd_l, adr, val);
+       if ((ret < 0) && (ret != -EINTR))
+               printk(KERN_ERR "omapdsp: register read error!\n");
+
+       return ret;
+}
+
+static int dsp_regwrite(enum dsp_space_e space, u16 adr, u16 val)
+{
+       u8 cmd_l = (space == SPACE_MEM) ? REGRW_MEMW : REGRW_IOW;
+       struct mb_exarg arg = {
+               .tid  = TID_ANON,
+               .argc = 1,
+               .argv = &val,
+       };
+
+       mbcompose_send_exarg(REGRW, cmd_l, adr, &arg);
+       return 0;
+}
+
+static int dsp_getvar(u8 varid, u16 *val)
+{
+       int ret;
+
+       ret = misc_mbcompose_send_and_wait(GETVAR, varid, 0, val);
+       if ((ret < 0) && (ret != -EINTR))
+               printk(KERN_ERR "omapdsp: variable read error!\n");
+
+       return ret;
+}
+
+static int dsp_setvar(u8 varid, u16 val)
+{
+       mbcompose_send(SETVAR, varid, val);
+       return 0;
+}
+
+/*
+ * dsp_cfg() return value
+ *  = 0: OK
+ *  = 1: failed, but state is clear. (DSPCFG command failed)
+ *  < 0: failed. need cleanup.
+ */
+static int dsp_cfg(void)
+{
+       int ret = 0;
+
+#ifdef CONFIG_ARCH_OMAP1
+       /* for safety */
+       dsp_mem_usecount_clear();
+#endif
+
+       /*
+        * DSPCFG command and dsp_mem_start() must be called
+        * while internal mem is on.
+        */
+       dsp_mem_enable((void *)dspmem_base);
+
+       dsp_mbox_start();
+       dsp_twch_start();
+       dsp_mem_start();
+       dsp_err_start();
+
+       mbox_revision = -1;
+
+       ret = misc_mbcompose_send_and_wait(DSPCFG, DSPCFG_REQ, 0, NULL);
+       if (ret < 0) {
+               if (ret != -EINTR)
+                       printk(KERN_ERR "omapdsp: configuration error!\n");
+               ret = 1;
+               goto out;
+       }
+
+#if defined(CONFIG_ARCH_OMAP1) && defined(OLD_BINARY_SUPPORT)
+       /*
+        * MBREV 3.2 or earlier doesn't assume DMA domain is on
+        * when DSPCFG command is sent
+        */
+       if ((mbox_revision == MBREV_3_0) ||
+           (mbox_revision == MBREV_3_2)) {
+               if ((ret = mbcompose_send(PM, PM_ENABLE, DSPREG_ICR_DMA)) < 0)
+                       goto out;
+       }
+#endif
+
+       if ((ret = dsp_task_config_all(n_stask)) < 0)
+               goto out;
+
+       /* initialization */
+#ifdef CONFIG_OMAP_DSP_FBEXPORT
+       fbstat = FBSTAT_ENABLED;
+#endif
+
+       /* send parameter */
+       if ((ret = dsp_setvar(VARID_ICRMASK, dsp_cpustat_get_icrmask())) < 0)
+               goto out;
+
+       /* create runtime sysfs entries */
+       ret = device_create_file(omap_dsp->dev, &dev_attr_loadinfo);
+       if (ret)
+               printk(KERN_ERR "device_create_file failed: %d\n", ret);
+
+out:
+       dsp_mem_disable((void *)dspmem_base);
+       return ret;
+}
+
+static int dsp_uncfg(void)
+{
+       if (dsp_taskmod_busy()) {
+               printk(KERN_WARNING "omapdsp: tasks are busy.\n");
+               return -EBUSY;
+       }
+
+       /* FIXME: lock task module */
+
+       /* remove runtime sysfs entries */
+       device_remove_file(omap_dsp->dev, &dev_attr_loadinfo);
+
+       dsp_mbox_stop();
+       dsp_twch_stop();
+       dsp_mem_stop();
+       dsp_err_stop();
+       dsp_dbg_stop();
+       dsp_task_unconfig_all();
+       ipbuf_stop();
+
+       return 0;
+}
+
+static int dsp_suspend(void)
+{
+       int ret;
+
+       ret = misc_mbcompose_send_and_wait(SUSPEND, 0, 0, NULL);
+       if (ret < 0) {
+               if (ret != -EINVAL)
+                       printk(KERN_ERR "omapdsp: DSP suspend error!\n");
+               return ret;
+       }
+
+       udelay(100);    /* wait for DSP-side execution */
+       return 0;
+}
+
+int dsp_cfgstat_request(enum cfgstat_e st_req)
+{
+       static DEFINE_MUTEX(cfgstat_lock);
+       int ret = 0, ret_override = 0;
+
+       if (mutex_lock_interruptible(&cfgstat_lock))
+               return -EINTR;
+
+again:
+       switch (st_req) {
+
+       /* cfgstat takes CLEAN, READY or SUSPEND,
+          while st_req can take SUSPEND in addition. */
+
+       case CFGSTAT_CLEAN:
+               if (cfgstat == CFGSTAT_CLEAN)
+                       goto up_out;
+               if ((ret = dsp_uncfg()) < 0)
+                       goto up_out;
+               break;
+
+       case CFGSTAT_READY:
+               if (cfgstat != CFGSTAT_CLEAN) {
+                       printk(KERN_ERR "omapdsp: DSP is ready already!\n");
+                       ret = -EINVAL;
+                       goto up_out;
+               }
+
+               ret = dsp_cfg();
+               if (ret > 0) {  /* failed, but state is clear. */
+                       ret = -EINVAL;
+                       goto up_out;
+               } else if (ret < 0) {   /* failed, need cleanup. */
+                       st_req = CFGSTAT_CLEAN;
+                       ret_override = ret;
+                       goto again;
+               }
+               break;
+
+       /*
+        * suspend / resume
+        * DSP is not reset within this code, but done in omap_pm_suspend.
+        * so if these functions are called from sysfs,
+        * DSP should be reset / unreset out of these functions.
+        */
+       case CFGSTAT_SUSPEND:
+               switch (cfgstat) {
+
+               case CFGSTAT_CLEAN:
+                       if (dsp_cpustat_get_stat() == CPUSTAT_RUN) {
+                               printk(KERN_WARNING
+                                      "omapdsp: illegal operation -- trying "
+                                      "suspend DSP while it is running but "
+                                      "not configured.\n"
+                                      "  Resetting DSP.\n");
+                               dsp_cpustat_request(CPUSTAT_RESET);
+                               ret = -EINVAL;
+                       }
+                       goto up_out;
+
+               case CFGSTAT_READY:
+                       if ((ret = dsp_suspend()) < 0)
+                               goto up_out;
+                       break;
+
+               case CFGSTAT_SUSPEND:
+                       goto up_out;
+
+               default:
+                       BUG();
+
+               }
+
+               break;
+
+       case CFGSTAT_RESUME:
+               if (cfgstat != CFGSTAT_SUSPEND) {
+                       printk(KERN_WARNING
+                              "omapdsp: DSP resume request, but DSP is not in "
+                              "suspend state.\n");
+                       ret = -EINVAL;
+                       goto up_out;
+               }
+               st_req = CFGSTAT_READY;
+               break;
+
+       default:
+               BUG();
+
+       }
+
+       cfgstat = st_req;
+up_out:
+       mutex_unlock(&cfgstat_lock);
+       return ret_override ? ret_override : ret;
+}
+
+enum cfgstat_e dsp_cfgstat_get_stat(void)
+{
+       return cfgstat;
+}
+
+/*
+ * polls all tasks
+ */
+static int dsp_poll(void)
+{
+       int ret;
+
+       ret = misc_mbcompose_send_and_wait(POLL, 0, 0, NULL);
+       if ((ret < 0) && (ret != -EINTR))
+               printk(KERN_ERR "omapdsp: poll error!\n");
+
+       return ret;
+}
+
+int dsp_set_runlevel(u8 level)
+{
+       if (level == RUNLEVEL_RECOVERY) {
+               if (mbcompose_send_recovery(RUNLEVEL, level, 0) < 0)
+                       return -EINVAL;
+       } else {
+               if ((level < RUNLEVEL_USER) ||
+                   (level > RUNLEVEL_SUPER))
+                       return -EINVAL;
+               if (mbcompose_send(RUNLEVEL, level, 0) < 0)
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_OMAP_DSP_FBEXPORT
+static void dsp_fbctl_enable(void)
+{
+       mbcompose_send(KFUNC, KFUNC_FBCTL, FBCTL_ENABLE);
+}
+
+static int dsp_fbctl_disable(void)
+{
+       int ret;
+
+       ret = misc_mbcompose_send_and_wait(KFUNC, KFUNC_FBCTL, FBCTL_DISABLE,
+                                          NULL);
+       if ((ret < 0) && (ret != -EINTR))
+               printk(KERN_ERR "omapdsp: fb disable error!\n");
+
+       return 0;
+}
+
+static int dsp_fbstat_request(enum fbstat_e st)
+{
+       static DEFINE_MUTEX(fbstat_lock);
+       int ret = 0;
+
+       if (mutex_lock_interruptible(&fbstat_lock))
+               return -EINTR;
+
+       if (st == fbstat)
+               goto up_out;
+
+       switch (st) {
+       case FBSTAT_ENABLED:
+               dsp_fbctl_enable();
+               break;
+       case FBSTAT_DISABLED:
+               if ((ret = dsp_fbctl_disable()) < 0)
+                       goto up_out;
+               break;
+       default:
+               BUG();
+       }
+
+       fbstat = st;
+up_out:
+       mutex_unlock(&fbstat_lock);
+       return 0;
+}
+#endif /* CONFIG_OMAP_DSP_FBEXPORT */
+
+/*
+ * DSP control device file operations
+ */
+static int dsp_ctl_ioctl(struct inode *inode, struct file *file,
+                        unsigned int cmd, unsigned long arg)
+{
+       int ret = 0;
+
+       switch (cmd) {
+       /*
+        * command level 1: commands which don't need lock
+        */
+       case DSPCTL_IOCTL_RUN:
+               dsp_cpustat_request(CPUSTAT_RUN);
+               break;
+
+       case DSPCTL_IOCTL_RESET:
+               dsp_cpustat_request(CPUSTAT_RESET);
+               break;
+
+       case DSPCTL_IOCTL_SETRSTVECT:
+               ret = dsp_set_rstvect((dsp_long_t)arg);
+               break;
+
+#ifdef CONFIG_ARCH_OMAP1
+       case DSPCTL_IOCTL_CPU_IDLE:
+               dsp_cpustat_request(CPUSTAT_CPU_IDLE);
+               break;
+
+       case DSPCTL_IOCTL_GBL_IDLE:
+               dsp_cpustat_request(CPUSTAT_GBL_IDLE);
+               break;
+
+       case DSPCTL_IOCTL_MPUI_WORDSWAP_ON:
+               mpui_wordswap_on();
+               break;
+
+       case DSPCTL_IOCTL_MPUI_WORDSWAP_OFF:
+               mpui_wordswap_off();
+               break;
+
+       case DSPCTL_IOCTL_MPUI_BYTESWAP_ON:
+               mpui_byteswap_on();
+               break;
+
+       case DSPCTL_IOCTL_MPUI_BYTESWAP_OFF:
+               mpui_byteswap_off();
+               break;
+#endif /* CONFIG_ARCH_OMAP1 */
+
+       case DSPCTL_IOCTL_TASKCNT:
+               ret = dsp_task_count();
+               break;
+
+       case DSPCTL_IOCTL_MBSEND:
+               {
+                       struct omap_dsp_mailbox_cmd u_cmd;
+                       mbox_msg_t msg;
+                       if (copy_from_user(&u_cmd, (void *)arg, sizeof(u_cmd)))
+                               return -EFAULT;
+                       msg = (u_cmd.cmd << 16) | u_cmd.data;
+                       ret = dsp_mbcmd_send((struct mbcmd *)&msg);
+                       break;
+               }
+
+       case DSPCTL_IOCTL_SETVAR:
+               {
+                       struct omap_dsp_varinfo var;
+                       if (copy_from_user(&var, (void *)arg, sizeof(var)))
+                               return -EFAULT;
+                       ret = dsp_setvar(var.varid, var.val[0]);
+                       break;
+               }
+
+       case DSPCTL_IOCTL_RUNLEVEL:
+               ret = dsp_set_runlevel(arg);
+               break;
+
+#ifdef CONFIG_OMAP_DSP_FBEXPORT
+       case DSPCTL_IOCTL_FBEN:
+               ret = dsp_fbstat_request(FBSTAT_ENABLED);
+               break;
+#endif
+
+       /*
+        * command level 2: commands which need lock
+        */
+       case DSPCTL_IOCTL_DSPCFG:
+               ret = dsp_cfgstat_request(CFGSTAT_READY);
+               break;
+
+       case DSPCTL_IOCTL_DSPUNCFG:
+               ret = dsp_cfgstat_request(CFGSTAT_CLEAN);
+               break;
+
+       case DSPCTL_IOCTL_POLL:
+               ret = dsp_poll();
+               break;
+
+#ifdef CONFIG_OMAP_DSP_FBEXPORT
+       case DSPCTL_IOCTL_FBDIS:
+               ret = dsp_fbstat_request(FBSTAT_DISABLED);
+               break;
+#endif
+
+       case DSPCTL_IOCTL_SUSPEND:
+               if ((ret = dsp_cfgstat_request(CFGSTAT_SUSPEND)) < 0)
+                       break;
+               dsp_cpustat_request(CPUSTAT_RESET);
+               break;
+
+       case DSPCTL_IOCTL_RESUME:
+               if ((ret = dsp_cfgstat_request(CFGSTAT_RESUME)) < 0)
+                       break;
+               dsp_cpustat_request(CPUSTAT_RUN);
+               break;
+
+       case DSPCTL_IOCTL_REGMEMR:
+               {
+                       struct omap_dsp_reginfo *u_reg = (void *)arg;
+                       u16 adr, val;
+
+                       if (copy_from_user(&adr, &u_reg->adr, sizeof(u16)))
+                               return -EFAULT;
+                       if ((ret = dsp_regread(SPACE_MEM, adr, &val)) < 0)
+                               return ret;
+                       if (copy_to_user(&u_reg->val, &val, sizeof(u16)))
+                               return -EFAULT;
+                       break;
+               }
+
+       case DSPCTL_IOCTL_REGMEMW:
+               {
+                       struct omap_dsp_reginfo reg;
+
+                       if (copy_from_user(&reg, (void *)arg, sizeof(reg)))
+                               return -EFAULT;
+                       ret = dsp_regwrite(SPACE_MEM, reg.adr, reg.val);
+                       break;
+               }
+
+       case DSPCTL_IOCTL_REGIOR:
+               {
+                       struct omap_dsp_reginfo *u_reg = (void *)arg;
+                       u16 adr, val;
+
+                       if (copy_from_user(&adr, &u_reg->adr, sizeof(u16)))
+                               return -EFAULT;
+                       if ((ret = dsp_regread(SPACE_IO, adr, &val)) < 0)
+                               return ret;
+                       if (copy_to_user(&u_reg->val, &val, sizeof(u16)))
+                               return -EFAULT;
+                       break;
+               }
+
+       case DSPCTL_IOCTL_REGIOW:
+               {
+                       struct omap_dsp_reginfo reg;
+
+                       if (copy_from_user(&reg, (void *)arg, sizeof(reg)))
+                               return -EFAULT;
+                       ret = dsp_regwrite(SPACE_IO, reg.adr, reg.val);
+                       break;
+               }
+
+       case DSPCTL_IOCTL_GETVAR:
+               {
+                       struct omap_dsp_varinfo *u_var = (void *)arg;
+                       u8 varid;
+                       u16 val[5]; /* maximum */
+                       int argc;
+
+                       if (copy_from_user(&varid, &u_var->varid, sizeof(u8)))
+                               return -EFAULT;
+                       switch (varid) {
+                       case VARID_ICRMASK:
+                               argc = 1;
+                               break;
+                       case VARID_LOADINFO:
+                               argc = 5;
+                               break;
+                       default:
+                               return -EINVAL;
+                       }
+                       if ((ret = dsp_getvar(varid, val)) < 0)
+                               return ret;
+                       if (copy_to_user(&u_var->val, val, sizeof(u16) * argc))
+                               return -EFAULT;
+                       break;
+               }
+
+       default:
+               return -ENOIOCTLCMD;
+       }
+
+       return ret;
+}
+
+/*
+ * functions called from mailbox interrupt routine
+ */
+void mbox_suspend(struct mbcmd *mb)
+{
+       misc_mbcmd_response(mb, 0, 0);
+}
+
+void mbox_dspcfg(struct mbcmd *mb)
+{
+       u8 last   = mb->cmd_l & 0x80;
+       u8 cfgcmd = mb->cmd_l & 0x7f;
+       static dsp_long_t tmp_ipb_adr;
+
+       if (!waitqueue_active(&misc_mb_wait.wait_q) ||
+           (misc_mb_wait.cmd_h != MBOX_CMD_DSP_DSPCFG)) {
+               printk(KERN_WARNING
+                      "mbox: DSPCFG command received, "
+                      "but nobody is waiting for it...\n");
+               return;
+       }
+
+       /* mailbox protocol check */
+       if (cfgcmd == DSPCFG_PROTREV) {
+               mbox_revision = mb->data;
+               if (mbox_revision == MBPROT_REVISION)
+                       return;
+#ifdef OLD_BINARY_SUPPORT
+               else if ((mbox_revision == MBREV_3_0) ||
+                        (mbox_revision == MBREV_3_2)) {
+                       printk(KERN_WARNING
+                              "mbox: ***** old DSP binary *****\n"
+                              "  Please update your DSP application.\n");
+                       return;
+               }
+#endif
+               else {
+                       printk(KERN_ERR
+                              "mbox: protocol revision check error!\n"
+                              "  expected=0x%04x, received=0x%04x\n",
+                              MBPROT_REVISION, mb->data);
+                       mbox_revision = -1;
+                       goto abort1;
+               }
+       }
+
+       /*
+        * following commands are accepted only after
+        * revision check has been passed.
+        */
+       if (!mbox_revision < 0) {
+               printk(KERN_INFO
+                      "mbox: DSPCFG command received, "
+                      "but revision check has not been passed.\n");
+               return;
+       }
+
+       switch (cfgcmd) {
+       case DSPCFG_SYSADRH:
+               tmp_ipb_adr = (u32)mb->data << 16;
+               break;
+
+       case DSPCFG_SYSADRL:
+               tmp_ipb_adr |= mb->data;
+               break;
+
+       case DSPCFG_ABORT:
+               goto abort1;
+
+       default:
+               printk(KERN_ERR
+                      "mbox: Unknown CFG command: cmd_l=0x%02x, data=0x%04x\n",
+                      mb->cmd_l, mb->data);
+               return;
+       }
+
+       if (last) {
+               void *badr;
+               u16 bln;
+               u16 bsz;
+               volatile u16 *buf;
+               void *ipb_sys_da, *ipb_sys_ad;
+               void *mbseq;     /* FIXME: 3.4 obsolete */
+               short *dbg_buf;
+               u16 dbg_buf_sz, dbg_line_sz;
+               struct mem_sync_struct mem_sync, *mem_syncp;
+
+               ipb_sys_da = dspword_to_virt(tmp_ipb_adr);
+               if (ipbuf_sys_config(ipb_sys_da, DIR_D2A) < 0)
+                       goto abort1;
+
+               if (dsp_mem_enable(ipbuf_sys_da) < 0) {
+                       printk(KERN_ERR "mbox: DSPCFG - ipbuf_sys_da read failed!\n");
+                       goto abort1;
+               }
+               if (sync_with_dsp(&ipbuf_sys_da->s, TID_ANON, 10) < 0) {
+                       printk(KERN_ERR "mbox: DSPCFG - IPBUF sync failed!\n");
+                       dsp_mem_disable(ipbuf_sys_da);
+                       goto abort1;
+               }
+               /*
+                * read configuration data on system IPBUF
+                * we must read with 16bit-access
+                */
+#ifdef OLD_BINARY_SUPPORT
+               if (mbox_revision == MBPROT_REVISION) {
+#endif
+                       buf = ipbuf_sys_da->d;
+                       n_stask        = buf[0];
+                       bln            = buf[1];
+                       bsz            = buf[2];
+                       badr           = MKVIRT(buf[3], buf[4]);
+                       /* ipb_sys_da     = MKVIRT(buf[5], buf[6]); */
+                       ipb_sys_ad     = MKVIRT(buf[7], buf[8]);
+                       mbseq          = MKVIRT(buf[9], buf[10]);
+                       dbg_buf        = MKVIRT(buf[11], buf[12]);
+                       dbg_buf_sz     = buf[13];
+                       dbg_line_sz    = buf[14];
+                       mem_sync.DARAM = MKVIRT(buf[15], buf[16]);
+                       mem_sync.SARAM = MKVIRT(buf[17], buf[18]);
+                       mem_sync.SDRAM = MKVIRT(buf[19], buf[20]);
+                       mem_syncp = &mem_sync;
+#ifdef OLD_BINARY_SUPPORT
+               } else if (mbox_revision == MBREV_3_2) {
+                       buf = ipbuf_sys_da->d;
+                       n_stask     = buf[0];
+                       bln         = buf[1];
+                       bsz         = buf[2];
+                       badr        = MKVIRT(buf[3], buf[4]);
+                       /* ipb_sys_da  = MKVIRT(buf[5], buf[6]); */
+                       ipb_sys_ad  = MKVIRT(buf[7], buf[8]);
+                       mbseq       = MKVIRT(buf[9], buf[10]);
+                       dbg_buf     = NULL;
+                       dbg_buf_sz  = 0;
+                       dbg_line_sz = 0;
+                       mem_syncp   = NULL;
+               } else if (mbox_revision == MBREV_3_0) {
+                       buf = ipbuf_sys_da->d;
+                       n_stask     = buf[0];
+                       bln         = buf[1];
+                       bsz         = buf[2];
+                       badr        = MKVIRT(buf[3], buf[4]);
+                       /* bkeep       = buf[5]; */
+                       /* ipb_sys_da  = MKVIRT(buf[6], buf[7]); */
+                       ipb_sys_ad  = MKVIRT(buf[8], buf[9]);
+                       mbseq       = MKVIRT(buf[10], buf[11]);
+                       dbg_buf     = NULL;
+                       dbg_buf_sz  = 0;
+                       dbg_line_sz = 0;
+                       mem_syncp   = NULL;
+               } else { /* should not occur */
+                       dsp_mem_disable(ipbuf_sys_da);
+                       goto abort1;
+               }
+#endif /* OLD_BINARY_SUPPORT */
+
+               release_ipbuf_pvt(ipbuf_sys_da);
+               dsp_mem_disable(ipbuf_sys_da);
+
+               /*
+                * following configurations need to be done before
+                * waking up the dspcfg initiator process.
+                */
+               if (ipbuf_sys_config(ipb_sys_ad, DIR_A2D) < 0)
+                       goto abort1;
+               if (ipbuf_config(bln, bsz, badr) < 0)
+                       goto abort1;
+               if (dsp_mbox_config(mbseq) < 0)
+                       goto abort2;
+               if (dsp_dbg_config(dbg_buf, dbg_buf_sz, dbg_line_sz) < 0)
+                       goto abort2;
+               if (dsp_mem_sync_config(mem_syncp) < 0)
+                       goto abort2;
+
+               misc_mb_wait.cmd_h = 0;
+               wake_up_interruptible(&misc_mb_wait.wait_q);
+       }
+       return;
+
+abort2:
+       ipbuf_stop();
+abort1:
+       wake_up_interruptible(&misc_mb_wait.wait_q);
+       return;
+}
+
+void mbox_poll(struct mbcmd *mb)
+{
+       misc_mbcmd_response(mb, 0, 0);
+}
+
+void mbox_regrw(struct mbcmd *mb)
+{
+       switch (mb->cmd_l) {
+       case REGRW_DATA:
+               misc_mbcmd_response(mb, 1, 0);
+               break;
+       default:
+               printk(KERN_ERR
+                      "mbox: Illegal REGRW command: "
+                      "cmd_l=0x%02x, data=0x%04x\n", mb->cmd_l, mb->data);
+               return;
+       }
+}
+
+void mbox_getvar(struct mbcmd *mb)
+{
+       switch (mb->cmd_l) {
+       case VARID_ICRMASK:
+               misc_mbcmd_response(mb, 1, 1);
+               break;
+       case VARID_LOADINFO:
+               misc_mbcmd_response(mb, 5, 1);
+               break;
+       default:
+               printk(KERN_ERR
+                      "mbox: Illegal GETVAR command: "
+                      "cmd_l=0x%02x, data=0x%04x\n", mb->cmd_l, mb->data);
+               return;
+       }
+}
+
+void mbox_fbctl_disable(struct mbcmd *mb)
+{
+       misc_mbcmd_response(mb, 0, 0);
+}
+
+struct file_operations dsp_ctl_fops = {
+       .owner   = THIS_MODULE,
+       .ioctl   = dsp_ctl_ioctl,
+};
+
+/*
+ * sysfs files
+ */
+
+/* ifver */
+static ssize_t ifver_show(struct device *dev, struct device_attribute *attr,
+                         char *buf)
+{
+       int len = 0;
+
+       /*
+        * I/F VERSION descriptions:
+        *
+        * 3.2: sysfs / udev support
+        *      KMEM_RESERVE / KMEM_RELEASE ioctls for mem device
+        * 3.3: added following ioctls
+        *      DSPCTL_IOCTL_GBL_IDLE
+        *      DSPCTL_IOCTL_CPU_IDLE (instead of DSPCTL_IOCTL_IDLE)
+        *      DSPCTL_IOCTL_POLL
+        */
+
+       /*
+        * print all supporting I/F VERSIONs, like followings.
+        *
+        * len += sprintf(buf, "3.2\n");
+        * len += sprintf(buf, "3.3\n");
+        */
+       len += sprintf(buf + len, "3.2\n");
+       len += sprintf(buf + len, "3.3\n");
+
+       return len;
+}
+
+/* cpustat */
+static char *cpustat_name[CPUSTAT_MAX] = {
+       [CPUSTAT_RESET]    = "reset",
+#ifdef CONFIG_ARCH_OMAP1
+       [CPUSTAT_GBL_IDLE] = "gbl_idle",
+       [CPUSTAT_CPU_IDLE] = "cpu_idle",
+#endif
+       [CPUSTAT_RUN]      = "run",
+};
+
+static ssize_t cpustat_show(struct device *dev, struct device_attribute *attr,
+                           char *buf)
+{
+       return sprintf(buf, "%s\n", cpustat_name[dsp_cpustat_get_stat()]);
+}
+
+/* icrmask */
+static ssize_t icrmask_show(struct device *dev, struct device_attribute *attr,
+                           char *buf)
+{
+       return sprintf(buf, "0x%04x\n", dsp_cpustat_get_icrmask());
+}
+
+static ssize_t icrmask_store(struct device *dev, struct device_attribute *attr,
+                            const char *buf, size_t count)
+{
+       u16 mask;
+       int ret;
+
+       mask = simple_strtol(buf, NULL, 16);
+       dsp_cpustat_set_icrmask(mask);
+
+       if (dsp_cfgstat_get_stat() == CFGSTAT_READY) {
+               ret = dsp_setvar(VARID_ICRMASK, mask);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return count;
+}
+
+/* loadinfo */
+static ssize_t loadinfo_show(struct device *dev, struct device_attribute *attr,
+                            char *buf)
+{
+       int len;
+       int ret;
+       u16 val[5];
+
+       if ((ret = dsp_getvar(VARID_LOADINFO, val)) < 0)
+               return ret;
+
+       /*
+        * load info value range is 0(free) - 10000(busy):
+        * if CPU load is not measured on DSP, it sets 0xffff at val[0].
+        */
+
+       if (val[0] == 0xffff) {
+               len = sprintf(buf,
+                             "currently DSP load info is not available.\n");
+               goto out;
+       }
+
+       len = sprintf(buf,
+                     "DSP load info:\n"
+                     "  10ms average = %3d.%02d%%\n"
+                     "  1sec average = %3d.%02d%%  busiest 10ms = %3d.%02d%%\n"
+                     "  1min average = %3d.%02d%%  busiest 1s   = %3d.%02d%%\n",
+                     val[0]/100, val[0]%100,
+                     val[1]/100, val[1]%100, val[2]/100, val[2]%100,
+                     val[3]/100, val[3]%100, val[4]/100, val[4]%100);
+out:
+       return len;
+}
+
+void __init dsp_ctl_init(void)
+{
+       int ret;
+
+       ret = device_create_file(omap_dsp->dev, &dev_attr_ifver);
+       ret |= device_create_file(omap_dsp->dev, &dev_attr_cpustat);
+       ret |= device_create_file(omap_dsp->dev, &dev_attr_icrmask);
+       if (ret)
+               printk(KERN_ERR "device_create_file failed: %d\n", ret);
+}
+
+void dsp_ctl_exit(void)
+{
+       device_remove_file(omap_dsp->dev, &dev_attr_ifver);
+       device_remove_file(omap_dsp->dev, &dev_attr_cpustat);
+       device_remove_file(omap_dsp->dev, &dev_attr_icrmask);
+}
diff --git a/arch/arm/plat-omap/dsp/dsp_ctl_core.c b/arch/arm/plat-omap/dsp/dsp_ctl_core.c
new file mode 100644 (file)
index 0000000..04420df
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2004-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/major.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include "dsp.h"
+
+#define CTL_MINOR      0
+#define MEM_MINOR      1
+#define TWCH_MINOR     2
+#define ERR_MINOR      3
+
+static struct class *dsp_ctl_class;
+extern struct file_operations dsp_ctl_fops,
+                             dsp_mem_fops,
+                             dsp_twch_fops,
+                             dsp_err_fops;
+
+static int dsp_ctl_core_open(struct inode *inode, struct file *file)
+{
+       static DEFINE_MUTEX(open_lock);
+       int ret = 0;
+
+       mutex_lock_interruptible(&open_lock);
+       if (omap_dsp->initialized == 0) {
+               ret = dsp_late_init();
+               if (ret != 0) {
+                       mutex_unlock(&open_lock);
+                       return ret;
+               }
+               omap_dsp->initialized = 1;
+       }
+       mutex_unlock(&open_lock);
+
+       switch (iminor(inode)) {
+       case CTL_MINOR:
+               file->f_op = &dsp_ctl_fops;
+               break;
+       case MEM_MINOR:
+               file->f_op = &dsp_mem_fops;
+               break;
+       case TWCH_MINOR:
+               file->f_op = &dsp_twch_fops;
+               break;
+       case ERR_MINOR:
+               file->f_op = &dsp_err_fops;
+               break;
+       default:
+               return -ENXIO;
+       }
+       if (file->f_op && file->f_op->open)
+               return file->f_op->open(inode, file);
+       return 0;
+}
+
+static struct file_operations dsp_ctl_core_fops = {
+       .owner = THIS_MODULE,
+       .open  = dsp_ctl_core_open,
+};
+
+static const struct dev_list {
+       unsigned int    minor;
+       char            *devname;
+       umode_t         mode;
+} dev_list[] = {
+       {CTL_MINOR,  "dspctl",  S_IRUSR | S_IWUSR},
+       {MEM_MINOR,  "dspmem",  S_IRUSR | S_IWUSR | S_IRGRP},
+       {TWCH_MINOR, "dsptwch", S_IRUSR | S_IWUSR | S_IRGRP},
+       {ERR_MINOR,  "dsperr",  S_IRUSR | S_IRGRP},
+};
+
+int __init dsp_ctl_core_init(void)
+{
+       int retval;
+       int i;
+
+       retval = register_chrdev(OMAP_DSP_CTL_MAJOR, "dspctl",
+                                &dsp_ctl_core_fops);
+       if (retval < 0) {
+               printk(KERN_ERR
+                      "omapdsp: failed to register dspctl device: %d\n",
+                      retval);
+               return retval;
+       }
+
+       dsp_ctl_class = class_create(THIS_MODULE, "dspctl");
+       for (i = 0; i < ARRAY_SIZE(dev_list); i++) {
+               class_device_create(dsp_ctl_class, NULL,
+                                   MKDEV(OMAP_DSP_CTL_MAJOR,
+                                         dev_list[i].minor),
+                                   NULL, dev_list[i].devname);
+       }
+
+       return 0;
+}
+
+void dsp_ctl_core_exit(void)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(dev_list); i++) {
+               class_device_destroy(dsp_ctl_class,
+                                    MKDEV(OMAP_DSP_CTL_MAJOR,
+                                          dev_list[i].minor));
+       }
+       class_destroy(dsp_ctl_class);
+
+       unregister_chrdev(OMAP_DSP_CTL_MAJOR, "dspctl");
+}
diff --git a/arch/arm/plat-omap/dsp/dsp_mbcmd.h b/arch/arm/plat-omap/dsp/dsp_mbcmd.h
new file mode 100644 (file)
index 0000000..d30c3bc
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/*
+ * mailbox command: 0x00 - 0x7f
+ * when a driver wants to use mailbox, it must reserve mailbox commands here.
+ */
+#define MBOX_CMD_DSP_WDSND     0x10
+#define MBOX_CMD_DSP_WDREQ     0x11
+#define MBOX_CMD_DSP_BKSND     0x20
+#define MBOX_CMD_DSP_BKREQ     0x21
+#define MBOX_CMD_DSP_BKYLD     0x23
+#define MBOX_CMD_DSP_BKSNDP    0x24
+#define MBOX_CMD_DSP_BKREQP    0x25
+#define MBOX_CMD_DSP_TCTL      0x30
+#define MBOX_CMD_DSP_TCTLDATA  0x31
+#define MBOX_CMD_DSP_POLL      0x32
+#define MBOX_CMD_DSP_WDT       0x50
+#define MBOX_CMD_DSP_RUNLEVEL  0x51
+#define MBOX_CMD_DSP_PM                0x52
+#define MBOX_CMD_DSP_SUSPEND   0x53
+#define MBOX_CMD_DSP_KFUNC     0x54
+#define MBOX_CMD_DSP_TCFG      0x60
+#define MBOX_CMD_DSP_TADD      0x62
+#define MBOX_CMD_DSP_TDEL      0x63
+#define MBOX_CMD_DSP_TSTOP     0x65
+#define MBOX_CMD_DSP_DSPCFG    0x70
+#define MBOX_CMD_DSP_REGRW     0x72
+#define MBOX_CMD_DSP_GETVAR    0x74
+#define MBOX_CMD_DSP_SETVAR    0x75
+#define MBOX_CMD_DSP_ERR       0x78
+#define MBOX_CMD_DSP_DBG       0x79
+
+/*
+ * DSP mailbox protocol definitions
+ */
+#define MBPROT_REVISION        0x0019
+
+#define TCTL_TINIT             0x0000
+#define TCTL_TEN               0x0001
+#define TCTL_TDIS              0x0002
+#define TCTL_TCLR              0x0003
+#define TCTL_TCLR_FORCE                0x0004
+
+#define RUNLEVEL_USER          0x01
+#define RUNLEVEL_SUPER         0x0e
+#define RUNLEVEL_RECOVERY      0x10
+
+#define PM_DISABLE             0x00
+#define PM_ENABLE              0x01
+
+#define KFUNC_FBCTL            0x00
+#define KFUNC_POWER            0x01
+
+#define FBCTL_UPD              0x0000
+#define FBCTL_ENABLE           0x0002
+#define FBCTL_DISABLE          0x0003
+
+/* KFUNC_POWER */
+#define AUDIO_PWR_UP           0x0000  /* ARM(exe/ack) <->  DSP(req)   */
+#define AUDIO_PWR_DOWN         0x0001  /* ARM(exe)     <-  DSP(req)    */
+#define AUDIO_PWR_DOWN1                AUDIO_PWR_DOWN
+#define AUDIO_PWR_DOWN2                0x0002
+#define DSP_PWR_UP             0x0003  /* ARM(exe/snd) ->  DSP(exe)    */
+#define DSP_PWR_DOWN           0x0004  /* ARM(exe)     <-  DSP(req)    */
+#define DVFS_START             0x0006  /* ARM(req)     <-> DSP(exe/ack)*/
+#define DVFS_STOP              0x0007  /* ARM(req)      -> DSP(exe)    */
+
+#define TDEL_SAFE              0x0000
+#define TDEL_KILL              0x0001
+
+#define DSPCFG_REQ             0x00
+#define DSPCFG_SYSADRH         0x28
+#define DSPCFG_SYSADRL         0x29
+#define DSPCFG_PROTREV         0x70
+#define DSPCFG_ABORT           0x78
+#define DSPCFG_LAST            0x80
+
+#define REGRW_MEMR             0x00
+#define REGRW_MEMW             0x01
+#define REGRW_IOR              0x02
+#define REGRW_IOW              0x03
+#define REGRW_DATA             0x04
+
+#define VARID_ICRMASK          0x00
+#define VARID_LOADINFO         0x01
+
+#define TTYP_ARCV              0x0001
+#define TTYP_ASND              0x0002
+#define TTYP_BKMD              0x0004
+#define TTYP_BKDM              0x0008
+#define TTYP_PVMD              0x0010
+#define TTYP_PVDM              0x0020
+
+#define EID_BADTID             0x10
+#define EID_BADTCN             0x11
+#define EID_BADBID             0x20
+#define EID_BADCNT             0x21
+#define EID_NOTLOCKED          0x22
+#define EID_STVBUF             0x23
+#define EID_BADADR             0x24
+#define EID_BADTCTL            0x30
+#define EID_BADPARAM           0x50
+#define EID_FATAL              0x58
+#define EID_NOMEM              0xc0
+#define EID_NORES              0xc1
+#define EID_IPBFULL            0xc2
+#define EID_WDT                        0xd0
+#define EID_TASKNOTRDY         0xe0
+#define EID_TASKBSY            0xe1
+#define EID_TASKERR            0xef
+#define EID_BADCFGTYP          0xf0
+#define EID_DEBUG              0xf8
+#define EID_BADSEQ             0xfe
+#define EID_BADCMD             0xff
+
+#define TNM_LEN                        16
+
+#define TID_FREE               0xff
+#define TID_ANON               0xfe
+
+#define BID_NULL               0xffff
+#define BID_PVT                        0xfffe
diff --git a/arch/arm/plat-omap/dsp/dsp_mem.c b/arch/arm/plat-omap/dsp/dsp_mem.c
new file mode 100644 (file)
index 0000000..8442a96
--- /dev/null
@@ -0,0 +1,2542 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * Conversion to mempool API and ARM MMU section mapping
+ * by Paul Mundt <paul.mundt@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/fb.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/mempool.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+#include <asm/arch/tc.h>
+#include <asm/arch/omapfb.h>
+#include <asm/arch/mailbox.h>
+#include <asm/arch/dsp_common.h>
+#include "uaccess_dsp.h"
+#include "dsp_mbcmd.h"
+#include "dsp.h"
+#include "ioctl.h"
+#include "ipbuf.h"
+
+#ifdef CONFIG_ARCH_OMAP2
+#define IOMAP_VAL      0x3f
+#endif
+
+#define SZ_1KB 0x400
+#define SZ_4KB 0x1000
+#define SZ_64KB        0x10000
+#define SZ_1MB 0x100000
+#define SZ_16MB        0x1000000
+#define is_aligned(adr,align)  (!((adr)&((align)-1)))
+#define ORDER_4KB      (12 - PAGE_SHIFT)
+#define ORDER_64KB     (16 - PAGE_SHIFT)
+#define ORDER_1MB      (20 - PAGE_SHIFT)
+
+/*
+ * absorb DSP MMU register size and location difference
+ */
+#if defined(CONFIG_ARCH_OMAP1)
+typedef u16 dsp_mmu_reg_t;
+#define dsp_mmu_read_reg(a)    omap_readw(a)
+#define dsp_mmu_write_reg(v,a) omap_writew(v,a)
+#elif defined(CONFIG_ARCH_OMAP2)
+typedef u32 dsp_mmu_reg_t;
+#define dsp_mmu_read_reg(a)    readl(a)
+#define dsp_mmu_write_reg(v,a) writel(v,a)
+#define dsp_ipi_read_reg(a)    readl(a)
+#define dsp_ipi_write_reg(v,a) writel(v,a)
+#endif
+
+#if defined(CONFIG_ARCH_OMAP1)
+
+#define dsp_mmu_enable() \
+       do { \
+               dsp_mmu_write_reg(DSP_MMU_CNTL_MMU_EN | DSP_MMU_CNTL_RESET_SW, \
+                                 DSP_MMU_CNTL); \
+       } while(0)
+#define dsp_mmu_disable() \
+       do { \
+               dsp_mmu_write_reg(0, DSP_MMU_CNTL); \
+       } while(0)
+#define __dsp_mmu_itack() \
+       do { \
+               dsp_mmu_write_reg(DSP_MMU_IT_ACK_IT_ACK, DSP_MMU_IT_ACK); \
+       } while(0)
+
+#elif defined(CONFIG_ARCH_OMAP2)
+
+#define dsp_mmu_enable() \
+       do { \
+               dsp_mmu_write_reg(DSP_MMU_CNTL_MMUENABLE, DSP_MMU_CNTL); \
+       } while(0)
+#define dsp_mmu_disable() \
+       do { \
+               dsp_mmu_write_reg(0, DSP_MMU_CNTL); \
+       } while(0)
+#define dsp_mmu_reset() \
+       do { \
+               dsp_mmu_write_reg(dsp_mmu_read_reg(DSP_MMU_SYSCONFIG) | \
+                                 DSP_MMU_SYSCONFIG_SOFTRESET, \
+                                 DSP_MMU_SYSCONFIG); \
+       } while(0)
+
+#endif /* CONFIG_ARCH_OMAP2 */
+
+#define dsp_mmu_flush() \
+       do { \
+               dsp_mmu_write_reg(DSP_MMU_FLUSH_ENTRY_FLUSH_ENTRY, \
+                                 DSP_MMU_FLUSH_ENTRY); \
+       } while(0)
+#define __dsp_mmu_gflush() \
+       do { \
+               dsp_mmu_write_reg(DSP_MMU_GFLUSH_GFLUSH, DSP_MMU_GFLUSH); \
+       } while(0)
+
+/*
+ * absorb register name difference
+ */
+#ifdef CONFIG_ARCH_OMAP1
+#define DSP_MMU_CAM_P                  DSP_MMU_CAM_L_P
+#define DSP_MMU_CAM_V                  DSP_MMU_CAM_L_V
+#define DSP_MMU_CAM_PAGESIZE_MASK      DSP_MMU_CAM_L_PAGESIZE_MASK
+#define DSP_MMU_CAM_PAGESIZE_1MB       DSP_MMU_CAM_L_PAGESIZE_1MB
+#define DSP_MMU_CAM_PAGESIZE_64KB      DSP_MMU_CAM_L_PAGESIZE_64KB
+#define DSP_MMU_CAM_PAGESIZE_4KB       DSP_MMU_CAM_L_PAGESIZE_4KB
+#define DSP_MMU_CAM_PAGESIZE_1KB       DSP_MMU_CAM_L_PAGESIZE_1KB
+#endif /* CONFIG_ARCH_OMAP1 */
+
+/*
+ * OMAP1 EMIFF access
+ */
+#ifdef CONFIG_ARCH_OMAP1
+#define EMIF_PRIO_LB_MASK      0x0000f000
+#define EMIF_PRIO_LB_SHIFT     12
+#define EMIF_PRIO_DMA_MASK     0x00000f00
+#define EMIF_PRIO_DMA_SHIFT    8
+#define EMIF_PRIO_DSP_MASK     0x00000070
+#define EMIF_PRIO_DSP_SHIFT    4
+#define EMIF_PRIO_MPU_MASK     0x00000007
+#define EMIF_PRIO_MPU_SHIFT    0
+#define set_emiff_dma_prio(prio) \
+       do { \
+               omap_writel((omap_readl(OMAP_TC_OCPT1_PRIOR) & \
+                            ~EMIF_PRIO_DMA_MASK) | \
+                           ((prio) << EMIF_PRIO_DMA_SHIFT), \
+                           OMAP_TC_OCPT1_PRIOR); \
+       } while(0)
+#endif /* CONFIG_ARCH_OMAP1 */
+
+enum exmap_type_e {
+       EXMAP_TYPE_MEM,
+       EXMAP_TYPE_FB
+};
+
+struct exmap_tbl_entry {
+       unsigned int valid:1;
+       unsigned int prsvd:1;   /* preserved */
+       int usecount;           /* reference count by mmap */
+       enum exmap_type_e type;
+       void *buf;              /* virtual address of the buffer,
+                                * i.e. 0xc0000000 - */
+       void *vadr;             /* DSP shadow space,
+                                * i.e. 0xe0000000 - 0xe0ffffff */
+       unsigned int order;
+       struct {
+               int prev;
+               int next;
+       } link;                 /* grouping */
+};
+
+#define INIT_EXMAP_TBL_ENTRY(ent,b,v,typ,od) \
+       do {\
+               (ent)->buf       = (b); \
+               (ent)->vadr      = (v); \
+               (ent)->valid     = 1; \
+               (ent)->prsvd     = 0; \
+               (ent)->usecount  = 0; \
+               (ent)->type      = (typ); \
+               (ent)->order     = (od); \
+               (ent)->link.next = -1; \
+               (ent)->link.prev = -1; \
+       } while (0)
+
+#define INIT_EXMAP_TBL_ENTRY_4KB_PRESERVED(ent,b,v) \
+       do {\
+               (ent)->buf       = (b); \
+               (ent)->vadr      = (v); \
+               (ent)->valid     = 1; \
+               (ent)->prsvd     = 1; \
+               (ent)->usecount  = 0; \
+               (ent)->type      = EXMAP_TYPE_MEM; \
+               (ent)->order     = 0; \
+               (ent)->link.next = -1; \
+               (ent)->link.prev = -1; \
+       } while (0)
+
+#define DSP_MMU_TLB_LINES      32
+static struct exmap_tbl_entry exmap_tbl[DSP_MMU_TLB_LINES];
+static int exmap_preserved_cnt;
+static DECLARE_RWSEM(exmap_sem);
+
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+static struct omapfb_notifier_block *omapfb_nb;
+static int omapfb_ready;
+#endif
+
+struct cam_ram_regset {
+#if defined(CONFIG_ARCH_OMAP1)
+       dsp_mmu_reg_t cam_h;
+       dsp_mmu_reg_t cam_l;
+       dsp_mmu_reg_t ram_h;
+       dsp_mmu_reg_t ram_l;
+#elif defined(CONFIG_ARCH_OMAP2)
+       dsp_mmu_reg_t cam;
+       dsp_mmu_reg_t ram;
+#endif
+};
+
+struct tlb_entry {
+       dsp_long_t va;
+       unsigned long pa;
+       dsp_mmu_reg_t pgsz, prsvd, valid;
+#if defined(CONFIG_ARCH_OMAP1)
+       dsp_mmu_reg_t ap;
+#elif defined(CONFIG_ARCH_OMAP2)
+       dsp_mmu_reg_t endian, elsz, mixed;
+#endif
+};
+
+#if defined(CONFIG_ARCH_OMAP1)
+#define INIT_TLB_ENTRY(ent,v,p,ps) \
+       do { \
+               (ent)->va = (v); \
+               (ent)->pa = (p); \
+               (ent)->pgsz = (ps); \
+               (ent)->prsvd = 0; \
+               (ent)->ap = DSP_MMU_RAM_L_AP_FA; \
+       } while (0)
+#define INIT_TLB_ENTRY_4KB_PRESERVED(ent,v,p) \
+       do { \
+               (ent)->va = (v); \
+               (ent)->pa = (p); \
+               (ent)->pgsz = DSP_MMU_CAM_PAGESIZE_4KB; \
+               (ent)->prsvd = DSP_MMU_CAM_P; \
+               (ent)->ap = DSP_MMU_RAM_L_AP_FA; \
+       } while (0)
+#elif defined(CONFIG_ARCH_OMAP2)
+#define INIT_TLB_ENTRY(ent,v,p,ps) \
+       do { \
+               (ent)->va = (v); \
+               (ent)->pa = (p); \
+               (ent)->pgsz = (ps); \
+               (ent)->prsvd = 0; \
+               (ent)->endian = DSP_MMU_RAM_ENDIANNESS_LITTLE; \
+               (ent)->elsz = DSP_MMU_RAM_ELEMENTSIZE_16; \
+               (ent)->mixed = 0; \
+       } while (0)
+#define INIT_TLB_ENTRY_4KB_PRESERVED(ent,v,p) \
+       do { \
+               (ent)->va = (v); \
+               (ent)->pa = (p); \
+               (ent)->pgsz = DSP_MMU_CAM_PAGESIZE_4KB; \
+               (ent)->prsvd = DSP_MMU_CAM_P; \
+               (ent)->endian = DSP_MMU_RAM_ENDIANNESS_LITTLE; \
+               (ent)->elsz = DSP_MMU_RAM_ELEMENTSIZE_16; \
+               (ent)->mixed = 0; \
+       } while (0)
+#define INIT_TLB_ENTRY_4KB_ES32_PRESERVED(ent,v,p) \
+       do { \
+               (ent)->va = (v); \
+               (ent)->pa = (p); \
+               (ent)->pgsz = DSP_MMU_CAM_PAGESIZE_4KB; \
+               (ent)->prsvd = DSP_MMU_CAM_P; \
+               (ent)->endian = DSP_MMU_RAM_ENDIANNESS_LITTLE; \
+               (ent)->elsz = DSP_MMU_RAM_ELEMENTSIZE_32; \
+               (ent)->mixed = 0; \
+       } while (0)
+#endif
+
+#if defined(CONFIG_ARCH_OMAP1)
+#define cam_ram_valid(cr)      ((cr).cam_l & DSP_MMU_CAM_V)
+#elif defined(CONFIG_ARCH_OMAP2)
+#define cam_ram_valid(cr)      ((cr).cam & DSP_MMU_CAM_V)
+#endif
+
+struct tlb_lock {
+       int base;
+       int victim;
+};
+
+static int dsp_exunmap(dsp_long_t dspadr);
+
+static void *dspvect_page;
+static u32 dsp_fault_adr;
+static struct mem_sync_struct mem_sync;
+
+static ssize_t mmu_show(struct device *dev, struct device_attribute *attr,
+                       char *buf);
+static ssize_t exmap_show(struct device *dev, struct device_attribute *attr,
+                         char *buf);
+static ssize_t mempool_show(struct device *dev, struct device_attribute *attr,
+                           char *buf);
+
+static struct device_attribute dev_attr_mmu =     __ATTR_RO(mmu);
+static struct device_attribute dev_attr_exmap =   __ATTR_RO(exmap);
+static struct device_attribute dev_attr_mempool = __ATTR_RO(mempool);
+
+/*
+ * special mempool function:
+ * hope this goes to mm/mempool.c
+ */
+static void *mempool_alloc_from_pool(mempool_t *pool, gfp_t gfp_mask)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&pool->lock, flags);
+       if (likely(pool->curr_nr)) {
+               void *element = pool->elements[--pool->curr_nr];
+               spin_unlock_irqrestore(&pool->lock, flags);
+               return element;
+       }
+       spin_unlock_irqrestore(&pool->lock, flags);
+
+       return mempool_alloc(pool, gfp_mask);
+}
+
+static __inline__ unsigned long lineup_offset(unsigned long adr,
+                                             unsigned long ref,
+                                             unsigned long mask)
+{
+       unsigned long newadr;
+
+       newadr = (adr & ~mask) | (ref & mask);
+       if (newadr < adr)
+               newadr += mask + 1;
+       return newadr;
+}
+
+int dsp_mem_sync_inc(void)
+{
+       if (dsp_mem_enable((void *)dspmem_base) < 0)
+               return -1;
+       if (mem_sync.DARAM)
+               mem_sync.DARAM->ad_arm++;
+       if (mem_sync.SARAM)
+               mem_sync.SARAM->ad_arm++;
+       if (mem_sync.SDRAM)
+               mem_sync.SDRAM->ad_arm++;
+       dsp_mem_disable((void *)dspmem_base);
+       return 0;
+}
+
+/*
+ * dsp_mem_sync_config() is called from mbox1 workqueue
+ */
+int dsp_mem_sync_config(struct mem_sync_struct *sync)
+{
+       size_t sync_seq_sz = sizeof(struct sync_seq);
+
+#ifdef OLD_BINARY_SUPPORT
+       if (sync == NULL) {
+               memset(&mem_sync, 0, sizeof(struct mem_sync_struct));
+               return 0;
+       }
+#endif
+       if ((dsp_mem_type(sync->DARAM, sync_seq_sz) != MEM_TYPE_DARAM) ||
+           (dsp_mem_type(sync->SARAM, sync_seq_sz) != MEM_TYPE_SARAM) ||
+           (dsp_mem_type(sync->SDRAM, sync_seq_sz) != MEM_TYPE_EXTERN)) {
+               printk(KERN_ERR
+                      "omapdsp: mem_sync address validation failure!\n"
+                      "  mem_sync.DARAM = 0x%p,\n"
+                      "  mem_sync.SARAM = 0x%p,\n"
+                      "  mem_sync.SDRAM = 0x%p,\n",
+                      sync->DARAM, sync->SARAM, sync->SDRAM);
+               return -1;
+       }
+       memcpy(&mem_sync, sync, sizeof(struct mem_sync_struct));
+       return 0;
+}
+
+static mempool_t *kmem_pool_1M;
+static mempool_t *kmem_pool_64K;
+
+static void *dsp_pool_alloc(unsigned int __nocast gfp, void *order)
+{
+       return (void *)__get_dma_pages(gfp, (unsigned int)order);
+}
+
+static void dsp_pool_free(void *buf, void *order)
+{
+       free_pages((unsigned long)buf, (unsigned int)order);
+}
+
+static void dsp_kmem_release(void)
+{
+       if (kmem_pool_64K) {
+               mempool_destroy(kmem_pool_64K);
+               kmem_pool_64K = NULL;
+       }
+
+       if (kmem_pool_1M) {
+               mempool_destroy(kmem_pool_1M);
+               kmem_pool_1M = NULL;
+       }
+}
+
+static int dsp_kmem_reserve(unsigned long size)
+{
+       unsigned long len = size;
+
+       /* alignment check */
+       if (!is_aligned(size, SZ_64KB)) {
+               printk(KERN_ERR
+                      "omapdsp: size(0x%lx) is not multiple of 64KB.\n", size);
+               return -EINVAL;
+       }
+
+       if (size > DSPSPACE_SIZE) {
+               printk(KERN_ERR
+                      "omapdsp: size(0x%lx) is larger than DSP memory space "
+                      "size (0x%x.\n", size, DSPSPACE_SIZE);
+               return -EINVAL;
+       }
+
+       if (size >= SZ_1MB) {
+               int nr = size >> 20;
+
+               if (likely(!kmem_pool_1M))
+                       kmem_pool_1M = mempool_create(nr,
+                                                     dsp_pool_alloc,
+                                                     dsp_pool_free,
+                                                     (void *)ORDER_1MB);
+               else
+                       mempool_resize(kmem_pool_1M, kmem_pool_1M->min_nr + nr,
+                                      GFP_KERNEL);
+
+               size &= ~(0xf << 20);
+       }
+
+       if (size >= SZ_64KB) {
+               int nr = size >> 16;
+
+               if (likely(!kmem_pool_64K))
+                       kmem_pool_64K = mempool_create(nr,
+                                                      dsp_pool_alloc,
+                                                      dsp_pool_free,
+                                                      (void *)ORDER_64KB);
+               else
+                       mempool_resize(kmem_pool_64K,
+                                      kmem_pool_64K->min_nr + nr, GFP_KERNEL);
+
+               size &= ~(0xf << 16);
+       }
+
+       if (size)
+               len -= size;
+
+       return len;
+}
+
+static void dsp_mem_free_pages(unsigned long buf, unsigned int order)
+{
+       struct page *page, *ps, *pe;
+
+       ps = virt_to_page(buf);
+       pe = virt_to_page(buf + (1 << (PAGE_SHIFT + order)));
+
+       for (page = ps; page < pe; page++)
+               ClearPageReserved(page);
+
+       if ((order == ORDER_64KB) && likely(kmem_pool_64K))
+               mempool_free((void *)buf, kmem_pool_64K);
+       else if ((order == ORDER_1MB) && likely(kmem_pool_1M))
+               mempool_free((void *)buf, kmem_pool_1M);
+       else
+               free_pages(buf, order);
+}
+
+static inline void
+exmap_alloc_pte(unsigned long virt, unsigned long phys, pgprot_t prot)
+{
+       pgd_t *pgd;
+       pud_t *pud;
+       pmd_t *pmd;
+       pte_t *pte;
+
+       pgd = pgd_offset_k(virt);
+       pud = pud_offset(pgd, virt);
+       pmd = pmd_offset(pud, virt);
+
+       if (pmd_none(*pmd)) {
+               pte = pte_alloc_one_kernel(&init_mm, 0);
+               if (!pte)
+                       return;
+
+               /* note: two PMDs will be set  */
+               pmd_populate_kernel(&init_mm, pmd, pte);
+       }
+
+       pte = pte_offset_kernel(pmd, virt);
+       set_pte_ext(pte, pfn_pte(phys >> PAGE_SHIFT, prot), 0);
+}
+
+#if 0
+static inline int
+exmap_alloc_sect(unsigned long virt, unsigned long phys, int prot)
+{
+       pgd_t *pgd;
+       pud_t *pud;
+       pmd_t *pmd;
+
+       pgd = pgd_offset_k(virt);
+       pud = pud_alloc(&init_mm, pgd, virt);
+       pmd = pmd_alloc(&init_mm, pud, virt);
+
+       if (virt & (1 << 20))
+               pmd++;
+
+       if (!pmd_none(*pmd))
+               /* No good, fall back on smaller mappings. */
+               return -EINVAL;
+
+       *pmd = __pmd(phys | prot);
+       flush_pmd_entry(pmd);
+
+       return 0;
+}
+#endif
+
+/*
+ * ARM MMU operations
+ */
+static int exmap_set_armmmu(unsigned long virt, unsigned long phys,
+                           unsigned long size)
+{
+       long off;
+       pgprot_t prot_pte;
+       int prot_sect;
+
+       printk(KERN_DEBUG
+              "omapdsp: mapping in ARM MMU, v=0x%08lx, p=0x%08lx, sz=0x%lx\n",
+              virt, phys, size);
+
+       prot_pte = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG |
+                           L_PTE_DIRTY | L_PTE_WRITE);
+
+       prot_sect = PMD_TYPE_SECT | PMD_SECT_UNCACHED |
+                   PMD_SECT_AP_WRITE | PMD_DOMAIN(DOMAIN_IO);
+
+       if (cpu_architecture() <= CPU_ARCH_ARMv5)
+               prot_sect |= PMD_BIT4;
+
+       off = phys - virt;
+
+       while ((virt & 0xfffff || (virt + off) & 0xfffff) && size >= PAGE_SIZE) {
+               exmap_alloc_pte(virt, virt + off, prot_pte);
+
+               virt += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+
+       /* XXX: Not yet.. confuses dspfb -- PFM. */
+#if 0
+       while (size >= (PGDIR_SIZE / 2)) {
+               if (exmap_alloc_sect(virt, virt + off, prot_sect) < 0)
+                       break;
+
+               virt += (PGDIR_SIZE / 2);
+               size -= (PGDIR_SIZE / 2);
+       }
+#endif
+
+       while (size >= PAGE_SIZE) {
+               exmap_alloc_pte(virt, virt + off, prot_pte);
+
+               virt += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+
+       BUG_ON(size);
+
+       return 0;
+}
+
+       /* XXX: T.Kobayashi
+        * A process can have old mappings. if we want to clear a pmd,
+        * we need to do it for all proceeses that use the old mapping.
+        */
+#if 0
+static inline void
+exmap_clear_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end)
+{
+       pte_t *pte;
+
+       pte = pte_offset_map(pmd, addr);
+       do {
+               if (pte_none(*pte))
+                       continue;
+
+               pte_clear(&init_mm, addr, pte);
+       } while (pte++, addr += PAGE_SIZE, addr != end);
+
+       pte_unmap(pte - 1);
+}
+
+static inline void
+exmap_clear_pmd_range(pud_t *pud, unsigned long addr, unsigned long end)
+{
+       pmd_t *pmd;
+       unsigned long next;
+
+       pmd = pmd_offset(pud, addr);
+       do {
+               next = pmd_addr_end(addr, end);
+
+               if (addr & (1 << 20))
+                       pmd++;
+
+               if ((pmd_val(*pmd) & PMD_TYPE_MASK) == PMD_TYPE_SECT) {
+                       *pmd = __pmd(0);
+                       clean_pmd_entry(pmd);
+                       continue;
+               }
+
+               if (pmd_none_or_clear_bad(pmd))
+                       continue;
+
+               exmap_clear_pte_range(pmd, addr, next);
+       } while (pmd++, addr = next, addr != end);
+}
+
+static inline void
+exmap_clear_pud_range(pgd_t *pgd, unsigned long addr, unsigned long end)
+{
+       pud_t *pud;
+       unsigned long next;
+
+       pud = pud_offset(pgd, addr);
+       do {
+               next = pud_addr_end(addr, end);
+               if (pud_none_or_clear_bad(pud))
+                       continue;
+
+               exmap_clear_pmd_range(pud, addr, next);
+       } while (pud++, addr = next, addr != end);
+}
+#endif
+
+static void exmap_clear_armmmu(unsigned long virt, unsigned long size)
+{
+#if 0
+       unsigned long next, end;
+       pgd_t *pgd;
+
+       printk(KERN_DEBUG
+              "omapdsp: unmapping in ARM MMU, v=%#010lx, sz=%#lx\n",
+              virt, size);
+
+       pgd = pgd_offset_k(virt);
+       end = virt + size;
+       do {
+               next = pgd_addr_end(virt, end);
+               if (pgd_none_or_clear_bad(pgd))
+                       continue;
+
+               exmap_clear_pud_range(pgd, virt, next);
+       } while (pgd++, virt = next, virt != end);
+#else
+       pgd_t *pgd;
+       pud_t *pud;
+       pmd_t *pmd;
+       pte_t *pte;
+
+       printk(KERN_DEBUG
+              "omapdsp: unmapping in ARM MMU, v=%#010lx, sz=%#lx\n",
+              virt, size);
+
+       while (size >= PAGE_SIZE) {
+               pgd = pgd_offset_k(virt);
+               pud = pud_offset(pgd, virt);
+               pmd = pmd_offset(pud, virt);
+               pte = pte_offset_kernel(pmd, virt);
+
+               pte_clear(&init_mm, virt, pte);
+               size -= PAGE_SIZE;
+               virt += PAGE_SIZE;
+       }
+
+       BUG_ON(size);
+#endif
+}
+
+static int exmap_valid(void *vadr, size_t len)
+{
+       /* exmap_sem should be held before calling this function */
+       int i;
+
+start:
+       for (i = 0; i < DSP_MMU_TLB_LINES; i++) {
+               void *mapadr;
+               unsigned long mapsize;
+               struct exmap_tbl_entry *ent = &exmap_tbl[i];
+
+               if (!ent->valid)
+                       continue;
+               mapadr = (void *)ent->vadr;
+               mapsize = 1 << (ent->order + PAGE_SHIFT);
+               if ((vadr >= mapadr) && (vadr < mapadr + mapsize)) {
+                       if (vadr + len <= mapadr + mapsize) {
+                               /* this map covers whole address. */
+                               return 1;
+                       } else {
+                               /*
+                                * this map covers partially.
+                                * check rest portion.
+                                */
+                               len -= mapadr + mapsize - vadr;
+                               vadr = mapadr + mapsize;
+                               goto start;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+enum dsp_mem_type_e dsp_mem_type(void *vadr, size_t len)
+{
+       void *ds = (void *)daram_base;
+       void *de = (void *)daram_base + daram_size;
+       void *ss = (void *)saram_base;
+       void *se = (void *)saram_base + saram_size;
+       int ret;
+
+       if ((vadr >= ds) && (vadr < de)) {
+               if (vadr + len > de)
+                       return MEM_TYPE_CROSSING;
+               else
+                       return MEM_TYPE_DARAM;
+       } else if ((vadr >= ss) && (vadr < se)) {
+               if (vadr + len > se)
+                       return MEM_TYPE_CROSSING;
+               else
+                       return MEM_TYPE_SARAM;
+       } else {
+               down_read(&exmap_sem);
+               if (exmap_valid(vadr, len))
+                       ret = MEM_TYPE_EXTERN;
+               else
+                       ret = MEM_TYPE_NONE;
+               up_read(&exmap_sem);
+               return ret;
+       }
+}
+
+int dsp_address_validate(void *p, size_t len, char *fmt, ...)
+{
+       if (dsp_mem_type(p, len) <= 0) {
+               if (fmt != NULL) {
+                       char s[64];
+                       va_list args;
+
+                       va_start(args, fmt);
+                       vsprintf(s, fmt, args);
+                       va_end(args);
+                       printk(KERN_ERR
+                              "omapdsp: %s address(0x%p) and size(0x%x) is "
+                              "not valid!\n"
+                              "         (crossing different type of memories, or \n"
+                              "          external memory space where no "
+                              "actual memory is mapped)\n",
+                              s, p, len);
+               }
+               return -1;
+       }
+
+       return 0;
+}
+
+/*
+ * exmap_use(), unuse():
+ * when the mapped area is exported to user space with mmap,
+ * the usecount is incremented.
+ * while the usecount > 0, that area can't be released.
+ */
+void exmap_use(void *vadr, size_t len)
+{
+       int i;
+
+       down_write(&exmap_sem);
+       for (i = 0; i < DSP_MMU_TLB_LINES; i++) {
+               void *mapadr;
+               unsigned long mapsize;
+               struct exmap_tbl_entry *ent = &exmap_tbl[i];
+
+               if (!ent->valid)
+                       continue;
+               mapadr = (void *)ent->vadr;
+               mapsize = 1 << (ent->order + PAGE_SHIFT);
+               if ((vadr + len > mapadr) && (vadr < mapadr + mapsize))
+                       ent->usecount++;
+       }
+       up_write(&exmap_sem);
+}
+
+void exmap_unuse(void *vadr, size_t len)
+{
+       int i;
+
+       down_write(&exmap_sem);
+       for (i = 0; i < DSP_MMU_TLB_LINES; i++) {
+               void *mapadr;
+               unsigned long mapsize;
+               struct exmap_tbl_entry *ent = &exmap_tbl[i];
+
+               if (!ent->valid)
+                       continue;
+               mapadr = (void *)ent->vadr;
+               mapsize = 1 << (ent->order + PAGE_SHIFT);
+               if ((vadr + len > mapadr) && (vadr < mapadr + mapsize))
+                       ent->usecount--;
+       }
+       up_write(&exmap_sem);
+}
+
+/*
+ * dsp_virt_to_phys()
+ * returns physical address, and sets len to valid length
+ */
+unsigned long dsp_virt_to_phys(void *vadr, size_t *len)
+{
+       int i;
+
+       if (is_dsp_internal_mem(vadr)) {
+               /* DSRAM or SARAM */
+               *len = dspmem_base + dspmem_size - (unsigned long)vadr;
+               return (unsigned long)vadr;
+       }
+
+       /* EXRAM */
+       for (i = 0; i < DSP_MMU_TLB_LINES; i++) {
+               void *mapadr;
+               unsigned long mapsize;
+               struct exmap_tbl_entry *ent = &exmap_tbl[i];
+
+               if (!ent->valid)
+                       continue;
+               mapadr = (void *)ent->vadr;
+               mapsize = 1 << (ent->order + PAGE_SHIFT);
+               if ((vadr >= mapadr) && (vadr < mapadr + mapsize)) {
+                       *len = mapadr + mapsize - vadr;
+                       return __pa(ent->buf) + vadr - mapadr;
+               }
+       }
+
+       /* valid mapping not found */
+       return 0;
+}
+
+/*
+ * DSP MMU operations
+ */
+#ifdef CONFIG_ARCH_OMAP1
+static dsp_mmu_reg_t get_cam_l_va_mask(dsp_mmu_reg_t pgsz)
+{
+       switch (pgsz) {
+       case DSP_MMU_CAM_PAGESIZE_1MB:
+               return DSP_MMU_CAM_L_VA_TAG_L1_MASK |
+                      DSP_MMU_CAM_L_VA_TAG_L2_MASK_1MB;
+       case DSP_MMU_CAM_PAGESIZE_64KB:
+               return DSP_MMU_CAM_L_VA_TAG_L1_MASK |
+                      DSP_MMU_CAM_L_VA_TAG_L2_MASK_64KB;
+       case DSP_MMU_CAM_PAGESIZE_4KB:
+               return DSP_MMU_CAM_L_VA_TAG_L1_MASK |
+                      DSP_MMU_CAM_L_VA_TAG_L2_MASK_4KB;
+       case DSP_MMU_CAM_PAGESIZE_1KB:
+               return DSP_MMU_CAM_L_VA_TAG_L1_MASK |
+                      DSP_MMU_CAM_L_VA_TAG_L2_MASK_1KB;
+       }
+       return 0;
+}
+#endif /* CONFIG_ARCH_OMAP1 */
+
+#if defined(CONFIG_ARCH_OMAP1)
+#define get_cam_va_mask(pgsz) \
+       ((u32)DSP_MMU_CAM_H_VA_TAG_H_MASK << 22 | \
+        (u32)get_cam_l_va_mask(pgsz) << 6)
+#elif defined(CONFIG_ARCH_OMAP2)
+#define get_cam_va_mask(pgsz) \
+       ((pgsz == DSP_MMU_CAM_PAGESIZE_16MB) ? 0xff000000 : \
+        (pgsz == DSP_MMU_CAM_PAGESIZE_1MB)  ? 0xfff00000 : \
+        (pgsz == DSP_MMU_CAM_PAGESIZE_64KB) ? 0xffff0000 : \
+        (pgsz == DSP_MMU_CAM_PAGESIZE_4KB)  ? 0xfffff000 : 0)
+#endif /* CONFIG_ARCH_OMAP2 */
+
+static void get_tlb_lock(struct tlb_lock *tlb_lock)
+{
+       dsp_mmu_reg_t lock = dsp_mmu_read_reg(DSP_MMU_LOCK);
+
+       tlb_lock->base = (lock & DSP_MMU_LOCK_BASE_MASK) >>
+                        DSP_MMU_LOCK_BASE_SHIFT;
+       tlb_lock->victim = (lock & DSP_MMU_LOCK_VICTIM_MASK) >>
+                          DSP_MMU_LOCK_VICTIM_SHIFT;
+}
+
+static void set_tlb_lock(struct tlb_lock *tlb_lock)
+{
+       dsp_mmu_write_reg((tlb_lock->base   << DSP_MMU_LOCK_BASE_SHIFT) |
+                         (tlb_lock->victim << DSP_MMU_LOCK_VICTIM_SHIFT),
+                         DSP_MMU_LOCK);
+}
+
+static void __read_tlb(struct tlb_lock *tlb_lock, struct cam_ram_regset *cr)
+{
+       /* set victim */
+       set_tlb_lock(tlb_lock);
+
+#if defined(CONFIG_ARCH_OMAP1)
+       /* read a TLB entry */
+       dsp_mmu_write_reg(DSP_MMU_LD_TLB_RD, DSP_MMU_LD_TLB);
+
+       cr->cam_h = dsp_mmu_read_reg(DSP_MMU_READ_CAM_H);
+       cr->cam_l = dsp_mmu_read_reg(DSP_MMU_READ_CAM_L);
+       cr->ram_h = dsp_mmu_read_reg(DSP_MMU_READ_RAM_H);
+       cr->ram_l = dsp_mmu_read_reg(DSP_MMU_READ_RAM_L);
+#elif defined(CONFIG_ARCH_OMAP2)
+       cr->cam = dsp_mmu_read_reg(DSP_MMU_READ_CAM);
+       cr->ram = dsp_mmu_read_reg(DSP_MMU_READ_RAM);
+#endif
+}
+
+static void __load_tlb(struct cam_ram_regset *cr)
+{
+#if defined(CONFIG_ARCH_OMAP1)
+       dsp_mmu_write_reg(cr->cam_h, DSP_MMU_CAM_H);
+       dsp_mmu_write_reg(cr->cam_l, DSP_MMU_CAM_L);
+       dsp_mmu_write_reg(cr->ram_h, DSP_MMU_RAM_H);
+       dsp_mmu_write_reg(cr->ram_l, DSP_MMU_RAM_L);
+#elif defined(CONFIG_ARCH_OMAP2)
+       dsp_mmu_write_reg(cr->cam | DSP_MMU_CAM_V, DSP_MMU_CAM);
+       dsp_mmu_write_reg(cr->ram, DSP_MMU_RAM);
+#endif
+
+       /* flush the entry */
+       dsp_mmu_flush();
+
+       /* load a TLB entry */
+       dsp_mmu_write_reg(DSP_MMU_LD_TLB_LD, DSP_MMU_LD_TLB);
+}
+
+static int dsp_mmu_load_tlb(struct tlb_entry *tlb_ent)
+{
+       struct tlb_lock tlb_lock;
+       struct cam_ram_regset cr;
+
+#ifdef CONFIG_ARCH_OMAP1
+       clk_enable(dsp_ck_handle);
+       omap_dsp_request_mem();
+#endif
+
+       get_tlb_lock(&tlb_lock);
+       for (tlb_lock.victim = 0;
+            tlb_lock.victim < tlb_lock.base;
+            tlb_lock.victim++) {
+               struct cam_ram_regset tmp_cr;
+
+               /* read a TLB entry */
+               __read_tlb(&tlb_lock, &tmp_cr);
+               if (!cam_ram_valid(tmp_cr))
+                       goto found_victim;
+       }
+       set_tlb_lock(&tlb_lock);
+
+found_victim:
+       /* The last (31st) entry cannot be locked? */
+       if (tlb_lock.victim == 31) {
+               printk(KERN_ERR "omapdsp: TLB is full.\n");
+               return -EBUSY;
+       }
+
+       if (tlb_ent->va & ~get_cam_va_mask(tlb_ent->pgsz)) {
+               printk(KERN_ERR
+                      "omapdsp: mapping vadr (0x%06x) is not "
+                      "aligned boundary\n", tlb_ent->va);
+               return -EINVAL;
+       }
+
+#if defined(CONFIG_ARCH_OMAP1)
+       cr.cam_h = tlb_ent->va >> 22;
+       cr.cam_l = (tlb_ent->va >> 6 & get_cam_l_va_mask(tlb_ent->pgsz)) |
+                  tlb_ent->prsvd | tlb_ent->pgsz;
+       cr.ram_h = tlb_ent->pa >> 16;
+       cr.ram_l = (tlb_ent->pa & DSP_MMU_RAM_L_RAM_LSB_MASK) | tlb_ent->ap;
+#elif defined(CONFIG_ARCH_OMAP2)
+       cr.cam = (tlb_ent->va & DSP_MMU_CAM_VATAG_MASK) |
+                tlb_ent->prsvd | tlb_ent->pgsz;
+       cr.ram = tlb_ent->pa | tlb_ent->endian | tlb_ent->elsz;
+#endif
+       __load_tlb(&cr);
+
+       /* update lock base */
+       if (tlb_lock.victim == tlb_lock.base)
+               tlb_lock.base++;
+       tlb_lock.victim = tlb_lock.base;
+       set_tlb_lock(&tlb_lock);
+
+#ifdef CONFIG_ARCH_OMAP1
+       omap_dsp_release_mem();
+       clk_disable(dsp_ck_handle);
+#endif
+       return 0;
+}
+
+static int dsp_mmu_clear_tlb(dsp_long_t vadr)
+{
+       struct tlb_lock tlb_lock;
+       int i;
+       int max_valid = 0;
+
+#ifdef CONFIG_ARCH_OMAP1
+       clk_enable(dsp_ck_handle);
+       omap_dsp_request_mem();
+#endif
+
+       get_tlb_lock(&tlb_lock);
+       for (i = 0; i < tlb_lock.base; i++) {
+               struct cam_ram_regset cr;
+               dsp_long_t cam_va;
+               dsp_mmu_reg_t pgsz;
+
+               /* read a TLB entry */
+               tlb_lock.victim = i;
+               __read_tlb(&tlb_lock, &cr);
+               if (!cam_ram_valid(cr))
+                       continue;
+
+#if defined(CONFIG_ARCH_OMAP1)
+               pgsz = cr.cam_l & DSP_MMU_CAM_PAGESIZE_MASK;
+               cam_va = (u32)(cr.cam_h & DSP_MMU_CAM_H_VA_TAG_H_MASK) << 22 |
+                        (u32)(cr.cam_l & get_cam_l_va_mask(pgsz)) << 6;
+#elif defined(CONFIG_ARCH_OMAP2)
+               pgsz = cr.cam & DSP_MMU_CAM_PAGESIZE_MASK;
+               cam_va = cr.cam & get_cam_va_mask(pgsz);
+#endif
+
+               if (cam_va == vadr)
+                       /* flush the entry */
+                       dsp_mmu_flush();
+               else
+                       max_valid = i;
+       }
+
+       /* set new lock base */
+       tlb_lock.base   = max_valid + 1;
+       tlb_lock.victim = max_valid + 1;
+       set_tlb_lock(&tlb_lock);
+
+#ifdef CONFIG_ARCH_OMAP1
+       omap_dsp_release_mem();
+       clk_disable(dsp_ck_handle);
+#endif
+       return 0;
+}
+
+static void dsp_mmu_gflush(void)
+{
+       struct tlb_lock tlb_lock;
+
+#ifdef CONFIG_ARCH_OMAP1
+       clk_enable(dsp_ck_handle);
+       omap_dsp_request_mem();
+#endif
+
+       __dsp_mmu_gflush();
+       tlb_lock.base   = exmap_preserved_cnt;
+       tlb_lock.victim = exmap_preserved_cnt;
+       set_tlb_lock(&tlb_lock);
+
+#ifdef CONFIG_ARCH_OMAP1
+       omap_dsp_release_mem();
+       clk_disable(dsp_ck_handle);
+#endif
+}
+
+/*
+ * dsp_exmap()
+ *
+ * MEM_IOCTL_EXMAP ioctl calls this function with padr=0.
+ * In this case, the buffer for DSP is allocated in this routine,
+ * then it is mapped.
+ * On the other hand, for example - frame buffer sharing, calls
+ * this function with padr set. It means some known address space
+ * pointed with padr is going to be shared with DSP.
+ */
+static int dsp_exmap(dsp_long_t dspadr, unsigned long padr, unsigned long size,
+                    enum exmap_type_e type)
+{
+       dsp_mmu_reg_t pgsz;
+       void *buf;
+       unsigned int order = 0;
+       unsigned long unit;
+       int prev = -1;
+       dsp_long_t _dspadr = dspadr;
+       unsigned long _padr = padr;
+       void *_vadr = dspbyte_to_virt(dspadr);
+       unsigned long _size = size;
+       struct tlb_entry tlb_ent;
+       struct exmap_tbl_entry *exmap_ent;
+       int status;
+       int idx;
+       int i;
+
+#define MINIMUM_PAGESZ SZ_4KB
+       /*
+        * alignment check
+        */
+       if (!is_aligned(size, MINIMUM_PAGESZ)) {
+               printk(KERN_ERR
+                      "omapdsp: size(0x%lx) is not multiple of 4KB.\n", size);
+               return -EINVAL;
+       }
+       if (!is_aligned(dspadr, MINIMUM_PAGESZ)) {
+               printk(KERN_ERR
+                      "omapdsp: DSP address(0x%x) is not aligned.\n", dspadr);
+               return -EINVAL;
+       }
+       if (!is_aligned(padr, MINIMUM_PAGESZ)) {
+               printk(KERN_ERR
+                      "omapdsp: physical address(0x%lx) is not aligned.\n",
+                      padr);
+               return -EINVAL;
+       }
+
+       /* address validity check */
+       if ((dspadr < dspmem_size) ||
+           (dspadr >= DSPSPACE_SIZE) ||
+           ((dspadr + size > DSP_INIT_PAGE) &&
+            (dspadr < DSP_INIT_PAGE + PAGE_SIZE))) {
+               printk(KERN_ERR
+                      "omapdsp: illegal address/size for dsp_exmap().\n");
+               return -EINVAL;
+       }
+
+       down_write(&exmap_sem);
+
+       /* overlap check */
+       for (i = 0; i < DSP_MMU_TLB_LINES; i++) {
+               unsigned long mapsize;
+               struct exmap_tbl_entry *tmp_ent = &exmap_tbl[i];
+
+               if (!tmp_ent->valid)
+                       continue;
+               mapsize = 1 << (tmp_ent->order + PAGE_SHIFT);
+               if ((_vadr + size > tmp_ent->vadr) &&
+                   (_vadr < tmp_ent->vadr + mapsize)) {
+                       printk(KERN_ERR "omapdsp: exmap page overlap!\n");
+                       up_write(&exmap_sem);
+                       return -EINVAL;
+               }
+       }
+
+start:
+       buf = NULL;
+       /* Are there any free TLB lines?  */
+       for (idx = 0; idx < DSP_MMU_TLB_LINES; idx++) {
+               if (!exmap_tbl[idx].valid)
+                       goto found_free;
+       }
+       printk(KERN_ERR "omapdsp: DSP TLB is full.\n");
+       status = -EBUSY;
+       goto fail;
+
+found_free:
+       exmap_ent = &exmap_tbl[idx];
+
+       /*
+        * we don't use
+        * 1KB mapping in OMAP1,
+        * 16MB mapping in OMAP2.
+        */
+       if ((_size >= SZ_1MB) &&
+           (is_aligned(_padr, SZ_1MB) || (padr == 0)) &&
+           is_aligned(_dspadr, SZ_1MB)) {
+               unit = SZ_1MB;
+               pgsz = DSP_MMU_CAM_PAGESIZE_1MB;
+       } else if ((_size >= SZ_64KB) &&
+                  (is_aligned(_padr, SZ_64KB) || (padr == 0)) &&
+                  is_aligned(_dspadr, SZ_64KB)) {
+               unit = SZ_64KB;
+               pgsz = DSP_MMU_CAM_PAGESIZE_64KB;
+       } else {
+               unit = SZ_4KB;
+               pgsz = DSP_MMU_CAM_PAGESIZE_4KB;
+       }
+
+       order = get_order(unit);
+
+       /* buffer allocation */
+       if (type == EXMAP_TYPE_MEM) {
+               struct page *page, *ps, *pe;
+
+               if ((order == ORDER_1MB) && likely(kmem_pool_1M))
+                       buf = mempool_alloc_from_pool(kmem_pool_1M, GFP_KERNEL);
+               else if ((order == ORDER_64KB) && likely(kmem_pool_64K))
+                       buf = mempool_alloc_from_pool(kmem_pool_64K,GFP_KERNEL);
+               else {
+                       buf = (void *)__get_dma_pages(GFP_KERNEL, order);
+                       if (buf == NULL) {
+                               status = -ENOMEM;
+                               goto fail;
+                       }
+               }
+
+               /* mark the pages as reserved; this is needed for mmap */
+               ps = virt_to_page(buf);
+               pe = virt_to_page(buf + unit);
+
+               for (page = ps; page < pe; page++)
+                       SetPageReserved(page);
+
+               _padr = __pa(buf);
+       }
+
+       /*
+        * mapping for ARM MMU:
+        * we should not access to the allocated memory through 'buf'
+        * since this area should not be cashed.
+        */
+       status = exmap_set_armmmu((unsigned long)_vadr, _padr, unit);
+       if (status < 0)
+               goto fail;
+
+       /* loading DSP TLB entry */
+       INIT_TLB_ENTRY(&tlb_ent, _dspadr, _padr, pgsz);
+       status = dsp_mmu_load_tlb(&tlb_ent);
+       if (status < 0) {
+               exmap_clear_armmmu((unsigned long)_vadr, unit);
+               goto fail;
+       }
+
+       INIT_EXMAP_TBL_ENTRY(exmap_ent, buf, _vadr, type, order);
+       exmap_ent->link.prev = prev;
+       if (prev >= 0)
+               exmap_tbl[prev].link.next = idx;
+
+       if ((_size -= unit) == 0) {     /* normal completion */
+               up_write(&exmap_sem);
+               return size;
+       }
+
+       _dspadr += unit;
+       _vadr   += unit;
+       _padr = padr ? _padr + unit : 0;
+       prev = idx;
+       goto start;
+
+fail:
+       up_write(&exmap_sem);
+       if (buf)
+               dsp_mem_free_pages((unsigned long)buf, order);
+       dsp_exunmap(dspadr);
+       return status;
+}
+
+static unsigned long unmap_free_arm(struct exmap_tbl_entry *ent)
+{
+       unsigned long size;
+
+       /* clearing ARM MMU */
+       size = 1 << (ent->order + PAGE_SHIFT);
+       exmap_clear_armmmu((unsigned long)ent->vadr, size);
+
+       /* freeing allocated memory */
+       if (ent->type == EXMAP_TYPE_MEM) {
+               dsp_mem_free_pages((unsigned long)ent->buf, ent->order);
+               printk(KERN_DEBUG
+                      "omapdsp: freeing 0x%lx bytes @ adr 0x%8p\n",
+                      size, ent->buf);
+       }
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+       else if (ent->type == EXMAP_TYPE_FB) {
+               int status;
+               if (omapfb_nb) {
+                       status = omapfb_unregister_client(omapfb_nb);
+                       if (!status)
+                               printk("omapfb_unregister_client(): "
+                                      "success\n");
+                       else
+                               printk("omapfb_runegister_client(): "
+                                      "failure(%d)\n", status);
+                       kfree(omapfb_nb);
+                       omapfb_nb = NULL;
+                       omapfb_ready = 0;
+               }
+       }
+#endif
+
+       return size;
+}
+
+static int dsp_exunmap(dsp_long_t dspadr)
+{
+       void *vadr;
+       unsigned long size;
+       int total = 0;
+       struct exmap_tbl_entry *ent;
+       int idx;
+
+       vadr = dspbyte_to_virt(dspadr);
+       down_write(&exmap_sem);
+       for (idx = 0; idx < DSP_MMU_TLB_LINES; idx++) {
+               ent = &exmap_tbl[idx];
+               if ((!ent->valid) || ent->prsvd)
+                       continue;
+               if (ent->vadr == vadr)
+                       goto found_map;
+       }
+       up_write(&exmap_sem);
+       printk(KERN_WARNING
+              "omapdsp: address %06x not found in exmap_tbl.\n", dspadr);
+       return -EINVAL;
+
+found_map:
+       if (ent->usecount > 0) {
+               printk(KERN_ERR
+                      "omapdsp: exmap reference count is not 0.\n"
+                      "   idx=%d, vadr=%p, order=%d, usecount=%d\n",
+                      idx, ent->vadr, ent->order, ent->usecount);
+               up_write(&exmap_sem);
+               return -EINVAL;
+       }
+       /* clearing DSP TLB entry */
+       dsp_mmu_clear_tlb(dspadr);
+
+       /* clear ARM MMU and free buffer */
+       size = unmap_free_arm(ent);
+       ent->valid = 0;
+       total += size;
+
+       /* we don't free PTEs */
+
+       /* flush TLB */
+       flush_tlb_kernel_range((unsigned long)vadr, (unsigned long)vadr + size);
+
+       if ((idx = ent->link.next) < 0)
+               goto up_out;    /* normal completion */
+       ent = &exmap_tbl[idx];
+       dspadr += size;
+       vadr   += size;
+       if (ent->vadr == vadr)
+               goto found_map; /* continue */
+
+       printk(KERN_ERR
+              "omapdsp: illegal exmap_tbl grouping!\n"
+              "expected vadr = %p, exmap_tbl[%d].vadr = %p\n",
+              vadr, idx, ent->vadr);
+       up_write(&exmap_sem);
+       return -EINVAL;
+
+up_out:
+       up_write(&exmap_sem);
+       return total;
+}
+
+static void exmap_flush(void)
+{
+       struct exmap_tbl_entry *ent;
+       int i;
+
+       down_write(&exmap_sem);
+
+       /* clearing DSP TLB entry */
+       dsp_mmu_gflush();
+
+       for (i = 0; i < DSP_MMU_TLB_LINES; i++) {
+               ent = &exmap_tbl[i];
+               if (ent->valid && (!ent->prsvd)) {
+                       unmap_free_arm(ent);
+                       ent->valid = 0;
+               }
+       }
+
+       /* flush TLB */
+       flush_tlb_kernel_range(dspmem_base + dspmem_size,
+                              dspmem_base + DSPSPACE_SIZE);
+       up_write(&exmap_sem);
+}
+
+#ifdef CONFIG_OMAP_DSP_FBEXPORT
+#ifndef CONFIG_FB
+#error You configured OMAP_DSP_FBEXPORT, but FB was not configured!
+#endif /* CONFIG_FB */
+
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+static int omapfb_notifier_cb(struct notifier_block *omapfb_nb,
+                             unsigned long event, void *fbi)
+{
+       /* XXX */
+       printk("omapfb_notifier_cb(): event = %s\n",
+              (event == OMAPFB_EVENT_READY)    ? "READY" :
+              (event == OMAPFB_EVENT_DISABLED) ? "DISABLED" : "Unknown");
+       if (event == OMAPFB_EVENT_READY)
+               omapfb_ready = 1;
+       else if (event == OMAPFB_EVENT_DISABLED)
+               omapfb_ready = 0;
+       return 0;
+}
+#endif
+
+static int dsp_fbexport(dsp_long_t *dspadr)
+{
+       dsp_long_t dspadr_actual;
+       unsigned long padr_sys, padr, fbsz_sys, fbsz;
+       int cnt;
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+       int status;
+#endif
+
+       printk(KERN_DEBUG "omapdsp: frame buffer export\n");
+
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+       if (omapfb_nb) {
+               printk(KERN_WARNING
+                      "omapdsp: frame buffer has been exported already!\n");
+               return -EBUSY;
+       }
+#endif
+
+       if (num_registered_fb == 0) {
+               printk(KERN_INFO "omapdsp: frame buffer not registered.\n");
+               return -EINVAL;
+       }
+       if (num_registered_fb != 1) {
+               printk(KERN_INFO
+                      "omapdsp: %d frame buffers found. we use first one.\n",
+                      num_registered_fb);
+       }
+       padr_sys = registered_fb[0]->fix.smem_start;
+       fbsz_sys = registered_fb[0]->fix.smem_len;
+       if (fbsz_sys == 0) {
+               printk(KERN_ERR
+                      "omapdsp: framebuffer doesn't seem to be configured "
+                      "correctly! (size=0)\n");
+               return -EINVAL;
+       }
+
+       /*
+        * align padr and fbsz to 4kB boundary
+        * (should be noted to the user afterwards!)
+        */
+       padr = padr_sys & ~(SZ_4KB-1);
+       fbsz = (fbsz_sys + padr_sys - padr + SZ_4KB-1) & ~(SZ_4KB-1);
+
+       /* line up dspadr offset with padr */
+       dspadr_actual =
+               (fbsz > SZ_1MB) ?  lineup_offset(*dspadr, padr, SZ_1MB-1) :
+               (fbsz > SZ_64KB) ? lineup_offset(*dspadr, padr, SZ_64KB-1) :
+               /* (fbsz > SZ_4KB) ? */ *dspadr;
+       if (dspadr_actual != *dspadr)
+               printk(KERN_DEBUG
+                      "omapdsp: actual dspadr for FBEXPORT = %08x\n",
+                      dspadr_actual);
+       *dspadr = dspadr_actual;
+
+       cnt = dsp_exmap(dspadr_actual, padr, fbsz, EXMAP_TYPE_FB);
+       if (cnt < 0) {
+               printk(KERN_ERR "omapdsp: exmap failure.\n");
+               return cnt;
+       }
+
+       if ((padr != padr_sys) || (fbsz != fbsz_sys)) {
+               printk(KERN_WARNING
+"  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
+"  !!  screen base address or size is not aligned in 4kB:           !!\n"
+"  !!    actual screen  adr = %08lx, size = %08lx             !!\n"
+"  !!    exporting      adr = %08lx, size = %08lx             !!\n"
+"  !!  Make sure that the framebuffer is allocated with 4kB-order!  !!\n"
+"  !!  Otherwise DSP can corrupt the kernel memory.                 !!\n"
+"  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n",
+                      padr_sys, fbsz_sys, padr, fbsz);
+       }
+
+#ifdef CONFIG_ARCH_OMAP1
+       /* increase the DMA priority */
+       set_emiff_dma_prio(15);
+#endif
+
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+       omapfb_nb = kzalloc(sizeof(struct omapfb_notifier_block), GFP_KERNEL);
+       if (omapfb_nb == NULL) {
+               printk(KERN_ERR
+                      "omapdsp: failed to allocate memory for omapfb_nb!\n");
+               dsp_exunmap(dspadr_actual);
+               return -ENOMEM;
+       }
+       status = omapfb_register_client(omapfb_nb, omapfb_notifier_cb, NULL);
+       if (!status)
+               printk("omapfb_register_client(): success\n");
+       else
+               printk("omapfb_register_client(): failure(%d)\n", status);
+#endif
+
+       return cnt;
+}
+
+#else /* CONFIG_OMAP_DSP_FBEXPORT */
+
+static int dsp_fbexport(dsp_long_t *dspadr)
+{
+       printk(KERN_ERR "omapdsp: FBEXPORT function is not enabled.\n");
+       return -EINVAL;
+}
+
+#endif /* CONFIG_OMAP_DSP_FBEXPORT */
+
+static void exmap_setup_preserved_mem_page(void *buf, dsp_long_t dspadr,
+                                          int exmap_idx)
+{
+       unsigned long phys;
+       void *virt;
+       struct tlb_entry tlb_ent;
+
+       phys = __pa(buf);
+       virt = dspbyte_to_virt(dspadr);
+       exmap_set_armmmu((unsigned long)virt, phys, PAGE_SIZE);
+       INIT_EXMAP_TBL_ENTRY_4KB_PRESERVED(&exmap_tbl[exmap_idx], buf, virt);
+       INIT_TLB_ENTRY_4KB_PRESERVED(&tlb_ent, dspadr, phys);
+       dsp_mmu_load_tlb(&tlb_ent);
+}
+
+static void exmap_clear_mem_page(dsp_long_t dspadr)
+{
+       void *virt;
+
+       virt = dspbyte_to_virt(dspadr);
+       exmap_clear_armmmu((unsigned long)virt, PAGE_SIZE);
+       /* DSP MMU is shutting down. not handled here. */
+}
+
+#ifdef CONFIG_ARCH_OMAP2
+static void exmap_setup_iomap_page(unsigned long phys, unsigned long dsp_io_adr,
+                                  int exmap_idx)
+{
+       dsp_long_t dspadr;
+       void *virt;
+       struct tlb_entry tlb_ent;
+
+       dspadr = (IOMAP_VAL << 18) + (dsp_io_adr << 1);
+       virt = dspbyte_to_virt(dspadr);
+       exmap_set_armmmu((unsigned long)virt, phys, PAGE_SIZE);
+       INIT_EXMAP_TBL_ENTRY_4KB_PRESERVED(&exmap_tbl[exmap_idx], NULL, virt);
+       INIT_TLB_ENTRY_4KB_ES32_PRESERVED(&tlb_ent, dspadr, phys);
+       dsp_mmu_load_tlb(&tlb_ent);
+}
+
+static void exmap_clear_iomap_page(unsigned long dsp_io_adr)
+{
+       dsp_long_t dspadr;
+       void *virt;
+
+       dspadr = (IOMAP_VAL << 18) + (dsp_io_adr << 1);
+       virt = dspbyte_to_virt(dspadr);
+       exmap_clear_armmmu((unsigned long)virt, PAGE_SIZE);
+       /* DSP MMU is shutting down. not handled here. */
+}
+#endif /* CONFIG_ARCH_OMAP2 */
+
+#define OMAP2420_GPT5_BASE     (L4_24XX_BASE + 0x7c000)
+#define OMAP2420_GPT6_BASE     (L4_24XX_BASE + 0x7e000)
+#define OMAP2420_GPT7_BASE     (L4_24XX_BASE + 0x80000)
+#define OMAP2420_GPT8_BASE     (L4_24XX_BASE + 0x82000)
+#define OMAP24XX_EAC_BASE      (L4_24XX_BASE + 0x90000)
+
+static int exmap_setup_preserved_entries(void)
+{
+       int n = 0;
+
+       exmap_setup_preserved_mem_page(dspvect_page, DSP_INIT_PAGE, n++);
+#ifdef CONFIG_ARCH_OMAP2
+       exmap_setup_iomap_page(OMAP24XX_PRCM_BASE,     0x7000, n++);
+#ifdef CONFIG_ARCH_OMAP2420
+       exmap_setup_iomap_page(OMAP2420_GPT5_BASE,     0xe000, n++);
+       exmap_setup_iomap_page(OMAP2420_GPT6_BASE,     0xe800, n++);
+       exmap_setup_iomap_page(OMAP2420_GPT7_BASE,     0xf000, n++);
+       exmap_setup_iomap_page(OMAP2420_GPT8_BASE,     0xf800, n++);
+#endif /* CONFIG_ARCH_OMAP2420 */
+       exmap_setup_iomap_page(OMAP24XX_EAC_BASE,     0x10000, n++);
+       exmap_setup_iomap_page(OMAP24XX_MAILBOX_BASE, 0x11000, n++);
+#endif /* CONFIG_ARCH_OMAP2 */
+
+       return n;
+}
+
+static void exmap_clear_preserved_entries(void)
+{
+       exmap_clear_mem_page(DSP_INIT_PAGE);
+#ifdef CONFIG_ARCH_OMAP2
+       exmap_clear_iomap_page(0x7000);         /* PRCM */
+#ifdef CONFIG_ARCH_OMAP2420
+       exmap_clear_iomap_page(0xe000);         /* GPT5 */
+       exmap_clear_iomap_page(0xe800);         /* GPT6 */
+       exmap_clear_iomap_page(0xf000);         /* GPT7 */
+       exmap_clear_iomap_page(0xf800);         /* GPT8 */
+#endif /* CONFIG_ARCH_OMAP2420 */
+       exmap_clear_iomap_page(0x10000);        /* EAC */
+       exmap_clear_iomap_page(0x11000);        /* MAILBOX */
+#endif /* CONFIG_ARCH_OMAP2 */
+}
+
+#ifdef CONFIG_ARCH_OMAP1
+static int dsp_mmu_itack(void)
+{
+       unsigned long dspadr;
+
+       printk(KERN_INFO "omapdsp: sending DSP MMU interrupt ack.\n");
+       if (!dsp_err_isset(ERRCODE_MMU)) {
+               printk(KERN_ERR "omapdsp: DSP MMU error has not been set.\n");
+               return -EINVAL;
+       }
+       dspadr = dsp_fault_adr & ~(SZ_4K-1);
+       dsp_exmap(dspadr, 0, SZ_4K, EXMAP_TYPE_MEM);    /* FIXME: reserve TLB entry for this */
+       printk(KERN_INFO "omapdsp: falling into recovery runlevel...\n");
+       dsp_set_runlevel(RUNLEVEL_RECOVERY);
+       __dsp_mmu_itack();
+       udelay(100);
+       dsp_exunmap(dspadr);
+       dsp_err_clear(ERRCODE_MMU);
+       return 0;
+}
+#endif /* CONFIG_ARCH_OMAP1 */
+
+#ifdef CONFIG_ARCH_OMAP2
+#define MMU_IRQ_MASK \
+       (DSP_MMU_IRQ_MULTIHITFAULT | \
+        DSP_MMU_IRQ_TABLEWALKFAULT | \
+        DSP_MMU_IRQ_EMUMISS | \
+        DSP_MMU_IRQ_TRANSLATIONFAULT | \
+        DSP_MMU_IRQ_TLBMISS)
+#endif
+
+static int is_mmu_init;
+
+static void dsp_mmu_init(void)
+{
+       struct tlb_lock tlb_lock;
+
+#ifdef CONFIG_ARCH_OMAP1
+       clk_enable(dsp_ck_handle);
+       omap_dsp_request_mem();
+#endif
+       down_write(&exmap_sem);
+
+#if defined(CONFIG_ARCH_OMAP1)
+       dsp_mmu_disable();      /* clear all */
+       udelay(100);
+#elif defined(CONFIG_ARCH_OMAP2)
+       dsp_mmu_reset();
+#endif
+       dsp_mmu_enable();
+
+       /* DSP TLB initialization */
+       tlb_lock.base   = 0;
+       tlb_lock.victim = 0;
+       set_tlb_lock(&tlb_lock);
+
+       exmap_preserved_cnt = exmap_setup_preserved_entries();
+
+#ifdef CONFIG_ARCH_OMAP2
+       /* MMU IRQ mask setup */
+       dsp_mmu_write_reg(MMU_IRQ_MASK, DSP_MMU_IRQENABLE);
+#endif
+
+       up_write(&exmap_sem);
+#ifdef CONFIG_ARCH_OMAP1
+       omap_dsp_release_mem();
+       clk_disable(dsp_ck_handle);
+#endif
+
+       is_mmu_init = 1;
+}
+
+static void dsp_mmu_shutdown(void)
+{
+       if (is_mmu_init) {
+               exmap_flush();
+               exmap_clear_preserved_entries();
+               dsp_mmu_disable();
+       }
+}
+
+#ifdef CONFIG_ARCH_OMAP1
+/*
+ * intmem_enable() / disable():
+ * if the address is in DSP internal memories,
+ * we send PM mailbox commands so that DSP DMA domain won't go in idle
+ * when ARM is accessing to those memories.
+ */
+static int intmem_enable(void)
+{
+       int ret = 0;
+
+       if (dsp_cfgstat_get_stat() == CFGSTAT_READY)
+               ret = mbcompose_send(PM, PM_ENABLE, DSPREG_ICR_DMA);
+
+       return ret;
+}
+
+static void intmem_disable(void) {
+       if (dsp_cfgstat_get_stat() == CFGSTAT_READY)
+               mbcompose_send(PM, PM_DISABLE, DSPREG_ICR_DMA);
+}
+#endif /* CONFIG_ARCH_OMAP1 */
+
+/*
+ * dsp_mem_enable() / disable()
+ */
+#ifdef CONFIG_ARCH_OMAP1
+int intmem_usecount;
+#endif
+
+int dsp_mem_enable(void *adr)
+{
+       int ret = 0;
+
+       if (is_dsp_internal_mem(adr)) {
+#ifdef CONFIG_ARCH_OMAP1
+               if (intmem_usecount++ == 0)
+                       ret = omap_dsp_request_mem();
+#endif
+       } else
+               down_read(&exmap_sem);
+
+       return ret;
+}
+
+void dsp_mem_disable(void *adr)
+{
+       if (is_dsp_internal_mem(adr)) {
+#ifdef CONFIG_ARCH_OMAP1
+               if (--intmem_usecount == 0)
+                       omap_dsp_release_mem();
+#endif
+       } else
+               up_read(&exmap_sem);
+}
+
+/* for safety */
+#ifdef CONFIG_ARCH_OMAP1
+void dsp_mem_usecount_clear(void)
+{
+       if (intmem_usecount != 0) {
+               printk(KERN_WARNING
+                      "omapdsp: unbalanced memory request/release detected.\n"
+                      "         intmem_usecount is not zero at where "
+                      "it should be! ... fixed to be zero.\n");
+               intmem_usecount = 0;
+               omap_dsp_release_mem();
+       }
+}
+#endif /* CONFIG_ARCH_OMAP1 */
+
+/*
+ * dsp_mem file operations
+ */
+static loff_t dsp_mem_lseek(struct file *file, loff_t offset, int orig)
+{
+       loff_t ret;
+
+       mutex_lock(&file->f_dentry->d_inode->i_mutex);
+       switch (orig) {
+       case 0:
+               file->f_pos = offset;
+               ret = file->f_pos;
+               break;
+       case 1:
+               file->f_pos += offset;
+               ret = file->f_pos;
+               break;
+       default:
+               ret = -EINVAL;
+       }
+       mutex_unlock(&file->f_dentry->d_inode->i_mutex);
+       return ret;
+}
+
+static ssize_t intmem_read(struct file *file, char __user *buf, size_t count,
+                          loff_t *ppos)
+{
+       unsigned long p = *ppos;
+       void *vadr = dspbyte_to_virt(p);
+       ssize_t size = dspmem_size;
+       ssize_t read;
+
+       if (p >= size)
+               return 0;
+#ifdef CONFIG_ARCH_OMAP1
+       clk_enable(api_ck_handle);
+#endif
+       read = count;
+       if (count > size - p)
+               read = size - p;
+       if (copy_to_user(buf, vadr, read)) {
+               read = -EFAULT;
+               goto out;
+       }
+       *ppos += read;
+out:
+#ifdef CONFIG_ARCH_OMAP1
+       clk_disable(api_ck_handle);
+#endif
+       return read;
+}
+
+static ssize_t exmem_read(struct file *file, char __user *buf, size_t count,
+                         loff_t *ppos)
+{
+       unsigned long p = *ppos;
+       void *vadr = dspbyte_to_virt(p);
+
+       if (!exmap_valid(vadr, count)) {
+               printk(KERN_ERR
+                      "omapdsp: DSP address %08lx / size %08x "
+                      "is not valid!\n", p, count);
+               return -EFAULT;
+       }
+       if (count > DSPSPACE_SIZE - p)
+               count = DSPSPACE_SIZE - p;
+       if (copy_to_user(buf, vadr, count))
+               return -EFAULT;
+       *ppos += count;
+
+       return count;
+}
+
+static ssize_t dsp_mem_read(struct file *file, char __user *buf, size_t count,
+                           loff_t *ppos)
+{
+       int ret;
+       void *vadr = dspbyte_to_virt(*(unsigned long *)ppos);
+
+       if (dsp_mem_enable(vadr) < 0)
+               return -EBUSY;
+       if (is_dspbyte_internal_mem(*ppos))
+               ret = intmem_read(file, buf, count, ppos);
+       else
+               ret = exmem_read(file, buf, count, ppos);
+       dsp_mem_disable(vadr);
+
+       return ret;
+}
+
+static ssize_t intmem_write(struct file *file, const char __user *buf,
+                           size_t count, loff_t *ppos)
+{
+       unsigned long p = *ppos;
+       void *vadr = dspbyte_to_virt(p);
+       ssize_t size = dspmem_size;
+       ssize_t written;
+
+       if (p >= size)
+               return 0;
+#ifdef CONFIG_ARCH_OMAP1
+       clk_enable(api_ck_handle);
+#endif
+       written = count;
+       if (count > size - p)
+               written = size - p;
+       if (copy_from_user(vadr, buf, written)) {
+               written = -EFAULT;
+               goto out;
+       }
+       *ppos += written;
+out:
+#ifdef CONFIG_ARCH_OMAP1
+       clk_disable(api_ck_handle);
+#endif
+       return written;
+}
+
+static ssize_t exmem_write(struct file *file, const char __user *buf,
+                          size_t count, loff_t *ppos)
+{
+       unsigned long p = *ppos;
+       void *vadr = dspbyte_to_virt(p);
+
+       if (!exmap_valid(vadr, count)) {
+               printk(KERN_ERR
+                      "omapdsp: DSP address %08lx / size %08x "
+                      "is not valid!\n", p, count);
+               return -EFAULT;
+       }
+       if (count > DSPSPACE_SIZE - p)
+               count = DSPSPACE_SIZE - p;
+       if (copy_from_user(vadr, buf, count))
+               return -EFAULT;
+       *ppos += count;
+
+       return count;
+}
+
+static ssize_t dsp_mem_write(struct file *file, const char __user *buf,
+                            size_t count, loff_t *ppos)
+{
+       int ret;
+       void *vadr = dspbyte_to_virt(*(unsigned long *)ppos);
+
+       if (dsp_mem_enable(vadr) < 0)
+               return -EBUSY;
+       if (is_dspbyte_internal_mem(*ppos))
+               ret = intmem_write(file, buf, count, ppos);
+       else
+               ret = exmem_write(file, buf, count, ppos);
+       dsp_mem_disable(vadr);
+
+       return ret;
+}
+
+static int dsp_mem_ioctl(struct inode *inode, struct file *file,
+                        unsigned int cmd, unsigned long arg)
+{
+       switch (cmd) {
+       case MEM_IOCTL_MMUINIT:
+               dsp_mmu_init();
+               return 0;
+
+       case MEM_IOCTL_EXMAP:
+               {
+                       struct omap_dsp_mapinfo mapinfo;
+                       if (copy_from_user(&mapinfo, (void __user *)arg,
+                                          sizeof(mapinfo)))
+                               return -EFAULT;
+                       return dsp_exmap(mapinfo.dspadr, 0, mapinfo.size,
+                                        EXMAP_TYPE_MEM);
+               }
+
+       case MEM_IOCTL_EXUNMAP:
+               return dsp_exunmap((unsigned long)arg);
+
+       case MEM_IOCTL_EXMAP_FLUSH:
+               exmap_flush();
+               return 0;
+
+       case MEM_IOCTL_FBEXPORT:
+               {
+                       dsp_long_t dspadr;
+                       int ret;
+                       if (copy_from_user(&dspadr, (void __user *)arg,
+                                          sizeof(dsp_long_t)))
+                               return -EFAULT;
+                       ret = dsp_fbexport(&dspadr);
+                       if (copy_to_user((void __user *)arg, &dspadr,
+                                        sizeof(dsp_long_t)))
+                               return -EFAULT;
+                       return ret;
+               }
+
+#ifdef CONFIG_ARCH_OMAP1
+       case MEM_IOCTL_MMUITACK:
+               return dsp_mmu_itack();
+#endif
+
+       case MEM_IOCTL_KMEM_RESERVE:
+               {
+                       __u32 size;
+                       if (copy_from_user(&size, (void __user *)arg,
+                                          sizeof(__u32)))
+                               return -EFAULT;
+                       return dsp_kmem_reserve(size);
+               }
+
+       case MEM_IOCTL_KMEM_RELEASE:
+               dsp_kmem_release();
+               return 0;
+
+       default:
+               return -ENOIOCTLCMD;
+       }
+}
+
+static int dsp_mem_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       /*
+        * FIXME
+        */
+       return -ENOSYS;
+}
+
+static int dsp_mem_open(struct inode *inode, struct file *file)
+{
+       if (!capable(CAP_SYS_RAWIO))
+               return -EPERM;
+
+       return 0;
+}
+
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+/*
+ * fb update functions:
+ * fbupd_response() is executed by the workqueue.
+ * fbupd_cb() is called when fb update is done, in interrupt context.
+ * mbox_fbupd() is called when KFUNC:FBCTL:UPD is received from DSP.
+ */
+static void fbupd_response(struct work_struct *unused)
+{
+       int status;
+
+       status = mbcompose_send(KFUNC, KFUNC_FBCTL, FBCTL_UPD);
+       if (status < 0) {
+               /* FIXME: DSP is busy !! */
+               printk(KERN_ERR
+                      "omapdsp: DSP is busy when trying to send FBCTL:UPD "
+                      "response!\n");
+       }
+}
+
+static DECLARE_WORK(fbupd_response_work, fbupd_response);
+
+static void fbupd_cb(void *arg)
+{
+       schedule_work(&fbupd_response_work);
+}
+
+void mbox_fbctl_upd(void)
+{
+       struct omapfb_update_window win;
+       volatile unsigned short *buf = ipbuf_sys_da->d;
+
+       /* FIXME: try count sometimes exceeds 1000. */
+       if (sync_with_dsp(&ipbuf_sys_da->s, TID_ANON, 5000) < 0) {
+               printk(KERN_ERR "mbox: FBCTL:UPD - IPBUF sync failed!\n");
+               return;
+       }
+       win.x = buf[0];
+       win.y = buf[1];
+       win.width = buf[2];
+       win.height = buf[3];
+       win.format = buf[4];
+       release_ipbuf_pvt(ipbuf_sys_da);
+
+       if (!omapfb_ready) {
+               printk(KERN_WARNING
+                      "omapdsp: fbupd() called while HWA742 is not ready!\n");
+               return;
+       }
+       //printk("calling omapfb_update_window_async()\n");
+       omapfb_update_window_async(registered_fb[0], &win, fbupd_cb, NULL);
+}
+
+#else /* CONFIG_FB_OMAP_LCDC_EXTERNAL */
+
+void mbox_fbctl_upd(void)
+{
+}
+#endif /* CONFIG_FB_OMAP_LCDC_EXTERNAL */
+
+/*
+ * sysfs files
+ */
+
+/* mmu */
+static ssize_t mmu_show(struct device *dev, struct device_attribute *attr,
+                       char *buf)
+{
+       int len;
+       struct tlb_lock tlb_lock_org;
+       int i;
+
+#ifdef CONFIG_ARCH_OMAP1
+       clk_enable(dsp_ck_handle);
+       omap_dsp_request_mem();
+#endif
+       down_read(&exmap_sem);
+
+       get_tlb_lock(&tlb_lock_org);
+
+#if defined(CONFIG_ARCH_OMAP1)
+       len = sprintf(buf, "P: preserved, V: valid\n"
+                          "ety P V size   cam_va     ram_pa ap\n");
+                        /* 00: P V  4KB 0x300000 0x10171800 FA */
+#elif defined(CONFIG_ARCH_OMAP2)
+       len = sprintf(buf, "P: preserved, V: valid\n"
+                          "B: big endian, L:little endian, "
+                          "M: mixed page attribute\n"
+                          "ety P V size   cam_va     ram_pa E ES M\n");
+                        /* 00: P V  4KB 0x300000 0x10171800 B 16 M */
+#endif
+
+       for (i = 0; i < DSP_MMU_TLB_LINES; i++) {
+               struct cam_ram_regset cr;
+               struct tlb_lock tlb_lock_tmp;
+               struct tlb_entry ent;
+#if defined(CONFIG_ARCH_OMAP1)
+               char *pgsz_str, *ap_str;
+#elif defined(CONFIG_ARCH_OMAP2)
+               char *pgsz_str, *elsz_str;
+#endif
+
+               /* read a TLB entry */
+               tlb_lock_tmp.base   = tlb_lock_org.base;
+               tlb_lock_tmp.victim = i;
+               __read_tlb(&tlb_lock_tmp, &cr);
+
+#if defined(CONFIG_ARCH_OMAP1)
+               ent.pgsz  = cr.cam_l & DSP_MMU_CAM_PAGESIZE_MASK;
+               ent.prsvd = cr.cam_l & DSP_MMU_CAM_P;
+               ent.valid = cr.cam_l & DSP_MMU_CAM_V;
+               ent.ap    = cr.ram_l & DSP_MMU_RAM_L_AP_MASK;
+               ent.va = (u32)(cr.cam_h & DSP_MMU_CAM_H_VA_TAG_H_MASK) << 22 |
+                        (u32)(cr.cam_l & get_cam_l_va_mask(ent.pgsz)) << 6;
+               ent.pa = (unsigned long)cr.ram_h << 16 |
+                        (cr.ram_l & DSP_MMU_RAM_L_RAM_LSB_MASK);
+
+               pgsz_str = (ent.pgsz == DSP_MMU_CAM_PAGESIZE_1MB)  ? " 1MB":
+                          (ent.pgsz == DSP_MMU_CAM_PAGESIZE_64KB) ? "64KB":
+                          (ent.pgsz == DSP_MMU_CAM_PAGESIZE_4KB)  ? " 4KB":
+                          (ent.pgsz == DSP_MMU_CAM_PAGESIZE_1KB)  ? " 1KB":
+                                                                    " ???";
+               ap_str = (ent.ap == DSP_MMU_RAM_L_AP_RO) ? "RO":
+                        (ent.ap == DSP_MMU_RAM_L_AP_FA) ? "FA":
+                        (ent.ap == DSP_MMU_RAM_L_AP_NA) ? "NA":
+                                                          "??";
+#elif defined(CONFIG_ARCH_OMAP2)
+               ent.pgsz   = cr.cam & DSP_MMU_CAM_PAGESIZE_MASK;
+               ent.prsvd  = cr.cam & DSP_MMU_CAM_P;
+               ent.valid  = cr.cam & DSP_MMU_CAM_V;
+               ent.va     = cr.cam & DSP_MMU_CAM_VATAG_MASK;
+               ent.endian = cr.ram & DSP_MMU_RAM_ENDIANNESS;
+               ent.elsz   = cr.ram & DSP_MMU_RAM_ELEMENTSIZE_MASK;
+               ent.pa     = cr.ram & DSP_MMU_RAM_PADDR_MASK;
+               ent.mixed  = cr.ram & DSP_MMU_RAM_MIXED;
+
+               pgsz_str = (ent.pgsz == DSP_MMU_CAM_PAGESIZE_16MB) ? "64MB":
+                          (ent.pgsz == DSP_MMU_CAM_PAGESIZE_1MB)  ? " 1MB":
+                          (ent.pgsz == DSP_MMU_CAM_PAGESIZE_64KB) ? "64KB":
+                          (ent.pgsz == DSP_MMU_CAM_PAGESIZE_4KB)  ? " 4KB":
+                                                                    " ???";
+               elsz_str = (ent.elsz == DSP_MMU_RAM_ELEMENTSIZE_8)  ? " 8":
+                          (ent.elsz == DSP_MMU_RAM_ELEMENTSIZE_16) ? "16":
+                          (ent.elsz == DSP_MMU_RAM_ELEMENTSIZE_32) ? "32":
+                                                                     "??";
+#endif
+
+               if (i == tlb_lock_org.base)
+                       len += sprintf(buf + len, "lock base = %d\n",
+                                      tlb_lock_org.base);
+               if (i == tlb_lock_org.victim)
+                       len += sprintf(buf + len, "victim    = %d\n",
+                                      tlb_lock_org.victim);
+#if defined(CONFIG_ARCH_OMAP1)
+               len += sprintf(buf + len,
+                              /* 00: P V  4KB 0x300000 0x10171800 FA */
+                              "%02d: %c %c %s 0x%06x 0x%08lx %s\n",
+                              i,
+                              ent.prsvd ? 'P' : ' ',
+                              ent.valid ? 'V' : ' ',
+                              pgsz_str, ent.va, ent.pa, ap_str);
+#elif defined(CONFIG_ARCH_OMAP2)
+               len += sprintf(buf + len,
+                              /* 00: P V  4KB 0x300000 0x10171800 B 16 M */
+                              "%02d: %c %c %s 0x%06x 0x%08lx %c %s %c\n",
+                              i,
+                              ent.prsvd ? 'P' : ' ',
+                              ent.valid ? 'V' : ' ',
+                              pgsz_str, ent.va, ent.pa,
+                              ent.endian ? 'B' : 'L',
+                              elsz_str,
+                              ent.mixed ? 'M' : ' ');
+#endif /* CONFIG_ARCH_OMAP2 */
+       }
+
+       /* restore victim entry */
+       set_tlb_lock(&tlb_lock_org);
+
+       up_read(&exmap_sem);
+#ifdef CONFIG_ARCH_OMAP1
+       omap_dsp_release_mem();
+       clk_disable(dsp_ck_handle);
+#endif
+       return len;
+}
+
+/* exmap */
+static ssize_t exmap_show(struct device *dev, struct device_attribute *attr,
+                         char *buf)
+{
+       int len;
+       int i;
+
+       down_read(&exmap_sem);
+       len = sprintf(buf, "  dspadr     size         buf     size uc\n");
+                        /* 0x300000 0x123000  0xc0171000 0x100000  0*/
+       for (i = 0; i < DSP_MMU_TLB_LINES; i++) {
+               struct exmap_tbl_entry *ent = &exmap_tbl[i];
+               void *vadr;
+               unsigned long size;
+               enum exmap_type_e type;
+               int idx;
+
+               /* find a top of link */
+               if (!ent->valid || (ent->link.prev >= 0))
+                       continue;
+
+               vadr = ent->vadr;
+               type = ent->type;
+               size = 0;
+               idx = i;
+               do {
+                       ent = &exmap_tbl[idx];
+                       size += PAGE_SIZE << ent->order;
+               } while ((idx = ent->link.next) >= 0);
+
+               len += sprintf(buf + len, "0x%06x %#8lx",
+                              virt_to_dspbyte(vadr), size);
+
+               if (type == EXMAP_TYPE_FB) {
+                       len += sprintf(buf + len, "    framebuf\n");
+               } else {
+                       len += sprintf(buf + len, "\n");
+                       idx = i;
+                       do {
+                               ent = &exmap_tbl[idx];
+                               len += sprintf(buf + len,
+                                              /* 0xc0171000 0x100000  0*/
+                                              "%19s0x%8p %#8lx %2d\n",
+                                              "", ent->buf,
+                                              PAGE_SIZE << ent->order,
+                                              ent->usecount);
+                       } while ((idx = ent->link.next) >= 0);
+               }
+       }
+
+       up_read(&exmap_sem);
+       return len;
+}
+
+/* mempool */
+static ssize_t mempool_show(struct device *dev, struct device_attribute *attr,
+                           char *buf)
+{
+       int min_nr_1M = 0, curr_nr_1M = 0;
+       int min_nr_64K = 0, curr_nr_64K = 0;
+       int total = 0;
+
+       if (likely(kmem_pool_1M)) {
+               min_nr_1M  = kmem_pool_1M->min_nr;
+               curr_nr_1M = kmem_pool_1M->curr_nr;
+               total += min_nr_1M * SZ_1MB;
+       }
+       if (likely(kmem_pool_64K)) {
+               min_nr_64K  = kmem_pool_64K->min_nr;
+               curr_nr_64K = kmem_pool_64K->curr_nr;
+               total += min_nr_64K * SZ_64KB;
+       }
+
+       return sprintf(buf,
+                      "0x%x\n"
+                      "1M  buffer: %d (%d free)\n"
+                      "64K buffer: %d (%d free)\n",
+                      total, min_nr_1M, curr_nr_1M, min_nr_64K, curr_nr_64K);
+}
+
+/*
+ * workqueue for mmu int
+ */
+#ifdef CONFIG_ARCH_OMAP1
+/*
+ * MMU fault mask:
+ * We ignore prefetch err.
+ */
+#define MMUFAULT_MASK \
+       (DSP_MMU_FAULT_ST_PERM |\
+        DSP_MMU_FAULT_ST_TLB_MISS |\
+        DSP_MMU_FAULT_ST_TRANS)
+#endif /* CONFIG_ARCH_OMAP1 */
+
+static void do_mmu_int(struct work_struct *unused)
+{
+#if defined(CONFIG_ARCH_OMAP1)
+
+       dsp_mmu_reg_t status;
+       dsp_mmu_reg_t adh, adl;
+       dsp_mmu_reg_t dp;
+
+       status = dsp_mmu_read_reg(DSP_MMU_FAULT_ST);
+       adh = dsp_mmu_read_reg(DSP_MMU_FAULT_AD_H);
+       adl = dsp_mmu_read_reg(DSP_MMU_FAULT_AD_L);
+       dp = adh & DSP_MMU_FAULT_AD_H_DP;
+       dsp_fault_adr = MK32(adh & DSP_MMU_FAULT_AD_H_ADR_MASK, adl);
+
+       /* if the fault is masked, nothing to do */
+       if ((status & MMUFAULT_MASK) == 0) {
+               printk(KERN_DEBUG "DSP MMU interrupt, but ignoring.\n");
+               /*
+                * note: in OMAP1710,
+                * when CACHE + DMA domain gets out of idle in DSP,
+                * MMU interrupt occurs but DSP_MMU_FAULT_ST is not set.
+                * in this case, we just ignore the interrupt.
+                */
+               if (status) {
+                       printk(KERN_DEBUG "%s%s%s%s\n",
+                              (status & DSP_MMU_FAULT_ST_PREF)?
+                                       "  (prefetch err)" : "",
+                              (status & DSP_MMU_FAULT_ST_PERM)?
+                                       "  (permission fault)" : "",
+                              (status & DSP_MMU_FAULT_ST_TLB_MISS)?
+                                       "  (TLB miss)" : "",
+                              (status & DSP_MMU_FAULT_ST_TRANS) ?
+                                       "  (translation fault)": "");
+                       printk(KERN_DEBUG "fault address = %#08x\n",
+                              dsp_fault_adr);
+               }
+               enable_irq(omap_dsp->mmu_irq);
+               return;
+       }
+
+#elif defined(CONFIG_ARCH_OMAP2)
+
+       dsp_mmu_reg_t status;
+
+       status = dsp_mmu_read_reg(DSP_MMU_IRQSTATUS);
+       dsp_fault_adr = dsp_mmu_read_reg(DSP_MMU_FAULT_AD);
+
+#endif /* CONFIG_ARCH_OMAP2 */
+
+       printk(KERN_INFO "DSP MMU interrupt!\n");
+
+#if defined(CONFIG_ARCH_OMAP1)
+
+       printk(KERN_INFO "%s%s%s%s\n",
+              (status & DSP_MMU_FAULT_ST_PREF)?
+                       (MMUFAULT_MASK & DSP_MMU_FAULT_ST_PREF)?
+                               "  prefetch err":
+                               "  (prefetch err)":
+                               "",
+              (status & DSP_MMU_FAULT_ST_PERM)?
+                       (MMUFAULT_MASK & DSP_MMU_FAULT_ST_PERM)?
+                               "  permission fault":
+                               "  (permission fault)":
+                               "",
+              (status & DSP_MMU_FAULT_ST_TLB_MISS)?
+                       (MMUFAULT_MASK & DSP_MMU_FAULT_ST_TLB_MISS)?
+                               "  TLB miss":
+                               "  (TLB miss)":
+                               "",
+              (status & DSP_MMU_FAULT_ST_TRANS)?
+                       (MMUFAULT_MASK & DSP_MMU_FAULT_ST_TRANS)?
+                               "  translation fault":
+                               "  (translation fault)":
+                               "");
+
+#elif defined(CONFIG_ARCH_OMAP2)
+
+       printk(KERN_INFO "%s%s%s%s%s\n",
+              (status & DSP_MMU_IRQ_MULTIHITFAULT)?
+                       (MMU_IRQ_MASK & DSP_MMU_IRQ_MULTIHITFAULT)?
+                               "  multi hit":
+                               "  (multi hit)":
+                               "",
+              (status & DSP_MMU_IRQ_TABLEWALKFAULT)?
+                       (MMU_IRQ_MASK & DSP_MMU_IRQ_TABLEWALKFAULT)?
+                               "  table walk fault":
+                               "  (table walk fault)":
+                               "",
+              (status & DSP_MMU_IRQ_EMUMISS)?
+                       (MMU_IRQ_MASK & DSP_MMU_IRQ_EMUMISS)?
+                               "  EMU miss":
+                               "  (EMU miss)":
+                               "",
+              (status & DSP_MMU_IRQ_TRANSLATIONFAULT)?
+                       (MMU_IRQ_MASK & DSP_MMU_IRQ_TRANSLATIONFAULT)?
+                               "  translation fault":
+                               "  (translation fault)":
+                               "",
+              (status & DSP_MMU_IRQ_TLBMISS)?
+                       (MMU_IRQ_MASK & DSP_MMU_IRQ_TLBMISS)?
+                               "  TLB miss":
+                               "  (TLB miss)":
+                               "");
+
+#endif /* CONFIG_ARCH_OMAP2 */
+
+       printk(KERN_INFO "fault address = %#08x\n", dsp_fault_adr);
+
+       if (dsp_cfgstat_get_stat() == CFGSTAT_READY)
+               dsp_err_set(ERRCODE_MMU, (unsigned long)dsp_fault_adr);
+       else {
+#ifdef CONFIG_ARCH_OMAP1
+               __dsp_mmu_itack();
+#endif
+               printk(KERN_INFO "Resetting DSP...\n");
+               dsp_cpustat_request(CPUSTAT_RESET);
+               /*
+                * if we enable followings, semaphore lock should be avoided.
+                *
+               printk(KERN_INFO "Flushing DSP MMU...\n");
+               exmap_flush();
+               dsp_mmu_init();
+                */
+       }
+
+#ifdef CONFIG_ARCH_OMAP2
+       dsp_mmu_disable();
+       dsp_mmu_write_reg(status, DSP_MMU_IRQSTATUS);
+       dsp_mmu_enable();
+#endif
+
+       enable_irq(omap_dsp->mmu_irq);
+}
+
+static DECLARE_WORK(mmu_int_work, do_mmu_int);
+
+/*
+ * DSP MMU interrupt handler
+ */
+
+static irqreturn_t dsp_mmu_interrupt(int irq, void *dev_id)
+{
+       disable_irq(omap_dsp->mmu_irq);
+       schedule_work(&mmu_int_work);
+       return IRQ_HANDLED;
+}
+
+/*
+ *
+ */
+struct file_operations dsp_mem_fops = {
+       .owner   = THIS_MODULE,
+       .llseek  = dsp_mem_lseek,
+       .read    = dsp_mem_read,
+       .write   = dsp_mem_write,
+       .ioctl   = dsp_mem_ioctl,
+       .mmap    = dsp_mem_mmap,
+       .open    = dsp_mem_open,
+};
+
+void dsp_mem_start(void)
+{
+#ifdef CONFIG_ARCH_OMAP1
+       dsp_register_mem_cb(intmem_enable, intmem_disable);
+#endif
+}
+
+void dsp_mem_stop(void)
+{
+       memset(&mem_sync, 0, sizeof(struct mem_sync_struct));
+#ifdef CONFIG_ARCH_OMAP1
+       dsp_unregister_mem_cb();
+#endif
+}
+
+/*
+ * later half of dsp memory initialization
+ */
+void dsp_mem_late_init(void)
+{
+#ifdef CONFIG_ARCH_OMAP2
+       int i;
+       int dspmem_pg_count;
+
+       dspmem_pg_count = dspmem_size >> 12;
+       for (i = 0; i < dspmem_pg_count; i++) {
+               dsp_ipi_write_reg(i, DSP_IPI_INDEX);
+               dsp_ipi_write_reg(DSP_IPI_ENTRY_ELMSIZEVALUE_16,
+                                 DSP_IPI_ENTRY);
+       }
+       dsp_ipi_write_reg(1, DSP_IPI_ENABLE);
+       dsp_ipi_write_reg(IOMAP_VAL, DSP_IPI_IOMAP);
+#endif
+       dsp_mmu_init();
+}
+
+static char devid_mmu;
+
+int __init dsp_mem_init(void)
+{
+       int i, ret;
+
+       for (i = 0; i < DSP_MMU_TLB_LINES; i++)
+               exmap_tbl[i].valid = 0;
+
+       dspvect_page = (void *)__get_dma_pages(GFP_KERNEL, 0);
+       if (dspvect_page == NULL) {
+               printk(KERN_ERR
+                      "omapdsp: failed to allocate memory "
+                      "for dsp vector table\n");
+               return -ENOMEM;
+       }
+
+       /*
+        * DSP MMU interrupt setup
+        */
+       ret = request_irq(omap_dsp->mmu_irq, dsp_mmu_interrupt, IRQF_DISABLED,
+                         "dsp_mmu",  &devid_mmu);
+       if (ret) {
+               printk(KERN_ERR
+                      "failed to register DSP MMU interrupt: %d\n", ret);
+               return ret;
+       }
+
+       /* MMU interrupt is not enabled until DSP runs */
+       disable_irq(omap_dsp->mmu_irq);
+
+       ret = device_create_file(omap_dsp->dev, &dev_attr_mmu);
+       ret |= device_create_file(omap_dsp->dev, &dev_attr_exmap);
+       ret |= device_create_file(omap_dsp->dev, &dev_attr_mempool);
+       if (ret)
+               printk(KERN_ERR "device_create_file failed: %d\n", ret);
+
+       return 0;
+}
+
+void dsp_mem_exit(void)
+{
+       free_irq(omap_dsp->mmu_irq, &devid_mmu);
+
+       /* recover disable_depth */
+       enable_irq(omap_dsp->mmu_irq);
+
+#ifdef CONFIG_ARCH_OMAP1
+       dsp_reset_idle_boot_base();
+#endif
+       dsp_mmu_shutdown();
+       dsp_kmem_release();
+
+       if (dspvect_page != NULL) {
+               free_page((unsigned long)dspvect_page);
+               dspvect_page = NULL;
+       }
+
+       device_remove_file(omap_dsp->dev, &dev_attr_mmu);
+       device_remove_file(omap_dsp->dev, &dev_attr_exmap);
+       device_remove_file(omap_dsp->dev, &dev_attr_mempool);
+}
diff --git a/arch/arm/plat-omap/dsp/error.c b/arch/arm/plat-omap/dsp/error.c
new file mode 100644 (file)
index 0000000..dc831ce
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <asm/uaccess.h>
+#include "dsp_mbcmd.h"
+#include "dsp.h"
+
+/*
+ * value seen through read()
+ */
+#define DSP_ERR_WDT    0x00000001
+#define DSP_ERR_MMU    0x00000002
+static unsigned long errval;
+
+static DECLARE_WAIT_QUEUE_HEAD(err_wait_q);
+static int errcnt;
+static u16 wdtval;     /* FIXME: read through ioctl */
+static u32 mmu_fadr;   /* FIXME: read through ioctl */
+
+/*
+ * DSP error detection device file operations
+ */
+static ssize_t dsp_err_read(struct file *file, char __user *buf, size_t count,
+                           loff_t *ppos)
+{
+       unsigned long flags;
+       int status;
+
+       if (count < 4)
+               return 0;
+
+       if (errcnt == 0) {
+               long current_state;
+               DECLARE_WAITQUEUE(wait, current);
+
+               add_wait_queue(&err_wait_q, &wait);
+               current_state = current->state;
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (errcnt == 0)        /* last check */
+                       schedule();
+               set_current_state(current_state);
+               remove_wait_queue(&err_wait_q, &wait);
+               if (signal_pending(current))
+                       return -EINTR;
+       }
+
+       local_irq_save(flags);
+       status = copy_to_user(buf, &errval, 4);
+       if (status) {
+               local_irq_restore(flags);
+               return -EFAULT;
+       }
+       errcnt = 0;
+       local_irq_restore(flags);
+
+       return 4;
+}
+
+static unsigned int dsp_err_poll(struct file *file, poll_table *wait)
+{
+       unsigned int mask = 0;
+
+       poll_wait(file, &err_wait_q, wait);
+       if (errcnt != 0)
+               mask |= POLLIN | POLLRDNORM;
+
+       return mask;
+}
+
+struct file_operations dsp_err_fops = {
+       .owner = THIS_MODULE,
+       .poll  = dsp_err_poll,
+       .read  = dsp_err_read,
+};
+
+/*
+ * set / clear functions
+ */
+
+/* DSP MMU */
+static void dsp_err_mmu_set(unsigned long arg)
+{
+       disable_irq(omap_dsp->mmu_irq);
+       mmu_fadr = (u32)arg;
+}
+
+static void dsp_err_mmu_clr(void)
+{
+       enable_irq(omap_dsp->mmu_irq);
+}
+
+/* WDT */
+static void dsp_err_wdt_set(unsigned long arg)
+{
+       wdtval = (u16)arg;
+}
+
+/*
+ * error code handler
+ */
+static struct {
+       unsigned long val;
+       void (*set)(unsigned long arg);
+       void (*clr)(void);
+} dsp_err_desc[ERRCODE_MAX] = {
+       [ERRCODE_MMU] = { DSP_ERR_MMU, dsp_err_mmu_set, dsp_err_mmu_clr },
+       [ERRCODE_WDT] = { DSP_ERR_WDT, dsp_err_wdt_set, NULL },
+};
+
+void dsp_err_set(enum errcode_e code, unsigned long arg)
+{
+       if (dsp_err_desc[code].set != NULL)
+               dsp_err_desc[code].set(arg);
+
+       errval |= dsp_err_desc[code].val;
+       errcnt++;
+       wake_up_interruptible(&err_wait_q);
+}
+
+void dsp_err_clear(enum errcode_e code)
+{
+       errval &= ~dsp_err_desc[code].val;
+
+       if (dsp_err_desc[code].clr != NULL)
+               dsp_err_desc[code].clr();
+}
+
+int dsp_err_isset(enum errcode_e code)
+{
+       return (errval & dsp_err_desc[code].val) ? 1 : 0;
+}
+
+/*
+ * functions called from mailbox interrupt routine
+ */
+static void mbox_err_wdt(u16 data)
+{
+       dsp_err_set(DSP_ERR_WDT, (unsigned long)data);
+}
+
+#ifdef OLD_BINARY_SUPPORT
+/* v3.3 obsolete */
+void mbox_wdt(struct mbcmd *mb)
+{
+       mbox_err_wdt(mb->data);
+}
+#endif
+
+extern void mbox_err_ipbfull(void);
+extern void mbox_err_fatal(u8 tid);
+
+void mbox_err(struct mbcmd *mb)
+{
+       u8 eid = mb->cmd_l;
+       char *eidnm = subcmd_name(mb);
+       u8 tid;
+
+       if (eidnm) {
+               printk(KERN_WARNING
+                      "mbox: ERR from DSP (%s): 0x%04x\n", eidnm, mb->data);
+       } else {
+               printk(KERN_WARNING
+                      "mbox: ERR from DSP (unknown EID=%02x): %04x\n",
+                      eid, mb->data);
+       }
+
+       switch (eid) {
+       case EID_IPBFULL:
+               mbox_err_ipbfull();
+               break;
+
+       case EID_FATAL:
+               tid = mb->data & 0x00ff;
+               mbox_err_fatal(tid);
+               break;
+
+       case EID_WDT:
+               mbox_err_wdt(mb->data);
+               break;
+       }
+}
+
+/*
+ *
+ */
+void dsp_err_start(void)
+{
+       enum errcode_e i;
+
+       for (i = 0; i < ERRCODE_MAX; i++) {
+               if (dsp_err_isset(i))
+                       dsp_err_clear(i);
+       }
+
+       errcnt = 0;
+}
+
+void dsp_err_stop(void)
+{
+       wake_up_interruptible(&err_wait_q);
+}
diff --git a/arch/arm/plat-omap/dsp/fifo.h b/arch/arm/plat-omap/dsp/fifo.h
new file mode 100644 (file)
index 0000000..3a79867
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+struct fifo_struct {
+       spinlock_t lock;
+       char *buf;
+       size_t sz;
+       size_t cnt;
+       unsigned int wp;
+};
+
+static inline int alloc_fifo(struct fifo_struct *fifo, size_t sz)
+{
+       if ((fifo->buf = kmalloc(sz, GFP_KERNEL)) == NULL) {
+               fifo->sz = 0;
+               return -ENOMEM;
+       }
+       fifo->sz = sz;
+       fifo->cnt = 0;
+       fifo->wp = 0;
+       return 0;
+}
+
+static inline int init_fifo(struct fifo_struct *fifo, size_t sz)
+{
+       spin_lock_init(&fifo->lock);
+       return alloc_fifo(fifo, sz);
+}
+
+static inline void free_fifo(struct fifo_struct *fifo)
+{
+       spin_lock(&fifo->lock);
+       if (fifo->buf == NULL) {
+               spin_unlock(&fifo->lock);
+               return;
+       }
+
+       kfree(fifo->buf);
+       fifo->buf = NULL;
+       fifo->sz = 0;
+       spin_unlock(&fifo->lock);
+}
+
+static inline void flush_fifo(struct fifo_struct *fifo)
+{
+       spin_lock(&fifo->lock);
+       fifo->cnt = 0;
+       fifo->wp = 0;
+       spin_unlock(&fifo->lock);
+}
+
+#define fifo_empty(fifo)       ((fifo)->cnt == 0)
+
+static inline int realloc_fifo(struct fifo_struct *fifo, size_t sz)
+{
+       int ret = sz;
+
+       spin_lock(&fifo->lock);
+       if (!fifo_empty(fifo)) {
+               ret = -EBUSY;
+               goto out;
+       }
+
+       /* free */
+       if (fifo->buf)
+               kfree(fifo->buf);
+
+       /* alloc */
+       ret = alloc_fifo(fifo, sz);
+
+out:
+       spin_unlock(&fifo->lock);
+       return ret;
+}
+
+static inline void write_word_to_fifo(struct fifo_struct *fifo, u16 word)
+{
+       spin_lock(&fifo->lock);
+       *(u16 *)&fifo->buf[fifo->wp] = word;
+       if ((fifo->wp += 2) == fifo->sz)
+               fifo->wp = 0;
+       if ((fifo->cnt += 2) > fifo->sz)
+               fifo->cnt = fifo->sz;
+       spin_unlock(&fifo->lock);
+}
+
+/*
+ * (before)
+ *
+ * [*******----------*************]
+ *         ^wp
+ *  <---------------------------->  sz = 30
+ *  <----->          <----------->  cnt = 20
+ *
+ * (read: count=16)
+ *  <->              <----------->  count = 16
+ *                   <----------->  cnt1 = 13
+ *                   ^rp
+ *
+ * (after)
+ * [---****-----------------------]
+ *         ^wp
+ */
+static inline ssize_t copy_to_user_fm_fifo(char *dst, struct fifo_struct *fifo,
+                                          size_t count)
+{
+       int rp;
+       ssize_t ret;
+
+       /* fifo size can be zero */
+       if (fifo->sz == 0)
+               return 0;
+
+       spin_lock(&fifo->lock);
+       if (count > fifo->cnt)
+               count = fifo->cnt;
+
+       if ((rp = fifo->wp - fifo->cnt) >= 0) {
+               /* valid area is straight */
+               if (copy_to_user(dst, &fifo->buf[rp], count)) {
+                       ret = -EFAULT;
+                       goto out;
+               }
+       } else {
+               int cnt1 = -rp;
+               rp += fifo->sz;
+               if (cnt1 >= count) {
+                       /* requested area is straight */
+                       if (copy_to_user(dst, &fifo->buf[rp], count)) {
+                               ret = -EFAULT;
+                               goto out;
+                       }
+               } else {
+                       if (copy_to_user(dst, &fifo->buf[rp], cnt1)) {
+                               ret = -EFAULT;
+                               goto out;
+                       }
+                       if (copy_to_user(dst+cnt1, fifo->buf, count-cnt1)) {
+                               ret = -EFAULT;
+                               goto out;
+                       }
+               }
+       }
+       fifo->cnt -= count;
+       ret = count;
+
+out:
+       spin_unlock(&fifo->lock);
+       return ret;
+}
diff --git a/arch/arm/plat-omap/dsp/hardware_dsp.h b/arch/arm/plat-omap/dsp/hardware_dsp.h
new file mode 100644 (file)
index 0000000..a15d9af
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * 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
+#ifdef CONFIG_ARCH_OMAP2
+#include "omap2_dsp.h"
+#endif
+
+#endif /* __OMAP_DSP_HARDWARE_DSP_H */
diff --git a/arch/arm/plat-omap/dsp/ioctl.h b/arch/arm/plat-omap/dsp/ioctl.h
new file mode 100644 (file)
index 0000000..27e8358
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/*
+ * for /dev/dspctl/ctl
+ */
+#define DSPCTL_IOCTL_RESET             1
+#define DSPCTL_IOCTL_RUN               2
+#define DSPCTL_IOCTL_SETRSTVECT                3
+#ifdef CONFIG_ARCH_OMAP1
+#define DSPCTL_IOCTL_CPU_IDLE          4
+#define DSPCTL_IOCTL_MPUI_WORDSWAP_ON  5
+#define DSPCTL_IOCTL_MPUI_WORDSWAP_OFF 6
+#define DSPCTL_IOCTL_MPUI_BYTESWAP_ON  7
+#define DSPCTL_IOCTL_MPUI_BYTESWAP_OFF 8
+#define DSPCTL_IOCTL_GBL_IDLE          9
+#endif /* CONFIG_ARCH_OMAP1 */
+#define DSPCTL_IOCTL_DSPCFG            10
+#define DSPCTL_IOCTL_DSPUNCFG          11
+#define DSPCTL_IOCTL_TASKCNT           12
+#define DSPCTL_IOCTL_POLL              13
+#define DSPCTL_IOCTL_REGMEMR           40
+#define DSPCTL_IOCTL_REGMEMW           41
+#define DSPCTL_IOCTL_REGIOR            42
+#define DSPCTL_IOCTL_REGIOW            43
+#define DSPCTL_IOCTL_GETVAR            44
+#define DSPCTL_IOCTL_SETVAR            45
+#define DSPCTL_IOCTL_RUNLEVEL          50
+#define DSPCTL_IOCTL_SUSPEND           51
+#define DSPCTL_IOCTL_RESUME            52
+#ifdef CONFIG_OMAP_DSP_FBEXPORT
+#define DSPCTL_IOCTL_FBEN              53
+#define DSPCTL_IOCTL_FBDIS             54
+#endif /* CONFIG_OMAP_DSP_FBEXPORT */
+#define DSPCTL_IOCTL_MBSEND            99
+
+struct omap_dsp_mailbox_cmd {
+       __u16 cmd;
+       __u16 data;
+};
+
+struct omap_dsp_reginfo {
+       __u16 adr;
+       __u16 val;
+};
+
+struct omap_dsp_varinfo {
+       __u8 varid;
+       __u16 val[0];
+};
+
+/*
+ * for taskdev
+ * (ioctls below should be >= 0x10000)
+ */
+#define TASK_IOCTL_BFLSH       0x10000
+#define TASK_IOCTL_SETBSZ      0x10001
+#define TASK_IOCTL_LOCK                0x10002
+#define TASK_IOCTL_UNLOCK      0x10003
+#define TASK_IOCTL_GETNAME     0x10004
+
+/*
+ * for /dev/dspctl/mem
+ */
+#define MEM_IOCTL_EXMAP                1
+#define MEM_IOCTL_EXUNMAP      2
+#define MEM_IOCTL_EXMAP_FLUSH  3
+#define MEM_IOCTL_FBEXPORT     5
+#ifdef CONFIG_ARCH_OMAP1
+#define MEM_IOCTL_MMUITACK     7
+#endif
+#define MEM_IOCTL_MMUINIT      9
+#define MEM_IOCTL_KMEM_RESERVE 11
+#define MEM_IOCTL_KMEM_RELEASE 12
+
+struct omap_dsp_mapinfo {
+       __u32 dspadr;
+       __u32 size;
+};
+
+/*
+ * for /dev/dspctl/twch
+ */
+#define TWCH_IOCTL_MKDEV       1
+#define TWCH_IOCTL_RMDEV       2
+#define TWCH_IOCTL_TADD                11
+#define TWCH_IOCTL_TDEL                12
+#define TWCH_IOCTL_TKILL       13
+
+struct omap_dsp_taddinfo {
+       __u8 minor;
+       __u32 taskadr;
+};
+
+#define TADD_ABORTADR  0xffffffff
diff --git a/arch/arm/plat-omap/dsp/ipbuf.c b/arch/arm/plat-omap/dsp/ipbuf.c
new file mode 100644 (file)
index 0000000..943943b
--- /dev/null
@@ -0,0 +1,354 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/sched.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <asm/arch/mailbox.h>
+#include "dsp_mbcmd.h"
+#include "dsp.h"
+#include "ipbuf.h"
+
+static struct ipbuf_head *g_ipbuf;
+struct ipbcfg ipbcfg;
+struct ipbuf_sys *ipbuf_sys_da, *ipbuf_sys_ad;
+static struct ipblink ipb_free = IPBLINK_INIT;
+static int ipbuf_sys_hold_mem_active;
+
+static ssize_t ipbuf_show(struct device *dev, struct device_attribute *attr,
+                         char *buf);
+static struct device_attribute dev_attr_ipbuf = __ATTR_RO(ipbuf);
+
+void ipbuf_stop(void)
+{
+       int i;
+
+       device_remove_file(omap_dsp->dev, &dev_attr_ipbuf);
+
+       spin_lock(&ipb_free.lock);
+       RESET_IPBLINK(&ipb_free);
+       spin_unlock(&ipb_free.lock);
+
+       ipbcfg.ln = 0;
+       if (g_ipbuf) {
+               kfree(g_ipbuf);
+               g_ipbuf = NULL;
+       }
+       for (i = 0; i < ipbuf_sys_hold_mem_active; i++) {
+               dsp_mem_disable((void *)daram_base);
+       }
+       ipbuf_sys_hold_mem_active = 0;
+}
+
+int ipbuf_config(u16 ln, u16 lsz, void *base)
+{
+       size_t lsz_byte = ((size_t)lsz) << 1;
+       size_t size;
+       int ret = 0;
+       int i;
+
+       /*
+        * global IPBUF
+        */
+       if (((unsigned long)base) & 0x3) {
+               printk(KERN_ERR
+                      "omapdsp: global ipbuf address(0x%p) is not "
+                      "32-bit aligned!\n", base);
+               return -EINVAL;
+       }
+       size = lsz_byte * ln;
+       if (dsp_address_validate(base, size, "global ipbuf") < 0)
+               return -EINVAL;
+
+       g_ipbuf = kmalloc(sizeof(struct ipbuf_head) * ln, GFP_KERNEL);
+       if (g_ipbuf == NULL) {
+               printk(KERN_ERR
+                      "omapdsp: memory allocation for ipbuf failed.\n");
+               return -ENOMEM;
+       }
+       for (i = 0; i < ln; i++) {
+               void *top, *btm;
+
+               top = base + (sizeof(struct ipbuf) + lsz_byte) * i;
+               btm = base + (sizeof(struct ipbuf) + lsz_byte) * (i+1) - 1;
+               g_ipbuf[i].p = (struct ipbuf *)top;
+               g_ipbuf[i].bid = i;
+               if (((unsigned long)top & 0xfffe0000) !=
+                   ((unsigned long)btm & 0xfffe0000)) {
+                       /*
+                        * an ipbuf line should not cross
+                        * 64k-word boundary.
+                        */
+                       printk(KERN_ERR
+                              "omapdsp: ipbuf[%d] crosses 64k-word boundary!\n"
+                              "  @0x%p, size=0x%08x\n", i, top, lsz_byte);
+                       ret = -EINVAL;
+                       goto free_out;
+               }
+       }
+       ipbcfg.ln       = ln;
+       ipbcfg.lsz      = lsz;
+       ipbcfg.base     = base;
+       ipbcfg.bsycnt   = ln;   /* DSP holds all ipbufs initially. */
+       ipbcfg.cnt_full = 0;
+
+       printk(KERN_INFO
+              "omapdsp: IPBUF configuration\n"
+              "           %d words * %d lines at 0x%p.\n",
+              ipbcfg.lsz, ipbcfg.ln, ipbcfg.base);
+
+       ret = device_create_file(omap_dsp->dev, &dev_attr_ipbuf);
+       if (ret)
+               printk(KERN_ERR "device_create_file failed: %d\n", ret);
+
+       return ret;
+
+free_out:
+       kfree(g_ipbuf);
+       g_ipbuf = NULL;
+       return ret;
+}
+
+int ipbuf_sys_config(void *p, arm_dsp_dir_t dir)
+{
+       char *dir_str = (dir == DIR_D2A) ? "D2A" : "A2D";
+
+       if (((unsigned long)p) & 0x3) {
+               printk(KERN_ERR
+                      "omapdsp: system ipbuf(%s) address(0x%p) is "
+                      "not 32-bit aligned!\n", dir_str, p);
+               return -1;
+       }
+       if (dsp_address_validate(p, sizeof(struct ipbuf_sys),
+                                "system ipbuf(%s)", dir_str) < 0)
+               return -1;
+       if (dsp_mem_type(p, sizeof(struct ipbuf_sys)) != MEM_TYPE_EXTERN) {
+               printk(KERN_WARNING
+                      "omapdsp: system ipbuf(%s) is placed in"
+                      " DSP internal memory.\n"
+                      "         It will prevent DSP from idling.\n", dir_str);
+               ipbuf_sys_hold_mem_active++;
+               /*
+                * dsp_mem_enable() never fails because
+                * it has been already enabled in dspcfg process and
+                * this will just increment the usecount.
+                */
+               dsp_mem_enable((void *)daram_base);
+       }
+
+       if (dir == DIR_D2A)
+               ipbuf_sys_da = p;
+       else
+               ipbuf_sys_ad = p;
+
+       return 0;
+}
+
+int ipbuf_p_validate(void *p, arm_dsp_dir_t dir)
+{
+       char *dir_str = (dir == DIR_D2A) ? "D2A" : "A2D";
+
+       if (((unsigned long)p) & 0x3) {
+               printk(KERN_ERR
+                      "omapdsp: private ipbuf(%s) address(0x%p) is "
+                      "not 32-bit aligned!\n", dir_str, p);
+               return -1;
+       }
+       return dsp_address_validate(p, sizeof(struct ipbuf_p),
+                                   "private ipbuf(%s)", dir_str);
+}
+
+/*
+ * Global IPBUF operations
+ */
+struct ipbuf_head *bid_to_ipbuf(u16 bid)
+{
+       return &g_ipbuf[bid];
+}
+
+struct ipbuf_head *get_free_ipbuf(u8 tid)
+{
+       struct ipbuf_head *ipb_h;
+
+       if (dsp_mem_enable_ipbuf() < 0)
+               return NULL;
+
+       spin_lock(&ipb_free.lock);
+
+       if (ipblink_empty(&ipb_free)) {
+               /* FIXME: wait on queue when not available.  */
+               ipb_h = NULL;
+               goto out;
+       }
+       ipb_h = &g_ipbuf[ipb_free.top];
+       ipb_h->p->la = tid;     /* lock */
+       __ipblink_del_top(&ipb_free);
+out:
+       spin_unlock(&ipb_free.lock);
+       dsp_mem_disable_ipbuf();
+
+       return ipb_h;
+}
+
+void release_ipbuf(struct ipbuf_head *ipb_h)
+{
+       if (ipb_h->p->la == TID_FREE) {
+               printk(KERN_WARNING
+                      "omapdsp: attempt to release unlocked IPBUF[%d].\n",
+                      ipb_h->bid);
+               /*
+                * FIXME: re-calc bsycnt
+                */
+               return;
+       }
+       ipb_h->p->la = TID_FREE;
+       ipb_h->p->sa = TID_FREE;
+       ipblink_add_tail(&ipb_free, ipb_h->bid);
+}
+
+static int try_yld(struct ipbuf_head *ipb_h)
+{
+       int status;
+
+       ipb_h->p->sa = TID_ANON;
+       status = mbcompose_send(BKYLD, 0, ipb_h->bid);
+       if (status < 0) {
+               /* DSP is busy and ARM keeps this line. */
+               release_ipbuf(ipb_h);
+               return status;
+       }
+
+       ipb_bsycnt_inc(&ipbcfg);
+       return 0;
+}
+
+/*
+ * balancing ipbuf lines with DSP
+ */
+static void do_balance_ipbuf(struct work_struct *unused)
+{
+       while (ipbcfg.bsycnt <= ipbcfg.ln / 4) {
+               struct ipbuf_head *ipb_h;
+
+               if ((ipb_h = get_free_ipbuf(TID_ANON)) == NULL)
+                       return;
+               if (try_yld(ipb_h) < 0)
+                       return;
+       }
+}
+
+static DECLARE_WORK(balance_ipbuf_work, do_balance_ipbuf);
+
+void balance_ipbuf(void)
+{
+       schedule_work(&balance_ipbuf_work);
+}
+
+/* for process context */
+void unuse_ipbuf(struct ipbuf_head *ipb_h)
+{
+       if (ipbcfg.bsycnt > ipbcfg.ln / 4) {
+               /* we don't have enough IPBUF lines. let's keep it. */
+               release_ipbuf(ipb_h);
+       } else {
+               /* we have enough IPBUF lines. let's return this line to DSP. */
+               ipb_h->p->la = TID_ANON;
+               try_yld(ipb_h);
+               balance_ipbuf();
+       }
+}
+
+/* for interrupt context */
+void unuse_ipbuf_nowait(struct ipbuf_head *ipb_h)
+{
+       release_ipbuf(ipb_h);
+       balance_ipbuf();
+}
+
+/*
+ * functions called from mailbox interrupt routine
+ */
+
+void mbox_err_ipbfull(void)
+{
+       ipbcfg.cnt_full++;
+}
+
+/*
+ * sysfs files
+ */
+static ssize_t ipbuf_show(struct device *dev, struct device_attribute *attr,
+                         char *buf)
+{
+       int len = 0;
+       u16 bid;
+
+       for (bid = 0; bid < ipbcfg.ln; bid++) {
+               struct ipbuf_head *ipb_h = &g_ipbuf[bid];
+               u16 la = ipb_h->p->la;
+               u16 ld = ipb_h->p->ld;
+               u16 c  = ipb_h->p->c;
+
+               if (len > PAGE_SIZE - 100) {
+                       len += sprintf(buf + len, "out of buffer.\n");
+                       goto finish;
+               }
+
+               len += sprintf(buf + len, "ipbuf[%d]: adr = 0x%p\n",
+                              bid, ipb_h->p);
+               if (la == TID_FREE) {
+                       len += sprintf(buf + len,
+                                      "  DSPtask[%d]->Linux "
+                                      "(already read and now free for Linux)\n",
+                                      ld);
+               } else if (ld == TID_FREE) {
+                       len += sprintf(buf + len,
+                                      "  Linux->DSPtask[%d] "
+                                      "(already read and now free for DSP)\n",
+                                      la);
+               } else if (ipbuf_is_held(ld, bid)) {
+                       len += sprintf(buf + len,
+                                      "  DSPtask[%d]->Linux "
+                                      "(waiting to be read)\n"
+                                      "  count = %d\n", ld, c);
+               } else {
+                       len += sprintf(buf + len,
+                                      "  Linux->DSPtask[%d] "
+                                      "(waiting to be read)\n"
+                                      "  count = %d\n", la, c);
+               }
+       }
+
+       len += sprintf(buf + len, "\nFree IPBUF link: ");
+       spin_lock(&ipb_free.lock);
+       ipblink_for_each(bid, &ipb_free) {
+               len += sprintf(buf + len, "%d ", bid);
+       }
+       spin_unlock(&ipb_free.lock);
+       len += sprintf(buf + len, "\n");
+       len += sprintf(buf + len, "IPBFULL error count: %ld\n",
+                      ipbcfg.cnt_full);
+
+finish:
+       return len;
+}
diff --git a/arch/arm/plat-omap/dsp/ipbuf.h b/arch/arm/plat-omap/dsp/ipbuf.h
new file mode 100644 (file)
index 0000000..efaa2b7
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+struct ipbuf {
+       u16 c;                  /* count */
+       u16 next;               /* link */
+       u16 la;                 /* lock owner (ARM side) */
+       u16 sa;                 /* sync word (ARM->DSP) */
+       u16 ld;                 /* lock owner (DSP side) */
+       u16 sd;                 /* sync word (DSP->ARM) */
+       unsigned char d[0];     /* data */
+};
+
+struct ipbuf_p {
+       u16 c;          /* count */
+       u16 s;          /* sync word */
+       u16 al;         /* data address lower */
+       u16 ah;         /* data address upper */
+};
+
+#define IPBUF_SYS_DLEN 31
+
+struct ipbuf_sys {
+       u16 s;                  /* sync word */
+       u16 d[IPBUF_SYS_DLEN];  /* data */
+};
+
+struct ipbcfg {
+       u16 ln;
+       u16 lsz;
+       void *base;
+       u16 bsycnt;
+       unsigned long cnt_full; /* count of IPBFULL error */
+};
+
+struct ipbuf_head {
+       u16 bid;
+       struct ipbuf *p;
+};
+
+extern struct ipbcfg ipbcfg;
+extern struct ipbuf_sys *ipbuf_sys_da, *ipbuf_sys_ad;
+
+#define ipb_bsycnt_inc(ipbcfg)                         \
+       do {                                            \
+               disable_irq(omap_dsp->mbox->irq);       \
+               (ipbcfg)->bsycnt++;                     \
+               enable_irq(omap_dsp->mbox->irq);        \
+       } while(0)
+
+#define ipb_bsycnt_dec(ipbcfg)                         \
+       do {                                            \
+               disable_irq(omap_dsp->mbox->irq);       \
+               (ipbcfg)->bsycnt--;                     \
+               enable_irq(omap_dsp->mbox->irq);        \
+       } while(0)
+
+#define dsp_mem_enable_ipbuf() dsp_mem_enable(ipbcfg.base)
+#define dsp_mem_disable_ipbuf()        dsp_mem_disable(ipbcfg.base)
+
+struct ipblink {
+       spinlock_t lock;
+       u16 top;
+       u16 tail;
+};
+
+#define IPBLINK_INIT {                         \
+               .lock = SPIN_LOCK_UNLOCKED,     \
+               .top  = BID_NULL,               \
+               .tail = BID_NULL,               \
+       }
+
+#define INIT_IPBLINK(link)                     \
+       do {                                    \
+               spin_lock_init(&(link)->lock);  \
+               (link)->top  = BID_NULL;        \
+               (link)->tail = BID_NULL;        \
+       } while(0)
+
+#define RESET_IPBLINK(link)                    \
+       do {                                    \
+               (link)->top  = BID_NULL;        \
+               (link)->tail = BID_NULL;        \
+       } while(0)
+
+#define ipblink_empty(link)    ((link)->top == BID_NULL)
+
+static __inline__ void __ipblink_del_top(struct ipblink *link)
+{
+       struct ipbuf_head *ipb_h = bid_to_ipbuf(link->top);
+
+       if ((link->top = ipb_h->p->next) == BID_NULL)
+               link->tail = BID_NULL;
+       else
+               ipb_h->p->next = BID_NULL;
+}
+
+static __inline__ void ipblink_del_top(struct ipblink *link)
+{
+       spin_lock(&link->lock);
+       __ipblink_del_top(link);
+       spin_unlock(&link->lock);
+}
+
+static __inline__ void __ipblink_add_tail(struct ipblink *link, u16 bid)
+{
+       if (ipblink_empty(link))
+               link->top = bid;
+       else
+               bid_to_ipbuf(link->tail)->p->next = bid;
+       link->tail = bid;
+}
+
+static __inline__ void ipblink_add_tail(struct ipblink *link, u16 bid)
+{
+       spin_lock(&link->lock);
+       __ipblink_add_tail(link, bid);
+       spin_unlock(&link->lock);
+}
+
+static __inline__ void __ipblink_flush(struct ipblink *link)
+{
+       u16 bid;
+
+       while (!ipblink_empty(link)) {
+               bid = link->top;
+               __ipblink_del_top(link);
+               unuse_ipbuf(bid_to_ipbuf(bid));
+       }
+}
+
+static __inline__ void ipblink_flush(struct ipblink *link)
+{
+       spin_lock(&link->lock);
+       __ipblink_flush(link);
+       spin_unlock(&link->lock);
+}
+
+static __inline__ void __ipblink_add_pvt(struct ipblink *link)
+{
+       link->top  = BID_PVT;
+       link->tail = BID_PVT;
+}
+
+static __inline__ void ipblink_add_pvt(struct ipblink *link)
+{
+       spin_lock(&link->lock);
+       __ipblink_add_pvt(link);
+       spin_unlock(&link->lock);
+}
+
+static __inline__ void __ipblink_del_pvt(struct ipblink *link)
+{
+       link->top  = BID_NULL;
+       link->tail = BID_NULL;
+}
+
+static __inline__ void ipblink_del_pvt(struct ipblink *link)
+{
+       spin_lock(&link->lock);
+       __ipblink_del_pvt(link);
+       spin_unlock(&link->lock);
+}
+
+static __inline__ void __ipblink_flush_pvt(struct ipblink *link)
+{
+       if (!ipblink_empty(link))
+               ipblink_del_pvt(link);
+}
+
+static __inline__ void ipblink_flush_pvt(struct ipblink *link)
+{
+       spin_lock(&link->lock);
+       __ipblink_flush_pvt(link);
+       spin_unlock(&link->lock);
+}
+
+#define ipblink_for_each(bid, link) \
+       for (bid = (link)->top; bid != BID_NULL; bid = bid_to_ipbuf(bid)->p->next)
diff --git a/arch/arm/plat-omap/dsp/mblog.c b/arch/arm/plat-omap/dsp/mblog.c
new file mode 100644 (file)
index 0000000..53ac4ae
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2003-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <asm/arch/mailbox.h>
+#include "dsp_mbcmd.h"
+#include "dsp.h"
+
+char *subcmd_name(struct mbcmd *mb)
+{
+       u8 cmd_h = mb->cmd_h;
+       u8 cmd_l = mb->cmd_l;
+       char *s;
+
+       switch (cmd_h) {
+       case MBOX_CMD_DSP_RUNLEVEL:
+               s = (cmd_l == RUNLEVEL_USER)     ? "USER":
+                   (cmd_l == RUNLEVEL_SUPER)    ? "SUPER":
+                   (cmd_l == RUNLEVEL_RECOVERY) ? "RECOVERY":
+                   NULL;
+               break;
+       case MBOX_CMD_DSP_PM:
+               s = (cmd_l == PM_DISABLE) ? "DISABLE":
+                   (cmd_l == PM_ENABLE)  ? "ENABLE":
+                   NULL;
+               break;
+       case MBOX_CMD_DSP_KFUNC:
+               s = (cmd_l == KFUNC_FBCTL) ? "FBCTL":
+                   (cmd_l == KFUNC_POWER) ? "POWER":
+                   NULL;
+               break;
+       case MBOX_CMD_DSP_DSPCFG:
+               {
+                       u8 cfgc = cmd_l & 0x7f;
+                       s = (cfgc == DSPCFG_REQ)     ? "REQ":
+                           (cfgc == DSPCFG_SYSADRH) ? "SYSADRH":
+                           (cfgc == DSPCFG_SYSADRL) ? "SYSADRL":
+                           (cfgc == DSPCFG_ABORT)   ? "ABORT":
+                           (cfgc == DSPCFG_PROTREV) ? "PROTREV":
+                           NULL;
+                       break;
+               }
+       case MBOX_CMD_DSP_REGRW:
+               s = (cmd_l == REGRW_MEMR) ? "MEMR":
+                   (cmd_l == REGRW_MEMW) ? "MEMW":
+                   (cmd_l == REGRW_IOR)  ? "IOR":
+                   (cmd_l == REGRW_IOW)  ? "IOW":
+                   (cmd_l == REGRW_DATA) ? "DATA":
+                   NULL;
+               break;
+       case MBOX_CMD_DSP_GETVAR:
+       case MBOX_CMD_DSP_SETVAR:
+               s = (cmd_l == VARID_ICRMASK)  ? "ICRMASK":
+                   (cmd_l == VARID_LOADINFO) ? "LOADINFO":
+                   NULL;
+               break;
+       case MBOX_CMD_DSP_ERR:
+               s = (cmd_l == EID_BADTID)     ? "BADTID":
+                   (cmd_l == EID_BADTCN)     ? "BADTCN":
+                   (cmd_l == EID_BADBID)     ? "BADBID":
+                   (cmd_l == EID_BADCNT)     ? "BADCNT":
+                   (cmd_l == EID_NOTLOCKED)  ? "NOTLOCKED":
+                   (cmd_l == EID_STVBUF)     ? "STVBUF":
+                   (cmd_l == EID_BADADR)     ? "BADADR":
+                   (cmd_l == EID_BADTCTL)    ? "BADTCTL":
+                   (cmd_l == EID_BADPARAM)   ? "BADPARAM":
+                   (cmd_l == EID_FATAL)      ? "FATAL":
+                   (cmd_l == EID_WDT)        ? "WDT":
+                   (cmd_l == EID_NOMEM)      ? "NOMEM":
+                   (cmd_l == EID_NORES)      ? "NORES":
+                   (cmd_l == EID_IPBFULL)    ? "IPBFULL":
+                   (cmd_l == EID_TASKNOTRDY) ? "TASKNOTRDY":
+                   (cmd_l == EID_TASKBSY)    ? "TASKBSY":
+                   (cmd_l == EID_TASKERR)    ? "TASKERR":
+                   (cmd_l == EID_BADCFGTYP)  ? "BADCFGTYP":
+                   (cmd_l == EID_DEBUG)      ? "DEBUG":
+                   (cmd_l == EID_BADSEQ)     ? "BADSEQ":
+                   (cmd_l == EID_BADCMD)     ? "BADCMD":
+                   NULL;
+               break;
+       default:
+               s = NULL;
+       }
+
+       return s;
+}
+
+/* output of show() method should fit to PAGE_SIZE */
+#define MBLOG_DEPTH    64
+
+struct mblogent {
+       unsigned long jiffies;
+       mbox_msg_t msg;
+       arm_dsp_dir_t dir;
+};
+
+static struct {
+       spinlock_t lock;
+       int wp;
+       unsigned long cnt, cnt_ad, cnt_da;
+       struct mblogent ent[MBLOG_DEPTH];
+} mblog = {
+       .lock = SPIN_LOCK_UNLOCKED,
+};
+
+#ifdef CONFIG_OMAP_DSP_MBCMD_VERBOSE
+static inline void mblog_print_cmd(struct mbcmd *mb, arm_dsp_dir_t dir)
+{
+       const struct cmdinfo *ci = cmdinfo[mb->cmd_h];
+       char *dir_str;
+       char *subname;
+
+       dir_str = (dir == DIR_A2D) ? "sending  " : "receiving";
+       switch (ci->cmd_l_type) {
+       case CMD_L_TYPE_SUBCMD:
+               subname = subcmd_name(mb);
+               if (unlikely(!subname))
+                       subname = "Unknown";
+               printk(KERN_DEBUG
+                      "mbox: %s seq=%d, cmd=%02x:%02x(%s:%s), data=%04x\n",
+                      dir_str, mb->seq, mb->cmd_h, mb->cmd_l,
+                      ci->name, subname, mb->data);
+               break;
+       case CMD_L_TYPE_TID:
+               printk(KERN_DEBUG
+                      "mbox: %s seq=%d, cmd=%02x:%02x(%s:task %d), data=%04x\n",
+                      dir_str, mb->seq, mb->cmd_h, mb->cmd_l,
+                      ci->name, mb->cmd_l, mb->data);
+               break;
+       case CMD_L_TYPE_NULL:
+               printk(KERN_DEBUG
+                      "mbox: %s seq=%d, cmd=%02x:%02x(%s), data=%04x\n",
+                      dir_str, mb->seq, mb->cmd_h, mb->cmd_l,
+                      ci->name, mb->data);
+               break;
+       }
+}
+#else
+static inline void mblog_print_cmd(struct mbcmd *mb, arm_dsp_dir_t dir) { }
+#endif
+
+void mblog_add(struct mbcmd *mb, arm_dsp_dir_t dir)
+{
+       struct mblogent *ent;
+
+       spin_lock(&mblog.lock);
+       ent = &mblog.ent[mblog.wp];
+       ent->jiffies = jiffies;
+       ent->msg = *(mbox_msg_t *)mb;
+       ent->dir = dir;
+       if (mblog.cnt < 0xffffffff)
+               mblog.cnt++;
+       switch (dir) {
+       case DIR_A2D:
+               if (mblog.cnt_ad < 0xffffffff)
+                       mblog.cnt_ad++;
+               break;
+       case DIR_D2A:
+               if (mblog.cnt_da < 0xffffffff)
+                       mblog.cnt_da++;
+               break;
+       }
+       if (++mblog.wp == MBLOG_DEPTH)
+               mblog.wp = 0;
+       spin_unlock(&mblog.lock);
+
+       mblog_print_cmd(mb, dir);
+}
+
+/*
+ * sysfs file
+ */
+static ssize_t mblog_show(struct device *dev, struct device_attribute *attr,
+                         char *buf)
+{
+       int len = 0;
+       int wp;
+       int i;
+
+       spin_lock(&mblog.lock);
+
+       wp = mblog.wp;
+       len += sprintf(buf + len,
+                      "log count:%ld / ARM->DSP:%ld, DSP->ARM:%ld\n",
+                      mblog.cnt, mblog.cnt_ad, mblog.cnt_da);
+       if (mblog.cnt == 0)
+               goto done;
+
+       len += sprintf(buf + len, "           ARM->DSP   ARM<-DSP\n");
+       len += sprintf(buf + len, " jiffies  cmd  data  cmd  data\n");
+       i = (mblog.cnt >= MBLOG_DEPTH) ? wp : 0;
+       do {
+               struct mblogent *ent = &mblog.ent[i];
+               struct mbcmd *mb = (struct mbcmd *)&ent->msg;
+               char *subname;
+               struct cmdinfo ci_null = {
+                       .name = "Unknown",
+                       .cmd_l_type = CMD_L_TYPE_NULL,
+               };
+               const struct cmdinfo *ci;
+
+               len += sprintf(buf + len,
+                              (ent->dir == DIR_A2D) ?
+                               "%08lx  %04x %04x            ":
+                               "%08lx             %04x %04x ",
+                              ent->jiffies,
+                              (ent->msg >> 16) & 0x7fff, ent->msg & 0xffff);
+
+               if ((ci = cmdinfo[mb->cmd_h]) == NULL)
+                       ci = &ci_null;
+
+               switch (ci->cmd_l_type) {
+               case CMD_L_TYPE_SUBCMD:
+                       if ((subname = subcmd_name(mb)) == NULL)
+                               subname = "Unknown";
+                       len += sprintf(buf + len, "%s:%s\n",
+                                      ci->name, subname);
+                       break;
+               case CMD_L_TYPE_TID:
+                       len += sprintf(buf + len, "%s:task %d\n",
+                                      ci->name, mb->cmd_l);
+                       break;
+               case CMD_L_TYPE_NULL:
+                       len += sprintf(buf + len, "%s\n", ci->name);
+                       break;
+               }
+
+               if (++i == MBLOG_DEPTH)
+                       i = 0;
+       } while (i != wp);
+
+done:
+       spin_unlock(&mblog.lock);
+
+       return len;
+}
+
+static struct device_attribute dev_attr_mblog = __ATTR_RO(mblog);
+
+void __init mblog_init(void)
+{
+       int ret;
+
+       ret = device_create_file(omap_dsp->dev, &dev_attr_mblog);
+       if (ret)
+               printk(KERN_ERR "device_create_file failed: %d\n", ret);
+}
+
+void mblog_exit(void)
+{
+       device_remove_file(omap_dsp->dev, &dev_attr_mblog);
+}
diff --git a/arch/arm/plat-omap/dsp/omap1_dsp.h b/arch/arm/plat-omap/dsp/omap1_dsp.h
new file mode 100644 (file)
index 0000000..8dfe4d6
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * 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 MMU
+ */
+#define DSP_MMU_BASE                   (0xfffed200)
+#define DSP_MMU_PREFETCH               (DSP_MMU_BASE + 0x00)
+#define DSP_MMU_WALKING_ST             (DSP_MMU_BASE + 0x04)
+#define DSP_MMU_CNTL                   (DSP_MMU_BASE + 0x08)
+#define DSP_MMU_FAULT_AD_H             (DSP_MMU_BASE + 0x0c)
+#define DSP_MMU_FAULT_AD_L             (DSP_MMU_BASE + 0x10)
+#define DSP_MMU_FAULT_ST               (DSP_MMU_BASE + 0x14)
+#define DSP_MMU_IT_ACK                 (DSP_MMU_BASE + 0x18)
+#define DSP_MMU_TTB_H                  (DSP_MMU_BASE + 0x1c)
+#define DSP_MMU_TTB_L                  (DSP_MMU_BASE + 0x20)
+#define DSP_MMU_LOCK                   (DSP_MMU_BASE + 0x24)
+#define DSP_MMU_LD_TLB                 (DSP_MMU_BASE + 0x28)
+#define DSP_MMU_CAM_H                  (DSP_MMU_BASE + 0x2c)
+#define DSP_MMU_CAM_L                  (DSP_MMU_BASE + 0x30)
+#define DSP_MMU_RAM_H                  (DSP_MMU_BASE + 0x34)
+#define DSP_MMU_RAM_L                  (DSP_MMU_BASE + 0x38)
+#define DSP_MMU_GFLUSH                 (DSP_MMU_BASE + 0x3c)
+#define DSP_MMU_FLUSH_ENTRY            (DSP_MMU_BASE + 0x40)
+#define DSP_MMU_READ_CAM_H             (DSP_MMU_BASE + 0x44)
+#define DSP_MMU_READ_CAM_L             (DSP_MMU_BASE + 0x48)
+#define DSP_MMU_READ_RAM_H             (DSP_MMU_BASE + 0x4c)
+#define DSP_MMU_READ_RAM_L             (DSP_MMU_BASE + 0x50)
+
+#define DSP_MMU_CNTL_BURST_16MNGT_EN   0x0020
+#define DSP_MMU_CNTL_WTL_EN            0x0004
+#define DSP_MMU_CNTL_MMU_EN            0x0002
+#define DSP_MMU_CNTL_RESET_SW          0x0001
+
+#define DSP_MMU_FAULT_AD_H_DP          0x0100
+#define DSP_MMU_FAULT_AD_H_ADR_MASK    0x00ff
+
+#define DSP_MMU_FAULT_ST_PREF          0x0008
+#define DSP_MMU_FAULT_ST_PERM          0x0004
+#define DSP_MMU_FAULT_ST_TLB_MISS      0x0002
+#define DSP_MMU_FAULT_ST_TRANS         0x0001
+
+#define DSP_MMU_IT_ACK_IT_ACK          0x0001
+
+#define DSP_MMU_LOCK_BASE_MASK         0xfc00
+#define DSP_MMU_LOCK_BASE_SHIFT                10
+#define DSP_MMU_LOCK_VICTIM_MASK       0x03f0
+#define DSP_MMU_LOCK_VICTIM_SHIFT      4
+
+#define DSP_MMU_CAM_H_VA_TAG_H_MASK            0x0003
+
+#define DSP_MMU_CAM_L_VA_TAG_L1_MASK           0xc000
+#define DSP_MMU_CAM_L_VA_TAG_L2_MASK_1MB       0x0000
+#define DSP_MMU_CAM_L_VA_TAG_L2_MASK_64KB      0x3c00
+#define DSP_MMU_CAM_L_VA_TAG_L2_MASK_4KB       0x3fc0
+#define DSP_MMU_CAM_L_VA_TAG_L2_MASK_1KB       0x3ff0
+#define DSP_MMU_CAM_L_P                                0x0008
+#define DSP_MMU_CAM_L_V                                0x0004
+#define DSP_MMU_CAM_L_PAGESIZE_MASK            0x0003
+#define DSP_MMU_CAM_L_PAGESIZE_1MB             0x0000
+#define DSP_MMU_CAM_L_PAGESIZE_64KB            0x0001
+#define DSP_MMU_CAM_L_PAGESIZE_4KB             0x0002
+#define DSP_MMU_CAM_L_PAGESIZE_1KB             0x0003
+
+#define DSP_MMU_RAM_L_RAM_LSB_MASK     0xfc00
+#define DSP_MMU_RAM_L_AP_MASK          0x0300
+#define DSP_MMU_RAM_L_AP_NA            0x0000
+#define DSP_MMU_RAM_L_AP_RO            0x0200
+#define DSP_MMU_RAM_L_AP_FA            0x0300
+
+#define DSP_MMU_GFLUSH_GFLUSH          0x0001
+
+#define DSP_MMU_FLUSH_ENTRY_FLUSH_ENTRY        0x0001
+
+#define DSP_MMU_LD_TLB_RD              0x0002
+#define DSP_MMU_LD_TLB_LD              0x0001
+
+/*
+ * 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 */
diff --git a/arch/arm/plat-omap/dsp/omap2_dsp.h b/arch/arm/plat-omap/dsp/omap2_dsp.h
new file mode 100644 (file)
index 0000000..28a98ad
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __OMAP_DSP_OMAP2_DSP_H
+#define __OMAP_DSP_OMAP2_DSP_H
+
+#ifdef CONFIG_ARCH_OMAP24XX
+#define OMAP24XX_DARAM_BASE    (DSP_MEM_24XX_VIRT + 0x0)
+#define OMAP24XX_DARAM_SIZE    0x10000
+#define OMAP24XX_SARAM_BASE    (DSP_MEM_24XX_VIRT + 0x10000)
+#define OMAP24XX_SARAM_SIZE    0x18000
+#endif
+
+#include <asm/arch/hardware.h>
+#include "../../mach-omap2/prcm-regs.h"
+
+/*
+ * DSP IPI registers: mapped to 0xe1000000 -- use readX(), writeX()
+ */
+#define DSP_IPI_BASE                   DSP_IPI_24XX_VIRT
+#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 MMU: mapped to 0xe2000000 -- use readX(), writeX()
+ */
+#define DSP_MMU_BASE                   DSP_MMU_24XX_VIRT
+#define DSP_MMU_REVISION               (DSP_MMU_BASE + 0x00)
+#define DSP_MMU_SYSCONFIG              (DSP_MMU_BASE + 0x10)
+#define DSP_MMU_SYSSTATUS              (DSP_MMU_BASE + 0x14)
+#define DSP_MMU_IRQSTATUS              (DSP_MMU_BASE + 0x18)
+#define DSP_MMU_IRQENABLE              (DSP_MMU_BASE + 0x1c)
+#define DSP_MMU_WALKING_ST             (DSP_MMU_BASE + 0x40)
+#define DSP_MMU_CNTL                   (DSP_MMU_BASE + 0x44)
+#define DSP_MMU_FAULT_AD               (DSP_MMU_BASE + 0x48)
+#define DSP_MMU_TTB                    (DSP_MMU_BASE + 0x4c)
+#define DSP_MMU_LOCK                   (DSP_MMU_BASE + 0x50)
+#define DSP_MMU_LD_TLB                 (DSP_MMU_BASE + 0x54)
+#define DSP_MMU_CAM                    (DSP_MMU_BASE + 0x58)
+#define DSP_MMU_RAM                    (DSP_MMU_BASE + 0x5c)
+#define DSP_MMU_GFLUSH                 (DSP_MMU_BASE + 0x60)
+#define DSP_MMU_FLUSH_ENTRY            (DSP_MMU_BASE + 0x64)
+#define DSP_MMU_READ_CAM               (DSP_MMU_BASE + 0x68)
+#define DSP_MMU_READ_RAM               (DSP_MMU_BASE + 0x6c)
+#define DSP_MMU_EMU_FAULT_AD           (DSP_MMU_BASE + 0x70)
+
+#define DSP_MMU_SYSCONFIG_CLOCKACTIVITY_MASK   0x00000300
+#define DSP_MMU_SYSCONFIG_IDLEMODE_MASK                0x00000018
+#define DSP_MMU_SYSCONFIG_SOFTRESET            0x00000002
+#define DSP_MMU_SYSCONFIG_AUTOIDLE             0x00000001
+
+#define DSP_MMU_IRQ_MULTIHITFAULT      0x00000010
+#define DSP_MMU_IRQ_TABLEWALKFAULT     0x00000008
+#define DSP_MMU_IRQ_EMUMISS            0x00000004
+#define DSP_MMU_IRQ_TRANSLATIONFAULT   0x00000002
+#define DSP_MMU_IRQ_TLBMISS            0x00000001
+
+#define DSP_MMU_CNTL_EMUTLBUPDATE      0x00000008
+#define DSP_MMU_CNTL_TWLENABLE         0x00000004
+#define DSP_MMU_CNTL_MMUENABLE         0x00000002
+
+#define DSP_MMU_LOCK_BASE_MASK         0x00007c00
+#define DSP_MMU_LOCK_BASE_SHIFT                10
+#define DSP_MMU_LOCK_VICTIM_MASK       0x000001f0
+#define DSP_MMU_LOCK_VICTIM_SHIFT      4
+
+#define DSP_MMU_CAM_VATAG_MASK         0xfffff000
+#define DSP_MMU_CAM_P                  0x00000008
+#define DSP_MMU_CAM_V                  0x00000004
+#define DSP_MMU_CAM_PAGESIZE_MASK      0x00000003
+#define DSP_MMU_CAM_PAGESIZE_1MB       0x00000000
+#define DSP_MMU_CAM_PAGESIZE_64KB      0x00000001
+#define DSP_MMU_CAM_PAGESIZE_4KB       0x00000002
+#define DSP_MMU_CAM_PAGESIZE_16MB      0x00000003
+
+#define DSP_MMU_RAM_PADDR_MASK         0xfffff000
+#define DSP_MMU_RAM_ENDIANNESS         0x00000200
+#define DSP_MMU_RAM_ENDIANNESS_BIG     0x00000200
+#define DSP_MMU_RAM_ENDIANNESS_LITTLE  0x00000000
+#define DSP_MMU_RAM_ELEMENTSIZE_MASK   0x00000180
+#define DSP_MMU_RAM_ELEMENTSIZE_8      0x00000000
+#define DSP_MMU_RAM_ELEMENTSIZE_16     0x00000080
+#define DSP_MMU_RAM_ELEMENTSIZE_32     0x00000100
+#define DSP_MMU_RAM_ELEMENTSIZE_NONE   0x00000180
+#define DSP_MMU_RAM_MIXED              0x00000040
+
+#define DSP_MMU_GFLUSH_GFLUSH          0x00000001
+
+#define DSP_MMU_FLUSH_ENTRY_FLUSH_ENTRY        0x00000001
+
+#define DSP_MMU_LD_TLB_LD              0x00000001
+
+/*
+ * 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 */
diff --git a/arch/arm/plat-omap/dsp/proclist.h b/arch/arm/plat-omap/dsp/proclist.h
new file mode 100644 (file)
index 0000000..cc5c3e0
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2004-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+struct proc_list {
+       struct list_head list_head;
+       pid_t pid;
+       struct file *file;
+};
+
+static __inline__ void proc_list_add(spinlock_t *lock, struct list_head *list,
+                                    struct task_struct *tsk, struct file *file)
+{
+       struct proc_list *new;
+
+       new = kmalloc(sizeof(struct proc_list), GFP_KERNEL);
+       new->pid = tsk->pid;
+       new->file = file;
+       spin_lock(lock);
+       list_add_tail(&new->list_head, list);
+       spin_unlock(lock);
+}
+
+static __inline__ void proc_list_del(spinlock_t *lock, struct list_head *list,
+                                    struct task_struct *tsk, struct file *file)
+{
+       struct proc_list *pl;
+
+       spin_lock(lock);
+       list_for_each_entry(pl, list, list_head) {
+               if (pl->file == file) {
+                       list_del(&pl->list_head);
+                       kfree(pl);
+                       spin_unlock(lock);
+                       return;
+               }
+       }
+
+       /* correspinding file struct isn't found in the list ???  */
+       printk(KERN_ERR "proc_list_del(): proc_list is inconsistent!\n"
+                       "struct file (%p) not found\n", file);
+       printk(KERN_ERR "listing proc_list...\n");
+       list_for_each_entry(pl, list, list_head)
+               printk(KERN_ERR "  pid:%d file:%p\n", pl->pid, pl->file);
+       spin_unlock(lock);
+}
+
+static __inline__ void proc_list_flush(spinlock_t *lock, struct list_head *list)
+{
+       struct proc_list *pl;
+
+       spin_lock(lock);
+       while (!list_empty(list)) {
+               pl = list_entry(list->next, struct proc_list, list_head);
+               list_del(&pl->list_head);
+               kfree(pl);
+       }
+       spin_unlock(lock);
+}
diff --git a/arch/arm/plat-omap/dsp/task.c b/arch/arm/plat-omap/dsp/task.c
new file mode 100644 (file)
index 0000000..807c408
--- /dev/null
@@ -0,0 +1,3025 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/major.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/arch/mailbox.h>
+#include "uaccess_dsp.h"
+#include "dsp_mbcmd.h"
+#include "dsp.h"
+#include "ipbuf.h"
+#include "fifo.h"
+#include "proclist.h"
+#include "ioctl.h"
+
+#define is_aligned(adr,align)  (!((adr)&((align)-1)))
+
+/*
+ * devstate: task device state machine
+ * NOTASK:     task is not attached.
+ * ATTACHED:   task is attached.
+ * GARBAGE:    task is detached. waiting for all processes to close this device.
+ * ADDREQ:     requesting for tadd
+ * DELREQ:     requesting for tdel. no process is opening this device.
+ * FREEZED:    task is attached, but reserved to be killed.
+ * ADDFAIL:    tadd failed.
+ * ADDING:     tadd in process.
+ * DELING:     tdel in process.
+ * KILLING:    tkill in process.
+ */
+#define TASKDEV_ST_NOTASK      0x00000001
+#define TASKDEV_ST_ATTACHED    0x00000002
+#define TASKDEV_ST_GARBAGE     0x00000004
+#define TASKDEV_ST_INVALID     0x00000008
+#define TASKDEV_ST_ADDREQ      0x00000100
+#define TASKDEV_ST_DELREQ      0x00000200
+#define TASKDEV_ST_FREEZED     0x00000400
+#define TASKDEV_ST_ADDFAIL     0x00001000
+#define TASKDEV_ST_ADDING      0x00010000
+#define TASKDEV_ST_DELING      0x00020000
+#define TASKDEV_ST_KILLING     0x00040000
+#define TASKDEV_ST_STATE_MASK  0x7fffffff
+#define TASKDEV_ST_STALE       0x80000000
+
+struct {
+       long state;
+       char *name;
+} devstate_desc[] = {
+       { TASKDEV_ST_NOTASK,   "notask" },
+       { TASKDEV_ST_ATTACHED, "attached" },
+       { TASKDEV_ST_GARBAGE,  "garbage" },
+       { TASKDEV_ST_INVALID,  "invalid" },
+       { TASKDEV_ST_ADDREQ,   "addreq" },
+       { TASKDEV_ST_DELREQ,   "delreq" },
+       { TASKDEV_ST_FREEZED,  "freezed" },
+       { TASKDEV_ST_ADDFAIL,  "addfail" },
+       { TASKDEV_ST_ADDING,   "adding" },
+       { TASKDEV_ST_DELING,   "deling" },
+       { TASKDEV_ST_KILLING,  "killing" },
+};
+
+static char *devstate_name(long state) {
+       int i;
+       int max = ARRAY_SIZE(devstate_desc);
+
+       for (i = 0; i < max; i++) {
+               if (state & devstate_desc[i].state)
+                       return devstate_desc[i].name;
+       }
+       return "unknown";
+}
+
+struct rcvdt_bk_struct {
+       struct ipblink link;
+       unsigned int rp;
+};
+
+struct taskdev {
+       struct bus_type *bus;
+       struct device dev;      /* Generic device interface */
+
+       long state;
+       struct rw_semaphore state_sem;
+       wait_queue_head_t state_wait_q;
+       struct mutex usecount_lock;
+       unsigned int usecount;
+       char name[TNM_LEN];
+       struct file_operations fops;
+       spinlock_t proc_list_lock;
+       struct list_head proc_list;
+       struct dsptask *task;
+
+       /* read stuff */
+       wait_queue_head_t read_wait_q;
+       struct mutex read_mutex;
+       union {
+               struct fifo_struct fifo;        /* for active word */
+               struct rcvdt_bk_struct bk;
+       } rcvdt;
+
+       /* write stuff */
+       wait_queue_head_t write_wait_q;
+       struct mutex write_mutex;
+       spinlock_t wsz_lock;
+       size_t wsz;
+
+       /* tctl stuff */
+       wait_queue_head_t tctl_wait_q;
+       struct mutex tctl_mutex;
+       int tctl_stat;
+       int tctl_ret;   /* return value for tctl_show() */
+
+       /* device lock */
+       struct mutex lock;
+       pid_t lock_pid;
+};
+
+#define to_taskdev(n) container_of(n, struct taskdev, dev)
+
+struct dsptask {
+       enum {
+               TASK_ST_ERR = 0,
+               TASK_ST_READY,
+               TASK_ST_CFGREQ
+       } state;
+       u8 tid;
+       char name[TNM_LEN];
+       u16 ttyp;
+       struct taskdev *dev;
+
+       /* read stuff */
+       struct ipbuf_p *ipbuf_pvt_r;
+
+       /* write stuff */
+       struct ipbuf_p *ipbuf_pvt_w;
+
+       /* mmap stuff */
+       void *map_base;
+       size_t map_length;
+};
+
+#define sndtyp_acv(ttyp)       ((ttyp) & TTYP_ASND)
+#define sndtyp_psv(ttyp)       (!((ttyp) & TTYP_ASND))
+#define sndtyp_bk(ttyp)                ((ttyp) & TTYP_BKDM)
+#define sndtyp_wd(ttyp)                (!((ttyp) & TTYP_BKDM))
+#define sndtyp_pvt(ttyp)       ((ttyp) & TTYP_PVDM)
+#define sndtyp_gbl(ttyp)       (!((ttyp) & TTYP_PVDM))
+#define rcvtyp_acv(ttyp)       ((ttyp) & TTYP_ARCV)
+#define rcvtyp_psv(ttyp)       (!((ttyp) & TTYP_ARCV))
+#define rcvtyp_bk(ttyp)                ((ttyp) & TTYP_BKMD)
+#define rcvtyp_wd(ttyp)                (!((ttyp) & TTYP_BKMD))
+#define rcvtyp_pvt(ttyp)       ((ttyp) & TTYP_PVMD)
+#define rcvtyp_gbl(ttyp)       (!((ttyp) & TTYP_PVMD))
+
+static __inline__ int has_taskdev_lock(struct taskdev *dev);
+static int dsp_rmdev_minor(unsigned char minor);
+static int taskdev_init(struct taskdev *dev, char *name, unsigned char minor);
+static void taskdev_delete(unsigned char minor);
+static int taskdev_attach_task(struct taskdev *dev, struct dsptask *task);
+static int dsp_tdel_bh(struct taskdev *dev, u16 type);
+
+static struct bus_type dsptask_bus = {
+       .name = "dsptask",
+};
+
+static struct class *dsp_task_class;
+static DEFINE_MUTEX(devmgr_lock);
+static struct taskdev *taskdev[TASKDEV_MAX];
+static struct dsptask *dsptask[TASKDEV_MAX];
+static DEFINE_MUTEX(cfg_lock);
+static u16 cfg_cmd;
+static u8 cfg_tid;
+static DECLARE_WAIT_QUEUE_HEAD(cfg_wait_q);
+static u8 n_task;      /* static task count */
+static void *heap;
+
+#define is_dynamic_task(tid)   ((tid) >= n_task)
+
+#define devstate_read_lock(dev, devstate) \
+               devstate_read_lock_timeout(dev, devstate, 0)
+#define devstate_read_unlock(dev)      up_read(&(dev)->state_sem)
+#define devstate_write_lock(dev, devstate) \
+               devstate_write_lock_timeout(dev, devstate, 0)
+#define devstate_write_unlock(dev)     up_write(&(dev)->state_sem)
+
+static ssize_t devname_show(struct device *d, struct device_attribute *attr,
+                           char *buf);
+static ssize_t devstate_show(struct device *d, struct device_attribute *attr,
+                            char *buf);
+static ssize_t proc_list_show(struct device *d, struct device_attribute *attr,
+                             char *buf);
+static ssize_t taskname_show(struct device *d, struct device_attribute *attr,
+                            char *buf);
+static ssize_t ttyp_show(struct device *d, struct device_attribute *attr,
+                        char *buf);
+static ssize_t fifosz_show(struct device *d, struct device_attribute *attr,
+                          char *buf);
+static int fifosz_store(struct device *d, struct device_attribute *attr,
+                       const char *buf, size_t count);
+static ssize_t fifocnt_show(struct device *d, struct device_attribute *attr,
+                           char *buf);
+static ssize_t ipblink_show(struct device *d, struct device_attribute *attr,
+                           char *buf);
+static ssize_t wsz_show(struct device *d, struct device_attribute *attr,
+                       char *buf);
+static ssize_t mmap_show(struct device *d, struct device_attribute *attr,
+                        char *buf);
+
+#define __ATTR_RW(_name,_mode) { \
+       .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE },     \
+       .show   = _name##_show,                                 \
+       .store  = _name##_store,                                        \
+}
+
+static struct device_attribute dev_attr_devname   = __ATTR_RO(devname);
+static struct device_attribute dev_attr_devstate  = __ATTR_RO(devstate);
+static struct device_attribute dev_attr_proc_list = __ATTR_RO(proc_list);
+static struct device_attribute dev_attr_taskname  = __ATTR_RO(taskname);
+static struct device_attribute dev_attr_ttyp      = __ATTR_RO(ttyp);
+static struct device_attribute dev_attr_fifosz    = __ATTR_RW(fifosz, 0666);
+static struct device_attribute dev_attr_fifocnt   = __ATTR_RO(fifocnt);
+static struct device_attribute dev_attr_ipblink   = __ATTR_RO(ipblink);
+static struct device_attribute dev_attr_wsz       = __ATTR_RO(wsz);
+static struct device_attribute dev_attr_mmap      = __ATTR_RO(mmap);
+
+/*
+ * devstate_read_lock_timeout()
+ * devstate_write_lock_timeout():
+ * timeout != 0: dev->state can be diffeent from what you want.
+ * timeout == 0: no timeout
+ */
+static int devstate_read_lock_timeout(struct taskdev *dev, long devstate,
+                                     int timeout)
+{
+       DECLARE_WAITQUEUE(wait, current);
+       long current_state = current->state;
+       int ret = 0;
+
+       down_read(&dev->state_sem);
+       if (dev->state & devstate)
+               return 0;
+
+       add_wait_queue(&dev->state_wait_q, &wait);
+       do {
+               set_current_state(TASK_INTERRUPTIBLE);
+               up_read(&dev->state_sem);
+               if (timeout) {
+                       if ((timeout = schedule_timeout(timeout)) == 0) {
+                               /* timeout */
+                               down_read(&dev->state_sem);
+                               break;
+                       }
+               } else
+                       schedule();
+               if (signal_pending(current)) {
+                       ret = -EINTR;
+                       break;
+               }
+               down_read(&dev->state_sem);
+       } while (!(dev->state & devstate));
+       remove_wait_queue(&dev->state_wait_q, &wait);
+       set_current_state(current_state);
+       return ret;
+}
+
+static int devstate_read_lock_and_test(struct taskdev *dev, long devstate)
+{
+       down_read(&dev->state_sem);
+       if (dev->state & devstate)
+               return 1;       /* success */
+       /* failure */
+       up_read(&dev->state_sem);
+       return 0;
+}
+
+static int devstate_write_lock_timeout(struct taskdev *dev, long devstate,
+                                      int timeout)
+{
+       DECLARE_WAITQUEUE(wait, current);
+       long current_state = current->state;
+       int ret = 0;
+
+       down_write(&dev->state_sem);
+       if (dev->state & devstate)
+               return 0;
+
+       add_wait_queue(&dev->state_wait_q, &wait);
+       do {
+               set_current_state(TASK_INTERRUPTIBLE);
+               up_write(&dev->state_sem);
+               if (timeout) {
+                       if ((timeout = schedule_timeout(timeout)) == 0) {
+                               /* timeout */
+                               down_write(&dev->state_sem);
+                               break;
+                       }
+               } else
+                       schedule();
+               if (signal_pending(current)) {
+                       ret = -EINTR;
+                       break;
+               }
+               down_write(&dev->state_sem);
+       } while (!(dev->state & devstate));
+       remove_wait_queue(&dev->state_wait_q, &wait);
+       set_current_state(current_state);
+       return ret;
+}
+
+static int devstate_write_lock_and_test(struct taskdev *dev, long devstate)
+{
+       down_write(&dev->state_sem);
+       if (dev->state & devstate)      /* success */
+               return 1;
+
+       /* failure */
+       up_write(&dev->state_sem);
+       return -1;
+}
+
+static int taskdev_lock_interruptible(struct taskdev *dev,
+                                     struct mutex *lock)
+{
+       int ret;
+
+       if (has_taskdev_lock(dev))
+               ret = mutex_lock_interruptible(lock);
+       else {
+               if ((ret = mutex_lock_interruptible(&dev->lock)) != 0)
+                       return ret;
+               ret = mutex_lock_interruptible(lock);
+               mutex_unlock(&dev->lock);
+       }
+
+       return ret;
+}
+
+static int taskdev_lock_and_statelock_attached(struct taskdev *dev,
+                                              struct mutex *lock)
+{
+       int ret;
+
+       if (!devstate_read_lock_and_test(dev, TASKDEV_ST_ATTACHED))
+               return -ENODEV;
+
+       if ((ret = taskdev_lock_interruptible(dev, lock)) != 0)
+               devstate_read_unlock(dev);
+
+       return ret;
+}
+
+static __inline__ void taskdev_unlock_and_stateunlock(struct taskdev *dev,
+                                                     struct mutex *lock)
+{
+       mutex_unlock(lock);
+       devstate_read_unlock(dev);
+}
+
+/*
+ * taskdev_flush_buf()
+ * must be called under state_lock(ATTACHED) and dev->read_mutex.
+ */
+static int taskdev_flush_buf(struct taskdev *dev)
+{
+       u16 ttyp = dev->task->ttyp;
+
+       if (sndtyp_wd(ttyp)) {
+               /* word receiving */
+               flush_fifo(&dev->rcvdt.fifo);
+       } else {
+               /* block receiving */
+               struct rcvdt_bk_struct *rcvdt = &dev->rcvdt.bk;
+
+               if (sndtyp_gbl(ttyp))
+                       ipblink_flush(&rcvdt->link);
+               else {
+                       ipblink_flush_pvt(&rcvdt->link);
+                       release_ipbuf_pvt(dev->task->ipbuf_pvt_r);
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * taskdev_set_fifosz()
+ * must be called under dev->read_mutex.
+ */
+static int taskdev_set_fifosz(struct taskdev *dev, unsigned long sz)
+{
+       u16 ttyp = dev->task->ttyp;
+       int stat;
+
+       if (!(sndtyp_wd(ttyp) && sndtyp_acv(ttyp))) {
+               printk(KERN_ERR
+                      "omapdsp: buffer size can be changed only for "
+                      "active word sending task.\n");
+               return -EINVAL;
+       }
+       if ((sz == 0) || (sz & 1)) {
+               printk(KERN_ERR "omapdsp: illegal buffer size! (%ld)\n"
+                               "it must be even and non-zero value.\n", sz);
+               return -EINVAL;
+       }
+
+       stat = realloc_fifo(&dev->rcvdt.fifo, sz);
+       if (stat == -EBUSY) {
+               printk(KERN_ERR "omapdsp: buffer is not empty!\n");
+               return stat;
+       } else if (stat < 0) {
+               printk(KERN_ERR
+                      "omapdsp: unable to change receive buffer size. "
+                      "(%ld bytes for %s)\n", sz, dev->name);
+               return stat;
+       }
+
+       return 0;
+}
+
+static __inline__ int has_taskdev_lock(struct taskdev *dev)
+{
+       return (dev->lock_pid == current->pid);
+}
+
+static int taskdev_lock(struct taskdev *dev)
+{
+       if (mutex_lock_interruptible(&dev->lock))
+               return -EINTR;
+       dev->lock_pid = current->pid;
+       return 0;
+}
+
+static int taskdev_unlock(struct taskdev *dev)
+{
+       if (!has_taskdev_lock(dev)) {
+               printk(KERN_ERR
+                      "omapdsp: an illegal process attempted to "
+                      "unlock the dsptask lock!\n");
+               return -EINVAL;
+       }
+       dev->lock_pid = 0;
+       mutex_unlock(&dev->lock);
+       return 0;
+}
+
+static int dsp_task_config(struct dsptask *task, u8 tid)
+{
+       u16 ttyp;
+       int ret;
+
+       task->tid = tid;
+       dsptask[tid] = task;
+
+       /* TCFG request */
+       task->state = TASK_ST_CFGREQ;
+       if (mutex_lock_interruptible(&cfg_lock)) {
+               ret = -EINTR;
+               goto fail_out;
+       }
+       cfg_cmd = MBOX_CMD_DSP_TCFG;
+       mbcompose_send_and_wait(TCFG, tid, 0, &cfg_wait_q);
+       cfg_cmd = 0;
+       mutex_unlock(&cfg_lock);
+
+       if (task->state != TASK_ST_READY) {
+               printk(KERN_ERR "omapdsp: task %d configuration error!\n", tid);
+               ret = -EINVAL;
+               goto fail_out;
+       }
+
+       if (strlen(task->name) <= 1)
+               sprintf(task->name, "%d", tid);
+       printk(KERN_INFO "omapdsp: task %d: name %s\n", tid, task->name);
+
+       ttyp = task->ttyp;
+
+       /*
+        * task info sanity check
+        */
+
+       /* task type check */
+       if (rcvtyp_psv(ttyp) && rcvtyp_pvt(ttyp)) {
+               printk(KERN_ERR "omapdsp: illegal task type(0x%04x), tid=%d\n",
+                      tid, ttyp);
+               ret = -EINVAL;
+               goto fail_out;
+       }
+
+       /* private buffer address check */
+       if (sndtyp_pvt(ttyp) &&
+           (ipbuf_p_validate(task->ipbuf_pvt_r, DIR_D2A) < 0)) {
+               ret = -EINVAL;
+               goto fail_out;
+       }
+       if (rcvtyp_pvt(ttyp) &&
+           (ipbuf_p_validate(task->ipbuf_pvt_w, DIR_A2D) < 0)) {
+               ret = -EINVAL;
+               goto fail_out;
+       }
+
+       /* mmap buffer configuration check */
+       if ((task->map_length > 0) &&
+           ((!is_aligned((unsigned long)task->map_base, PAGE_SIZE)) ||
+            (!is_aligned(task->map_length, PAGE_SIZE)) ||
+            (dsp_mem_type(task->map_base, task->map_length) != MEM_TYPE_EXTERN))) {
+               printk(KERN_ERR
+                      "omapdsp: illegal mmap buffer address(0x%p) or "
+                      "length(0x%x).\n"
+                      "  It needs to be page-aligned and located at "
+                      "external memory.\n",
+                      task->map_base, task->map_length);
+               ret = -EINVAL;
+               goto fail_out;
+       }
+
+       return 0;
+
+fail_out:
+       dsptask[tid] = NULL;
+       return ret;
+}
+
+static void dsp_task_init(struct dsptask *task)
+{
+       mbcompose_send(TCTL, task->tid, TCTL_TINIT);
+}
+
+int dsp_task_config_all(u8 n)
+{
+       int i, ret;
+       struct taskdev *devheap;
+       struct dsptask *taskheap;
+       size_t devheapsz, taskheapsz;
+
+       printk(KERN_INFO "omapdsp: found %d task(s)\n", n);
+       if (n == 0)
+               return 0;
+
+       /*
+        * reducing kmalloc!
+        */
+       devheapsz  = sizeof(struct taskdev) * n;
+       taskheapsz = sizeof(struct dsptask) * n;
+       heap = kzalloc(devheapsz + taskheapsz, GFP_KERNEL);
+       if (heap == NULL)
+               return -ENOMEM;
+       devheap  = heap;
+       taskheap = heap + devheapsz;
+
+       n_task = n;
+       for (i = 0; i < n; i++) {
+               struct taskdev *dev  = &devheap[i];
+               struct dsptask *task = &taskheap[i];
+
+               if ((ret = dsp_task_config(task, i)) < 0)
+                       return ret;
+               if ((ret = taskdev_init(dev, task->name, i)) < 0)
+                       return ret;
+               if ((ret = taskdev_attach_task(dev, task)) < 0)
+                       return ret;
+               dsp_task_init(task);
+               printk(KERN_INFO "omapdsp: taskdev %s enabled.\n", dev->name);
+       }
+
+       return 0;
+}
+
+static void dsp_task_unconfig(struct dsptask *task)
+{
+       dsptask[task->tid] = NULL;
+}
+
+void dsp_task_unconfig_all(void)
+{
+       unsigned char minor;
+       u8 tid;
+       struct dsptask *task;
+
+       for (minor = 0; minor < n_task; minor++) {
+               /*
+                * taskdev[minor] can be NULL in case of
+                * configuration failure
+                */
+               if (taskdev[minor])
+                       taskdev_delete(minor);
+       }
+       for (; minor < TASKDEV_MAX; minor++) {
+               if (taskdev[minor])
+                       dsp_rmdev_minor(minor);
+       }
+
+       for (tid = 0; tid < n_task; tid++) {
+               /*
+                * dsptask[tid] can be NULL in case of
+                * configuration failure
+                */
+               task = dsptask[tid];
+               if (task)
+                       dsp_task_unconfig(task);
+       }
+       for (; tid < TASKDEV_MAX; tid++) {
+               task = dsptask[tid];
+               if (task) {
+                       /*
+                        * on-demand tasks should be deleted in
+                        * rmdev_minor(), but just in case.
+                        */
+                       dsp_task_unconfig(task);
+                       kfree(task);
+               }
+       }
+
+       if (heap) {
+               kfree(heap);
+               heap = NULL;
+       }
+
+       n_task = 0;
+}
+
+static struct device_driver dsptask_driver = {
+       .name   = "dsptask",
+       .bus    = &dsptask_bus,
+};
+
+u8 dsp_task_count(void)
+{
+       return n_task;
+}
+
+int dsp_taskmod_busy(void)
+{
+       struct taskdev *dev;
+       unsigned char minor;
+       unsigned int usecount;
+
+       for (minor = 0; minor < TASKDEV_MAX; minor++) {
+               dev = taskdev[minor];
+               if (dev == NULL)
+                       continue;
+               if ((usecount = dev->usecount) > 0) {
+                       printk("dsp_taskmod_busy(): %s: usecount=%d\n",
+                              dev->name, usecount);
+                       return 1;
+               }
+/*
+               if ((dev->state & (TASKDEV_ST_ADDREQ |
+                                  TASKDEV_ST_DELREQ)) {
+*/
+               if (dev->state & TASKDEV_ST_ADDREQ) {
+                       printk("dsp_taskmod_busy(): %s is in %s\n",
+                              dev->name, devstate_name(dev->state));
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+/*
+ * DSP task device file operations
+ */
+static ssize_t dsp_task_read_wd_acv(struct file *file, char __user *buf,
+                                   size_t count, loff_t *ppos)
+{
+       unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+       struct taskdev *dev = taskdev[minor];
+       int ret = 0;
+
+       if (count == 0) {
+               return 0;
+       } else if (count & 0x1) {
+               printk(KERN_ERR
+                      "omapdsp: odd count is illegal for DSP task device.\n");
+               return -EINVAL;
+       }
+
+       if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+               return -ENODEV;
+
+       if (fifo_empty(&dev->rcvdt.fifo)) {
+               long current_state = current->state;
+               DECLARE_WAITQUEUE(wait, current);
+
+               set_current_state(TASK_INTERRUPTIBLE);
+               add_wait_queue(&dev->read_wait_q, &wait);
+               if (fifo_empty(&dev->rcvdt.fifo))       /* last check */
+                       schedule();
+               set_current_state(current_state);
+               remove_wait_queue(&dev->read_wait_q, &wait);
+               if (fifo_empty(&dev->rcvdt.fifo)) {
+                       /* failure */
+                       if (signal_pending(current))
+                               ret = -EINTR;
+                       goto up_out;
+               }
+       }
+
+       ret = copy_to_user_fm_fifo(buf, &dev->rcvdt.fifo, count);
+
+up_out:
+       taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
+       return ret;
+}
+
+static ssize_t dsp_task_read_bk_acv(struct file *file, char __user *buf,
+                                   size_t count, loff_t *ppos)
+{
+       unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+       struct taskdev *dev = taskdev[minor];
+       struct rcvdt_bk_struct *rcvdt = &dev->rcvdt.bk;
+       ssize_t ret = 0;
+
+       if (count == 0) {
+               return 0;
+       } else if (count & 0x1) {
+               printk(KERN_ERR
+                      "omapdsp: odd count is illegal for DSP task device.\n");
+               return -EINVAL;
+       } else if ((int)buf & 0x1) {
+               printk(KERN_ERR
+                      "omapdsp: buf should be word aligned for "
+                      "dsp_task_read().\n");
+               return -EINVAL;
+       }
+
+       if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+               return -ENODEV;
+
+       if (ipblink_empty(&rcvdt->link)) {
+               long current_state;
+               DECLARE_WAITQUEUE(wait, current);
+
+               add_wait_queue(&dev->read_wait_q, &wait);
+               current_state = current->state;
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (ipblink_empty(&rcvdt->link))        /* last check */
+                       schedule();
+               set_current_state(current_state);
+               remove_wait_queue(&dev->read_wait_q, &wait);
+               if (ipblink_empty(&rcvdt->link)) {
+                       /* failure */
+                       if (signal_pending(current))
+                               ret = -EINTR;
+                       goto up_out;
+               }
+       }
+
+       /* copy from delayed IPBUF */
+       if (sndtyp_pvt(dev->task->ttyp)) {
+               /* private */
+               if (!ipblink_empty(&rcvdt->link)) {
+                       struct ipbuf_p *ipbp = dev->task->ipbuf_pvt_r;
+                       unsigned char *base, *src;
+                       size_t bkcnt;
+
+                       if (dsp_mem_enable(ipbp) < 0) {
+                               ret = -EBUSY;
+                               goto up_out;
+                       }
+                       base = MKVIRT(ipbp->ah, ipbp->al);
+                       bkcnt = ((unsigned long)ipbp->c) * 2 - rcvdt->rp;
+                       if (dsp_address_validate(base, bkcnt,
+                                                "task %s read buffer",
+                                                dev->task->name) < 0) {
+                               ret = -EINVAL;
+                               goto pv_out1;
+                       }
+                       if (dsp_mem_enable(base) < 0) {
+                               ret = -EBUSY;
+                               goto pv_out1;
+                       }
+                       src = base + rcvdt->rp;
+                       if (bkcnt > count) {
+                               if (copy_to_user_dsp(buf, src, count)) {
+                                       ret = -EFAULT;
+                                       goto pv_out2;
+                               }
+                               ret = count;
+                               rcvdt->rp += count;
+                       } else {
+                               if (copy_to_user_dsp(buf, src, bkcnt)) {
+                                       ret = -EFAULT;
+                                       goto pv_out2;
+                               }
+                               ret = bkcnt;
+                               ipblink_del_pvt(&rcvdt->link);
+                               release_ipbuf_pvt(ipbp);
+                               rcvdt->rp = 0;
+                       }
+pv_out2:
+                       dsp_mem_disable(src);
+pv_out1:
+                       dsp_mem_disable(ipbp);
+               }
+       } else {
+               /* global */
+               if (dsp_mem_enable_ipbuf() < 0) {
+                       ret = -EBUSY;
+                       goto up_out;
+               }
+               while (!ipblink_empty(&rcvdt->link)) {
+                       unsigned char *src;
+                       size_t bkcnt;
+                       struct ipbuf_head *ipb_h = bid_to_ipbuf(rcvdt->link.top);
+
+                       src = ipb_h->p->d + rcvdt->rp;
+                       bkcnt = ((unsigned long)ipb_h->p->c) * 2 - rcvdt->rp;
+                       if (bkcnt > count) {
+                               if (copy_to_user_dsp(buf, src, count)) {
+                                       ret = -EFAULT;
+                                       goto gb_out;
+                               }
+                               ret += count;
+                               rcvdt->rp += count;
+                               break;
+                       } else {
+                               if (copy_to_user_dsp(buf, src, bkcnt)) {
+                                       ret = -EFAULT;
+                                       goto gb_out;
+                               }
+                               ret += bkcnt;
+                               buf += bkcnt;
+                               count -= bkcnt;
+                               ipblink_del_top(&rcvdt->link);
+                               unuse_ipbuf(ipb_h);
+                               rcvdt->rp = 0;
+                       }
+               }
+gb_out:
+               dsp_mem_disable_ipbuf();
+       }
+
+up_out:
+       taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
+       return ret;
+}
+
+static ssize_t dsp_task_read_wd_psv(struct file *file, char __user *buf,
+                                   size_t count, loff_t *ppos)
+{
+       unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+       struct taskdev *dev = taskdev[minor];
+       int ret = 0;
+
+       if (count == 0) {
+               return 0;
+       } else if (count & 0x1) {
+               printk(KERN_ERR
+                      "omapdsp: odd count is illegal for DSP task device.\n");
+               return -EINVAL;
+       } else {
+               /* force! */
+               count = 2;
+       }
+
+       if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+               return -ENODEV;
+
+       mbcompose_send_and_wait(WDREQ, dev->task->tid, 0, &dev->read_wait_q);
+
+       if (fifo_empty(&dev->rcvdt.fifo)) {
+               /* failure */
+               if (signal_pending(current))
+                       ret = -EINTR;
+               goto up_out;
+       }
+
+       ret = copy_to_user_fm_fifo(buf, &dev->rcvdt.fifo, count);
+
+up_out:
+       taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
+       return ret;
+}
+
+static ssize_t dsp_task_read_bk_psv(struct file *file, char __user *buf,
+                                   size_t count, loff_t *ppos)
+{
+       unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+       struct taskdev *dev = taskdev[minor];
+       struct rcvdt_bk_struct *rcvdt = &dev->rcvdt.bk;
+       int ret = 0;
+
+       if (count == 0) {
+               return 0;
+       } else if (count & 0x1) {
+               printk(KERN_ERR
+                      "omapdsp: odd count is illegal for DSP task device.\n");
+               return -EINVAL;
+       } else if ((int)buf & 0x1) {
+               printk(KERN_ERR
+                      "omapdsp: buf should be word aligned for "
+                      "dsp_task_read().\n");
+               return -EINVAL;
+       }
+
+       if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+               return -ENODEV;
+
+       mbcompose_send_and_wait(BKREQ, dev->task->tid, count/2,
+                               &dev->read_wait_q);
+
+       if (ipblink_empty(&rcvdt->link)) {
+               /* failure */
+               if (signal_pending(current))
+                       ret = -EINTR;
+               goto up_out;
+       }
+
+       /*
+        * We will not receive more than requested count.
+        */
+       if (sndtyp_pvt(dev->task->ttyp)) {
+               /* private */
+               struct ipbuf_p *ipbp = dev->task->ipbuf_pvt_r;
+               size_t rcvcnt;
+               void *src;
+
+               if (dsp_mem_enable(ipbp) < 0) {
+                       ret = -EBUSY;
+                       goto up_out;
+               }
+               src = MKVIRT(ipbp->ah, ipbp->al);
+               rcvcnt = ((unsigned long)ipbp->c) * 2;
+               if (dsp_address_validate(src, rcvcnt, "task %s read buffer",
+                                        dev->task->name) < 0) {
+                       ret = -EINVAL;
+                       goto pv_out1;
+               }
+               if (dsp_mem_enable(src) < 0) {
+                       ret = -EBUSY;
+                       goto pv_out1;
+               }
+               if (count > rcvcnt)
+                       count = rcvcnt;
+               if (copy_to_user_dsp(buf, src, count)) {
+                       ret = -EFAULT;
+                       goto pv_out2;
+               }
+               ipblink_del_pvt(&rcvdt->link);
+               release_ipbuf_pvt(ipbp);
+               ret = count;
+pv_out2:
+               dsp_mem_disable(src);
+pv_out1:
+               dsp_mem_disable(ipbp);
+       } else {
+               /* global */
+               struct ipbuf_head *ipb_h = bid_to_ipbuf(rcvdt->link.top);
+               size_t rcvcnt;
+
+               if (dsp_mem_enable_ipbuf() < 0) {
+                       ret = -EBUSY;
+                       goto up_out;
+               }
+               rcvcnt = ((unsigned long)ipb_h->p->c) * 2;
+               if (count > rcvcnt)
+                       count = rcvcnt;
+               if (copy_to_user_dsp(buf, ipb_h->p->d, count)) {
+                       ret = -EFAULT;
+                       goto gb_out;
+               }
+               ipblink_del_top(&rcvdt->link);
+               unuse_ipbuf(ipb_h);
+               ret = count;
+gb_out:
+               dsp_mem_disable_ipbuf();
+       }
+
+up_out:
+       taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
+       return ret;
+}
+
+static ssize_t dsp_task_write_wd(struct file *file, const char __user *buf,
+                                size_t count, loff_t *ppos)
+{
+       unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+       struct taskdev *dev = taskdev[minor];
+       u16 wd;
+       int ret = 0;
+
+       if (count == 0) {
+               return 0;
+       } else if (count & 0x1) {
+               printk(KERN_ERR
+                      "omapdsp: odd count is illegal for DSP task device.\n");
+               return -EINVAL;
+       } else {
+               /* force! */
+               count = 2;
+       }
+
+       if (taskdev_lock_and_statelock_attached(dev, &dev->write_mutex))
+               return -ENODEV;
+
+       if (dev->wsz == 0) {
+               long current_state;
+               DECLARE_WAITQUEUE(wait, current);
+
+               add_wait_queue(&dev->write_wait_q, &wait);
+               current_state = current->state;
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (dev->wsz == 0)      /* last check */
+                       schedule();
+               set_current_state(current_state);
+               remove_wait_queue(&dev->write_wait_q, &wait);
+               if (dev->wsz == 0) {
+                       /* failure */
+                       if (signal_pending(current))
+                               ret = -EINTR;
+                       goto up_out;
+               }
+       }
+
+       if (copy_from_user(&wd, buf, count)) {
+               ret = -EFAULT;
+               goto up_out;
+       }
+
+       spin_lock(&dev->wsz_lock);
+       if (mbcompose_send(WDSND, dev->task->tid, wd) < 0) {
+               spin_unlock(&dev->wsz_lock);
+               goto up_out;
+       }
+       ret = count;
+       if (rcvtyp_acv(dev->task->ttyp))
+               dev->wsz = 0;
+       spin_unlock(&dev->wsz_lock);
+
+up_out:
+       taskdev_unlock_and_stateunlock(dev, &dev->write_mutex);
+       return ret;
+}
+
+static ssize_t dsp_task_write_bk(struct file *file, const char __user *buf,
+                                size_t count, loff_t *ppos)
+{
+       unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+       struct taskdev *dev = taskdev[minor];
+       int ret = 0;
+
+       if (count == 0) {
+               return 0;
+       } else if (count & 0x1) {
+               printk(KERN_ERR
+                      "omapdsp: odd count is illegal for DSP task device.\n");
+               return -EINVAL;
+       } else if ((int)buf & 0x1) {
+               printk(KERN_ERR
+                      "omapdsp: buf should be word aligned for "
+                      "dsp_task_write().\n");
+               return -EINVAL;
+       }
+
+       if (taskdev_lock_and_statelock_attached(dev, &dev->write_mutex))
+               return -ENODEV;
+
+       if (dev->wsz == 0) {
+               long current_state;
+               DECLARE_WAITQUEUE(wait, current);
+
+               add_wait_queue(&dev->write_wait_q, &wait);
+               current_state = current->state;
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (dev->wsz == 0)      /* last check */
+                       schedule();
+               set_current_state(current_state);
+               remove_wait_queue(&dev->write_wait_q, &wait);
+               if (dev->wsz == 0) {
+                       /* failure */
+                       if (signal_pending(current))
+                               ret = -EINTR;
+                       goto up_out;
+               }
+       }
+
+       if (count > dev->wsz)
+               count = dev->wsz;
+
+       if (rcvtyp_pvt(dev->task->ttyp)) {
+               /* private */
+               struct ipbuf_p *ipbp = dev->task->ipbuf_pvt_w;
+               unsigned char *dst;
+
+               if (dsp_mem_enable(ipbp) < 0) {
+                       ret = -EBUSY;
+                       goto up_out;
+               }
+               dst = MKVIRT(ipbp->ah, ipbp->al);
+               if (dsp_address_validate(dst, count, "task %s write buffer",
+                                        dev->task->name) < 0) {
+                       ret = -EINVAL;
+                       goto pv_out1;
+               }
+               if (dsp_mem_enable(dst) < 0) {
+                       ret = -EBUSY;
+                       goto pv_out1;
+               }
+               if (copy_from_user_dsp(dst, buf, count)) {
+                       ret = -EFAULT;
+                       goto pv_out2;
+               }
+               ipbp->c = count/2;
+               ipbp->s = dev->task->tid;
+               spin_lock(&dev->wsz_lock);
+               if (mbcompose_send(BKSNDP, dev->task->tid, 0) == 0) {
+                       if (rcvtyp_acv(dev->task->ttyp))
+                               dev->wsz = 0;
+                       ret = count;
+               }
+               spin_unlock(&dev->wsz_lock);
+pv_out2:
+               dsp_mem_disable(dst);
+pv_out1:
+               dsp_mem_disable(ipbp);
+       } else {
+               /* global */
+               struct ipbuf_head *ipb_h;
+
+               if (dsp_mem_enable_ipbuf() < 0) {
+                       ret = -EBUSY;
+                       goto up_out;
+               }
+               if ((ipb_h = get_free_ipbuf(dev->task->tid)) == NULL)
+                       goto gb_out;
+               if (copy_from_user_dsp(ipb_h->p->d, buf, count)) {
+                       release_ipbuf(ipb_h);
+                       ret = -EFAULT;
+                       goto gb_out;
+               }
+               ipb_h->p->c  = count/2;
+               ipb_h->p->sa = dev->task->tid;
+               spin_lock(&dev->wsz_lock);
+               if (mbcompose_send(BKSND, dev->task->tid, ipb_h->bid) == 0) {
+                       if (rcvtyp_acv(dev->task->ttyp))
+                               dev->wsz = 0;
+                       ret = count;
+                       ipb_bsycnt_inc(&ipbcfg);
+               } else
+                       release_ipbuf(ipb_h);
+               spin_unlock(&dev->wsz_lock);
+gb_out:
+               dsp_mem_disable_ipbuf();
+       }
+
+up_out:
+       taskdev_unlock_and_stateunlock(dev, &dev->write_mutex);
+       return ret;
+}
+
+static unsigned int dsp_task_poll(struct file * file, poll_table * wait)
+{
+       unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+       struct taskdev *dev = taskdev[minor];
+       struct dsptask *task = dev->task;
+       unsigned int mask = 0;
+
+       if (!devstate_read_lock_and_test(dev, TASKDEV_ST_ATTACHED))
+               return 0;
+       poll_wait(file, &dev->read_wait_q, wait);
+       poll_wait(file, &dev->write_wait_q, wait);
+       if (sndtyp_psv(task->ttyp) ||
+           (sndtyp_wd(task->ttyp) && !fifo_empty(&dev->rcvdt.fifo)) ||
+           (sndtyp_bk(task->ttyp) && !ipblink_empty(&dev->rcvdt.bk.link)))
+               mask |= POLLIN | POLLRDNORM;
+       if (dev->wsz)
+               mask |= POLLOUT | POLLWRNORM;
+       devstate_read_unlock(dev);
+
+       return mask;
+}
+
+static int dsp_tctl_issue(struct taskdev *dev, u16 cmd, int argc, u16 argv[])
+{
+       int tctl_argc;
+       struct mb_exarg mbarg, *mbargp;
+       int interactive;
+       u8 tid;
+       int ret = 0;
+
+       if (cmd < 0x8000) {
+               /*
+                * 0x0000 - 0x7fff
+                * system reserved TCTL commands
+                */
+               switch (cmd) {
+               case TCTL_TEN:
+               case TCTL_TDIS:
+                       tctl_argc = 0;
+                       interactive = 0;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       }
+       /*
+        * 0x8000 - 0xffff
+        * user-defined TCTL commands
+        */
+       else if (cmd < 0x8100) {
+               /* 0x8000-0x80ff: no arg, non-interactive */
+               tctl_argc = 0;
+               interactive = 0;
+       } else if (cmd < 0x8200) {
+               /* 0x8100-0x81ff: 1 arg, non-interactive */
+               tctl_argc = 1;
+               interactive = 0;
+       } else if (cmd < 0x9000) {
+               /* 0x8200-0x8fff: reserved */
+               return -EINVAL;
+       } else if (cmd < 0x9100) {
+               /* 0x9000-0x90ff: no arg, interactive */
+               tctl_argc = 0;
+               interactive = 1;
+       } else if (cmd < 0x9200) {
+               /* 0x9100-0x91ff: 1 arg, interactive */
+               tctl_argc = 1;
+               interactive = 1;
+       } else {
+               /* 0x9200-0xffff: reserved */
+               return -EINVAL;
+       }
+
+       /*
+        * if argc < 0, use tctl_argc as is.
+        * if argc >= 0, check arg count.
+        */
+       if ((argc >= 0) && (argc != tctl_argc))
+               return -EINVAL;
+
+       /*
+        * issue TCTL
+        */
+       if (taskdev_lock_interruptible(dev, &dev->tctl_mutex))
+               return -EINTR;
+
+       tid = dev->task->tid;
+       if (tctl_argc > 0) {
+               mbarg.argc = tctl_argc;
+               mbarg.tid  = tid;
+               mbarg.argv = argv;
+               mbargp = &mbarg;
+       } else
+               mbargp = NULL;
+
+       if (interactive) {
+               dev->tctl_stat = -EINVAL;
+
+               mbcompose_send_and_wait_exarg(TCTL, tid, cmd, mbargp,
+                                             &dev->tctl_wait_q);
+               if (signal_pending(current)) {
+                       ret = -EINTR;
+                       goto up_out;
+               }
+               if ((ret = dev->tctl_stat) < 0) {
+                       printk(KERN_ERR "omapdsp: TCTL not responding.\n");
+                       goto up_out;
+               }
+       } else
+               mbcompose_send_exarg(TCTL, tid, cmd, mbargp);
+
+up_out:
+       mutex_unlock(&dev->tctl_mutex);
+       return ret;
+}
+
+static int dsp_task_ioctl(struct inode *inode, struct file *file,
+                         unsigned int cmd, unsigned long arg)
+{
+       unsigned int minor = MINOR(inode->i_rdev);
+       struct taskdev *dev = taskdev[minor];
+       int ret;
+
+       if (cmd < 0x10000) {
+               /* issue TCTL */
+               u16 mbargv[1];
+
+               mbargv[0] = arg & 0xffff;
+               return dsp_tctl_issue(dev, cmd, -1, mbargv);
+       }
+
+       /* non TCTL ioctls */
+       switch (cmd) {
+
+       case TASK_IOCTL_LOCK:
+               ret = taskdev_lock(dev);
+               break;
+
+       case TASK_IOCTL_UNLOCK:
+               ret = taskdev_unlock(dev);
+               break;
+
+       case TASK_IOCTL_BFLSH:
+               if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+                       return -ENODEV;
+               ret = taskdev_flush_buf(dev);
+               taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
+               break;
+
+       case TASK_IOCTL_SETBSZ:
+               if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+                       return -ENODEV;
+               ret = taskdev_set_fifosz(dev, arg);
+               taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
+               break;
+
+       case TASK_IOCTL_GETNAME:
+               ret = 0;
+               if (copy_to_user((void __user *)arg, dev->name,
+                                strlen(dev->name) + 1))
+                       ret = -EFAULT;
+               break;
+
+       default:
+               ret = -ENOIOCTLCMD;
+
+       }
+
+       return ret;
+}
+
+static void dsp_task_mmap_open(struct vm_area_struct *vma)
+{
+       struct taskdev *dev = (struct taskdev *)vma->vm_private_data;
+       struct dsptask *task;
+       size_t len = vma->vm_end - vma->vm_start;
+
+       BUG_ON(!(dev->state & TASKDEV_ST_ATTACHED));
+       task = dev->task;
+       exmap_use(task->map_base, len);
+}
+
+static void dsp_task_mmap_close(struct vm_area_struct *vma)
+{
+       struct taskdev *dev = (struct taskdev *)vma->vm_private_data;
+       struct dsptask *task;
+       size_t len = vma->vm_end - vma->vm_start;
+
+       BUG_ON(!(dev->state & TASKDEV_ST_ATTACHED));
+       task = dev->task;
+       exmap_unuse(task->map_base, len);
+}
+
+/**
+ * On demand page allocation is not allowed. The mapping area is defined by
+ * corresponding DSP tasks.
+ */
+static struct page *dsp_task_mmap_nopage(struct vm_area_struct *vma,
+                                        unsigned long address, int *type)
+{
+       return NOPAGE_SIGBUS;
+}
+
+static struct vm_operations_struct dsp_task_vm_ops = {
+       .open = dsp_task_mmap_open,
+       .close = dsp_task_mmap_close,
+       .nopage = dsp_task_mmap_nopage,
+};
+
+static int dsp_task_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+       void *tmp_vadr;
+       unsigned long tmp_padr, tmp_vmadr, off;
+       size_t req_len, tmp_len;
+       unsigned int minor = MINOR(filp->f_dentry->d_inode->i_rdev);
+       struct taskdev *dev = taskdev[minor];
+       struct dsptask *task;
+       int ret = 0;
+
+       if (!devstate_read_lock_and_test(dev, TASKDEV_ST_ATTACHED))
+               return -ENODEV;
+       task = dev->task;
+
+       /*
+        * Don't swap this area out
+        * Don't dump this area to a core file
+        */
+       vma->vm_flags |= VM_RESERVED | VM_IO;
+
+       /* Do not cache this area */
+       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+       req_len = vma->vm_end - vma->vm_start;
+       off = vma->vm_pgoff << PAGE_SHIFT;
+       tmp_vmadr = vma->vm_start;
+       tmp_vadr = task->map_base + off;
+       do {
+               tmp_padr = dsp_virt_to_phys(tmp_vadr, &tmp_len);
+               if (tmp_padr == 0) {
+                       printk(KERN_ERR
+                              "omapdsp: task %s: illegal address "
+                              "for mmap: %p", task->name, tmp_vadr);
+                       /* partial mapping will be cleared in upper layer */
+                       ret = -EINVAL;
+                       goto unlock_out;
+               }
+               if (tmp_len > req_len)
+                       tmp_len = req_len;
+
+               printk(KERN_DEBUG
+                      "omapdsp: mmap info: "
+                      "vmadr = %08lx, padr = %08lx, len = %x\n",
+                      tmp_vmadr, tmp_padr, tmp_len);
+               if (remap_pfn_range(vma, tmp_vmadr, tmp_padr >> PAGE_SHIFT,
+                                   tmp_len, vma->vm_page_prot) != 0) {
+                       printk(KERN_ERR
+                              "omapdsp: task %s: remap_page_range() failed.\n",
+                              task->name);
+                       /* partial mapping will be cleared in upper layer */
+                       ret = -EINVAL;
+                       goto unlock_out;
+               }
+
+               req_len   -= tmp_len;
+               tmp_vmadr += tmp_len;
+               tmp_vadr  += tmp_len;
+       } while (req_len);
+
+       vma->vm_ops = &dsp_task_vm_ops;
+       vma->vm_private_data = dev;
+       exmap_use(task->map_base, vma->vm_end - vma->vm_start);
+
+unlock_out:
+       devstate_read_unlock(dev);
+       return ret;
+}
+
+static int dsp_task_open(struct inode *inode, struct file *file)
+{
+       unsigned int minor = MINOR(inode->i_rdev);
+       struct taskdev *dev;
+       int ret = 0;
+
+       if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL))
+               return -ENODEV;
+
+restart:
+       mutex_lock(&dev->usecount_lock);
+       down_write(&dev->state_sem);
+
+       /* state can be NOTASK, ATTACHED/FREEZED, KILLING, GARBAGE or INVALID here. */
+       switch (dev->state & TASKDEV_ST_STATE_MASK) {
+               case TASKDEV_ST_NOTASK:
+                       break;
+               case TASKDEV_ST_ATTACHED:
+                       goto attached;
+
+               case TASKDEV_ST_INVALID:
+                       up_write(&dev->state_sem);
+                       mutex_unlock(&dev->usecount_lock);
+                       return -ENODEV;
+
+               case TASKDEV_ST_FREEZED:
+               case TASKDEV_ST_KILLING:
+               case TASKDEV_ST_GARBAGE:
+               case TASKDEV_ST_DELREQ:
+                       /* on the kill process. wait until it becomes NOTASK. */
+                       up_write(&dev->state_sem);
+                       mutex_unlock(&dev->usecount_lock);
+                       if (devstate_write_lock(dev, TASKDEV_ST_NOTASK) < 0)
+                               return -EINTR;
+                       devstate_write_unlock(dev);
+                       goto restart;
+       }
+
+       /* NOTASK */
+       dev->state = TASKDEV_ST_ADDREQ;
+       /* wake up twch daemon for tadd */
+       dsp_twch_touch();
+       up_write(&dev->state_sem);
+       if (devstate_write_lock(dev, TASKDEV_ST_ATTACHED |
+                                    TASKDEV_ST_ADDFAIL) < 0) {
+               /* cancelled */
+               if (!devstate_write_lock_and_test(dev, TASKDEV_ST_ADDREQ)) {
+                       mutex_unlock(&dev->usecount_lock);
+                       /* out of control ??? */
+                       return -EINTR;
+               }
+               dev->state = TASKDEV_ST_NOTASK;
+               ret = -EINTR;
+               goto change_out;
+       }
+       if (dev->state & TASKDEV_ST_ADDFAIL) {
+               printk(KERN_ERR "omapdsp: task attach failed for %s!\n",
+                      dev->name);
+               ret = -EBUSY;
+               dev->state = TASKDEV_ST_NOTASK;
+               goto change_out;
+       }
+
+attached:
+       /* ATTACHED */
+#ifndef CONFIG_OMAP_DSP_TASK_MULTIOPEN
+       if (dev->usecount > 0) {
+               up_write(&dev->state_sem);
+               return -EBUSY;
+       }
+#endif
+       dev->usecount++;
+       proc_list_add(&dev->proc_list_lock, &dev->proc_list, current, file);
+       file->f_op = &dev->fops;
+       up_write(&dev->state_sem);
+       mutex_unlock(&dev->usecount_lock);
+
+#ifdef DSP_PTE_FREE    /* not used currently. */
+       dsp_map_update(current);
+       dsp_cur_users_add(current);
+#endif /* DSP_PTE_FREE */
+       return 0;
+
+change_out:
+       wake_up_interruptible_all(&dev->state_wait_q);
+       up_write(&dev->state_sem);
+       mutex_unlock(&dev->usecount_lock);
+       return ret;
+}
+
+static int dsp_task_release(struct inode *inode, struct file *file)
+{
+       unsigned int minor = MINOR(inode->i_rdev);
+       struct taskdev *dev = taskdev[minor];
+
+#ifdef DSP_PTE_FREE    /* not used currently. */
+       dsp_cur_users_del(current);
+#endif /* DSP_PTE_FREE */
+
+       if (has_taskdev_lock(dev))
+               taskdev_unlock(dev);
+
+       proc_list_del(&dev->proc_list_lock, &dev->proc_list, current, file);
+       mutex_lock(&dev->usecount_lock);
+       if (--dev->usecount > 0) {
+               /* other processes are using this device. no state change. */
+               mutex_unlock(&dev->usecount_lock);
+               return 0;
+       }
+
+       /* usecount == 0 */
+       down_write(&dev->state_sem);
+
+       /* state can be ATTACHED/FREEZED, KILLING or GARBAGE here. */
+       switch (dev->state & TASKDEV_ST_STATE_MASK) {
+
+       case TASKDEV_ST_KILLING:
+               break;
+
+       case TASKDEV_ST_GARBAGE:
+               dev->state = TASKDEV_ST_NOTASK;
+               wake_up_interruptible_all(&dev->state_wait_q);
+               break;
+
+       case TASKDEV_ST_ATTACHED:
+       case TASKDEV_ST_FREEZED:
+               if (is_dynamic_task(minor)) {
+                       dev->state = TASKDEV_ST_DELREQ;
+                       /* wake up twch daemon for tdel */
+                       dsp_twch_touch();
+               }
+               break;
+
+       }
+
+       up_write(&dev->state_sem);
+       mutex_unlock(&dev->usecount_lock);
+       return 0;
+}
+
+/*
+ * mkdev / rmdev
+ */
+int dsp_mkdev(char *name)
+{
+       struct taskdev *dev;
+       int status;
+       unsigned char minor;
+       int ret;
+
+       if (dsp_cfgstat_get_stat() != CFGSTAT_READY) {
+               printk(KERN_ERR "omapdsp: dsp has not been configured.\n");
+               return -EINVAL;
+       }
+
+       if (mutex_lock_interruptible(&devmgr_lock))
+               return -EINTR;
+
+       /* naming check */
+       for (minor = 0; minor < TASKDEV_MAX; minor++) {
+               if (taskdev[minor] && !strcmp(taskdev[minor]->name, name)) {
+                       printk(KERN_ERR
+                              "omapdsp: task device name %s is already "
+                              "in use.\n", name);
+                       ret = -EINVAL;
+                       goto out;
+               }
+       }
+
+       /* find free minor number */
+       for (minor = n_task; minor < TASKDEV_MAX; minor++) {
+               if (taskdev[minor] == NULL)
+                       goto do_make;
+       }
+       printk(KERN_ERR "omapdsp: Too many task devices.\n");
+       ret = -EBUSY;
+       goto out;
+
+do_make:
+       if ((dev = kzalloc(sizeof(struct taskdev), GFP_KERNEL)) == NULL) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       if ((status = taskdev_init(dev, name, minor)) < 0) {
+               kfree(dev);
+               ret = status;
+               goto out;
+       }
+       ret = minor;
+
+out:
+       mutex_unlock(&devmgr_lock);
+       return ret;
+}
+
+int dsp_rmdev(char *name)
+{
+       unsigned char minor;
+       int status;
+       int ret;
+
+       if (dsp_cfgstat_get_stat() != CFGSTAT_READY) {
+               printk(KERN_ERR "omapdsp: dsp has not been configured.\n");
+               return -EINVAL;
+       }
+
+       if (mutex_lock_interruptible(&devmgr_lock))
+               return -EINTR;
+
+       /* find in dynamic devices */
+       for (minor = n_task; minor < TASKDEV_MAX; minor++) {
+               if (taskdev[minor] && !strcmp(taskdev[minor]->name, name))
+                       goto do_remove;
+       }
+
+       /* find in static devices */
+       for (minor = 0; minor < n_task; minor++) {
+               if (taskdev[minor] && !strcmp(taskdev[minor]->name, name)) {
+                       printk(KERN_ERR
+                              "omapdsp: task device %s is static.\n", name);
+                       ret = -EINVAL;
+                       goto out;
+               }
+       }
+
+       printk(KERN_ERR "omapdsp: task device %s not found.\n", name);
+       return -EINVAL;
+
+do_remove:
+       ret = minor;
+       if ((status = dsp_rmdev_minor(minor)) < 0)
+               ret = status;
+out:
+       mutex_unlock(&devmgr_lock);
+       return ret;
+}
+
+static int dsp_rmdev_minor(unsigned char minor)
+{
+       struct taskdev *dev = taskdev[minor];
+
+       while (!down_write_trylock(&dev->state_sem)) {
+               down_read(&dev->state_sem);
+               if (dev->state & (TASKDEV_ST_ATTACHED |
+                                 TASKDEV_ST_FREEZED)) {
+                       /*
+                        * task is working. kill it.
+                        * ATTACHED -> FREEZED can be changed under
+                        * down_read of state_sem..
+                        */
+                       dev->state = TASKDEV_ST_FREEZED;
+                       wake_up_interruptible_all(&dev->read_wait_q);
+                       wake_up_interruptible_all(&dev->write_wait_q);
+                       wake_up_interruptible_all(&dev->tctl_wait_q);
+               }
+               up_read(&dev->state_sem);
+               schedule();
+       }
+
+       switch (dev->state & TASKDEV_ST_STATE_MASK) {
+
+       case TASKDEV_ST_NOTASK:
+               /* fine */
+               goto notask;
+
+       case TASKDEV_ST_ATTACHED:
+       case TASKDEV_ST_FREEZED:
+               /* task is working. kill it. */
+               dev->state = TASKDEV_ST_KILLING;
+               up_write(&dev->state_sem);
+               dsp_tdel_bh(dev, TDEL_KILL);
+               goto invalidate;
+
+       case TASKDEV_ST_ADDREQ:
+               /* open() is waiting. drain it. */
+               dev->state = TASKDEV_ST_ADDFAIL;
+               wake_up_interruptible_all(&dev->state_wait_q);
+               break;
+
+       case TASKDEV_ST_DELREQ:
+               /* nobody is waiting. */
+               dev->state = TASKDEV_ST_NOTASK;
+               wake_up_interruptible_all(&dev->state_wait_q);
+               break;
+
+       case TASKDEV_ST_ADDING:
+       case TASKDEV_ST_DELING:
+       case TASKDEV_ST_KILLING:
+       case TASKDEV_ST_GARBAGE:
+       case TASKDEV_ST_ADDFAIL:
+               /* transient state. wait for a moment. */
+               break;
+
+       }
+
+       up_write(&dev->state_sem);
+
+invalidate:
+       /* wait for some time and hope the state is settled */
+       devstate_read_lock_timeout(dev, TASKDEV_ST_NOTASK, 5 * HZ);
+       if (!(dev->state & TASKDEV_ST_NOTASK)) {
+               printk(KERN_WARNING
+                      "omapdsp: illegal device state (%s) on rmdev %s.\n",
+                      devstate_name(dev->state), dev->name);
+       }
+notask:
+       dev->state = TASKDEV_ST_INVALID;
+       devstate_read_unlock(dev);
+
+       taskdev_delete(minor);
+       kfree(dev);
+
+       return 0;
+}
+
+struct file_operations dsp_task_fops = {
+       .owner   = THIS_MODULE,
+       .poll    = dsp_task_poll,
+       .ioctl   = dsp_task_ioctl,
+       .open    = dsp_task_open,
+       .release = dsp_task_release,
+};
+
+static void dsptask_dev_release(struct device *dev)
+{
+}
+
+static int taskdev_init(struct taskdev *dev, char *name, unsigned char minor)
+{
+       int ret;
+
+       taskdev[minor] = dev;
+
+       spin_lock_init(&dev->proc_list_lock);
+       INIT_LIST_HEAD(&dev->proc_list);
+       init_waitqueue_head(&dev->read_wait_q);
+       init_waitqueue_head(&dev->write_wait_q);
+       init_waitqueue_head(&dev->tctl_wait_q);
+       mutex_init(&dev->read_mutex);
+       mutex_init(&dev->write_mutex);
+       mutex_init(&dev->tctl_mutex);
+       mutex_init(&dev->lock);
+       spin_lock_init(&dev->wsz_lock);
+       dev->tctl_ret = -EINVAL;
+       dev->lock_pid = 0;
+
+       strncpy(dev->name, name, TNM_LEN);
+       dev->name[TNM_LEN-1] = '\0';
+       dev->state = (minor < n_task) ? TASKDEV_ST_ATTACHED : TASKDEV_ST_NOTASK;
+       dev->usecount = 0;
+       mutex_init(&dev->usecount_lock);
+       memcpy(&dev->fops, &dsp_task_fops, sizeof(struct file_operations));
+
+       dev->dev.parent = omap_dsp->dev;
+       dev->dev.bus = &dsptask_bus;
+       sprintf(dev->dev.bus_id, "dsptask%d", minor);
+       dev->dev.release = dsptask_dev_release;
+       ret = device_register(&dev->dev);
+       if (ret)
+               printk(KERN_ERR "device_register failed: %d\n", ret);
+       ret = device_create_file(&dev->dev, &dev_attr_devname);
+       ret |= device_create_file(&dev->dev, &dev_attr_devstate);
+       ret |= device_create_file(&dev->dev, &dev_attr_proc_list);
+       if (ret)
+               printk(KERN_ERR "device_create_file failed: %d\n", ret);
+       class_device_create(dsp_task_class, NULL,
+                           MKDEV(OMAP_DSP_TASK_MAJOR, minor),
+                           NULL, "dsptask%d", minor);
+
+       init_waitqueue_head(&dev->state_wait_q);
+       init_rwsem(&dev->state_sem);
+
+       return 0;
+}
+
+static void taskdev_delete(unsigned char minor)
+{
+       struct taskdev *dev = taskdev[minor];
+
+       if (!dev)
+               return;
+       device_remove_file(&dev->dev, &dev_attr_devname);
+       device_remove_file(&dev->dev, &dev_attr_devstate);
+       device_remove_file(&dev->dev, &dev_attr_proc_list);
+       class_device_destroy(dsp_task_class, MKDEV(OMAP_DSP_TASK_MAJOR, minor));
+       device_unregister(&dev->dev);
+       proc_list_flush(&dev->proc_list_lock, &dev->proc_list);
+       taskdev[minor] = NULL;
+}
+
+static int taskdev_attach_task(struct taskdev *dev, struct dsptask *task)
+{
+       u16 ttyp = task->ttyp;
+       int ret;
+
+       dev->fops.read =
+               sndtyp_acv(ttyp) ?
+                       sndtyp_wd(ttyp) ? dsp_task_read_wd_acv:
+                       /* sndtyp_bk */   dsp_task_read_bk_acv:
+               /* sndtyp_psv */
+                       sndtyp_wd(ttyp) ? dsp_task_read_wd_psv:
+                       /* sndtyp_bk */   dsp_task_read_bk_psv;
+       if (sndtyp_wd(ttyp)) {
+               /* word */
+               size_t fifosz;
+
+               fifosz = sndtyp_psv(ttyp) ? 2 : /* passive */
+                                           32; /* active */
+               if (init_fifo(&dev->rcvdt.fifo, fifosz) < 0) {
+                       printk(KERN_ERR
+                              "omapdsp: unable to allocate receive buffer. "
+                              "(%d bytes for %s)\n", fifosz, dev->name);
+                       return -ENOMEM;
+               }
+       } else {
+               /* block */
+               INIT_IPBLINK(&dev->rcvdt.bk.link);
+               dev->rcvdt.bk.rp = 0;
+       }
+
+       dev->fops.write =
+               rcvtyp_wd(ttyp) ? dsp_task_write_wd:
+               /* rcvbyp_bk */   dsp_task_write_bk;
+       dev->wsz = rcvtyp_acv(ttyp) ? 0 :               /* active */
+                  rcvtyp_wd(ttyp)  ? 2 :               /* passive word */
+                                     ipbcfg.lsz*2;     /* passive block */
+
+       if (task->map_length)
+               dev->fops.mmap = dsp_task_mmap;
+
+       ret = device_create_file(&dev->dev, &dev_attr_taskname);
+       ret |= device_create_file(&dev->dev, &dev_attr_ttyp);
+       if (sndtyp_wd(ttyp)) {
+               ret |= device_create_file(&dev->dev, &dev_attr_fifosz);
+               ret |= device_create_file(&dev->dev, &dev_attr_fifocnt);
+       } else
+               ret |= device_create_file(&dev->dev, &dev_attr_ipblink);
+       ret |= device_create_file(&dev->dev, &dev_attr_wsz);
+       if (task->map_length)
+               ret |= device_create_file(&dev->dev, &dev_attr_mmap);
+       if (ret)
+               printk(KERN_ERR "device_create_file failed: %d\n", ret);
+
+       dev->task = task;
+       task->dev = dev;
+
+       return 0;
+}
+
+static void taskdev_detach_task(struct taskdev *dev)
+{
+       u16 ttyp = dev->task->ttyp;
+
+       device_remove_file(&dev->dev, &dev_attr_taskname);
+       device_remove_file(&dev->dev, &dev_attr_ttyp);
+       if (sndtyp_wd(ttyp)) {
+               device_remove_file(&dev->dev, &dev_attr_fifosz);
+               device_remove_file(&dev->dev, &dev_attr_fifocnt);
+       } else
+               device_remove_file(&dev->dev, &dev_attr_ipblink);
+       device_remove_file(&dev->dev, &dev_attr_wsz);
+       if (dev->task->map_length)
+               device_remove_file(&dev->dev, &dev_attr_mmap);
+
+       dev->fops.read = NULL;
+       taskdev_flush_buf(dev);
+       if (sndtyp_wd(ttyp))
+               free_fifo(&dev->rcvdt.fifo);
+
+       dev->fops.write = NULL;
+       dev->wsz = 0;
+
+       printk(KERN_INFO "omapdsp: taskdev %s disabled.\n", dev->name);
+       dev->task = NULL;
+}
+
+/*
+ * tadd / tdel / tkill
+ */
+static int dsp_tadd(struct taskdev *dev, dsp_long_t adr)
+{
+       struct dsptask *task;
+       struct mb_exarg arg;
+       u8 tid, tid_response;
+       u16 argv[2];
+       int ret = 0;
+
+       if (!devstate_write_lock_and_test(dev, TASKDEV_ST_ADDREQ)) {
+               printk(KERN_ERR
+                      "omapdsp: taskdev %s is not requesting for tadd. "
+                      "(state is %s)\n", dev->name, devstate_name(dev->state));
+               return -EINVAL;
+       }
+       dev->state = TASKDEV_ST_ADDING;
+       devstate_write_unlock(dev);
+
+       if (adr == TADD_ABORTADR) {
+               /* aborting tadd intentionally */
+               printk(KERN_INFO "omapdsp: tadd address is ABORTADR.\n");
+               goto fail_out;
+       }
+       if (adr >= DSPSPACE_SIZE) {
+               printk(KERN_ERR
+                      "omapdsp: illegal address 0x%08x for tadd\n", adr);
+               ret = -EINVAL;
+               goto fail_out;
+       }
+
+       adr >>= 1;      /* word address */
+       argv[0] = adr >> 16;    /* addrh */
+       argv[1] = adr & 0xffff; /* addrl */
+
+       if (mutex_lock_interruptible(&cfg_lock)) {
+               ret = -EINTR;
+               goto fail_out;
+       }
+       cfg_tid = TID_ANON;
+       cfg_cmd = MBOX_CMD_DSP_TADD;
+       arg.tid  = TID_ANON;
+       arg.argc = 2;
+       arg.argv = argv;
+
+       if (dsp_mem_sync_inc() < 0) {
+               printk(KERN_ERR "omapdsp: memory sync failed!\n");
+               ret = -EBUSY;
+               goto fail_out;
+       }
+       mbcompose_send_and_wait_exarg(TADD, 0, 0, &arg, &cfg_wait_q);
+
+       tid = cfg_tid;
+       cfg_tid = TID_ANON;
+       cfg_cmd = 0;
+       mutex_unlock(&cfg_lock);
+
+       if (tid == TID_ANON) {
+               printk(KERN_ERR "omapdsp: tadd failed!\n");
+               ret = -EINVAL;
+               goto fail_out;
+       }
+       if ((tid < n_task) || dsptask[tid]) {
+               printk(KERN_ERR "omapdsp: illegal tid (%d)!\n", tid);
+               ret = -EINVAL;
+               goto fail_out;
+       }
+       if ((task = kzalloc(sizeof(struct dsptask), GFP_KERNEL)) == NULL) {
+               ret = -ENOMEM;
+               goto del_out;
+       }
+
+       if ((ret = dsp_task_config(task, tid)) < 0)
+               goto free_out;
+
+       if (strcmp(dev->name, task->name)) {
+               printk(KERN_ERR
+                      "omapdsp: task name (%s) doesn't match with "
+                      "device name (%s).\n", task->name, dev->name);
+               ret = -EINVAL;
+               goto free_out;
+       }
+
+       if ((ret = taskdev_attach_task(dev, task)) < 0)
+               goto free_out;
+
+       dsp_task_init(task);
+       printk(KERN_INFO "omapdsp: taskdev %s enabled.\n", dev->name);
+       dev->state = TASKDEV_ST_ATTACHED;
+       wake_up_interruptible_all(&dev->state_wait_q);
+       return 0;
+
+free_out:
+       kfree(task);
+
+del_out:
+       printk(KERN_ERR "omapdsp: deleting the task...\n");
+
+       dev->state = TASKDEV_ST_DELING;
+
+       if (mutex_lock_interruptible(&cfg_lock)) {
+               printk(KERN_ERR "omapdsp: aborting tdel process. "
+                               "DSP side could be corrupted.\n");
+               goto fail_out;
+       }
+       cfg_tid = TID_ANON;
+       cfg_cmd = MBOX_CMD_DSP_TDEL;
+       mbcompose_send_and_wait(TDEL, tid, TDEL_KILL, &cfg_wait_q);
+       tid_response = cfg_tid;
+       cfg_tid = TID_ANON;
+       cfg_cmd = 0;
+       mutex_unlock(&cfg_lock);
+
+       if (tid_response != tid)
+               printk(KERN_ERR "omapdsp: tdel failed. "
+                               "DSP side could be corrupted.\n");
+
+fail_out:
+       dev->state = TASKDEV_ST_ADDFAIL;
+       wake_up_interruptible_all(&dev->state_wait_q);
+       return ret;
+}
+
+int dsp_tadd_minor(unsigned char minor, dsp_long_t adr)
+{
+       struct taskdev *dev;
+       int status;
+       int ret;
+
+       if (mutex_lock_interruptible(&devmgr_lock))
+               return -EINTR;
+
+       if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL)) {
+               printk(KERN_ERR
+                      "omapdsp: no task device with minor %d\n", minor);
+               ret = -EINVAL;
+               goto out;
+       }
+       ret = minor;
+       if ((status = dsp_tadd(dev, adr)) < 0)
+               ret = status;
+
+out:
+       mutex_unlock(&devmgr_lock);
+       return ret;
+}
+
+static int dsp_tdel(struct taskdev *dev)
+{
+       if (!devstate_write_lock_and_test(dev, TASKDEV_ST_DELREQ)) {
+               printk(KERN_ERR
+                      "omapdsp: taskdev %s is not requesting for tdel. "
+                      "(state is %s)\n", dev->name, devstate_name(dev->state));
+               return -EINVAL;
+       }
+       dev->state = TASKDEV_ST_DELING;
+       devstate_write_unlock(dev);
+
+       return dsp_tdel_bh(dev, TDEL_SAFE);
+}
+
+int dsp_tdel_minor(unsigned char minor)
+{
+       struct taskdev *dev;
+       int status;
+       int ret;
+
+       if (mutex_lock_interruptible(&devmgr_lock))
+               return -EINTR;
+
+       if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL)) {
+               printk(KERN_ERR
+                      "omapdsp: no task device with minor %d\n", minor);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       ret = minor;
+       if ((status = dsp_tdel(dev)) < 0)
+               ret = status;
+
+out:
+       mutex_unlock(&devmgr_lock);
+       return ret;
+}
+
+static int dsp_tkill(struct taskdev *dev)
+{
+       while (!down_write_trylock(&dev->state_sem)) {
+               if (!devstate_read_lock_and_test(dev, (TASKDEV_ST_ATTACHED |
+                                                      TASKDEV_ST_FREEZED))) {
+                       printk(KERN_ERR
+                              "omapdsp: task has not been attached for "
+                              "taskdev %s\n", dev->name);
+                       return -EINVAL;
+               }
+               /* ATTACHED -> FREEZED can be changed under read semaphore. */
+               dev->state = TASKDEV_ST_FREEZED;
+               wake_up_interruptible_all(&dev->read_wait_q);
+               wake_up_interruptible_all(&dev->write_wait_q);
+               wake_up_interruptible_all(&dev->tctl_wait_q);
+               devstate_read_unlock(dev);
+               schedule();
+       }
+
+       if (!(dev->state & (TASKDEV_ST_ATTACHED |
+                           TASKDEV_ST_FREEZED))) {
+               printk(KERN_ERR
+                      "omapdsp: task has not been attached for taskdev %s\n",
+                      dev->name);
+               devstate_write_unlock(dev);
+               return -EINVAL;
+       }
+       if (!is_dynamic_task(dev->task->tid)) {
+               printk(KERN_ERR "omapdsp: task %s is not a dynamic task.\n",
+                      dev->name);
+               devstate_write_unlock(dev);
+               return -EINVAL;
+       }
+       dev->state = TASKDEV_ST_KILLING;
+       devstate_write_unlock(dev);
+
+       return dsp_tdel_bh(dev, TDEL_KILL);
+}
+
+int dsp_tkill_minor(unsigned char minor)
+{
+       struct taskdev *dev;
+       int status;
+       int ret;
+
+       if (mutex_lock_interruptible(&devmgr_lock))
+               return -EINTR;
+
+       if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL)) {
+               printk(KERN_ERR
+                      "omapdsp: no task device with minor %d\n", minor);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       ret = minor;
+       if ((status = dsp_tkill(dev)) < 0)
+               ret = status;
+
+out:
+       mutex_unlock(&devmgr_lock);
+       return ret;
+}
+
+static int dsp_tdel_bh(struct taskdev *dev, u16 type)
+{
+       struct dsptask *task;
+       u8 tid, tid_response;
+       int ret = 0;
+
+       task = dev->task;
+       tid = task->tid;
+       if (mutex_lock_interruptible(&cfg_lock)) {
+               if (type == TDEL_SAFE) {
+                       dev->state = TASKDEV_ST_DELREQ;
+                       return -EINTR;
+               } else {
+                       tid_response = TID_ANON;
+                       ret = -EINTR;
+                       goto detach_out;
+               }
+       }
+       cfg_tid = TID_ANON;
+       cfg_cmd = MBOX_CMD_DSP_TDEL;
+       mbcompose_send_and_wait(TDEL, tid, type, &cfg_wait_q);
+       tid_response = cfg_tid;
+       cfg_tid = TID_ANON;
+       cfg_cmd = 0;
+       mutex_unlock(&cfg_lock);
+
+detach_out:
+       taskdev_detach_task(dev);
+       dsp_task_unconfig(task);
+       kfree(task);
+
+       if (tid_response != tid) {
+               printk(KERN_ERR "omapdsp: %s failed!\n",
+                      (type == TDEL_SAFE) ? "tdel" : "tkill");
+               ret = -EINVAL;
+       }
+       down_write(&dev->state_sem);
+       dev->state = (dev->usecount > 0) ? TASKDEV_ST_GARBAGE :
+                                          TASKDEV_ST_NOTASK;
+       wake_up_interruptible_all(&dev->state_wait_q);
+       up_write(&dev->state_sem);
+
+       return ret;
+}
+
+/*
+ * state inquiry
+ */
+long taskdev_state_stale(unsigned char minor)
+{
+       if (taskdev[minor]) {
+               long state = taskdev[minor]->state;
+               taskdev[minor]->state |= TASKDEV_ST_STALE;
+               return state;
+       } else
+               return TASKDEV_ST_NOTASK;
+}
+
+/*
+ * functions called from mailbox interrupt routine
+ */
+void mbox_wdsnd(struct mbcmd *mb)
+{
+       u8 tid = mb->cmd_l;
+       struct dsptask *task = dsptask[tid];
+
+       if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+               printk(KERN_ERR "mbox: WDSND with illegal tid! %d\n", tid);
+               return;
+       }
+       if (sndtyp_bk(task->ttyp)) {
+               printk(KERN_ERR
+                      "mbox: WDSND from block sending task! (task%d)\n", tid);
+               return;
+       }
+       if (sndtyp_psv(task->ttyp) &&
+           !waitqueue_active(&task->dev->read_wait_q)) {
+               printk(KERN_WARNING
+                      "mbox: WDSND from passive sending task (task%d) "
+                      "without request!\n", tid);
+               return;
+       }
+
+       write_word_to_fifo(&task->dev->rcvdt.fifo, mb->data);
+       wake_up_interruptible(&task->dev->read_wait_q);
+}
+
+void mbox_wdreq(struct mbcmd *mb)
+{
+       u8 tid = mb->cmd_l;
+       struct dsptask *task = dsptask[tid];
+       struct taskdev *dev;
+
+       if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+               printk(KERN_ERR "mbox: WDREQ with illegal tid! %d\n", tid);
+               return;
+       }
+       if (rcvtyp_psv(task->ttyp)) {
+               printk(KERN_ERR
+                      "mbox: WDREQ from passive receiving task! (task%d)\n",
+                      tid);
+               return;
+       }
+
+       dev = task->dev;
+       spin_lock(&dev->wsz_lock);
+       dev->wsz = 2;
+       spin_unlock(&dev->wsz_lock);
+       wake_up_interruptible(&dev->write_wait_q);
+}
+
+void mbox_bksnd(struct mbcmd *mb)
+{
+       u8 tid = mb->cmd_l;
+       u16 bid = mb->data;
+       struct dsptask *task = dsptask[tid];
+       struct ipbuf_head *ipb_h;
+       u16 cnt;
+
+       if (bid >= ipbcfg.ln) {
+               printk(KERN_ERR "mbox: BKSND with illegal bid! %d\n", bid);
+               return;
+       }
+       ipb_h = bid_to_ipbuf(bid);
+       ipb_bsycnt_dec(&ipbcfg);
+       if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+               printk(KERN_ERR "mbox: BKSND with illegal tid! %d\n", tid);
+               goto unuse_ipbuf_out;
+       }
+       if (sndtyp_wd(task->ttyp)) {
+               printk(KERN_ERR
+                      "mbox: BKSND from word sending task! (task%d)\n", tid);
+               goto unuse_ipbuf_out;
+       }
+       if (sndtyp_pvt(task->ttyp)) {
+               printk(KERN_ERR
+                      "mbox: BKSND from private sending task! (task%d)\n", tid);
+               goto unuse_ipbuf_out;
+       }
+       if (sync_with_dsp(&ipb_h->p->sd, tid, 10) < 0) {
+               printk(KERN_ERR "mbox: BKSND - IPBUF sync failed!\n");
+               return;
+       }
+
+       /* should be done in DSP, but just in case. */
+       ipb_h->p->next = BID_NULL;
+
+       cnt = ipb_h->p->c;
+       if (cnt > ipbcfg.lsz) {
+               printk(KERN_ERR "mbox: BKSND cnt(%d) > ipbuf line size(%d)!\n",
+                      cnt, ipbcfg.lsz);
+               goto unuse_ipbuf_out;
+       }
+
+       if (cnt == 0) {
+               /* 0-byte send from DSP */
+               unuse_ipbuf_nowait(ipb_h);
+               goto done;
+       }
+       ipblink_add_tail(&task->dev->rcvdt.bk.link, bid);
+       /* we keep coming bid and return alternative line to DSP. */
+       balance_ipbuf();
+
+done:
+       wake_up_interruptible(&task->dev->read_wait_q);
+       return;
+
+unuse_ipbuf_out:
+       unuse_ipbuf_nowait(ipb_h);
+       return;
+}
+
+void mbox_bkreq(struct mbcmd *mb)
+{
+       u8 tid = mb->cmd_l;
+       u16 cnt = mb->data;
+       struct dsptask *task = dsptask[tid];
+       struct taskdev *dev;
+
+       if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+               printk(KERN_ERR "mbox: BKREQ with illegal tid! %d\n", tid);
+               return;
+       }
+       if (rcvtyp_wd(task->ttyp)) {
+               printk(KERN_ERR
+                      "mbox: BKREQ from word receiving task! (task%d)\n", tid);
+               return;
+       }
+       if (rcvtyp_pvt(task->ttyp)) {
+               printk(KERN_ERR
+                      "mbox: BKREQ from private receiving task! (task%d)\n",
+                      tid);
+               return;
+       }
+       if (rcvtyp_psv(task->ttyp)) {
+               printk(KERN_ERR
+                      "mbox: BKREQ from passive receiving task! (task%d)\n",
+                      tid);
+               return;
+       }
+
+       dev = task->dev;
+       spin_lock(&dev->wsz_lock);
+       dev->wsz = cnt*2;
+       spin_unlock(&dev->wsz_lock);
+       wake_up_interruptible(&dev->write_wait_q);
+}
+
+void mbox_bkyld(struct mbcmd *mb)
+{
+       u16 bid = mb->data;
+       struct ipbuf_head *ipb_h;
+
+       if (bid >= ipbcfg.ln) {
+               printk(KERN_ERR "mbox: BKYLD with illegal bid! %d\n", bid);
+               return;
+       }
+       ipb_h = bid_to_ipbuf(bid);
+
+       /* should be done in DSP, but just in case. */
+       ipb_h->p->next = BID_NULL;
+
+       /* we don't need to sync with DSP */
+       ipb_bsycnt_dec(&ipbcfg);
+       release_ipbuf(ipb_h);
+}
+
+void mbox_bksndp(struct mbcmd *mb)
+{
+       u8 tid = mb->cmd_l;
+       struct dsptask *task = dsptask[tid];
+       struct ipbuf_p *ipbp;
+
+       if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+               printk(KERN_ERR "mbox: BKSNDP with illegal tid! %d\n", tid);
+               return;
+       }
+       if (sndtyp_wd(task->ttyp)) {
+               printk(KERN_ERR
+                      "mbox: BKSNDP from word sending task! (task%d)\n", tid);
+               return;
+       }
+       if (sndtyp_gbl(task->ttyp)) {
+               printk(KERN_ERR
+                      "mbox: BKSNDP from non-private sending task! (task%d)\n",
+                      tid);
+               return;
+       }
+
+       /*
+        * we should not have delayed block at this point
+        * because read() routine releases the lock of the buffer and
+        * until then DSP can't send next data.
+        */
+
+       ipbp = task->ipbuf_pvt_r;
+       if (sync_with_dsp(&ipbp->s, tid, 10) < 0) {
+               printk(KERN_ERR "mbox: BKSNDP - IPBUF sync failed!\n");
+               return;
+       }
+       printk(KERN_DEBUG "mbox: ipbuf_pvt_r->a = 0x%08lx\n",
+              MKLONG(ipbp->ah, ipbp->al));
+       ipblink_add_pvt(&task->dev->rcvdt.bk.link);
+       wake_up_interruptible(&task->dev->read_wait_q);
+}
+
+void mbox_bkreqp(struct mbcmd *mb)
+{
+       u8 tid = mb->cmd_l;
+       struct dsptask *task = dsptask[tid];
+       struct taskdev *dev;
+       struct ipbuf_p *ipbp;
+
+       if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+               printk(KERN_ERR "mbox: BKREQP with illegal tid! %d\n", tid);
+               return;
+       }
+       if (rcvtyp_wd(task->ttyp)) {
+               printk(KERN_ERR
+                      "mbox: BKREQP from word receiving task! (task%d)\n", tid);
+               return;
+       }
+       if (rcvtyp_gbl(task->ttyp)) {
+               printk(KERN_ERR
+                      "mbox: BKREQP from non-private receiving task! (task%d)\n", tid);
+               return;
+       }
+       if (rcvtyp_psv(task->ttyp)) {
+               printk(KERN_ERR
+                      "mbox: BKREQP from passive receiving task! (task%d)\n", tid);
+               return;
+       }
+
+       ipbp = task->ipbuf_pvt_w;
+       if (sync_with_dsp(&ipbp->s, TID_FREE, 10) < 0) {
+               printk(KERN_ERR "mbox: BKREQP - IPBUF sync failed!\n");
+               return;
+       }
+       printk(KERN_DEBUG "mbox: ipbuf_pvt_w->a = 0x%08lx\n",
+              MKLONG(ipbp->ah, ipbp->al));
+       dev = task->dev;
+       spin_lock(&dev->wsz_lock);
+       dev->wsz = ipbp->c*2;
+       spin_unlock(&dev->wsz_lock);
+       wake_up_interruptible(&dev->write_wait_q);
+}
+
+void mbox_tctl(struct mbcmd *mb)
+{
+       u8 tid = mb->cmd_l;
+       struct dsptask *task = dsptask[tid];
+
+       if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+               printk(KERN_ERR "mbox: TCTL with illegal tid! %d\n", tid);
+               return;
+       }
+
+       if (!waitqueue_active(&task->dev->tctl_wait_q)) {
+               printk(KERN_WARNING "mbox: unexpected TCTL from DSP!\n");
+               return;
+       }
+
+       task->dev->tctl_stat = mb->data;
+       wake_up_interruptible(&task->dev->tctl_wait_q);
+}
+
+void mbox_tcfg(struct mbcmd *mb)
+{
+       u8 tid = mb->cmd_l;
+       struct dsptask *task = dsptask[tid];
+       u16 *tnm;
+       volatile u16 *buf;
+       int i;
+
+       if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+               printk(KERN_ERR "mbox: TCFG with illegal tid! %d\n", tid);
+               return;
+       }
+       if ((task->state != TASK_ST_CFGREQ) || (cfg_cmd != MBOX_CMD_DSP_TCFG)) {
+               printk(KERN_WARNING "mbox: unexpected TCFG from DSP!\n");
+               return;
+       }
+
+       if (dsp_mem_enable(ipbuf_sys_da) < 0) {
+               printk(KERN_ERR "mbox: TCFG - ipbuf_sys_da read failed!\n");
+               dsp_mem_disable(ipbuf_sys_da);
+               goto out;
+       }
+       if (sync_with_dsp(&ipbuf_sys_da->s, tid, 10) < 0) {
+               printk(KERN_ERR "mbox: TCFG - IPBUF sync failed!\n");
+               dsp_mem_disable(ipbuf_sys_da);
+               goto out;
+       }
+
+       /*
+        * read configuration data on system IPBUF
+        */
+       buf = ipbuf_sys_da->d;
+       task->ttyp        = buf[0];
+       task->ipbuf_pvt_r = MKVIRT(buf[1], buf[2]);
+       task->ipbuf_pvt_w = MKVIRT(buf[3], buf[4]);
+       task->map_base    = MKVIRT(buf[5], buf[6]);
+       task->map_length  = MKLONG(buf[7], buf[8]) << 1;        /* word -> byte */
+       tnm               = MKVIRT(buf[9], buf[10]);
+       release_ipbuf_pvt(ipbuf_sys_da);
+       dsp_mem_disable(ipbuf_sys_da);
+
+       /*
+        * copy task name string
+        */
+       if (dsp_address_validate(tnm, TNM_LEN, "task name buffer") < 0) {
+               task->name[0] = '\0';
+               goto out;
+       }
+
+       for (i = 0; i < TNM_LEN-1; i++) {
+               /* avoiding byte access */
+               u16 tmp = tnm[i];
+               task->name[i] = tmp & 0x00ff;
+               if (!tmp)
+                       break;
+       }
+       task->name[TNM_LEN-1] = '\0';
+
+       task->state = TASK_ST_READY;
+out:
+       wake_up_interruptible(&cfg_wait_q);
+}
+
+void mbox_tadd(struct mbcmd *mb)
+{
+       u8 tid = mb->cmd_l;
+
+       if ((!waitqueue_active(&cfg_wait_q)) || (cfg_cmd != MBOX_CMD_DSP_TADD)) {
+               printk(KERN_WARNING "mbox: unexpected TADD from DSP!\n");
+               return;
+       }
+       cfg_tid = tid;
+       wake_up_interruptible(&cfg_wait_q);
+}
+
+void mbox_tdel(struct mbcmd *mb)
+{
+       u8 tid = mb->cmd_l;
+
+       if ((!waitqueue_active(&cfg_wait_q)) || (cfg_cmd != MBOX_CMD_DSP_TDEL)) {
+               printk(KERN_WARNING "mbox: unexpected TDEL from DSP!\n");
+               return;
+       }
+       cfg_tid = tid;
+       wake_up_interruptible(&cfg_wait_q);
+}
+
+void mbox_err_fatal(u8 tid)
+{
+       struct dsptask *task = dsptask[tid];
+       struct taskdev *dev;
+
+       if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+               printk(KERN_ERR "mbox: FATAL ERR with illegal tid! %d\n", tid);
+               return;
+       }
+
+       /* wake up waiting processes */
+       dev = task->dev;
+       wake_up_interruptible_all(&dev->read_wait_q);
+       wake_up_interruptible_all(&dev->write_wait_q);
+       wake_up_interruptible_all(&dev->tctl_wait_q);
+}
+
+static u16 *dbg_buf;
+static u16 dbg_buf_sz, dbg_line_sz;
+static int dbg_rp;
+
+int dsp_dbg_config(u16 *buf, u16 sz, u16 lsz)
+{
+#ifdef OLD_BINARY_SUPPORT
+       if ((mbox_revision == MBREV_3_0) || (mbox_revision == MBREV_3_2)) {
+               dbg_buf = NULL;
+               dbg_buf_sz = 0;
+               dbg_line_sz = 0;
+               dbg_rp = 0;
+               return 0;
+       }
+#endif
+
+       if (dsp_address_validate(buf, sz, "debug buffer") < 0)
+               return -1;
+
+       if (lsz > sz) {
+               printk(KERN_ERR
+                      "omapdsp: dbg_buf lsz (%d) is greater than its "
+                      "buffer size (%d)\n", lsz, sz);
+               return -1;
+       }
+
+       dbg_buf = buf;
+       dbg_buf_sz = sz;
+       dbg_line_sz = lsz;
+       dbg_rp = 0;
+
+       return 0;
+}
+
+void dsp_dbg_stop(void)
+{
+       dbg_buf = NULL;
+}
+
+#ifdef OLD_BINARY_SUPPORT
+static void mbox_dbg_old(struct mbcmd *mb);
+#endif
+
+void mbox_dbg(struct mbcmd *mb)
+{
+       u8 tid = mb->cmd_l;
+       int cnt = mb->data;
+       char s[80], *s_end = &s[79], *p;
+       u16 *src;
+       int i;
+
+#ifdef OLD_BINARY_SUPPORT
+       if ((mbox_revision == MBREV_3_0) || (mbox_revision == MBREV_3_2)) {
+               mbox_dbg_old(mb);
+               return;
+       }
+#endif
+
+       if (((tid >= TASKDEV_MAX) || (dsptask[tid] == NULL)) &&
+           (tid != TID_ANON)) {
+               printk(KERN_ERR "mbox: DBG with illegal tid! %d\n", tid);
+               return;
+       }
+       if (dbg_buf == NULL) {
+               printk(KERN_ERR "mbox: DBG command received, but "
+                      "dbg_buf has not been configured yet.\n");
+               return;
+       }
+
+       if (dsp_mem_enable(dbg_buf) < 0)
+               return;
+
+       src = &dbg_buf[dbg_rp];
+       p = s;
+       for (i = 0; i < cnt; i++) {
+               u16 tmp;
+               /*
+                * Be carefull that dbg_buf should not be read with
+                * 1-byte access since it might be placed in DARAM/SARAM
+                * and it can cause unexpected byteswap.
+                * For example,
+                *   *(p++) = *(src++) & 0xff;
+                * causes 1-byte access!
+                */
+               tmp = *src++;
+               *(p++) = tmp & 0xff;
+               if (*(p-1) == '\n') {
+                       *p = '\0';
+                       printk(KERN_INFO "%s", s);
+                       p = s;
+                       continue;
+               }
+               if (p == s_end) {
+                       *p = '\0';
+                       printk(KERN_INFO "%s\n", s);
+                       p = s;
+                       continue;
+               }
+       }
+       if (p > s) {
+               *p = '\0';
+               printk(KERN_INFO "%s\n", s);
+       }
+       if ((dbg_rp += cnt + 1) > dbg_buf_sz - dbg_line_sz)
+               dbg_rp = 0;
+
+       dsp_mem_disable(dbg_buf);
+}
+
+#ifdef OLD_BINARY_SUPPORT
+static void mbox_dbg_old(struct mbcmd *mb)
+{
+       u8 tid = mb->cmd_l;
+       char s[80], *s_end = &s[79], *p;
+       u16 *src;
+       volatile u16 *buf;
+       int cnt;
+       int i;
+
+       if (((tid >= TASKDEV_MAX) || (dsptask[tid] == NULL)) &&
+           (tid != TID_ANON)) {
+               printk(KERN_ERR "mbox: DBG with illegal tid! %d\n", tid);
+               return;
+       }
+       if (dsp_mem_enable(ipbuf_sys_da) < 0) {
+               printk(KERN_ERR "mbox: DBG - ipbuf_sys_da read failed!\n");
+               return;
+       }
+       if (sync_with_dsp(&ipbuf_sys_da->s, tid, 10) < 0) {
+               printk(KERN_ERR "mbox: DBG - IPBUF sync failed!\n");
+               goto out1;
+       }
+       buf = ipbuf_sys_da->d;
+       cnt = buf[0];
+       src = MKVIRT(buf[1], buf[2]);
+       if (dsp_address_validate(src, cnt, "dbg buffer") < 0)
+               goto out2;
+
+       if (dsp_mem_enable(src) < 0)
+               goto out2;
+
+       p = s;
+       for (i = 0; i < cnt; i++) {
+               u16 tmp;
+               /*
+                * Be carefull that ipbuf should not be read with
+                * 1-byte access since it might be placed in DARAM/SARAM
+                * and it can cause unexpected byteswap.
+                * For example,
+                *   *(p++) = *(src++) & 0xff;
+                * causes 1-byte access!
+                */
+               tmp = *src++;
+               *(p++) = tmp & 0xff;
+               if (*(p-1) == '\n') {
+                       *p = '\0';
+                       printk(KERN_INFO "%s", s);
+                       p = s;
+                       continue;
+               }
+               if (p == s_end) {
+                       *p = '\0';
+                       printk(KERN_INFO "%s\n", s);
+                       p = s;
+                       continue;
+               }
+       }
+       if (p > s) {
+               *p = '\0';
+               printk(KERN_INFO "%s\n", s);
+       }
+
+       dsp_mem_disable(src);
+out2:
+       release_ipbuf_pvt(ipbuf_sys_da);
+out1:
+       dsp_mem_disable(ipbuf_sys_da);
+}
+#endif /* OLD_BINARY_SUPPORT */
+
+/*
+ * sysfs files: for each device
+ */
+
+/* devname */
+static ssize_t devname_show(struct device *d, struct device_attribute *attr,
+                           char *buf)
+{
+       return sprintf(buf, "%s\n", to_taskdev(d)->name);
+}
+
+/* devstate */
+static ssize_t devstate_show(struct device *d, struct device_attribute *attr,
+                            char *buf)
+{
+       return sprintf(buf, "%s\n", devstate_name(to_taskdev(d)->state));
+}
+
+/* proc_list */
+static ssize_t proc_list_show(struct device *d, struct device_attribute *attr,
+                             char *buf)
+{
+       struct taskdev *dev;
+       struct proc_list *pl;
+       int len = 0;
+
+       dev = to_taskdev(d);
+       spin_lock(&dev->proc_list_lock);
+       list_for_each_entry(pl, &dev->proc_list, list_head) {
+               /* need to lock tasklist_lock before calling
+                * find_task_by_pid_type. */
+               if (find_task_by_pid_type(PIDTYPE_PID, pl->pid) != NULL)
+                       len += sprintf(buf + len, "%d\n", pl->pid);
+               read_unlock(&tasklist_lock);
+       }
+       spin_unlock(&dev->proc_list_lock);
+
+       return len;
+}
+
+/* taskname */
+static ssize_t taskname_show(struct device *d, struct device_attribute *attr,
+                            char *buf)
+{
+       struct taskdev *dev = to_taskdev(d);
+       int len;
+
+       if (!devstate_read_lock_and_test(dev, TASKDEV_ST_ATTACHED))
+               return -ENODEV;
+
+       len = sprintf(buf, "%s\n", dev->task->name);
+
+       devstate_read_unlock(dev);
+       return len;
+}
+
+/* ttyp */
+static ssize_t ttyp_show(struct device *d, struct device_attribute *attr,
+                        char *buf)
+{
+       struct taskdev *dev = to_taskdev(d);
+       u16 ttyp;
+       int len = 0;
+
+       if (!devstate_read_lock_and_test(dev, TASKDEV_ST_ATTACHED))
+               return -ENODEV;
+
+       ttyp = dev->task->ttyp;
+       len += sprintf(buf + len, "0x%04x\n", ttyp);
+       len += sprintf(buf + len, "%s %s send\n",
+                       (sndtyp_acv(ttyp)) ? "active" :
+                                            "passive",
+                       (sndtyp_wd(ttyp))  ? "word" :
+                       (sndtyp_pvt(ttyp)) ? "private block" :
+                                            "global block");
+       len += sprintf(buf + len, "%s %s receive\n",
+                       (rcvtyp_acv(ttyp)) ? "active" :
+                                            "passive",
+                       (rcvtyp_wd(ttyp))  ? "word" :
+                       (rcvtyp_pvt(ttyp)) ? "private block" :
+                                            "global block");
+
+       devstate_read_unlock(dev);
+       return len;
+}
+
+/* fifosz */
+static ssize_t fifosz_show(struct device *d, struct device_attribute *attr,
+                          char *buf)
+{
+       struct fifo_struct *fifo = &to_taskdev(d)->rcvdt.fifo;
+       return sprintf(buf, "%d\n", fifo->sz);
+}
+
+static int fifosz_store(struct device *d, struct device_attribute *attr,
+                       const char *buf, size_t count)
+{
+       struct taskdev *dev = to_taskdev(d);
+       unsigned long fifosz;
+       int ret;
+
+       fifosz = simple_strtol(buf, NULL, 10);
+       ret = taskdev_set_fifosz(dev, fifosz);
+
+       return (ret < 0) ? ret : strlen(buf);
+}
+
+/* fifocnt */
+static ssize_t fifocnt_show(struct device *d, struct device_attribute *attr,
+                           char *buf)
+{
+       struct fifo_struct *fifo = &to_taskdev(d)->rcvdt.fifo;
+       return sprintf(buf, "%d\n", fifo->cnt);
+}
+
+/* ipblink */
+static __inline__ char *bid_name(u16 bid)
+{
+       static char s[6];
+
+       switch (bid) {
+       case BID_NULL:
+               return "NULL";
+       case BID_PVT:
+               return "PRIVATE";
+       default:
+               sprintf(s, "%d", bid);
+               return s;
+       }
+}
+
+static ssize_t ipblink_show(struct device *d, struct device_attribute *attr,
+                           char *buf)
+{
+       struct rcvdt_bk_struct *rcvdt = &to_taskdev(d)->rcvdt.bk;
+       int len;
+
+       spin_lock(&rcvdt->link.lock);
+       len = sprintf(buf, "top  %s\ntail %s\n",
+                     bid_name(rcvdt->link.top), bid_name(rcvdt->link.tail));
+       spin_unlock(&rcvdt->link.lock);
+
+       return len;
+}
+
+/* wsz */
+static ssize_t wsz_show(struct device *d, struct device_attribute *attr,
+                       char *buf)
+{
+       return sprintf(buf, "%d\n", to_taskdev(d)->wsz);
+}
+
+/* mmap */
+static ssize_t mmap_show(struct device *d, struct device_attribute *attr,
+                        char *buf)
+{
+       struct dsptask *task = to_taskdev(d)->task;
+       return sprintf(buf, "0x%p 0x%x\n", task->map_base, task->map_length);
+}
+
+/*
+ * called from ipbuf_show()
+ */
+int ipbuf_is_held(u8 tid, u16 bid)
+{
+       struct dsptask *task = dsptask[tid];
+       struct ipblink *link;
+       u16 b;
+       int ret = 0;
+
+       if (task == NULL)
+               return 0;
+
+       link = &task->dev->rcvdt.bk.link;
+       spin_lock(&link->lock);
+       ipblink_for_each(b, link) {
+               if (b == bid) { /* found */
+                       ret = 1;
+                       break;
+               }
+       }
+       spin_unlock(&link->lock);
+
+       return ret;
+}
+
+int __init dsp_taskmod_init(void)
+{
+       int retval;
+
+       memset(taskdev, 0, sizeof(void *) * TASKDEV_MAX);
+       memset(dsptask, 0, sizeof(void *) * TASKDEV_MAX);
+
+       retval = register_chrdev(OMAP_DSP_TASK_MAJOR, "dsptask",
+                                &dsp_task_fops);
+       if (retval < 0) {
+               printk(KERN_ERR
+                      "omapdsp: failed to register task device: %d\n", retval);
+               return retval;
+       }
+
+       retval = bus_register(&dsptask_bus);
+       if (retval) {
+               printk(KERN_ERR
+                      "omapdsp: failed to register DSP task bus: %d\n",
+                      retval);
+               unregister_chrdev(OMAP_DSP_TASK_MAJOR, "dsptask");
+               return -EINVAL;
+       }
+       retval = driver_register(&dsptask_driver);
+       if (retval) {
+               printk(KERN_ERR
+                      "omapdsp: failed to register DSP task driver: %d\n",
+                      retval);
+               bus_unregister(&dsptask_bus);
+               unregister_chrdev(OMAP_DSP_TASK_MAJOR, "dsptask");
+               return -EINVAL;
+       }
+       dsp_task_class = class_create(THIS_MODULE, "dsptask");
+
+       return 0;
+}
+
+void dsp_taskmod_exit(void)
+{
+       class_destroy(dsp_task_class);
+       driver_unregister(&dsptask_driver);
+       bus_unregister(&dsptask_bus);
+       unregister_chrdev(OMAP_DSP_TASK_MAJOR, "dsptask");
+}
diff --git a/arch/arm/plat-omap/dsp/taskwatch.c b/arch/arm/plat-omap/dsp/taskwatch.c
new file mode 100644 (file)
index 0000000..cfec6b3
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <asm/uaccess.h>
+#include "dsp_mbcmd.h"
+#include "dsp.h"
+#include "ioctl.h"
+
+static DECLARE_WAIT_QUEUE_HEAD(read_wait_q);
+static unsigned int change_cnt;
+
+void dsp_twch_touch(void)
+{
+       change_cnt++;
+       wake_up_interruptible(&read_wait_q);
+}
+
+/*
+ * @count: represents the device counts of the user's interst
+ */
+static ssize_t dsp_twch_read(struct file *file, char __user *buf, size_t count,
+                            loff_t *ppos)
+{
+       long taskstat[TASKDEV_MAX];
+       int devcount = count / sizeof(long);
+       int i;
+
+       if (dsp_cfgstat_get_stat() != CFGSTAT_READY) {
+               printk(KERN_ERR "omapdsp: dsp has not been configured.\n");
+               return -EINVAL;
+       }
+
+       if (change_cnt == 0) {
+               long current_state;
+               DECLARE_WAITQUEUE(wait, current);
+
+               add_wait_queue(&read_wait_q, &wait);
+               current_state = current->state;
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (change_cnt == 0)    /* last check */
+                       schedule();
+               set_current_state(current_state);
+               remove_wait_queue(&read_wait_q, &wait);
+
+               /* unconfigured while waiting ;-( */
+               if (dsp_cfgstat_get_stat() != CFGSTAT_READY)
+                       return -EINVAL;
+       }
+
+       if (devcount > TASKDEV_MAX)
+               devcount = TASKDEV_MAX;
+
+       count = devcount * sizeof(long);
+       change_cnt = 0;
+       for (i = 0; i < devcount; i++) {
+               /*
+                * once the device state is read, the 'STALE' bit will be set
+                * so that the Dynamic Loader can distinguish the new request
+                * from the old one.
+                */
+               taskstat[i] = taskdev_state_stale(i);
+       }
+
+       if (copy_to_user(buf, taskstat, count))
+               return -EFAULT;
+
+       return count;
+}
+
+static unsigned int dsp_twch_poll(struct file *file, poll_table *wait)
+{
+       unsigned int mask = 0;
+
+       poll_wait(file, &read_wait_q, wait);
+       if (change_cnt)
+               mask |= POLLIN | POLLRDNORM;
+
+       return mask;
+}
+
+static int dsp_twch_ioctl(struct inode *inode, struct file *file,
+                         unsigned int cmd, unsigned long arg)
+{
+       int ret;
+
+       switch (cmd) {
+       case TWCH_IOCTL_MKDEV:
+               {
+                       char name[TNM_LEN];
+                       if (copy_from_user(name, (void __user *)arg, TNM_LEN))
+                               return -EFAULT;
+                       name[TNM_LEN-1] = '\0';
+                       ret = dsp_mkdev(name);
+                       break;
+               }
+
+       case TWCH_IOCTL_RMDEV:
+               {
+                       char name[TNM_LEN];
+                       if (copy_from_user(name, (void __user *)arg, TNM_LEN))
+                               return -EFAULT;
+                       name[TNM_LEN-1] = '\0';
+                       ret = dsp_rmdev(name);
+                       break;
+               }
+
+       case TWCH_IOCTL_TADD:
+               {
+                       struct omap_dsp_taddinfo ti;
+                       if (copy_from_user(&ti, (void __user *)arg, sizeof(ti)))
+                               return -EFAULT;
+                       ret = dsp_tadd_minor(ti.minor, ti.taskadr);
+                       break;
+               }
+
+       case TWCH_IOCTL_TDEL:
+               ret = dsp_tdel_minor(arg);
+               break;
+
+       case TWCH_IOCTL_TKILL:
+               ret = dsp_tkill_minor(arg);
+               break;
+
+       default:
+               return -ENOIOCTLCMD;
+       }
+
+       return ret;
+}
+
+struct file_operations dsp_twch_fops = {
+       .owner = THIS_MODULE,
+       .read  = dsp_twch_read,
+       .poll  = dsp_twch_poll,
+       .ioctl = dsp_twch_ioctl,
+};
+
+void dsp_twch_start(void)
+{
+       change_cnt = 1;         /* first read will not wait */
+}
+
+void dsp_twch_stop(void)
+{
+       wake_up_interruptible(&read_wait_q);
+}
diff --git a/arch/arm/plat-omap/dsp/uaccess_dsp.S b/arch/arm/plat-omap/dsp/uaccess_dsp.S
new file mode 100644 (file)
index 0000000..bcf4a54
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2004-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+
+               .text
+
+/* Prototype: int __copy_to_user_dsp_2b(void *to, const char *from)
+ * Purpose  : copy 2 bytes to user memory from kernel(DSP) memory
+ *            escaping from unexpected byte swap using __copy_to_user()
+ *            in OMAP architecture.
+ * Params   : to   - user memory
+ *          : from - kernel(DSP) memory
+ * Returns  : success = 0, failure = 2
+ */
+
+ENTRY(__copy_to_user_dsp_2b)
+               stmfd   sp!, {r4, lr}
+               ldrb    r3, [r1], #1
+               ldrb    r4, [r1], #1
+USER(          strbt   r4, [r0], #1)                   @ May fault
+USER(          strbt   r3, [r0], #1)                   @ May fault
+               mov     r0, #0
+               ldmfd   sp!, {r4, pc}
+
+               .section .fixup,"ax"
+               .align  0
+9001:          mov     r0, #2
+               ldmfd   sp!, {r4, pc}
+               .previous
+
+/* Prototype: unsigned long __copy_from_user_dsp_2b(void *to, const void *from);
+ * Purpose  : copy 2 bytes from user memory to kernel(DSP) memory
+ *            escaping from unexpected byte swap using __copy_to_user()
+ *            in OMAP architecture.
+ * Params   : to   - kernel (DSP) memory
+ *          : from - user memory
+ * Returns  : success = 0, failure = 2
+ */
+
+ENTRY(__copy_from_user_dsp_2b)
+               stmfd   sp!, {r4, lr}
+USER(          ldrbt   r3, [r1], #1)                   @ May fault
+USER(          ldrbt   r4, [r1], #1)                   @ May fault
+               strb    r4, [r0], #1
+               strb    r3, [r0], #1
+               mov     r0, #0
+               ldmfd   sp!, {r4, pc}
+
+               .section .fixup,"ax"
+               .align  0
+9001:          mov     r3, #0
+               strh    r3, [r0], #2
+               mov     r0, #2
+               ldmfd   sp!, {r4, pc}
+               .previous
diff --git a/arch/arm/plat-omap/dsp/uaccess_dsp.h b/arch/arm/plat-omap/dsp/uaccess_dsp.h
new file mode 100644 (file)
index 0000000..a2ac7b6
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef _OMAP_DSP_UACCESS_DSP_H
+#define _OMAP_DSP_UACCESS_DSP_H
+
+#include <asm/uaccess.h>
+#include "dsp_common.h"
+
+#define HAVE_ASM_COPY_FROM_USER_DSP_2B
+
+#ifdef HAVE_ASM_COPY_FROM_USER_DSP_2B
+extern unsigned long __copy_from_user_dsp_2b(void *to,
+                                                 const void __user *from);
+extern unsigned long __copy_to_user_dsp_2b(void __user *to,
+                                               const void *from);
+#endif
+
+#ifndef HAVE_ASM_COPY_FROM_USER_DSP_2B
+static __inline__ unsigned long copy_from_user_dsp_2b(void *to,
+                                                     const void *from)
+{
+       unsigned short tmp;
+
+       if (__copy_from_user(&tmp, from, 2))
+               return 2;
+       /* expecting compiler to generate "strh" instruction */
+       *((unsigned short *)to) = tmp;
+       return 0;
+}
+#endif
+
+/*
+ * @n must be multiple of 2
+ */
+static __inline__ unsigned long copy_from_user_dsp(void *to, const void *from,
+                                                  unsigned long n)
+{
+       if (access_ok(VERIFY_READ, from, n)) {
+               if ((is_dsp_internal_mem(to)) &&
+                   (((unsigned long)to & 2) || (n & 2))) {
+                       /*
+                        * DARAM/SARAM with odd word alignment
+                        */
+                       unsigned long n4;
+                       unsigned long last_n;
+
+                       /* dest not aligned -- copy 2 bytes */
+                       if (((unsigned long)to & 2) && (n >= 2)) {
+#ifdef HAVE_ASM_COPY_FROM_USER_DSP_2B
+                               if (__copy_from_user_dsp_2b(to, from))
+#else
+                               if (copy_from_user_dsp_2b(to, from))
+#endif
+                                       return n;
+                               to += 2;
+                               from += 2;
+                               n -= 2;
+                       }
+                       /* middle 4*n bytes */
+                       last_n = n & 2;
+                       n4 = n - last_n;
+                       if ((n = __copy_from_user(to, from, n4)) != 0)
+                               return n + last_n;
+                       /* last 2 bytes */
+                       if (last_n) {
+                               to += n4;
+                               from += n4;
+#ifdef HAVE_ASM_COPY_FROM_USER_DSP_2B
+                               if (__copy_from_user_dsp_2b(to, from))
+#else
+                               if (copy_from_user_dsp_2b(to, from))
+#endif
+                                       return 2;
+                               n = 0;
+                       }
+               } else {
+                       /*
+                        * DARAM/SARAM with 4-byte alignment or
+                        * external memory
+                        */
+                       n = __copy_from_user(to, from, n);
+               }
+       }
+       else    /* security hole - plug it */
+               memzero(to, n);
+       return n;
+}
+
+#ifndef HAVE_ASM_COPY_FROM_USER_DSP_2B
+static __inline__ unsigned long copy_to_user_dsp_2b(void *to, const void *from)
+{
+       /* expecting compiler to generate "strh" instruction */
+       unsigned short tmp = *(unsigned short *)from;
+
+       return __copy_to_user(to, &tmp, 2);
+}
+#endif
+
+/*
+ * @n must be multiple of 2
+ */
+static __inline__ unsigned long copy_to_user_dsp(void *to, const void *from,
+                                                unsigned long n)
+{
+       if (access_ok(VERIFY_WRITE, to, n)) {
+               if ((is_dsp_internal_mem(from)) &&
+                   (((unsigned long)to & 2) || (n & 2))) {
+                       /*
+                        * DARAM/SARAM with odd word alignment
+                        */
+                       unsigned long n4;
+                       unsigned long last_n;
+
+                       /* dest not aligned -- copy 2 bytes */
+                       if (((unsigned long)to & 2) && (n >= 2)) {
+#ifdef HAVE_ASM_COPY_FROM_USER_DSP_2B
+                               if (__copy_to_user_dsp_2b(to, from))
+#else
+                               if (copy_to_user_dsp_2b(to, from))
+#endif
+                                       return n;
+                               to += 2;
+                               from += 2;
+                               n -= 2;
+                       }
+                       /* middle 4*n bytes */
+                       last_n = n & 2;
+                       n4 = n - last_n;
+                       if ((n = __copy_to_user(to, from, n4)) != 0)
+                               return n + last_n;
+                       /* last 2 bytes */
+                       if (last_n) {
+                               to += n4;
+                               from += n4;
+#ifdef HAVE_ASM_COPY_FROM_USER_DSP_2B
+                               if (__copy_to_user_dsp_2b(to, from))
+#else
+                               if (copy_to_user_dsp_2b(to, from))
+#endif
+                                       return 2;
+                               n = 0;
+                       }
+               } else {
+                       /*
+                        * DARAM/SARAM with 4-byte alignment or
+                        * external memory
+                        */
+                       n = __copy_to_user(to, from, n);
+               }
+       }
+       return n;
+}
+
+#endif /* _OMAP_DSP_UACCESS_DSP_H */
index 56acb8720f789ad7047daef09ba4ec6717e70d5b..a302d9194f572f6f93d5e38c555817fac92e5aeb 100644 (file)
@@ -1,3 +1,26 @@
+/*
+ * File: arch/arm/plat-omap/fb.c
+ *
+ * Framebuffer device registration for TI OMAP platforms
+ *
+ * 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/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -34,25 +57,47 @@ static struct platform_device omap_fb_device = {
 void omapfb_reserve_mem(void)
 {
        const struct omap_fbmem_config *fbmem_conf;
+       unsigned long total_size;
+       int i;
+
+       if (!omap_fb_sram_valid) {
+               /* FBMEM SRAM configuration was already found to be invalid.
+                * Ignore the whole configuration block. */
+               omapfb_config.mem_desc.region_cnt = 0;
+               return;
+       }
 
-       omapfb_config.fbmem.fb_sram_start = omap_fb_sram_start;
-       omapfb_config.fbmem.fb_sram_size = omap_fb_sram_size;
-
-       fbmem_conf = omap_get_config(OMAP_TAG_FBMEM, struct omap_fbmem_config);
-
-       if (fbmem_conf != NULL) {
-               /* indicate that the bootloader already initialized the
-                * fb device, so we'll skip that part in the fb driver
-                */
-               omapfb_config.fbmem.fb_sdram_start = fbmem_conf->fb_sdram_start;
-               omapfb_config.fbmem.fb_sdram_size = fbmem_conf->fb_sdram_size;
-               if (fbmem_conf->fb_sdram_size) {
-                       pr_info("Reserving %u bytes SDRAM for frame buffer\n",
-                               fbmem_conf->fb_sdram_size);
-                       reserve_bootmem(fbmem_conf->fb_sdram_start,
-                                       fbmem_conf->fb_sdram_size);
+       i = 0;
+       total_size = 0;
+       while ((fbmem_conf = omap_get_nr_config(OMAP_TAG_FBMEM,
+                               struct omap_fbmem_config, i)) != NULL) {
+               unsigned long start;
+               unsigned long size;
+
+               if (i == OMAPFB_PLANE_NUM) {
+                       printk(KERN_ERR "ignoring extra plane info\n");
+                       break;
+               }
+               start = fbmem_conf->start;
+               size  = fbmem_conf->size;
+               omapfb_config.mem_desc.region[i].paddr = start;
+               omapfb_config.mem_desc.region[i].size = size;
+               if (omap_fb_sram_plane != i && start) {
+                       reserve_bootmem(start, size);
+                       total_size += size;
                }
+               i++;
        }
+       omapfb_config.mem_desc.region_cnt = i;
+       if (total_size)
+               pr_info("Reserving %lu bytes SDRAM for frame buffer\n",
+                        total_size);
+
+}
+
+void omapfb_set_ctrl_platform_data(void *data)
+{
+       omapfb_config.ctrl_platform_data = data;
 }
 
 static inline int omap_init_fb(void)
diff --git a/arch/arm/plat-omap/gpio-switch.c b/arch/arm/plat-omap/gpio-switch.c
new file mode 100644 (file)
index 0000000..ddc26d6
--- /dev/null
@@ -0,0 +1,549 @@
+/*
+ *  linux/arch/arm/plat-omap/gpio-switch.c
+ *
+ *  Copyright (C) 2004-2006 Nokia Corporation
+ *  Written by Juha Yrjölä <juha.yrjola@nokia.com>
+ *         and Paul Mundt <paul.mundt@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/timer.h>
+#include <linux/err.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/irqs.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/board.h>
+#include <asm/arch/gpio-switch.h>
+
+struct gpio_switch {
+       char            name[14];
+       u16             gpio;
+       unsigned        flags:4;
+       unsigned        type:4;
+       unsigned        state:1;
+       unsigned        both_edges:1;
+
+       u16             debounce_rising;
+       u16             debounce_falling;
+
+       void (* notify)(void *data, int state);
+       void *notify_data;
+
+       struct work_struct      work;
+       struct timer_list       timer;
+       struct platform_device  pdev;
+
+       struct list_head        node;
+};
+
+static LIST_HEAD(gpio_switches);
+static struct platform_device *gpio_sw_platform_dev;
+static struct platform_driver gpio_sw_driver;
+
+static const struct omap_gpio_switch *board_gpio_sw_table;
+static int board_gpio_sw_count;
+
+static const char *cover_str[2] = { "open", "closed" };
+static const char *connection_str[2] = { "disconnected", "connected" };
+static const char *activity_str[2] = { "inactive", "active" };
+
+/*
+ * GPIO switch state default debounce delay in ms
+ */
+#define OMAP_GPIO_SW_DEFAULT_DEBOUNCE          10
+
+static const char **get_sw_str(struct gpio_switch *sw)
+{
+       switch (sw->type) {
+       case OMAP_GPIO_SWITCH_TYPE_COVER:
+               return cover_str;
+       case OMAP_GPIO_SWITCH_TYPE_CONNECTION:
+               return connection_str;
+       case OMAP_GPIO_SWITCH_TYPE_ACTIVITY:
+               return activity_str;
+       default:
+               BUG();
+               return NULL;
+       }
+}
+
+static const char *get_sw_type(struct gpio_switch *sw)
+{
+       switch (sw->type) {
+       case OMAP_GPIO_SWITCH_TYPE_COVER:
+               return "cover";
+       case OMAP_GPIO_SWITCH_TYPE_CONNECTION:
+               return "connection";
+       case OMAP_GPIO_SWITCH_TYPE_ACTIVITY:
+               return "activity";
+       default:
+               BUG();
+               return NULL;
+       }
+}
+
+static void print_sw_state(struct gpio_switch *sw, int state)
+{
+       const char **str;
+
+       str = get_sw_str(sw);
+       if (str != NULL)
+               printk(KERN_INFO "%s (GPIO %d) is now %s\n", sw->name, sw->gpio, str[state]);
+}
+
+static int gpio_sw_get_state(struct gpio_switch *sw)
+{
+       int state;
+
+       state = omap_get_gpio_datain(sw->gpio);
+       if (sw->flags & OMAP_GPIO_SWITCH_FLAG_INVERTED)
+               state = !state;
+
+       return state;
+}
+
+static ssize_t gpio_sw_state_store(struct device *dev,
+                                  struct device_attribute *attr,
+                                  const char *buf,
+                                  size_t count)
+{
+       struct gpio_switch *sw = dev_get_drvdata(dev);
+       const char **str;
+       char state[16];
+       int enable;
+
+       if (!(sw->flags & OMAP_GPIO_SWITCH_FLAG_OUTPUT))
+               return -EPERM;
+
+       if (sscanf(buf, "%15s", state) != 1)
+               return -EINVAL;
+
+       str = get_sw_str(sw);
+       if (strcmp(state, str[0]) == 0)
+               enable = 0;
+       else if (strcmp(state, str[1]) == 0)
+               enable = 1;
+       else
+               return -EINVAL;
+       if (sw->flags & OMAP_GPIO_SWITCH_FLAG_INVERTED)
+               enable = !enable;
+       omap_set_gpio_dataout(sw->gpio, enable);
+
+       return count;
+}
+
+static ssize_t gpio_sw_state_show(struct device *dev,
+                                 struct device_attribute *attr,
+                                 char *buf)
+{
+       struct gpio_switch *sw = dev_get_drvdata(dev);
+       const char **str;
+
+       str = get_sw_str(sw);
+       return sprintf(buf, "%s\n", str[sw->state]);
+}
+
+static DEVICE_ATTR(state, S_IRUGO | S_IWUSR, gpio_sw_state_show,
+                  gpio_sw_state_store);
+
+static ssize_t gpio_sw_type_show(struct device *dev,
+                                struct device_attribute *attr,
+                                char *buf)
+{
+       struct gpio_switch *sw = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%s\n", get_sw_type(sw));
+}
+
+static DEVICE_ATTR(type, S_IRUGO, gpio_sw_type_show, NULL);
+
+static ssize_t gpio_sw_direction_show(struct device *dev,
+                                     struct device_attribute *attr,
+                                     char *buf)
+{
+       struct gpio_switch *sw = dev_get_drvdata(dev);
+       int is_output;
+
+       is_output = sw->flags & OMAP_GPIO_SWITCH_FLAG_OUTPUT;
+       return sprintf(buf, "%s\n", is_output ? "output" : "input");
+}
+
+static DEVICE_ATTR(direction, S_IRUGO, gpio_sw_direction_show, NULL);
+
+
+static irqreturn_t gpio_sw_irq_handler(int irq, void *arg)
+{
+       struct gpio_switch *sw = arg;
+       unsigned long timeout;
+       int state;
+
+       if (!sw->both_edges) {
+               if (omap_get_gpio_datain(sw->gpio))
+                       set_irq_type(OMAP_GPIO_IRQ(sw->gpio), IRQT_FALLING);
+               else
+                       set_irq_type(OMAP_GPIO_IRQ(sw->gpio), IRQT_RISING);
+       }
+
+       state = gpio_sw_get_state(sw);
+       if (sw->state == state)
+               return IRQ_HANDLED;
+
+       if (state)
+               timeout = sw->debounce_rising;
+       else
+               timeout = sw->debounce_falling;
+       if (!timeout)
+               schedule_work(&sw->work);
+       else
+               mod_timer(&sw->timer, jiffies + msecs_to_jiffies(timeout));
+
+       return IRQ_HANDLED;
+}
+
+static void gpio_sw_timer(unsigned long arg)
+{
+       struct gpio_switch *sw = (struct gpio_switch *) arg;
+
+       schedule_work(&sw->work);
+}
+
+static void gpio_sw_handler(struct work_struct *work)
+{
+       struct gpio_switch *sw = container_of(work, struct gpio_switch, work);
+       int state;
+
+       state = gpio_sw_get_state(sw);
+       if (sw->state == state)
+               return;
+
+       sw->state = state;
+       if (sw->notify != NULL)
+               sw->notify(sw->notify_data, state);
+       sysfs_notify(&sw->pdev.dev.kobj, NULL, "state");
+       print_sw_state(sw, state);
+}
+
+static int __init can_do_both_edges(struct gpio_switch *sw)
+{
+       if (!cpu_class_is_omap1())
+               return 1;
+       if (OMAP_GPIO_IS_MPUIO(sw->gpio))
+               return 0;
+       else
+               return 1;
+}
+
+static void gpio_sw_release(struct device *dev)
+{
+}
+
+static int __init new_switch(struct gpio_switch *sw)
+{
+       int r, direction, trigger;
+
+       switch (sw->type) {
+       case OMAP_GPIO_SWITCH_TYPE_COVER:
+       case OMAP_GPIO_SWITCH_TYPE_CONNECTION:
+       case OMAP_GPIO_SWITCH_TYPE_ACTIVITY:
+               break;
+       default:
+               printk(KERN_ERR "invalid GPIO switch type: %d\n", sw->type);
+               return -EINVAL;
+       }
+
+       sw->pdev.name   = sw->name;
+       sw->pdev.id     = -1;
+
+       sw->pdev.dev.parent = &gpio_sw_platform_dev->dev;
+       sw->pdev.dev.driver = &gpio_sw_driver.driver;
+       sw->pdev.dev.release = gpio_sw_release;
+
+       r = platform_device_register(&sw->pdev);
+       if (r) {
+               printk(KERN_ERR "gpio-switch: platform device registration "
+                      "failed for %s", sw->name);
+               return r;
+       }
+       dev_set_drvdata(&sw->pdev.dev, sw);
+
+       r = omap_request_gpio(sw->gpio);
+       if (r < 0) {
+               platform_device_unregister(&sw->pdev);
+               return r;
+       }
+
+       /* input: 1, output: 0 */
+       direction = !(sw->flags & OMAP_GPIO_SWITCH_FLAG_OUTPUT);
+       omap_set_gpio_direction(sw->gpio, direction);
+
+       sw->state = gpio_sw_get_state(sw);
+
+       r = 0;
+       r |= device_create_file(&sw->pdev.dev, &dev_attr_state);
+       r |= device_create_file(&sw->pdev.dev, &dev_attr_type);
+       r |= device_create_file(&sw->pdev.dev, &dev_attr_direction);
+       if (r)
+               printk(KERN_ERR "gpio-switch: attribute file creation "
+                      "failed for %s\n", sw->name);
+
+       if (!direction)
+               return 0;
+
+       if (can_do_both_edges(sw)) {
+               trigger = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING;
+               sw->both_edges = 1;
+       } else {
+               if (omap_get_gpio_datain(sw->gpio))
+                       trigger = IRQF_TRIGGER_FALLING;
+               else
+                       trigger = IRQF_TRIGGER_RISING;
+       }
+       r = request_irq(OMAP_GPIO_IRQ(sw->gpio), gpio_sw_irq_handler,
+                       IRQF_SHIRQ | trigger, sw->name, sw);
+       if (r < 0) {
+               printk(KERN_ERR "gpio-switch: request_irq() failed "
+                      "for GPIO %d\n", sw->gpio);
+               platform_device_unregister(&sw->pdev);
+               omap_free_gpio(sw->gpio);
+               return r;
+       }
+
+       INIT_WORK(&sw->work, gpio_sw_handler);
+       init_timer(&sw->timer);
+
+       sw->timer.function = gpio_sw_timer;
+       sw->timer.data = (unsigned long)sw;
+
+       list_add(&sw->node, &gpio_switches);
+
+       return 0;
+}
+
+static int __init add_atag_switches(void)
+{
+       const struct omap_gpio_switch_config *cfg;
+       struct gpio_switch *sw;
+       int i, r;
+
+       for (i = 0; ; i++) {
+               cfg = omap_get_nr_config(OMAP_TAG_GPIO_SWITCH,
+                                        struct omap_gpio_switch_config, i);
+               if (cfg == NULL)
+                       break;
+               sw = kzalloc(sizeof(*sw), GFP_KERNEL);
+               if (sw == NULL) {
+                       printk(KERN_ERR "gpio-switch: kmalloc failed\n");
+                       return -ENOMEM;
+               }
+               strncpy(sw->name, cfg->name, sizeof(cfg->name));
+               sw->gpio = cfg->gpio;
+               sw->flags = cfg->flags;
+               sw->type = cfg->type;
+               sw->debounce_rising = OMAP_GPIO_SW_DEFAULT_DEBOUNCE;
+               sw->debounce_falling = OMAP_GPIO_SW_DEFAULT_DEBOUNCE;
+               if ((r = new_switch(sw)) < 0) {
+                       kfree(sw);
+                       return r;
+               }
+       }
+       return 0;
+}
+
+static struct gpio_switch * __init find_switch(int gpio, const char *name)
+{
+       struct gpio_switch *sw;
+
+       list_for_each_entry(sw, &gpio_switches, node) {
+               if ((gpio < 0 || sw->gpio != gpio) &&
+                   (name == NULL || strcmp(sw->name, name) != 0))
+                       continue;
+
+               if (gpio < 0 || name == NULL)
+                       goto no_check;
+
+               if (strcmp(sw->name, name) != 0)
+                       printk("gpio-switch: name mismatch for %d (%s, %s)\n",
+                              gpio, name, sw->name);
+               else if (sw->gpio != gpio)
+                       printk("gpio-switch: GPIO mismatch for %s (%d, %d)\n",
+                              name, gpio, sw->gpio);
+no_check:
+               return sw;
+       }
+       return NULL;
+}
+
+static int __init add_board_switches(void)
+{
+       int i;
+
+       for (i = 0; i < board_gpio_sw_count; i++) {
+               const struct omap_gpio_switch *cfg;
+               struct gpio_switch *sw;
+               int r;
+
+               cfg = board_gpio_sw_table + i;
+               if (strlen(cfg->name) > sizeof(sw->name) - 1)
+                       return -EINVAL;
+               /* Check whether we only update an existing switch
+                * or add a new switch. */
+               sw = find_switch(cfg->gpio, cfg->name);
+               if (sw != NULL) {
+                       sw->debounce_rising = cfg->debounce_rising;
+                       sw->debounce_falling = cfg->debounce_falling;
+                       sw->notify = cfg->notify;
+                       sw->notify_data = cfg->notify_data;
+                       continue;
+               } else {
+                       if (cfg->gpio < 0 || cfg->name == NULL) {
+                               printk("gpio-switch: required switch not "
+                                      "found (%d, %s)\n", cfg->gpio,
+                                      cfg->name);
+                               continue;
+                       }
+               }
+               sw = kzalloc(sizeof(*sw), GFP_KERNEL);
+               if (sw == NULL) {
+                       printk(KERN_ERR "gpio-switch: kmalloc failed\n");
+                       return -ENOMEM;
+               }
+               strlcpy(sw->name, cfg->name, sizeof(sw->name));
+               sw->gpio = cfg->gpio;
+               sw->flags = cfg->flags;
+               sw->type = cfg->type;
+               sw->debounce_rising = cfg->debounce_rising;
+               sw->debounce_falling = cfg->debounce_falling;
+               sw->notify = cfg->notify;
+               sw->notify_data = cfg->notify_data;
+               if ((r = new_switch(sw)) < 0) {
+                       kfree(sw);
+                       return r;
+               }
+       }
+       return 0;
+}
+
+static void gpio_sw_cleanup(void)
+{
+       struct gpio_switch *sw = NULL, *old = NULL;
+
+       list_for_each_entry(sw, &gpio_switches, node) {
+               if (old != NULL)
+                       kfree(old);
+               flush_scheduled_work();
+               del_timer_sync(&sw->timer);
+
+               free_irq(OMAP_GPIO_IRQ(sw->gpio), sw);
+
+               device_remove_file(&sw->pdev.dev, &dev_attr_state);
+               device_remove_file(&sw->pdev.dev, &dev_attr_type);
+               device_remove_file(&sw->pdev.dev, &dev_attr_direction);
+
+               platform_device_unregister(&sw->pdev);
+               omap_free_gpio(sw->gpio);
+               old = sw;
+       }
+       kfree(old);
+}
+
+static void __init report_initial_state(void)
+{
+       struct gpio_switch *sw;
+
+       list_for_each_entry(sw, &gpio_switches, node) {
+               int state;
+
+               state = omap_get_gpio_datain(sw->gpio);
+               if (sw->flags & OMAP_GPIO_SWITCH_FLAG_INVERTED)
+                       state = !state;
+               if (sw->notify != NULL)
+                       sw->notify(sw->notify_data, state);
+               print_sw_state(sw, state);
+       }
+}
+
+static int gpio_sw_remove(struct platform_device *dev)
+{
+       return 0;
+}
+
+static struct platform_driver gpio_sw_driver = {
+       .remove         = gpio_sw_remove,
+       .driver         = {
+               .name   = "gpio-switch",
+       },
+};
+
+void __init omap_register_gpio_switches(const struct omap_gpio_switch *tbl,
+                                       int count)
+{
+       BUG_ON(board_gpio_sw_table != NULL);
+
+       board_gpio_sw_table = tbl;
+       board_gpio_sw_count = count;
+}
+
+static int __init gpio_sw_init(void)
+{
+       int r;
+
+       printk(KERN_INFO "OMAP GPIO switch handler initializing\n");
+
+       r = platform_driver_register(&gpio_sw_driver);
+       if (r)
+               return r;
+
+       gpio_sw_platform_dev = platform_device_register_simple("gpio-switch",
+                                                              -1, NULL, 0);
+       if (IS_ERR(gpio_sw_platform_dev)) {
+               r = PTR_ERR(gpio_sw_platform_dev);
+               goto err1;
+       }
+
+       r = add_atag_switches();
+       if (r < 0)
+               goto err2;
+
+       r = add_board_switches();
+       if (r < 0)
+               goto err2;
+
+       report_initial_state();
+
+       return 0;
+err2:
+       gpio_sw_cleanup();
+       platform_device_unregister(gpio_sw_platform_dev);
+err1:
+       platform_driver_unregister(&gpio_sw_driver);
+       return r;
+}
+
+static void __exit gpio_sw_exit(void)
+{
+       gpio_sw_cleanup();
+       platform_device_unregister(gpio_sw_platform_dev);
+       platform_driver_unregister(&gpio_sw_driver);
+}
+
+#ifndef MODULE
+late_initcall(gpio_sw_init);
+#else
+module_init(gpio_sw_init);
+#endif
+module_exit(gpio_sw_exit);
+
+MODULE_AUTHOR("Juha Yrjölä <juha.yrjola@nokia.com>, Paul Mundt <paul.mundt@nokia.com");
+MODULE_DESCRIPTION("GPIO switch driver");
+MODULE_LICENSE("GPL");
index 4f2fd55913379a10b080412408f9d8e2a2b132c4..8c37571d1cc20c68843d6f08614c69adc06b8185 100644 (file)
@@ -13,7 +13,6 @@
 
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/ptrace.h>
 #include <linux/sysdev.h>
@@ -22,6 +21,7 @@
 
 #include <asm/hardware.h>
 #include <asm/irq.h>
+#include <asm/delay.h>
 #include <asm/arch/irqs.h>
 #include <asm/arch/gpio.h>
 #include <asm/mach/irq.h>
 /*
  * omap24xx specific GPIO registers
  */
-#define OMAP24XX_GPIO1_BASE            (void __iomem *)0x48018000
-#define OMAP24XX_GPIO2_BASE            (void __iomem *)0x4801a000
-#define OMAP24XX_GPIO3_BASE            (void __iomem *)0x4801c000
-#define OMAP24XX_GPIO4_BASE            (void __iomem *)0x4801e000
+#define OMAP242X_GPIO1_BASE            (void __iomem *)0x48018000
+#define OMAP242X_GPIO2_BASE            (void __iomem *)0x4801a000
+#define OMAP242X_GPIO3_BASE            (void __iomem *)0x4801c000
+#define OMAP242X_GPIO4_BASE            (void __iomem *)0x4801e000
+
+#define OMAP243X_GPIO1_BASE            (void __iomem *)0x4900C000
+#define OMAP243X_GPIO2_BASE            (void __iomem *)0x4900E000
+#define OMAP243X_GPIO3_BASE            (void __iomem *)0x49010000
+#define OMAP243X_GPIO4_BASE            (void __iomem *)0x49012000
+#define OMAP243X_GPIO5_BASE            (void __iomem *)0x480B6000
+
 #define OMAP24XX_GPIO_REVISION         0x0000
 #define OMAP24XX_GPIO_SYSCONFIG                0x0010
 #define OMAP24XX_GPIO_SYSSTATUS                0x0014
@@ -118,8 +125,18 @@ struct gpio_bank {
        u16 virtual_irq_start;
        int method;
        u32 reserved_map;
+#if defined (CONFIG_ARCH_OMAP16XX) || defined (CONFIG_ARCH_OMAP24XX)
        u32 suspend_wakeup;
        u32 saved_wakeup;
+#endif
+#ifdef CONFIG_ARCH_OMAP24XX
+       u32 non_wakeup_gpios;
+       u32 enabled_non_wakeup_gpios;
+
+       u32 saved_datain;
+       u32 saved_fallingdetect;
+       u32 saved_risingdetect;
+#endif
        spinlock_t lock;
 };
 
@@ -159,12 +176,22 @@ static struct gpio_bank gpio_bank_730[7] = {
 #endif
 
 #ifdef CONFIG_ARCH_OMAP24XX
-static struct gpio_bank gpio_bank_24xx[4] = {
-       { OMAP24XX_GPIO1_BASE, INT_24XX_GPIO_BANK1, IH_GPIO_BASE,       METHOD_GPIO_24XX },
-       { OMAP24XX_GPIO2_BASE, INT_24XX_GPIO_BANK2, IH_GPIO_BASE + 32,  METHOD_GPIO_24XX },
-       { OMAP24XX_GPIO3_BASE, INT_24XX_GPIO_BANK3, IH_GPIO_BASE + 64,  METHOD_GPIO_24XX },
-       { OMAP24XX_GPIO4_BASE, INT_24XX_GPIO_BANK4, IH_GPIO_BASE + 96,  METHOD_GPIO_24XX },
+
+static struct gpio_bank gpio_bank_242x[4] = {
+       { OMAP242X_GPIO1_BASE, INT_24XX_GPIO_BANK1, IH_GPIO_BASE,       METHOD_GPIO_24XX },
+       { OMAP242X_GPIO2_BASE, INT_24XX_GPIO_BANK2, IH_GPIO_BASE + 32,  METHOD_GPIO_24XX },
+       { OMAP242X_GPIO3_BASE, INT_24XX_GPIO_BANK3, IH_GPIO_BASE + 64,  METHOD_GPIO_24XX },
+       { OMAP242X_GPIO4_BASE, INT_24XX_GPIO_BANK4, IH_GPIO_BASE + 96,  METHOD_GPIO_24XX },
+};
+
+static struct gpio_bank gpio_bank_243x[5] = {
+       { OMAP243X_GPIO1_BASE, INT_24XX_GPIO_BANK1, IH_GPIO_BASE,       METHOD_GPIO_24XX },
+       { OMAP243X_GPIO2_BASE, INT_24XX_GPIO_BANK2, IH_GPIO_BASE + 32,  METHOD_GPIO_24XX },
+       { OMAP243X_GPIO3_BASE, INT_24XX_GPIO_BANK3, IH_GPIO_BASE + 64,  METHOD_GPIO_24XX },
+       { OMAP243X_GPIO4_BASE, INT_24XX_GPIO_BANK4, IH_GPIO_BASE + 96,  METHOD_GPIO_24XX },
+       { OMAP243X_GPIO5_BASE, INT_24XX_GPIO_BANK5, IH_GPIO_BASE + 128, METHOD_GPIO_24XX },
 };
+
 #endif
 
 static struct gpio_bank *gpio_bank;
@@ -258,21 +285,34 @@ static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input)
        u32 l;
 
        switch (bank->method) {
+#ifdef CONFIG_ARCH_OMAP1
        case METHOD_MPUIO:
                reg += OMAP_MPUIO_IO_CNTL;
                break;
+#endif
+#ifdef CONFIG_ARCH_OMAP15XX
        case METHOD_GPIO_1510:
                reg += OMAP1510_GPIO_DIR_CONTROL;
                break;
+#endif
+#ifdef CONFIG_ARCH_OMAP16XX
        case METHOD_GPIO_1610:
                reg += OMAP1610_GPIO_DIRECTION;
                break;
+#endif
+#ifdef CONFIG_ARCH_OMAP730
        case METHOD_GPIO_730:
                reg += OMAP730_GPIO_DIR_CONTROL;
                break;
+#endif
+#ifdef CONFIG_ARCH_OMAP24XX
        case METHOD_GPIO_24XX:
                reg += OMAP24XX_GPIO_OE;
                break;
+#endif
+       default:
+               WARN_ON(1);
+               return;
        }
        l = __raw_readl(reg);
        if (is_input)
@@ -300,6 +340,7 @@ static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable)
        u32 l = 0;
 
        switch (bank->method) {
+#ifdef CONFIG_ARCH_OMAP1
        case METHOD_MPUIO:
                reg += OMAP_MPUIO_OUTPUT;
                l = __raw_readl(reg);
@@ -308,6 +349,8 @@ static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable)
                else
                        l &= ~(1 << gpio);
                break;
+#endif
+#ifdef CONFIG_ARCH_OMAP15XX
        case METHOD_GPIO_1510:
                reg += OMAP1510_GPIO_DATA_OUTPUT;
                l = __raw_readl(reg);
@@ -316,6 +359,8 @@ static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable)
                else
                        l &= ~(1 << gpio);
                break;
+#endif
+#ifdef CONFIG_ARCH_OMAP16XX
        case METHOD_GPIO_1610:
                if (enable)
                        reg += OMAP1610_GPIO_SET_DATAOUT;
@@ -323,6 +368,8 @@ static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable)
                        reg += OMAP1610_GPIO_CLEAR_DATAOUT;
                l = 1 << gpio;
                break;
+#endif
+#ifdef CONFIG_ARCH_OMAP730
        case METHOD_GPIO_730:
                reg += OMAP730_GPIO_DATA_OUTPUT;
                l = __raw_readl(reg);
@@ -331,6 +378,8 @@ static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable)
                else
                        l &= ~(1 << gpio);
                break;
+#endif
+#ifdef CONFIG_ARCH_OMAP24XX
        case METHOD_GPIO_24XX:
                if (enable)
                        reg += OMAP24XX_GPIO_SETDATAOUT;
@@ -338,8 +387,9 @@ static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable)
                        reg += OMAP24XX_GPIO_CLEARDATAOUT;
                l = 1 << gpio;
                break;
+#endif
        default:
-               BUG();
+               WARN_ON(1);
                return;
        }
        __raw_writel(l, reg);
@@ -363,28 +413,37 @@ int omap_get_gpio_datain(int gpio)
        void __iomem *reg;
 
        if (check_gpio(gpio) < 0)
-               return -1;
+               return -EINVAL;
        bank = get_gpio_bank(gpio);
        reg = bank->base;
        switch (bank->method) {
+#ifdef CONFIG_ARCH_OMAP1
        case METHOD_MPUIO:
                reg += OMAP_MPUIO_INPUT_LATCH;
                break;
+#endif
+#ifdef CONFIG_ARCH_OMAP15XX
        case METHOD_GPIO_1510:
                reg += OMAP1510_GPIO_DATA_INPUT;
                break;
+#endif
+#ifdef CONFIG_ARCH_OMAP16XX
        case METHOD_GPIO_1610:
                reg += OMAP1610_GPIO_DATAIN;
                break;
+#endif
+#ifdef CONFIG_ARCH_OMAP730
        case METHOD_GPIO_730:
                reg += OMAP730_GPIO_DATA_INPUT;
                break;
+#endif
+#ifdef CONFIG_ARCH_OMAP24XX
        case METHOD_GPIO_24XX:
                reg += OMAP24XX_GPIO_DATAIN;
                break;
+#endif
        default:
-               BUG();
-               return -1;
+               return -EINVAL;
        }
        return (__raw_readl(reg)
                        & (1 << get_gpio_index(gpio))) != 0;
@@ -398,8 +457,10 @@ do {       \
        __raw_writel(l, base + reg); \
 } while(0)
 
-static inline void set_24xx_gpio_triggering(void __iomem *base, int gpio, int trigger)
+#ifdef CONFIG_ARCH_OMAP24XX
+static inline void set_24xx_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
 {
+       void __iomem *base = bank->base;
        u32 gpio_bit = 1 << gpio;
 
        MOD_REG_BIT(OMAP24XX_GPIO_LEVELDETECT0, gpio_bit,
@@ -410,9 +471,21 @@ static inline void set_24xx_gpio_triggering(void __iomem *base, int gpio, int tr
                trigger & __IRQT_RISEDGE);
        MOD_REG_BIT(OMAP24XX_GPIO_FALLINGDETECT, gpio_bit,
                trigger & __IRQT_FALEDGE);
+       if (likely(!(bank->non_wakeup_gpios & gpio_bit))) {
+               if (trigger != 0)
+                       __raw_writel(1 << gpio, bank->base + OMAP24XX_GPIO_SETWKUENA);
+               else
+                       __raw_writel(1 << gpio, bank->base + OMAP24XX_GPIO_CLEARWKUENA);
+       } else {
+               if (trigger != 0)
+                       bank->enabled_non_wakeup_gpios |= gpio_bit;
+               else
+                       bank->enabled_non_wakeup_gpios &= ~gpio_bit;
+       }
        /* FIXME: Possibly do 'set_irq_handler(j, handle_level_irq)' if only level
         * triggering requested. */
 }
+#endif
 
 static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
 {
@@ -420,6 +493,7 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
        u32 l = 0;
 
        switch (bank->method) {
+#ifdef CONFIG_ARCH_OMAP1
        case METHOD_MPUIO:
                reg += OMAP_MPUIO_GPIO_INT_EDGE;
                l = __raw_readl(reg);
@@ -430,6 +504,8 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
                else
                        goto bad;
                break;
+#endif
+#ifdef CONFIG_ARCH_OMAP15XX
        case METHOD_GPIO_1510:
                reg += OMAP1510_GPIO_INT_CONTROL;
                l = __raw_readl(reg);
@@ -440,22 +516,28 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
                else
                        goto bad;
                break;
+#endif
+#ifdef CONFIG_ARCH_OMAP16XX
        case METHOD_GPIO_1610:
                if (gpio & 0x08)
                        reg += OMAP1610_GPIO_EDGE_CTRL2;
                else
                        reg += OMAP1610_GPIO_EDGE_CTRL1;
                gpio &= 0x07;
-               /* We allow only edge triggering, i.e. two lowest bits */
-               if (trigger & (__IRQT_LOWLVL | __IRQT_HIGHLVL))
-                       BUG();
                l = __raw_readl(reg);
                l &= ~(3 << (gpio << 1));
                if (trigger & __IRQT_RISEDGE)
                        l |= 2 << (gpio << 1);
                if (trigger & __IRQT_FALEDGE)
                        l |= 1 << (gpio << 1);
+               if (trigger)
+                       /* Enable wake-up during idle for dynamic tick */
+                       __raw_writel(1 << gpio, bank->base + OMAP1610_GPIO_SET_WAKEUPENA);
+               else
+                       __raw_writel(1 << gpio, bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA);
                break;
+#endif
+#ifdef CONFIG_ARCH_OMAP730
        case METHOD_GPIO_730:
                reg += OMAP730_GPIO_INT_CONTROL;
                l = __raw_readl(reg);
@@ -466,11 +548,13 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
                else
                        goto bad;
                break;
+#endif
+#ifdef CONFIG_ARCH_OMAP24XX
        case METHOD_GPIO_24XX:
-               set_24xx_gpio_triggering(reg, gpio, trigger);
+               set_24xx_gpio_triggering(bank, gpio, trigger);
                break;
+#endif
        default:
-               BUG();
                goto bad;
        }
        __raw_writel(l, reg);
@@ -485,7 +569,7 @@ static int gpio_irq_type(unsigned irq, unsigned type)
        unsigned gpio;
        int retval;
 
-       if (irq > IH_MPUIO_BASE)
+       if (!cpu_is_omap24xx() && irq > IH_MPUIO_BASE)
                gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE);
        else
                gpio = irq - IH_GPIO_BASE;
@@ -493,14 +577,21 @@ static int gpio_irq_type(unsigned irq, unsigned type)
        if (check_gpio(gpio) < 0)
                return -EINVAL;
 
-       if (type & IRQT_PROBE)
+       if (type & ~IRQ_TYPE_SENSE_MASK)
                return -EINVAL;
-       if (!cpu_is_omap24xx() && (type & (__IRQT_LOWLVL|__IRQT_HIGHLVL)))
+
+       /* OMAP1 allows only only edge triggering */
+       if (!cpu_is_omap24xx()
+                       && (type & (IRQ_TYPE_LEVEL_LOW|IRQ_TYPE_LEVEL_HIGH)))
                return -EINVAL;
 
-       bank = get_gpio_bank(gpio);
+       bank = get_irq_chip_data(irq);
        spin_lock(&bank->lock);
        retval = _set_gpio_triggering(bank, get_gpio_index(gpio), type);
+       if (retval == 0) {
+               irq_desc[irq].status &= ~IRQ_TYPE_SENSE_MASK;
+               irq_desc[irq].status |= type;
+       }
        spin_unlock(&bank->lock);
        return retval;
 }
@@ -510,24 +601,34 @@ static void _clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
        void __iomem *reg = bank->base;
 
        switch (bank->method) {
+#ifdef CONFIG_ARCH_OMAP1
        case METHOD_MPUIO:
                /* MPUIO irqstatus is reset by reading the status register,
                 * so do nothing here */
                return;
+#endif
+#ifdef CONFIG_ARCH_OMAP15XX
        case METHOD_GPIO_1510:
                reg += OMAP1510_GPIO_INT_STATUS;
                break;
+#endif
+#ifdef CONFIG_ARCH_OMAP16XX
        case METHOD_GPIO_1610:
                reg += OMAP1610_GPIO_IRQSTATUS1;
                break;
+#endif
+#ifdef CONFIG_ARCH_OMAP730
        case METHOD_GPIO_730:
                reg += OMAP730_GPIO_INT_STATUS;
                break;
+#endif
+#ifdef CONFIG_ARCH_OMAP24XX
        case METHOD_GPIO_24XX:
                reg += OMAP24XX_GPIO_IRQSTATUS1;
                break;
+#endif
        default:
-               BUG();
+               WARN_ON(1);
                return;
        }
        __raw_writel(gpio_mask, reg);
@@ -550,31 +651,41 @@ static u32 _get_gpio_irqbank_mask(struct gpio_bank *bank)
        u32 mask;
 
        switch (bank->method) {
+#ifdef CONFIG_ARCH_OMAP1
        case METHOD_MPUIO:
                reg += OMAP_MPUIO_GPIO_MASKIT;
                mask = 0xffff;
                inv = 1;
                break;
+#endif
+#ifdef CONFIG_ARCH_OMAP15XX
        case METHOD_GPIO_1510:
                reg += OMAP1510_GPIO_INT_MASK;
                mask = 0xffff;
                inv = 1;
                break;
+#endif
+#ifdef CONFIG_ARCH_OMAP16XX
        case METHOD_GPIO_1610:
                reg += OMAP1610_GPIO_IRQENABLE1;
                mask = 0xffff;
                break;
+#endif
+#ifdef CONFIG_ARCH_OMAP730
        case METHOD_GPIO_730:
                reg += OMAP730_GPIO_INT_MASK;
                mask = 0xffffffff;
                inv = 1;
                break;
+#endif
+#ifdef CONFIG_ARCH_OMAP24XX
        case METHOD_GPIO_24XX:
                reg += OMAP24XX_GPIO_IRQENABLE1;
                mask = 0xffffffff;
                break;
+#endif
        default:
-               BUG();
+               WARN_ON(1);
                return 0;
        }
 
@@ -591,6 +702,7 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enab
        u32 l;
 
        switch (bank->method) {
+#ifdef CONFIG_ARCH_OMAP1
        case METHOD_MPUIO:
                reg += OMAP_MPUIO_GPIO_MASKIT;
                l = __raw_readl(reg);
@@ -599,6 +711,8 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enab
                else
                        l |= gpio_mask;
                break;
+#endif
+#ifdef CONFIG_ARCH_OMAP15XX
        case METHOD_GPIO_1510:
                reg += OMAP1510_GPIO_INT_MASK;
                l = __raw_readl(reg);
@@ -607,6 +721,8 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enab
                else
                        l |= gpio_mask;
                break;
+#endif
+#ifdef CONFIG_ARCH_OMAP16XX
        case METHOD_GPIO_1610:
                if (enable)
                        reg += OMAP1610_GPIO_SET_IRQENABLE1;
@@ -614,6 +730,8 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enab
                        reg += OMAP1610_GPIO_CLEAR_IRQENABLE1;
                l = gpio_mask;
                break;
+#endif
+#ifdef CONFIG_ARCH_OMAP730
        case METHOD_GPIO_730:
                reg += OMAP730_GPIO_INT_MASK;
                l = __raw_readl(reg);
@@ -622,6 +740,8 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enab
                else
                        l |= gpio_mask;
                break;
+#endif
+#ifdef CONFIG_ARCH_OMAP24XX
        case METHOD_GPIO_24XX:
                if (enable)
                        reg += OMAP24XX_GPIO_SETIRQENABLE1;
@@ -629,8 +749,9 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enab
                        reg += OMAP24XX_GPIO_CLEARIRQENABLE1;
                l = gpio_mask;
                break;
+#endif
        default:
-               BUG();
+               WARN_ON(1);
                return;
        }
        __raw_writel(l, reg);
@@ -652,15 +773,39 @@ static inline void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int ena
 static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable)
 {
        switch (bank->method) {
+#ifdef CONFIG_ARCH_OMAP16XX
+       case METHOD_MPUIO:
        case METHOD_GPIO_1610:
+               spin_lock(&bank->lock);
+               if (enable) {
+                       bank->suspend_wakeup |= (1 << gpio);
+                       enable_irq_wake(bank->irq);
+               } else {
+                       disable_irq_wake(bank->irq);
+                       bank->suspend_wakeup &= ~(1 << gpio);
+               }
+               spin_unlock(&bank->lock);
+               return 0;
+#endif
+#ifdef CONFIG_ARCH_OMAP24XX
        case METHOD_GPIO_24XX:
+               if (bank->non_wakeup_gpios & (1 << gpio)) {
+                       printk(KERN_ERR "Unable to modify wakeup on "
+                                       "non-wakeup GPIO%d\n",
+                                       (bank - gpio_bank) * 32 + gpio);
+                       return -EINVAL;
+               }
                spin_lock(&bank->lock);
-               if (enable)
+               if (enable) {
                        bank->suspend_wakeup |= (1 << gpio);
-               else
+                       enable_irq_wake(bank->irq);
+               } else {
+                       disable_irq_wake(bank->irq);
                        bank->suspend_wakeup &= ~(1 << gpio);
+               }
                spin_unlock(&bank->lock);
                return 0;
+#endif
        default:
                printk(KERN_ERR "Can't enable GPIO wakeup for method %i\n",
                       bank->method);
@@ -685,7 +830,7 @@ static int gpio_wake_enable(unsigned int irq, unsigned int enable)
 
        if (check_gpio(gpio) < 0)
                return -ENODEV;
-       bank = get_gpio_bank(gpio);
+       bank = get_irq_chip_data(irq);
        retval = _set_gpio_wakeup(bank, get_gpio_index(gpio), enable);
 
        return retval;
@@ -721,20 +866,6 @@ int omap_request_gpio(int gpio)
                reg = bank->base + OMAP1510_GPIO_PIN_CONTROL;
                __raw_writel(__raw_readl(reg) | (1 << get_gpio_index(gpio)), reg);
        }
-#endif
-#ifdef CONFIG_ARCH_OMAP16XX
-       if (bank->method == METHOD_GPIO_1610) {
-               /* Enable wake-up during idle for dynamic tick */
-               void __iomem *reg = bank->base + OMAP1610_GPIO_SET_WAKEUPENA;
-               __raw_writel(1 << get_gpio_index(gpio), reg);
-       }
-#endif
-#ifdef CONFIG_ARCH_OMAP24XX
-       if (bank->method == METHOD_GPIO_24XX) {
-               /* Enable wake-up during idle for dynamic tick */
-               void __iomem *reg = bank->base + OMAP24XX_GPIO_SETWKUENA;
-               __raw_writel(1 << get_gpio_index(gpio), reg);
-       }
 #endif
        spin_unlock(&bank->lock);
 
@@ -795,8 +926,10 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
        desc->chip->ack(irq);
 
        bank = get_irq_data(irq);
+#ifdef CONFIG_ARCH_OMAP1
        if (bank->method == METHOD_MPUIO)
                isr_reg = bank->base + OMAP_MPUIO_GPIO_INT;
+#endif
 #ifdef CONFIG_ARCH_OMAP15XX
        if (bank->method == METHOD_GPIO_1510)
                isr_reg = bank->base + OMAP1510_GPIO_INT_STATUS;
@@ -912,7 +1045,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
 static void gpio_irq_shutdown(unsigned int irq)
 {
        unsigned int gpio = irq - IH_GPIO_BASE;
-       struct gpio_bank *bank = get_gpio_bank(gpio);
+       struct gpio_bank *bank = get_irq_chip_data(irq);
 
        _reset_gpio(bank, gpio);
 }
@@ -920,7 +1053,7 @@ static void gpio_irq_shutdown(unsigned int irq)
 static void gpio_ack_irq(unsigned int irq)
 {
        unsigned int gpio = irq - IH_GPIO_BASE;
-       struct gpio_bank *bank = get_gpio_bank(gpio);
+       struct gpio_bank *bank = get_irq_chip_data(irq);
 
        _clear_gpio_irqstatus(bank, gpio);
 }
@@ -928,7 +1061,7 @@ static void gpio_ack_irq(unsigned int irq)
 static void gpio_mask_irq(unsigned int irq)
 {
        unsigned int gpio = irq - IH_GPIO_BASE;
-       struct gpio_bank *bank = get_gpio_bank(gpio);
+       struct gpio_bank *bank = get_irq_chip_data(irq);
 
        _set_gpio_irqenable(bank, gpio, 0);
 }
@@ -937,11 +1070,27 @@ static void gpio_unmask_irq(unsigned int irq)
 {
        unsigned int gpio = irq - IH_GPIO_BASE;
        unsigned int gpio_idx = get_gpio_index(gpio);
-       struct gpio_bank *bank = get_gpio_bank(gpio);
+       struct gpio_bank *bank = get_irq_chip_data(irq);
 
        _set_gpio_irqenable(bank, gpio_idx, 1);
 }
 
+static struct irq_chip gpio_irq_chip = {
+       .name           = "GPIO",
+       .shutdown       = gpio_irq_shutdown,
+       .ack            = gpio_ack_irq,
+       .mask           = gpio_mask_irq,
+       .unmask         = gpio_unmask_irq,
+       .set_type       = gpio_irq_type,
+       .set_wake       = gpio_wake_enable,
+};
+
+/*---------------------------------------------------------------------*/
+
+#ifdef CONFIG_ARCH_OMAP1
+
+/* MPUIO uses the always-on 32k clock */
+
 static void mpuio_ack_irq(unsigned int irq)
 {
        /* The ISR is reset automatically, so do nothing here. */
@@ -950,7 +1099,7 @@ static void mpuio_ack_irq(unsigned int irq)
 static void mpuio_mask_irq(unsigned int irq)
 {
        unsigned int gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE);
-       struct gpio_bank *bank = get_gpio_bank(gpio);
+       struct gpio_bank *bank = get_irq_chip_data(irq);
 
        _set_gpio_irqenable(bank, gpio, 0);
 }
@@ -958,32 +1107,106 @@ static void mpuio_mask_irq(unsigned int irq)
 static void mpuio_unmask_irq(unsigned int irq)
 {
        unsigned int gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE);
-       struct gpio_bank *bank = get_gpio_bank(gpio);
+       struct gpio_bank *bank = get_irq_chip_data(irq);
 
        _set_gpio_irqenable(bank, gpio, 1);
 }
 
-static struct irq_chip gpio_irq_chip = {
-       .name           = "GPIO",
-       .shutdown       = gpio_irq_shutdown,
-       .ack            = gpio_ack_irq,
-       .mask           = gpio_mask_irq,
-       .unmask         = gpio_unmask_irq,
+static struct irq_chip mpuio_irq_chip = {
+       .name           = "MPUIO",
+       .ack            = mpuio_ack_irq,
+       .mask           = mpuio_mask_irq,
+       .unmask         = mpuio_unmask_irq,
        .set_type       = gpio_irq_type,
+#ifdef CONFIG_ARCH_OMAP16XX
+       /* REVISIT: assuming only 16xx supports MPUIO wake events */
        .set_wake       = gpio_wake_enable,
+#endif
 };
 
-static struct irq_chip mpuio_irq_chip = {
-       .name   = "MPUIO",
-       .ack    = mpuio_ack_irq,
-       .mask   = mpuio_mask_irq,
-       .unmask = mpuio_unmask_irq
+
+#define bank_is_mpuio(bank)    ((bank)->method == METHOD_MPUIO)
+
+
+#ifdef CONFIG_ARCH_OMAP16XX
+
+#include <linux/platform_device.h>
+
+static int omap_mpuio_suspend_late(struct platform_device *pdev, pm_message_t mesg)
+{
+       struct gpio_bank        *bank = platform_get_drvdata(pdev);
+       void __iomem            *mask_reg = bank->base + OMAP_MPUIO_GPIO_MASKIT;
+
+       spin_lock(&bank->lock);
+       bank->saved_wakeup = __raw_readl(mask_reg);
+       __raw_writel(0xffff & ~bank->suspend_wakeup, mask_reg);
+       spin_unlock(&bank->lock);
+
+       return 0;
+}
+
+static int omap_mpuio_resume_early(struct platform_device *pdev)
+{
+       struct gpio_bank        *bank = platform_get_drvdata(pdev);
+       void __iomem            *mask_reg = bank->base + OMAP_MPUIO_GPIO_MASKIT;
+
+       spin_lock(&bank->lock);
+       __raw_writel(bank->saved_wakeup, mask_reg);
+       spin_unlock(&bank->lock);
+
+       return 0;
+}
+
+/* use platform_driver for this, now that there's no longer any
+ * point to sys_device (other than not disturbing old code).
+ */
+static struct platform_driver omap_mpuio_driver = {
+       .suspend_late   = omap_mpuio_suspend_late,
+       .resume_early   = omap_mpuio_resume_early,
+       .driver         = {
+               .name   = "mpuio",
+       },
+};
+
+static struct platform_device omap_mpuio_device = {
+       .name           = "mpuio",
+       .id             = -1,
+       .dev = {
+               .driver = &omap_mpuio_driver.driver,
+       }
+       /* could list the /proc/iomem resources */
 };
 
+static inline void mpuio_init(void)
+{
+       if (platform_driver_register(&omap_mpuio_driver) == 0)
+               (void) platform_device_register(&omap_mpuio_device);
+}
+
+#else
+static inline void mpuio_init(void) {}
+#endif /* 16xx */
+
+#else
+
+extern struct irq_chip mpuio_irq_chip;
+
+#define bank_is_mpuio(bank)    0
+static inline void mpuio_init(void) {}
+
+#endif
+
+/*---------------------------------------------------------------------*/
+
 static int initialized;
 static struct clk * gpio_ick;
 static struct clk * gpio_fck;
 
+#ifdef CONFIG_ARCH_OMAP2430
+static struct clk * gpio5_ick;
+static struct clk * gpio5_fck;
+#endif
+
 static int __init _omap_gpio_init(void)
 {
        int i;
@@ -1009,7 +1232,25 @@ static int __init _omap_gpio_init(void)
                        printk("Could not get gpios_fck\n");
                else
                        clk_enable(gpio_fck);
-       }
+
+               /*
+                * On 2430 GPIO 5 uses CORE L4 ICLK
+                */
+#ifdef CONFIG_ARCH_OMAP2430
+               if (cpu_is_omap2430()) {
+                       gpio5_ick = clk_get(NULL, "gpio5_ick");
+                       if (IS_ERR(gpio5_ick))
+                               printk("Could not get gpio5_ick\n");
+                       else
+                               clk_enable(gpio5_ick);
+                       gpio5_fck = clk_get(NULL, "gpio5_fck");
+                       if (IS_ERR(gpio5_fck))
+                               printk("Could not get gpio5_fck\n");
+                       else
+                               clk_enable(gpio5_fck);
+               }
+#endif
+}
 
 #ifdef CONFIG_ARCH_OMAP15XX
        if (cpu_is_omap15xx()) {
@@ -1036,14 +1277,24 @@ static int __init _omap_gpio_init(void)
                gpio_bank = gpio_bank_730;
        }
 #endif
+
 #ifdef CONFIG_ARCH_OMAP24XX
-       if (cpu_is_omap24xx()) {
+       if (cpu_is_omap242x()) {
                int rev;
 
                gpio_bank_count = 4;
-               gpio_bank = gpio_bank_24xx;
+               gpio_bank = gpio_bank_242x;
+               rev = omap_readl(gpio_bank[0].base + OMAP24XX_GPIO_REVISION);
+               printk(KERN_INFO "OMAP242x GPIO hardware version %d.%d\n",
+                       (rev >> 4) & 0x0f, rev & 0x0f);
+       }
+       if (cpu_is_omap243x()) {
+               int rev;
+
+               gpio_bank_count = 5;
+               gpio_bank = gpio_bank_243x;
                rev = omap_readl(gpio_bank[0].base + OMAP24XX_GPIO_REVISION);
-               printk(KERN_INFO "OMAP24xx GPIO hardware version %d.%d\n",
+               printk(KERN_INFO "OMAP243x GPIO hardware version %d.%d\n",
                        (rev >> 4) & 0x0f, rev & 0x0f);
        }
 #endif
@@ -1054,9 +1305,8 @@ static int __init _omap_gpio_init(void)
                bank->reserved_map = 0;
                bank->base = IO_ADDRESS(bank->base);
                spin_lock_init(&bank->lock);
-               if (bank->method == METHOD_MPUIO) {
+               if (bank_is_mpuio(bank))
                        omap_writew(0xFFFF, OMAP_MPUIO_BASE + OMAP_MPUIO_GPIO_MASKIT);
-               }
 #ifdef CONFIG_ARCH_OMAP15XX
                if (bank->method == METHOD_GPIO_1510) {
                        __raw_writew(0xffff, bank->base + OMAP1510_GPIO_INT_MASK);
@@ -1080,15 +1330,25 @@ static int __init _omap_gpio_init(void)
 #endif
 #ifdef CONFIG_ARCH_OMAP24XX
                if (bank->method == METHOD_GPIO_24XX) {
+                       static const u32 non_wakeup_gpios[] = {
+                               0xe203ffc0, 0x08700040
+                       };
+
                        __raw_writel(0x00000000, bank->base + OMAP24XX_GPIO_IRQENABLE1);
                        __raw_writel(0xffffffff, bank->base + OMAP24XX_GPIO_IRQSTATUS1);
+                       __raw_writew(0x0015, bank->base + OMAP24XX_GPIO_SYSCONFIG);
 
+                       /* Initialize interface clock ungated, module enabled */
+                       __raw_writel(0, bank->base + OMAP24XX_GPIO_CTRL);
+                       if (i < ARRAY_SIZE(non_wakeup_gpios))
+                               bank->non_wakeup_gpios = non_wakeup_gpios[i];
                        gpio_count = 32;
                }
 #endif
                for (j = bank->virtual_irq_start;
                     j < bank->virtual_irq_start + gpio_count; j++) {
-                       if (bank->method == METHOD_MPUIO)
+                       set_irq_chip_data(j, bank);
+                       if (bank_is_mpuio(bank))
                                set_irq_chip(j, &mpuio_irq_chip);
                        else
                                set_irq_chip(j, &gpio_irq_chip);
@@ -1104,6 +1364,12 @@ static int __init _omap_gpio_init(void)
        if (cpu_is_omap16xx())
                omap_writel(omap_readl(ULPD_CAM_CLK_CTRL) | 0x04, ULPD_CAM_CLK_CTRL);
 
+#ifdef CONFIG_ARCH_OMAP24XX
+       /* Enable autoidle for the OCP interface */
+       if (cpu_is_omap24xx())
+               omap_writel(1 << 0, 0x48019010);
+#endif
+
        return 0;
 }
 
@@ -1122,16 +1388,20 @@ static int omap_gpio_suspend(struct sys_device *dev, pm_message_t mesg)
                void __iomem *wake_set;
 
                switch (bank->method) {
+#ifdef CONFIG_ARCH_OMAP16XX
                case METHOD_GPIO_1610:
                        wake_status = bank->base + OMAP1610_GPIO_WAKEUPENABLE;
                        wake_clear = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA;
                        wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA;
                        break;
+#endif
+#ifdef CONFIG_ARCH_OMAP24XX
                case METHOD_GPIO_24XX:
                        wake_status = bank->base + OMAP24XX_GPIO_SETWKUENA;
                        wake_clear = bank->base + OMAP24XX_GPIO_CLEARWKUENA;
                        wake_set = bank->base + OMAP24XX_GPIO_SETWKUENA;
                        break;
+#endif
                default:
                        continue;
                }
@@ -1159,14 +1429,18 @@ static int omap_gpio_resume(struct sys_device *dev)
                void __iomem *wake_set;
 
                switch (bank->method) {
+#ifdef CONFIG_ARCH_OMAP16XX
                case METHOD_GPIO_1610:
                        wake_clear = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA;
                        wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA;
                        break;
+#endif
+#ifdef CONFIG_ARCH_OMAP24XX
                case METHOD_GPIO_24XX:
                        wake_clear = bank->base + OMAP24XX_GPIO_CLEARWKUENA;
                        wake_set = bank->base + OMAP24XX_GPIO_SETWKUENA;
                        break;
+#endif
                default:
                        continue;
                }
@@ -1190,13 +1464,87 @@ static struct sys_device omap_gpio_device = {
        .id             = 0,
        .cls            = &omap_gpio_sysclass,
 };
+
+#endif
+
+#ifdef CONFIG_ARCH_OMAP24XX
+
+static int workaround_enabled;
+
+void omap2_gpio_prepare_for_retention(void)
+{
+       int i, c = 0;
+
+       /* Remove triggering for all non-wakeup GPIOs.  Otherwise spurious
+        * IRQs will be generated.  See OMAP2420 Errata item 1.101. */
+       for (i = 0; i < gpio_bank_count; i++) {
+               struct gpio_bank *bank = &gpio_bank[i];
+               u32 l1, l2;
+
+               if (!(bank->enabled_non_wakeup_gpios))
+                       continue;
+               bank->saved_datain = __raw_readl(bank->base + OMAP24XX_GPIO_DATAIN);
+               l1 = __raw_readl(bank->base + OMAP24XX_GPIO_FALLINGDETECT);
+               l2 = __raw_readl(bank->base + OMAP24XX_GPIO_RISINGDETECT);
+               bank->saved_fallingdetect = l1;
+               bank->saved_risingdetect = l2;
+               l1 &= ~bank->enabled_non_wakeup_gpios;
+               l2 &= ~bank->enabled_non_wakeup_gpios;
+               __raw_writel(l1, bank->base + OMAP24XX_GPIO_FALLINGDETECT);
+               __raw_writel(l2, bank->base + OMAP24XX_GPIO_RISINGDETECT);
+               c++;
+       }
+       if (!c) {
+               workaround_enabled = 0;
+               return;
+       }
+       workaround_enabled = 1;
+}
+
+void omap2_gpio_resume_after_retention(void)
+{
+       int i;
+
+       if (!workaround_enabled)
+               return;
+       for (i = 0; i < gpio_bank_count; i++) {
+               struct gpio_bank *bank = &gpio_bank[i];
+               u32 l;
+
+               if (!(bank->enabled_non_wakeup_gpios))
+                       continue;
+               __raw_writel(bank->saved_fallingdetect,
+                                bank->base + OMAP24XX_GPIO_FALLINGDETECT);
+               __raw_writel(bank->saved_risingdetect,
+                                bank->base + OMAP24XX_GPIO_RISINGDETECT);
+               /* Check if any of the non-wakeup interrupt GPIOs have changed
+                * state.  If so, generate an IRQ by software.  This is
+                * horribly racy, but it's the best we can do to work around
+                * this silicon bug. */
+               l = __raw_readl(bank->base + OMAP24XX_GPIO_DATAIN);
+               l ^= bank->saved_datain;
+               l &= bank->non_wakeup_gpios;
+               if (l) {
+                       u32 old0, old1;
+
+                       old0 = __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT0);
+                       old1 = __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT1);
+                       __raw_writel(old0 | l, bank->base + OMAP24XX_GPIO_LEVELDETECT0);
+                       __raw_writel(old1 | l, bank->base + OMAP24XX_GPIO_LEVELDETECT1);
+                       __raw_writel(old0, bank->base + OMAP24XX_GPIO_LEVELDETECT0);
+                       __raw_writel(old1, bank->base + OMAP24XX_GPIO_LEVELDETECT1);
+               }
+       }
+
+}
+
 #endif
 
 /*
  * This may get called early from board specific init
  * for boards that have interrupts routed via FPGA.
  */
-int omap_gpio_init(void)
+int __init omap_gpio_init(void)
 {
        if (!initialized)
                return _omap_gpio_init();
@@ -1211,6 +1559,8 @@ static int __init omap_gpio_sysinit(void)
        if (!initialized)
                ret = _omap_gpio_init();
 
+       mpuio_init();
+
 #if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP24XX)
        if (cpu_is_omap16xx() || cpu_is_omap24xx()) {
                if (ret == 0) {
@@ -1231,3 +1581,128 @@ EXPORT_SYMBOL(omap_set_gpio_dataout);
 EXPORT_SYMBOL(omap_get_gpio_datain);
 
 arch_initcall(omap_gpio_sysinit);
+
+
+#ifdef CONFIG_DEBUG_FS
+
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+static int gpio_is_input(struct gpio_bank *bank, int mask)
+{
+       void __iomem *reg = bank->base;
+
+       switch (bank->method) {
+       case METHOD_MPUIO:
+               reg += OMAP_MPUIO_IO_CNTL;
+               break;
+       case METHOD_GPIO_1510:
+               reg += OMAP1510_GPIO_DIR_CONTROL;
+               break;
+       case METHOD_GPIO_1610:
+               reg += OMAP1610_GPIO_DIRECTION;
+               break;
+       case METHOD_GPIO_730:
+               reg += OMAP730_GPIO_DIR_CONTROL;
+               break;
+       case METHOD_GPIO_24XX:
+               reg += OMAP24XX_GPIO_OE;
+               break;
+       }
+       return __raw_readl(reg) & mask;
+}
+
+
+static int dbg_gpio_show(struct seq_file *s, void *unused)
+{
+       unsigned        i, j, gpio;
+
+       for (i = 0, gpio = 0; i < gpio_bank_count; i++) {
+               struct gpio_bank        *bank = gpio_bank + i;
+               unsigned                bankwidth = 16;
+               u32                     mask = 1;
+
+               if (bank_is_mpuio(bank))
+                       gpio = OMAP_MPUIO(0);
+               else if (cpu_is_omap24xx() || cpu_is_omap730())
+                       bankwidth = 32;
+
+               for (j = 0; j < bankwidth; j++, gpio++, mask <<= 1) {
+                       unsigned        irq, value, is_in, irqstat;
+
+                       if (!(bank->reserved_map & mask))
+                               continue;
+
+                       irq = bank->virtual_irq_start + j;
+                       value = omap_get_gpio_datain(gpio);
+                       is_in = gpio_is_input(bank, mask);
+
+                       if (bank_is_mpuio(bank))
+                               seq_printf(s, "MPUIO %2d: ", j);
+                       else
+                               seq_printf(s, "GPIO %3d: ", gpio);
+                       seq_printf(s, "%s %s",
+                                       is_in ? "in " : "out",
+                                       value ? "hi"  : "lo");
+
+                       irqstat = irq_desc[irq].status;
+                       if (is_in && ((bank->suspend_wakeup & mask)
+                                       || irqstat & IRQ_TYPE_SENSE_MASK)) {
+                               char    *trigger = NULL;
+
+                               switch (irqstat & IRQ_TYPE_SENSE_MASK) {
+                               case IRQ_TYPE_EDGE_FALLING:
+                                       trigger = "falling";
+                                       break;
+                               case IRQ_TYPE_EDGE_RISING:
+                                       trigger = "rising";
+                                       break;
+                               case IRQ_TYPE_EDGE_BOTH:
+                                       trigger = "bothedge";
+                                       break;
+                               case IRQ_TYPE_LEVEL_LOW:
+                                       trigger = "low";
+                                       break;
+                               case IRQ_TYPE_LEVEL_HIGH:
+                                       trigger = "high";
+                                       break;
+                               case IRQ_TYPE_NONE:
+                                       trigger = "(unspecified)";
+                                       break;
+                               }
+                               seq_printf(s, ", irq-%d %s%s",
+                                               irq, trigger,
+                                               (bank->suspend_wakeup & mask)
+                                                       ? " wakeup" : "");
+                       }
+                       seq_printf(s, "\n");
+               }
+
+               if (bank_is_mpuio(bank)) {
+                       seq_printf(s, "\n");
+                       gpio = 0;
+               }
+       }
+       return 0;
+}
+
+static int dbg_gpio_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, dbg_gpio_show, &inode->i_private);
+}
+
+static const struct file_operations debug_fops = {
+       .open           = dbg_gpio_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int __init omap_gpio_debuginit(void)
+{
+       (void) debugfs_create_file("omap_gpio", S_IRUGO,
+                                       NULL, NULL, &debug_fops);
+       return 0;
+}
+late_initcall(omap_gpio_debuginit);
+#endif
diff --git a/arch/arm/plat-omap/mailbox.c b/arch/arm/plat-omap/mailbox.c
new file mode 100644 (file)
index 0000000..26ace23
--- /dev/null
@@ -0,0 +1,353 @@
+/*
+ * OMAP mailbox driver
+ *
+ * Copyright (C) 2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *             Restructured by 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/init.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <asm/io.h>
+#include <asm/delay.h>
+#include <asm/arch/mailbox.h>
+#include "mailbox.h"
+
+static struct omap_mbox *mboxes;
+static DEFINE_RWLOCK(mboxes_lock);
+
+static struct omap_mbox **find_mboxes(const char *name)
+{
+       struct omap_mbox **p;
+
+       for (p = &mboxes; *p; p = &(*p)->next) {
+               if (strcmp((*p)->name, name) == 0)
+                       break;
+       }
+
+       return p;
+}
+
+struct omap_mbox *omap_mbox_get(const char *name)
+{
+       struct omap_mbox *mbox;
+
+       read_lock(&mboxes_lock);
+       mbox = *(find_mboxes(name));
+       read_unlock(&mboxes_lock);
+
+       return mbox;
+}
+EXPORT_SYMBOL(omap_mbox_get);
+
+/* Mailbox Sequence Bit function */
+void omap_mbox_init_seq(struct omap_mbox *mbox)
+{
+       mbox_seq_init(mbox);
+}
+EXPORT_SYMBOL(omap_mbox_init_seq);
+
+/*
+ * message sender
+ */
+int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg, void* arg)
+{
+       int ret;
+       int i = 1000;
+       static DEFINE_MUTEX(msg_send_lock);
+
+       while (mbox_fifo_full(mbox)) {
+               if (mbox->ops->type == OMAP_MBOX_TYPE2) {
+                       enable_mbox_irq(mbox, IRQ_TX);
+                       wait_event_interruptible(mbox->tx_waitq,
+                                                !mbox_fifo_full(mbox));
+               } else
+                       udelay(1);
+
+               if (--i == 0)
+                       return -1;
+       }
+
+
+       mutex_lock(&msg_send_lock);
+
+       if (mbox->msg_sender_cb && arg) {
+               ret = mbox->msg_sender_cb(arg);
+               if (ret)
+                       goto out;
+       }
+
+       mbox_seq_toggle(mbox, &msg);
+       mbox_fifo_write(mbox, msg);
+ out:
+       mutex_unlock(&msg_send_lock);
+
+       return 0;
+}
+EXPORT_SYMBOL(omap_mbox_msg_send);
+
+/*
+ * Message receiver(workqueue)
+ */
+static void mbox_msg_receiver(struct work_struct *work)
+{
+       struct omap_mbox *mbox =
+               container_of(work, struct omap_mbox, msg_receive);
+       struct omap_mbq *mbq = mbox->mbq;
+       mbox_msg_t msg;
+       int was_full;
+
+       while (!mbq_empty(mbq)) {
+               was_full = mbq_full(mbq);
+               msg = mbq_get(mbq);
+               if (was_full)   /* now we have a room in the mbq. */
+                       enable_mbox_irq(mbox, IRQ_RX);
+
+               if (unlikely(mbox_seq_test(mbox, msg))) {
+                       printk(KERN_ERR
+                              "mbox: illegal seq bit! ignoring this command. "
+                              "(%08x)\n", msg);
+                       continue;
+               }
+
+               if (likely(mbox->msg_receive_cb))
+                       mbox->msg_receive_cb(msg);
+       }
+}
+
+/*
+ * Mailbox interrupt handler
+ */
+static irqreturn_t mbox_interrupt(int irq, void *p)
+{
+       mbox_msg_t msg;
+       struct omap_mbox *mbox = (struct omap_mbox *)p;
+
+       if (is_mbox_irq(mbox, IRQ_TX)) {
+               disable_mbox_irq(mbox, IRQ_TX);
+               /*
+                * NOTE: this doesn't seeem to work as explained in the manual.
+                * IRQSTATUS:NOTFULL can't be cleared even we write 1 to that bit.
+                * It is always set when it's not full, regardless of IRQENABLE setting.
+                */
+               ack_mbox_irq(mbox, IRQ_TX);
+               wake_up_interruptible_all(&mbox->tx_waitq);
+       }
+
+       if (!is_mbox_irq(mbox, IRQ_RX))
+               return IRQ_HANDLED;
+
+       while (!mbox_fifo_empty(mbox)) {
+               msg = mbox_fifo_read(mbox);
+               if (mbq_add(mbox->mbq, msg)) {  /* mbq full */
+                       disable_mbox_irq(mbox, IRQ_RX);
+                       goto flush_queue;
+               }
+               if (mbox->ops->type == OMAP_MBOX_TYPE1)
+                       break;
+       }
+
+       /* no more messages in the fifo. clear IRQ source. */
+       ack_mbox_irq(mbox, IRQ_RX);
+ flush_queue:
+       schedule_work(&mbox->msg_receive);
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * sysfs files
+ */
+static ssize_t mbox_attr_write(struct class_device *dev, const char *buf,
+                             size_t count)
+{
+       int ret;
+       mbox_msg_t msg;
+       struct omap_mbox *mbox = class_get_devdata(dev);
+
+       msg = (mbox_msg_t) simple_strtoul(buf, NULL, 16);
+
+       ret = omap_mbox_msg_send(mbox, msg, NULL);
+       if (ret)
+               return -1;
+
+       return count;
+}
+
+static ssize_t mbox_attr_read(struct class_device *dev, char *buf)
+{
+       struct omap_mbox *mbox = class_get_devdata(dev);
+
+       return sprintf(buf, mbox->name);
+}
+
+static CLASS_DEVICE_ATTR(mbox, S_IALLUGO, mbox_attr_read, mbox_attr_write);
+
+static ssize_t mbox_show(struct class *class, char *buf)
+{
+       return sprintf(buf, "mbox");
+}
+
+static CLASS_ATTR(mbox, S_IRUGO, mbox_show, NULL);
+
+static struct class omap_mbox_class = {
+       .name = "mbox",
+};
+
+static int omap_mbox_init(struct omap_mbox *mbox)
+{
+       int ret;
+
+       if (likely(mbox->ops->startup)) {
+               ret = mbox->ops->startup(mbox);
+               if (unlikely(ret))
+                       return ret;
+       }
+
+       mbox->class_dev.class = &omap_mbox_class;
+       strlcpy(mbox->class_dev.class_id, mbox->name, KOBJ_NAME_LEN);
+       class_set_devdata(&mbox->class_dev, mbox);
+
+       ret = class_device_register(&mbox->class_dev);
+       if (unlikely(ret))
+               return ret;
+
+       ret = class_device_create_file(&mbox->class_dev, &class_device_attr_mbox);
+       if (unlikely(ret)) {
+               printk(KERN_ERR
+                      "class_device_create_file failed: %d\n", ret);
+               goto fail1;
+       }
+
+       spin_lock_init(&mbox->lock);
+       INIT_WORK(&mbox->msg_receive, mbox_msg_receiver);
+       init_waitqueue_head(&mbox->tx_waitq);
+
+       ret = mbq_init(&mbox->mbq);
+       if (unlikely(ret))
+               goto fail2;
+
+       ret = request_irq(mbox->irq, mbox_interrupt, IRQF_DISABLED,
+                         mbox->name, mbox);
+       if (unlikely(ret)) {
+               printk(KERN_ERR
+                      "failed to register mailbox interrupt:%d\n", ret);
+               goto fail3;
+       }
+       disable_mbox_irq(mbox, IRQ_RX);
+       enable_mbox_irq(mbox, IRQ_RX);
+
+       return 0;
+
+ fail3:
+       kfree(mbox->mbq);
+ fail2:
+       class_remove_file(&omap_mbox_class, &class_attr_mbox);
+ fail1:
+       class_unregister(&omap_mbox_class);
+       if (unlikely(mbox->ops->shutdown))
+               mbox->ops->shutdown(mbox);
+
+       return ret;
+}
+
+static void omap_mbox_shutdown(struct omap_mbox *mbox)
+{
+       free_irq(mbox->irq, mbox);
+       kfree(mbox->mbq);
+       class_remove_file(&omap_mbox_class, &class_attr_mbox);
+       class_unregister(&omap_mbox_class);
+
+       if (unlikely(mbox->ops->shutdown))
+               mbox->ops->shutdown(mbox);
+}
+
+int omap_mbox_register(struct omap_mbox *mbox)
+{
+       int ret = 0;
+       struct omap_mbox **tmp;
+
+       if (!mbox)
+               return -EINVAL;
+       if (mbox->next)
+               return -EBUSY;
+
+       ret = omap_mbox_init(mbox);
+       if (ret)
+               return ret;
+
+       write_lock(&mboxes_lock);
+       tmp = find_mboxes(mbox->name);
+       if (*tmp)
+               ret = -EBUSY;
+       else
+               *tmp = mbox;
+       write_unlock(&mboxes_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL(omap_mbox_register);
+
+int omap_mbox_unregister(struct omap_mbox *mbox)
+{
+       struct omap_mbox **tmp;
+
+       write_lock(&mboxes_lock);
+       tmp = &mboxes;
+       while (*tmp) {
+               if (mbox == *tmp) {
+                       *tmp = mbox->next;
+                       mbox->next = NULL;
+                       write_unlock(&mboxes_lock);
+
+                       omap_mbox_shutdown(mbox);
+
+                       return 0;
+               }
+               tmp = &(*tmp)->next;
+       }
+       write_unlock(&mboxes_lock);
+
+       return -EINVAL;
+}
+EXPORT_SYMBOL(omap_mbox_unregister);
+
+static int __init omap_mbox_class_init(void)
+{
+       int ret = class_register(&omap_mbox_class);
+       if (!ret)
+               ret = class_create_file(&omap_mbox_class, &class_attr_mbox);
+
+       return ret;
+}
+
+static void __exit omap_mbox_class_exit(void)
+{
+       class_remove_file(&omap_mbox_class, &class_attr_mbox);
+       class_unregister(&omap_mbox_class);
+}
+
+subsys_initcall(omap_mbox_class_init);
+module_exit(omap_mbox_class_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/plat-omap/mailbox.h b/arch/arm/plat-omap/mailbox.h
new file mode 100644 (file)
index 0000000..c3f8f2c
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * 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 queue handling API
+ */
+
+#define MBQ_DEPTH      16
+struct omap_mbq {
+       rwlock_t lock;
+       mbox_msg_t msg[MBQ_DEPTH];
+       mbox_msg_t *rp, *wp;
+       int cnt;
+};
+
+static inline int mbq_init(struct omap_mbq **addr)
+{
+       struct omap_mbq *m = kmalloc(sizeof(struct omap_mbq), GFP_KERNEL);
+       if (!m)
+               return -ENOMEM;
+
+       rwlock_init(&m->lock);
+
+       write_lock_irq(&m->lock);
+       m->rp = m->wp = &m->msg[0];
+       m->cnt = 0;
+       write_unlock_irq(&m->lock);
+
+       *addr = m;
+
+       return 0;
+}
+
+static inline int mbq_empty(struct omap_mbq *mbq)
+{
+       int ret;
+
+       read_lock_irq(&mbq->lock);
+       ret = (mbq->cnt == 0);
+       read_unlock_irq(&mbq->lock);
+
+       return ret;
+}
+
+static inline int mbq_full(struct omap_mbq *mbq)
+{
+       int ret;
+
+       read_lock_irq(&mbq->lock);
+       ret = (mbq->cnt == MBQ_DEPTH);
+       read_unlock_irq(&mbq->lock);
+
+       return ret;
+}
+
+static inline int mbq_add(struct omap_mbq *mbq, mbox_msg_t msg)
+{
+       int ret = 0;
+
+       write_lock_irq(&mbq->lock);
+
+       *mbq->wp = msg;
+       if (++mbq->wp == &mbq->msg[MBQ_DEPTH])
+               mbq->wp = &mbq->msg[0];
+
+       if (++mbq->cnt == MBQ_DEPTH)    /* full */
+               ret = -1;
+
+       write_unlock_irq(&mbq->lock);
+
+       return ret;
+}
+
+static inline mbox_msg_t mbq_get(struct omap_mbq *mbq)
+{
+       mbox_msg_t msg;
+
+       write_lock_irq(&mbq->lock);
+
+       msg = *mbq->rp;
+
+       if (++mbq->rp == &mbq->msg[MBQ_DEPTH])
+               mbq->rp = &mbq->msg[0];
+       mbq->cnt--;
+
+       write_unlock_irq(&mbq->lock);
+
+       return msg;
+}
+
+static inline void mbq_exit(struct omap_mbq **addr)
+{
+       if (*addr)
+               kfree(*addr);
+}
+
+/*
+ * 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 */
index ec50008a2df6421e46275d0ec022231bdf9a3b8f..3b74e2215085cf3f0f0200c0260e06ce8c22aca4 100644 (file)
@@ -197,6 +197,7 @@ static int omap_mcbsp_check(unsigned int id)
 static void omap_mcbsp_dsp_request(void)
 {
        if (cpu_is_omap15xx() || cpu_is_omap16xx()) {
+               omap_dsp_request_mem();
                clk_enable(mcbsp_dsp_ck);
                clk_enable(mcbsp_api_ck);
 
@@ -215,6 +216,7 @@ static void omap_mcbsp_dsp_request(void)
 static void omap_mcbsp_dsp_free(void)
 {
        if (cpu_is_omap15xx() || cpu_is_omap16xx()) {
+               omap_dsp_release_mem();
                clk_disable(mcbsp_dspxor_ck);
                clk_disable(mcbsp_dsp_ck);
                clk_disable(mcbsp_api_ck);
@@ -225,11 +227,16 @@ static void omap_mcbsp_dsp_free(void)
 #ifdef CONFIG_ARCH_OMAP2
 static void omap2_mcbsp2_mux_setup(void)
 {
-       omap_cfg_reg(Y15_24XX_MCBSP2_CLKX);
-       omap_cfg_reg(R14_24XX_MCBSP2_FSX);
-       omap_cfg_reg(W15_24XX_MCBSP2_DR);
-       omap_cfg_reg(V15_24XX_MCBSP2_DX);
-       omap_cfg_reg(V14_24XX_GPIO117);
+       if (cpu_is_omap2420()) {
+               omap_cfg_reg(Y15_24XX_MCBSP2_CLKX);
+               omap_cfg_reg(R14_24XX_MCBSP2_FSX);
+               omap_cfg_reg(W15_24XX_MCBSP2_DR);
+               omap_cfg_reg(V15_24XX_MCBSP2_DX);
+               omap_cfg_reg(V14_24XX_GPIO117);
+       }
+       /*
+        * Need to add MUX settings for OMAP 2430 SDP
+        */
 }
 #endif
 
index 042105ac30b8ea5058861343058d62112e44b288..75211f20ccb3db11dc04347f991a30d82a5447a3 100644 (file)
@@ -83,10 +83,21 @@ int __init_or_module omap_cfg_reg(const unsigned long index)
                        reg |= OMAP24XX_PULL_ENA;
                if(cfg->pu_pd_val)
                        reg |= OMAP24XX_PULL_UP;
-#ifdef CONFIG_OMAP_MUX_DEBUG
-               printk("Muxing %s (0x%08x): 0x%02x -> 0x%02x\n",
-                      cfg->name, OMAP24XX_L4_BASE + cfg->mux_reg,
-                      omap_readb(OMAP24XX_L4_BASE + cfg->mux_reg), reg);
+#if defined(CONFIG_OMAP_MUX_DEBUG) || defined(CONFIG_OMAP_MUX_WARNINGS)
+               {
+                       u8 orig = omap_readb(OMAP24XX_L4_BASE + cfg->mux_reg);
+                       u8 debug = 0;
+
+#ifdef CONFIG_OMAP_MUX_DEBUG
+                       debug = cfg->debug;
+#endif
+                       warn = (orig != reg);
+                       if (debug || warn)
+                               printk("MUX: setup %s (0x%08x): 0x%02x -> 0x%02x\n",
+                                               cfg->name,
+                                               OMAP24XX_L4_BASE + cfg->mux_reg,
+                                               orig, reg);
+               }
 #endif
                omap_writeb(reg, OMAP24XX_L4_BASE + cfg->mux_reg);
 
@@ -116,7 +127,7 @@ int __init_or_module omap_cfg_reg(const unsigned long index)
        }
 
        /* Check for pull up or pull down selection on 1610 */
-       if (!cpu_is_omap1510()) {
+       if (!cpu_is_omap15xx()) {
                if (cfg->pu_pd_reg && cfg->pull_val) {
                        spin_lock_irqsave(&mux_spin_lock, flags);
                        pu_pd_orig = omap_readl(cfg->pu_pd_reg);
@@ -172,7 +183,7 @@ int __init_or_module omap_cfg_reg(const unsigned long index)
                printk("      %s (0x%08x) = 0x%08x -> 0x%08x\n",
                       cfg->mux_reg_name, cfg->mux_reg, reg_orig, reg);
 
-               if (!cpu_is_omap1510()) {
+               if (!cpu_is_omap15xx()) {
                        if (cfg->pu_pd_reg && cfg->pull_val) {
                                printk("      %s (0x%08x) = 0x%08x -> 0x%08x\n",
                                       cfg->pu_pd_name, cfg->pu_pd_reg,
index 19014b2ff4c6315a6e190c3c2c03e17c33eb184b..7e5f8877e05191c69d226d9a6a117be1b0b9da33 100644 (file)
 
 #define ROUND_DOWN(value,boundary)     ((value) & (~((boundary)-1)))
 
+static unsigned long omap_sram_start;
 static unsigned long omap_sram_base;
 static unsigned long omap_sram_size;
 static unsigned long omap_sram_ceil;
 
-unsigned long omap_fb_sram_start;
-unsigned long omap_fb_sram_size;
+int    omap_fb_sram_plane = -1;
+int    omap_fb_sram_valid;
 
 /* Depending on the target RAMFS firewall setup, the public usable amount of
  * SRAM varies.  The default accessable size for all device types is 2k. A GP
@@ -77,30 +78,43 @@ static int is_sram_locked(void)
                return 1; /* assume locked with no PPA or security driver */
 }
 
-void get_fb_sram_conf(unsigned long start_avail, unsigned size_avail,
-                     unsigned long *start, unsigned long *size)
+static int get_fb_sram_conf(unsigned long start_avail, unsigned size_avail,
+                             unsigned long *start, int *plane_idx)
 {
        const struct omap_fbmem_config *fbmem_conf;
-
-       fbmem_conf = omap_get_config(OMAP_TAG_FBMEM, struct omap_fbmem_config);
-       if (fbmem_conf != NULL) {
-               *start = fbmem_conf->fb_sram_start;
-               *size = fbmem_conf->fb_sram_size;
-       } else {
-               *size = 0;
-               *start = 0;
+       unsigned long size = 0;
+       int i;
+
+       i = 0;
+       *start = 0;
+       *plane_idx = -1;
+       while ((fbmem_conf = omap_get_nr_config(OMAP_TAG_FBMEM,
+                               struct omap_fbmem_config, i)) != NULL) {
+               u32 paddr, end;
+
+               paddr = fbmem_conf->start;
+               end = fbmem_conf->start + fbmem_conf->size;
+               if (paddr > omap_sram_start &&
+                   paddr < omap_sram_start + omap_sram_size) {
+                       if (*plane_idx != -1 || paddr < start_avail ||
+                           paddr == end ||
+                           end > start_avail + size_avail) {
+                               printk(KERN_ERR "invalid FB SRAM configuration");
+                               *start = 0;
+                               return -1;
+                       }
+                       *plane_idx = i;
+                       *start = fbmem_conf->start;
+                       size = fbmem_conf->size;
+               }
+               i++;
        }
 
-       if (*size && (
-           *start < start_avail ||
-           *start + *size > start_avail + size_avail)) {
-               printk(KERN_ERR "invalid FB SRAM configuration\n");
-               *start = start_avail;
-               *size = size_avail;
-       }
+       if (*plane_idx >= 0)
+               pr_info("Reserving %lu bytes SRAM frame buffer "
+                       "for plane %d\n", size, *plane_idx);
 
-       if (*size)
-               pr_info("Reserving %lu bytes SRAM for frame buffer\n", *size);
+       return 0;
 }
 
 /*
@@ -111,16 +125,16 @@ void get_fb_sram_conf(unsigned long start_avail, unsigned size_avail,
  */
 void __init omap_detect_sram(void)
 {
-       unsigned long sram_start;
+       unsigned long fb_sram_start;
 
        if (cpu_is_omap24xx()) {
                if (is_sram_locked()) {
                        omap_sram_base = OMAP2_SRAM_PUB_VA;
-                       sram_start = OMAP2_SRAM_PUB_PA;
+                       omap_sram_start = OMAP2_SRAM_PUB_PA;
                        omap_sram_size = 0x800; /* 2K */
                } else {
                        omap_sram_base = OMAP2_SRAM_VA;
-                       sram_start = OMAP2_SRAM_PA;
+                       omap_sram_start = OMAP2_SRAM_PA;
                        if (cpu_is_omap242x())
                                omap_sram_size = 0xa0000; /* 640K */
                        else if (cpu_is_omap243x())
@@ -128,7 +142,7 @@ void __init omap_detect_sram(void)
                }
        } else {
                omap_sram_base = OMAP1_SRAM_VA;
-               sram_start = OMAP1_SRAM_PA;
+               omap_sram_start = OMAP1_SRAM_PA;
 
                if (cpu_is_omap730())
                        omap_sram_size = 0x32000;       /* 200K */
@@ -144,12 +158,13 @@ void __init omap_detect_sram(void)
                        omap_sram_size = 0x4000;
                }
        }
-       get_fb_sram_conf(sram_start + SRAM_BOOTLOADER_SZ,
-                        omap_sram_size - SRAM_BOOTLOADER_SZ,
-                        &omap_fb_sram_start, &omap_fb_sram_size);
-       if (omap_fb_sram_size)
-               omap_sram_size -= sram_start + omap_sram_size -
-                                 omap_fb_sram_start;
+       if (get_fb_sram_conf(omap_sram_start + SRAM_BOOTLOADER_SZ,
+                           omap_sram_size - SRAM_BOOTLOADER_SZ,
+                           &fb_sram_start, &omap_fb_sram_plane) == 0)
+               omap_fb_sram_valid = 1;
+       if (omap_fb_sram_valid && omap_fb_sram_plane >= 0)
+               omap_sram_size -= omap_sram_start + omap_sram_size -
+                                 fb_sram_start;
        omap_sram_ceil = omap_sram_base + omap_sram_size;
 }
 
diff --git a/arch/arm/plat-omap/sti/Makefile b/arch/arm/plat-omap/sti/Makefile
new file mode 100644 (file)
index 0000000..6ad9bb3
--- /dev/null
@@ -0,0 +1,4 @@
+obj-y += sti.o sti-fifo.o
+
+obj-$(CONFIG_OMAP_STI_CONSOLE) += sti-console.o
+obj-$(CONFIG_NET)              += sti-netlink.o
diff --git a/arch/arm/plat-omap/sti/sti-console.c b/arch/arm/plat-omap/sti/sti-console.c
new file mode 100644 (file)
index 0000000..451a139
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * Console support for OMAP STI/XTI
+ *
+ * Copyright (C) 2004, 2005, 2006 Nokia Corporation
+ * Written by: Paul Mundt <paul.mundt@nokia.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <asm/arch/sti.h>
+#include <asm/arch/board.h>
+
+#define DRV_NAME "sticon"
+
+static struct tty_driver *tty_driver;
+static DEFINE_SPINLOCK(sti_console_lock);
+static unsigned int sti_console_channel = -1;
+static int sti_line_done = -1;
+
+/*
+ * Write a string to any channel (including terminating NULL)
+ * Returns number of characters written.
+ */
+static int sti_channel_puts(const char *string, unsigned int channel, int len)
+{
+       int count = 0;
+
+       /*
+        * sti_line_done is needed to determine when we have reached the
+        * end of the line. write() has a tendency to hand us small
+        * strings which otherwise end up creating newlines.. we need to
+        * keep the channel open and in append mode until the line has
+        * been terminated.
+        */
+       if (sti_line_done != 0) {
+#ifdef __LITTLE_ENDIAN
+               sti_channel_writeb(0xc3, channel);
+#else
+               sti_channel_writeb(0xc0, channel);
+#endif
+               xchg(&sti_line_done, 0);
+       }
+
+       while (*string && count != len) {
+               char c = *string++;
+
+               count++;
+
+               if (c == '\n') {
+                       xchg(&sti_line_done, 1);
+                       sti_channel_writeb(0, channel);
+                       break;
+               } else
+                       sti_channel_writeb(c, channel);
+       }
+
+       if (sti_line_done)
+               sti_channel_flush(channel);
+
+       return count;
+}
+
+static int sti_tty_open(struct tty_struct *tty, struct file *filp)
+{
+       return 0;
+}
+
+static int sti_tty_write(struct tty_struct *tty,
+                        const unsigned char *buf, int len)
+{
+       unsigned long flags;
+       int bytes;
+
+       spin_lock_irqsave(&sti_console_lock, flags);
+       bytes = sti_channel_puts(buf, sti_console_channel, len);
+       spin_unlock_irqrestore(&sti_console_lock, flags);
+
+       return bytes;
+}
+
+static int sti_tty_write_room(struct tty_struct *tty)
+{
+       return 0x100000;
+}
+
+static int sti_tty_chars_in_buffer(struct tty_struct *tty)
+{
+       return 0;
+}
+
+static struct tty_operations sti_tty_ops = {
+       .open                   = sti_tty_open,
+       .write                  = sti_tty_write,
+       .write_room             = sti_tty_write_room,
+       .chars_in_buffer        = sti_tty_chars_in_buffer,
+};
+
+static void sti_console_write(struct console *c, const char *s, unsigned n)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&sti_console_lock, flags);
+       sti_channel_puts(s, sti_console_channel, n);
+       spin_unlock_irqrestore(&sti_console_lock, flags);
+}
+
+static struct tty_driver *sti_console_device(struct console *c, int *index)
+{
+       *index = c->index;
+       return tty_driver;
+}
+
+static int sti_console_setup(struct console *c, char *opts)
+{
+       return 0;
+}
+
+static struct console sti_console = {
+       .name           = DRV_NAME,
+       .write          = sti_console_write,
+       .device         = sti_console_device,
+       .setup          = sti_console_setup,
+       .flags          = CON_PRINTBUFFER | CON_ENABLED,
+       .index          = -1,
+};
+
+static int __init sti_console_init(void)
+{
+       const struct omap_sti_console_config *info;
+
+       info = omap_get_config(OMAP_TAG_STI_CONSOLE,
+                              struct omap_sti_console_config);
+       if (info && info->enable) {
+               add_preferred_console(DRV_NAME, 0, NULL);
+
+               sti_console_channel = info->channel;
+       }
+
+       if (unlikely(sti_console_channel == -1))
+               return -EINVAL;
+
+       register_console(&sti_console);
+
+       return 0;
+}
+__initcall(sti_console_init);
+
+static int __init sti_tty_init(void)
+{
+       struct tty_driver *tty;
+       int ret;
+
+       tty = alloc_tty_driver(1);
+       if (!tty)
+               return -ENOMEM;
+
+       tty->name               = DRV_NAME;
+       tty->driver_name        = DRV_NAME;
+       tty->major              = 0;    /* dynamic major */
+       tty->minor_start        = 0;
+       tty->type               = TTY_DRIVER_TYPE_SYSTEM;
+       tty->subtype            = SYSTEM_TYPE_SYSCONS;
+       tty->init_termios       = tty_std_termios;
+
+       tty_set_operations(tty, &sti_tty_ops);
+
+       ret = tty_register_driver(tty);
+       if (ret) {
+               put_tty_driver(tty);
+               return ret;
+       }
+
+       tty_driver = tty;
+       return 0;
+}
+late_initcall(sti_tty_init);
+
+module_param(sti_console_channel, uint, 0);
+MODULE_PARM_DESC(sti_console_channel, "STI console channel");
+MODULE_AUTHOR("Paul Mundt");
+MODULE_DESCRIPTION("OMAP STI console support");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/plat-omap/sti/sti-fifo.c b/arch/arm/plat-omap/sti/sti-fifo.c
new file mode 100644 (file)
index 0000000..4069d9b
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * STI RX FIFO Support
+ *
+ * Copyright (C) 2005, 2006 Nokia Corporation
+ * Written by:  Paul Mundt <paul.mundt@nokia.com> and
+ *             Roman Tereshonkov <roman.tereshonkov@nokia.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <asm/arch/sti.h>
+
+#define STI_READ_BUFFER_SIZE   1024
+#define sti_buf_pos(pos)       ((sti_crb->bufpos + (pos)) % \
+                                STI_READ_BUFFER_SIZE)
+
+static struct sti_cycle_buffer {
+       int bufpos;
+       int datalen;
+       unsigned char *buf;
+} *sti_crb;
+
+/**
+ * sti_read_packet - STI read packet (read an entire STI packet)
+ * @buf: Buffer to store the packet.
+ * @maxsize: Maximum size requested.
+ *
+ * This reads in a single completed STI packet from the RX FIFOs and
+ * places it in @buf for further processing.
+ *
+ * The return value is < 0 on error, and >= 0 for the number of bytes
+ * actually read. As per the STI specification, we require a 0xC1 to
+ * indicate the end of the packet, and we don't return the packet until
+ * we've read the entire thing in.
+ *
+ * Due to the size of the FIFOs, it's unrealistic to constantly drain
+ * this for 1 or 2 bytes at a time, so we assemble it here and return
+ * the whole thing.
+ */
+int sti_read_packet(unsigned char *buf, int maxsize)
+{
+       unsigned int pos;
+
+       if (unlikely(!buf))
+               return -EINVAL;
+       if (!sti_crb->datalen)
+               return 0;
+
+       pos = sti_buf_pos(sti_crb->datalen - 1);
+       /* End of packet */
+       if (sti_crb->buf[pos] == 0xC1) {
+               int i;
+
+               for (i = 0; i < sti_crb->datalen && i < maxsize; i++) {
+                       pos = sti_buf_pos(i);
+                       buf[i] = sti_crb->buf[pos];
+               }
+
+               sti_crb->bufpos = sti_buf_pos(i);
+               sti_crb->datalen -= i;
+
+               return i;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(sti_read_packet);
+
+static void sti_fifo_irq(unsigned long arg)
+{
+       /* If there is data read it */
+       while (!(sti_readl(STI_RX_STATUS) & STI_RXFIFO_EMPTY)) {
+               unsigned int pos = sti_buf_pos(sti_crb->datalen);
+
+               sti_crb->buf[pos] = sti_readl(STI_RX_DR);
+               sti_crb->datalen++;
+       }
+
+       sti_ack_irq(STI_RX_INT);
+}
+
+static int __init sti_fifo_init(void)
+{
+       unsigned int size;
+       int ret;
+
+       size = sizeof(struct sti_cycle_buffer) + STI_READ_BUFFER_SIZE;
+       sti_crb = kmalloc(size, GFP_KERNEL);
+       if (!sti_crb)
+               return -ENOMEM;
+
+       sti_crb->bufpos = sti_crb->datalen = 0;
+       sti_crb->buf = (unsigned char *)(sti_crb + sizeof(*sti_crb));
+
+       ret = sti_request_irq(STI_RX_INT, sti_fifo_irq, 0);
+       if (ret != 0)
+               kfree(sti_crb);
+
+       return ret;
+}
+
+static void __exit sti_fifo_exit(void)
+{
+       sti_free_irq(STI_RX_INT);
+       kfree(sti_crb);
+}
+
+module_init(sti_fifo_init);
+module_exit(sti_fifo_exit);
+
+MODULE_AUTHOR("Paul Mundt, Roman Tereshonkov");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/plat-omap/sti/sti-netlink.c b/arch/arm/plat-omap/sti/sti-netlink.c
new file mode 100644 (file)
index 0000000..5593aee
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * OMAP STI/XTI communications interface via netlink socket.
+ *
+ * Copyright (C) 2004, 2005, 2006 Nokia Corporation
+ * Written by: Paul Mundt <paul.mundt@nokia.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/netlink.h>
+#include <linux/socket.h>
+#include <linux/skbuff.h>
+#include <linux/mutex.h>
+#include <net/sock.h>
+#include <asm/arch/sti.h>
+
+static struct sock *sti_sock;
+static DEFINE_MUTEX(sti_netlink_mutex);
+
+enum {
+       STI_READ,
+       STI_WRITE,
+};
+
+static int sti_netlink_read(int pid, int seq, void *payload, int size)
+{
+       struct sk_buff *skb;
+       struct nlmsghdr *nlh;
+       int ret, len = NLMSG_SPACE(size);
+       unsigned char *tail;
+
+       skb = alloc_skb(len, GFP_KERNEL);
+       if (!skb)
+               return -ENOMEM;
+
+       tail = skb->tail;
+       nlh = NLMSG_PUT(skb, pid, seq, STI_READ,
+                       len - (sizeof(struct nlmsghdr)));
+       nlh->nlmsg_flags = 0;
+       memcpy(NLMSG_DATA(nlh), payload, size);
+       nlh->nlmsg_len = skb->tail - tail;
+
+       ret = netlink_unicast(sti_sock, skb, pid, MSG_DONTWAIT);
+       if (ret > 0)
+               ret = 0;
+
+       return ret;
+
+nlmsg_failure:
+       if (skb)
+               kfree_skb(skb);
+
+       return -EINVAL;
+}
+
+/*
+ * We abuse nlmsg_type and nlmsg_flags for our purposes.
+ *
+ * The ID is encoded into the upper 8 bits of the nlmsg_type, while the
+ * channel number is encoded into the upper 8 bits of the nlmsg_flags.
+ */
+static int sti_netlink_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+{
+       void *data;
+       u8 chan, id;
+       int size, ret = 0, len = 0;
+
+       data    = NLMSG_DATA(nlh);
+       chan    = (nlh->nlmsg_flags >> 8) & 0xff;
+       id      = (nlh->nlmsg_type  >> 8) & 0xff;
+       size    = (int)(nlh->nlmsg_len - ((char *)data - (char *)nlh));
+
+       switch (nlh->nlmsg_type & 0xff) {
+       case STI_WRITE:
+               sti_channel_write_trace(size, id, data, chan);
+               break;
+       case STI_READ:
+               data = kmalloc(size, GFP_KERNEL);
+               if (!data)
+                       return -ENOMEM;
+               memset(data, 0, size);
+
+               len = sti_read_packet(data, size);
+               ret = sti_netlink_read(NETLINK_CB(skb).pid, nlh->nlmsg_seq,
+                                      data, len);
+               kfree(data);
+               break;
+       default:
+               return -ENOTTY;
+       }
+
+       return ret;
+}
+
+static int sti_netlink_receive_skb(struct sk_buff *skb)
+{
+       while (skb->len >= NLMSG_SPACE(0)) {
+               struct nlmsghdr *nlh;
+               u32 rlen;
+               int ret;
+
+               nlh = (struct nlmsghdr *)skb->data;
+               if (nlh->nlmsg_len < sizeof(struct nlmsghdr) ||
+                   skb->len < nlh->nlmsg_len)
+                       break;
+
+               rlen = NLMSG_ALIGN(nlh->nlmsg_len);
+               if (rlen > skb->len)
+                       rlen = skb->len;
+
+               ret = sti_netlink_receive_msg(skb, nlh);
+               if (ret)
+                       netlink_ack(skb, nlh, -ret);
+               else if (nlh->nlmsg_flags & NLM_F_ACK)
+                       netlink_ack(skb, nlh, 0);
+
+               skb_pull(skb, rlen);
+       }
+
+       return 0;
+}
+
+static void sti_netlink_receive(struct sock *sk, int len)
+{
+       struct sk_buff *skb;
+
+       if (!mutex_trylock(&sti_netlink_mutex))
+               return;
+
+       while ((skb = skb_dequeue(&sk->sk_receive_queue)))
+               if (sti_netlink_receive_skb(skb) && skb->len)
+                       skb_queue_head(&sk->sk_receive_queue, skb);
+               else
+                       kfree_skb(skb);
+
+       mutex_unlock(&sti_netlink_mutex);
+}
+
+static int __init sti_netlink_init(void)
+{
+       sti_sock = netlink_kernel_create(NETLINK_USERSOCK, 0,
+                                        sti_netlink_receive, THIS_MODULE);
+       if (!sti_sock) {
+               printk(KERN_ERR "STI: Failed to create netlink socket\n");
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+module_init(sti_netlink_init);
+
+MODULE_AUTHOR("Paul Mundt");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("STI netlink-driven communications interface");
diff --git a/arch/arm/plat-omap/sti/sti.c b/arch/arm/plat-omap/sti/sti.c
new file mode 100644 (file)
index 0000000..e828860
--- /dev/null
@@ -0,0 +1,432 @@
+/*
+ * Support functions for OMAP STI/XTI (Serial Tracing Interface)
+ *
+ * Copyright (C) 2004, 2005, 2006 Nokia Corporation
+ * Written by: Paul Mundt <paul.mundt@nokia.com>
+ *
+ * STI initialization code and channel handling
+ * from Juha Yrjölä <juha.yrjola@nokia.com>.
+ *
+ * XTI initialization
+ * from Roman Tereshonkov <roman.tereshonkov@nokia.com>.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <asm/arch/sti.h>
+#include <asm/byteorder.h>
+
+static struct clk *sti_ck;
+unsigned long sti_base, sti_channel_base;
+static unsigned long sti_kern_mask = STIEn;
+static unsigned long sti_irq_mask = STI_IRQSTATUS_MASK;
+static DEFINE_SPINLOCK(sti_lock);
+
+static struct sti_irqdesc {
+       irqreturn_t (*func)(unsigned long);
+       unsigned long data;
+} ____cacheline_aligned sti_irq_desc[STI_NR_IRQS];
+
+void sti_channel_write_trace(int len, int id, void *data, unsigned int channel)
+{
+       const u8 *tpntr = data;
+
+       sti_channel_writeb(id, channel);
+
+       if (cpu_is_omap16xx())
+               /* Check u32 boundary */
+               if (!((u32)data & (STI_PERCHANNEL_SIZE - 1)) &&
+                    (len >= STI_PERCHANNEL_SIZE)) {
+                       const u32 *asrc = data;
+
+                       do {
+                               sti_channel_writel(cpu_to_be32(*asrc++),
+                                                  channel);
+                               len -= STI_PERCHANNEL_SIZE;
+                       } while (len >= STI_PERCHANNEL_SIZE);
+
+                       tpntr = (const u8 *)asrc;
+               }
+
+       while (len--)
+               sti_channel_writeb(*tpntr++, channel);
+
+       sti_channel_flush(channel);
+}
+EXPORT_SYMBOL(sti_channel_write_trace);
+
+void sti_enable_irq(unsigned int id)
+{
+       spin_lock_irq(&sti_lock);
+       sti_writel(1 << id, STI_IRQSETEN);
+       spin_unlock_irq(&sti_lock);
+}
+EXPORT_SYMBOL(sti_enable_irq);
+
+void sti_disable_irq(unsigned int id)
+{
+       spin_lock_irq(&sti_lock);
+
+       if (cpu_is_omap16xx())
+               sti_writel(1 << id, STI_IRQCLREN);
+       else if (cpu_is_omap24xx())
+               sti_writel(sti_readl(STI_IRQSETEN) & ~(1 << id), STI_IRQSETEN);
+       else
+               BUG();
+
+       spin_unlock_irq(&sti_lock);
+}
+EXPORT_SYMBOL(sti_disable_irq);
+
+void sti_ack_irq(unsigned int id)
+{
+       /* Even though the clear state is 0, we have to write 1 to clear */
+       sti_writel(1 << id, STI_IRQSTATUS);
+}
+EXPORT_SYMBOL(sti_ack_irq);
+
+int sti_request_irq(unsigned int irq, void *handler, unsigned long arg)
+{
+       struct sti_irqdesc *desc;
+
+       if (unlikely(!handler || irq > STI_NR_IRQS))
+               return -EINVAL;
+
+       desc = sti_irq_desc + irq;
+       if (unlikely(desc->func)) {
+               printk(KERN_WARNING "STI: Attempting to request in-use IRQ "
+                                   "%d, consider fixing your code..\n", irq);
+               return -EBUSY;
+       }
+
+       desc->func = handler;
+       desc->data = arg;
+
+       sti_enable_irq(irq);
+       return 0;
+}
+EXPORT_SYMBOL(sti_request_irq);
+
+void sti_free_irq(unsigned int irq)
+{
+       struct sti_irqdesc *desc = sti_irq_desc + irq;
+
+       if (unlikely(irq > STI_NR_IRQS))
+               return;
+
+       sti_disable_irq(irq);
+
+       desc->func = NULL;
+       desc->data = 0;
+}
+EXPORT_SYMBOL(sti_free_irq);
+
+/*
+ * This is a bit heavy, so normally we would defer this to a tasklet.
+ * Unfortunately tasklets are too slow for the RX FIFO interrupt (and
+ * possibly some others), so we just do the irqdesc walking here.
+ */
+static irqreturn_t sti_interrupt(int irq, void *dev_id)
+{
+       int ret = IRQ_NONE;
+       u16 status;
+       int i;
+
+       status = sti_readl(STI_IRQSTATUS) & sti_irq_mask;
+
+       for (i = 0; status; i++) {
+               struct sti_irqdesc *desc = sti_irq_desc + i;
+               u16 id = 1 << i;
+
+               if (!(status & id))
+                       continue;
+
+               if (likely(desc && desc->func))
+                       ret |= desc->func(desc->data);
+               if (unlikely(ret == IRQ_NONE)) {
+                       printk("STI: spurious interrupt (id %d)\n", id);
+                       sti_disable_irq(i);
+                       sti_ack_irq(i);
+                       ret = IRQ_HANDLED;
+               }
+
+               status &= ~id;
+       }
+
+       return IRQ_RETVAL(ret);
+}
+
+static void omap_sti_reset(void)
+{
+       int i;
+
+       /* Reset STI module */
+       sti_writel(0x02, STI_SYSCONFIG);
+
+       /* Wait a while for the STI module to complete its reset */
+       for (i = 0; i < 10000; i++)
+               if (sti_readl(STI_SYSSTATUS) & 1)
+                       break;
+}
+
+static int __init sti_init(void)
+{
+       char buf[64];
+       int i;
+
+       if (cpu_is_omap16xx()) {
+               /* Release ARM Rhea buses peripherals enable */
+               sti_writel(sti_readl(ARM_RSTCT2) | 0x0001, ARM_RSTCT2);
+
+               /* Enable TC1_CK (functional clock) */
+               sti_ck = clk_get(NULL, "tc1_ck");
+       } else if (cpu_is_omap24xx())
+               /* Enable emulation tools clock */
+               sti_ck = clk_get(NULL, "emul_ck");
+
+       if (IS_ERR(sti_ck))
+               return PTR_ERR(sti_ck);
+
+       clk_enable(sti_ck);
+
+       /* Reset STI module */
+       omap_sti_reset();
+
+       /* Enable STI */
+       sti_trace_enable(MPUCmdEn);
+
+       /* Change to custom serial protocol */
+       sti_writel(0x01, STI_SERIAL_CFG);
+
+       /* Set STI clock control register to normal mode */
+       sti_writel(0x00, STI_CLK_CTRL);
+
+       i = sti_readl(STI_REVISION);
+       snprintf(buf, sizeof(buf), "OMAP STI support loaded (HW v%u.%u)\n",
+               (i >> 4) & 0x0f, i & 0x0f);
+       printk(KERN_INFO "%s", buf);
+
+       sti_channel_write_trace(strlen(buf), 0xc3, buf, 239);
+
+       return 0;
+}
+
+static void sti_exit(void)
+{
+       u32 tmp;
+
+       /*
+        * This should have already been done by reset, but we switch off
+        * STI entirely just for added sanity..
+        */
+       tmp = sti_readl(STI_ER);
+       tmp &= ~STIEn;
+       sti_writel(tmp, STI_ER);
+
+       clk_disable(sti_ck);
+       clk_put(sti_ck);
+}
+
+static void __sti_trace_enable(int event)
+{
+       u32 tmp;
+
+       tmp = sti_readl(STI_ER);
+       tmp |= sti_kern_mask | event;
+       sti_writel(tmp, STI_ER);
+}
+
+int sti_trace_enable(int event)
+{
+       spin_lock_irq(&sti_lock);
+       sti_kern_mask |= event;
+       __sti_trace_enable(event);
+       spin_unlock_irq(&sti_lock);
+
+       return 0;
+}
+EXPORT_SYMBOL(sti_trace_enable);
+
+static void __sti_trace_disable(int event)
+{
+       u32 tmp;
+
+       tmp = sti_readl(STI_DR);
+
+       if (cpu_is_omap16xx()) {
+               tmp |= event;
+               tmp &= ~sti_kern_mask;
+       } else if (cpu_is_omap24xx()) {
+               tmp &= ~event;
+               tmp |= sti_kern_mask;
+       } else
+               BUG();
+
+       sti_writel(tmp, STI_DR);
+}
+
+void sti_trace_disable(int event)
+{
+       spin_lock_irq(&sti_lock);
+       sti_kern_mask &= ~event;
+       __sti_trace_disable(event);
+       spin_unlock_irq(&sti_lock);
+}
+EXPORT_SYMBOL(sti_trace_disable);
+
+static ssize_t
+sti_trace_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "0x%08lx\n", sti_readl(STI_ER));
+}
+
+static ssize_t
+sti_trace_store(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       int evt = simple_strtoul(buf, NULL, 0);
+       int mask = ~evt;
+
+       spin_lock_irq(&sti_lock);
+       __sti_trace_disable(mask);
+       __sti_trace_enable(evt);
+       spin_unlock_irq(&sti_lock);
+
+       return count;
+}
+static DEVICE_ATTR(trace, S_IRUGO | S_IWUSR, sti_trace_show, sti_trace_store);
+
+static ssize_t
+sti_imask_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "0x%04lx\n", sti_irq_mask);
+}
+
+static ssize_t
+sti_imask_store(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       spin_lock_irq(&sti_lock);
+       sti_irq_mask = simple_strtoul(buf, NULL, 0);
+       spin_unlock_irq(&sti_lock);
+
+       return count;
+}
+static DEVICE_ATTR(imask, S_IRUGO | S_IWUSR, sti_imask_show, sti_imask_store);
+
+static int __devinit sti_probe(struct platform_device *pdev)
+{
+       struct resource *res, *cres;
+       int ret;
+
+       if (pdev->num_resources != 3) {
+               dev_err(&pdev->dev, "invalid number of resources: %d\n",
+                       pdev->num_resources);
+               return -ENODEV;
+       }
+
+       /* STI base */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (unlikely(!res)) {
+               dev_err(&pdev->dev, "invalid mem resource\n");
+               return -ENODEV;
+       }
+
+       /* Channel base */
+       cres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (unlikely(!cres)) {
+               dev_err(&pdev->dev, "invalid channel mem resource\n");
+               return -ENODEV;
+       }
+
+       ret = device_create_file(&pdev->dev, &dev_attr_trace);
+       if (unlikely(ret != 0))
+               return ret;
+
+       ret = device_create_file(&pdev->dev, &dev_attr_imask);
+       if (unlikely(ret != 0))
+               goto err;
+
+       sti_base = res->start;
+
+       /*
+        * OMAP 16xx keeps channels in a relatively sane location,
+        * whereas 24xx maps them much further out, and so they must be
+        * remapped.
+        */
+       if (cpu_is_omap16xx())
+               sti_channel_base = cres->start;
+       else if (cpu_is_omap24xx()) {
+               unsigned int size = cres->end - cres->start;
+
+               sti_channel_base = (unsigned long)ioremap(cres->start, size);
+               if (unlikely(!sti_channel_base)) {
+                       ret = -ENODEV;
+                       goto err_badremap;
+               }
+       }
+
+       ret = request_irq(platform_get_irq(pdev, 0), sti_interrupt,
+                         IRQF_DISABLED, "sti", NULL);
+       if (unlikely(ret != 0))
+               goto err_badirq;
+
+       return sti_init();
+
+err_badirq:
+       iounmap((void *)sti_channel_base);
+err_badremap:
+       device_remove_file(&pdev->dev, &dev_attr_imask);
+err:
+       device_remove_file(&pdev->dev, &dev_attr_trace);
+
+       return ret;
+}
+
+static int __devexit sti_remove(struct platform_device *pdev)
+{
+       unsigned int irq = platform_get_irq(pdev, 0);
+
+       if (cpu_is_omap24xx())
+               iounmap((void *)sti_channel_base);
+
+       device_remove_file(&pdev->dev, &dev_attr_trace);
+       device_remove_file(&pdev->dev, &dev_attr_imask);
+       free_irq(irq, NULL);
+       sti_exit();
+
+       return 0;
+}
+
+static struct platform_driver sti_driver = {
+       .probe          = sti_probe,
+       .remove         = __devexit_p(sti_remove),
+       .driver         = {
+               .name   = "sti",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init sti_module_init(void)
+{
+       return platform_driver_register(&sti_driver);
+}
+
+static void __exit sti_module_exit(void)
+{
+       platform_driver_unregister(&sti_driver);
+}
+subsys_initcall(sti_module_init);
+module_exit(sti_module_exit);
+
+MODULE_AUTHOR("Paul Mundt, Juha Yrjölä, Roman Tereshonkov");
+MODULE_LICENSE("GPL");
index 2653106011618b2a2279eb894298b8390ff2c1ed..38b7b91e075c6cfd7ec2b38c64ad6dbb32f6f7fa 100644 (file)
@@ -42,6 +42,7 @@
 #include <linux/spinlock.h>
 #include <linux/err.h>
 #include <linux/clk.h>
+#include <linux/clocksource.h>
 
 #include <asm/system.h>
 #include <asm/hardware.h>
@@ -170,15 +171,6 @@ omap_32k_ticks_to_nsecs(unsigned long ticks_32k)
 
 static unsigned long omap_32k_last_tick = 0;
 
-/*
- * Returns elapsed usecs since last 32k timer interrupt
- */
-static unsigned long omap_32k_timer_gettimeoffset(void)
-{
-       unsigned long now = omap_32k_sync_timer_read();
-       return omap_32k_ticks_to_usecs(now - omap_32k_last_tick);
-}
-
 /*
  * Returns current time from boot in nsecs. It's OK for this to wrap
  * around for now, as it's just a relative time stamp.
@@ -217,11 +209,6 @@ static inline irqreturn_t _omap_32k_timer_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static irqreturn_t omap_32k_timer_handler(int irq, void *dev_id)
-{
-       return _omap_32k_timer_interrupt(irq, dev_id);
-}
-
 static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id)
 {
        unsigned long flags;
@@ -269,6 +256,22 @@ static int omap_32k_timer_disable_dyn_tick(void)
        return 0;
 }
 
+static irqreturn_t omap_32k_timer_handler(int irq, void *dev_id)
+{
+       unsigned long now;
+
+       now = omap_32k_sync_timer_read();
+
+       /* Don't bother reprogramming timer if last tick was before next
+        * jiffie. We will get another interrupt when previously programmed
+        * timer expires. This cuts down interrupt load quite a bit.
+        */
+       if (now - omap_32k_last_tick < OMAP_32K_TICKS_PER_HZ)
+               return IRQ_HANDLED;
+
+       return _omap_32k_timer_interrupt(irq, dev_id);
+}
+
 static struct dyn_tick_timer omap_dyn_tick_timer = {
        .enable         = omap_32k_timer_enable_dyn_tick,
        .disable        = omap_32k_timer_disable_dyn_tick,
@@ -291,7 +294,6 @@ static __init void omap_init_32k_timer(void)
 
        if (cpu_class_is_omap1())
                setup_irq(INT_OS_TIMER, &omap_32k_timer_irq);
-       omap_timer.offset  = omap_32k_timer_gettimeoffset;
        omap_32k_last_tick = omap_32k_sync_timer_read();
 
 #ifdef CONFIG_ARCH_OMAP2
@@ -326,5 +328,4 @@ static void __init omap_timer_init(void)
 
 struct sys_timer omap_timer = {
        .init           = omap_timer_init,
-       .offset         = NULL,         /* Initialized later */
 };
index 7e8096809be2bc227ef4e8acb310455a92d8cbfb..25489aafb11398f16849bb7cb225ee624d07c5e7 100644 (file)
 #include <asm/arch/usb.h>
 #include <asm/arch/board.h>
 
+#ifdef CONFIG_ARCH_OMAP1
+
+#define INT_USB_IRQ_GEN                IH2_BASE + 20
+#define INT_USB_IRQ_NISO       IH2_BASE + 30
+#define INT_USB_IRQ_ISO                IH2_BASE + 29
+#define INT_USB_IRQ_HGEN       INT_USB_HHC_1
+#define INT_USB_IRQ_OTG                IH2_BASE + 8
+
+#else
+
+#define INT_USB_IRQ_GEN                INT_24XX_USB_IRQ_GEN
+#define INT_USB_IRQ_NISO       INT_24XX_USB_IRQ_NISO
+#define INT_USB_IRQ_ISO                INT_24XX_USB_IRQ_ISO
+#define INT_USB_IRQ_HGEN       INT_24XX_USB_IRQ_HGEN
+#define INT_USB_IRQ_OTG                INT_24XX_USB_IRQ_OTG
+
+#endif
+
+
 /* These routines should handle the standard chip-specific modes
  * for usb0/1/2 ports, covering basic mux and transceiver setup.
- * Call omap_usb_init() once, from INIT_MACHINE().
  *
  * Some board-*.c files will need to set up additional mux options,
  * like for suspend handling, vbus sensing, GPIOs, and the D+ pullup.
@@ -96,19 +114,26 @@ static u32 __init omap_usb0_init(unsigned nwires, unsigned is_device)
 {
        u32     syscon1 = 0;
 
+       if (cpu_is_omap24xx())
+               CONTROL_DEVCONF_REG &= ~USBT0WRMODEI(USB_BIDIR_TLL);
+
        if (nwires == 0) {
-               if (!cpu_is_omap15xx()) {
+               if (cpu_class_is_omap1() && !cpu_is_omap15xx()) {
                        /* pulldown D+/D- */
                        USB_TRANSCEIVER_CTRL_REG &= ~(3 << 1);
                }
                return 0;
        }
 
-       if (is_device)
-               omap_cfg_reg(W4_USB_PUEN);
+       if (is_device) {
+               if (cpu_is_omap24xx())
+                       omap_cfg_reg(J20_24XX_USB0_PUEN);
+               else
+                       omap_cfg_reg(W4_USB_PUEN);
+       }
 
-       /* internal transceiver */
-       if (nwires == 2) {
+       /* internal transceiver (unavailable on 17xx, 24xx) */
+       if (!cpu_class_is_omap2() && nwires == 2) {
                // omap_cfg_reg(P9_USB_DP);
                // omap_cfg_reg(R8_USB_DM);
 
@@ -136,29 +161,50 @@ static u32 __init omap_usb0_init(unsigned nwires, unsigned is_device)
                return 0;
        }
 
-       omap_cfg_reg(V6_USB0_TXD);
-       omap_cfg_reg(W9_USB0_TXEN);
-       omap_cfg_reg(W5_USB0_SE0);
+       if (cpu_is_omap24xx()) {
+               omap_cfg_reg(K18_24XX_USB0_DAT);
+               omap_cfg_reg(K19_24XX_USB0_TXEN);
+               omap_cfg_reg(J14_24XX_USB0_SE0);
+               if (nwires != 3)
+                       omap_cfg_reg(J18_24XX_USB0_RCV);
+       } else {
+               omap_cfg_reg(V6_USB0_TXD);
+               omap_cfg_reg(W9_USB0_TXEN);
+               omap_cfg_reg(W5_USB0_SE0);
+               if (nwires != 3)
+                       omap_cfg_reg(Y5_USB0_RCV);
+       }
 
-       /* NOTE:  SPEED and SUSP aren't configured here */
+       /* NOTE:  SPEED and SUSP aren't configured here.  OTG hosts
+        * may be able to use I2C requests to set those bits along
+        * with VBUS switching and overcurrent detction.
+        */
 
-       if (nwires != 3)
-               omap_cfg_reg(Y5_USB0_RCV);
-       if (nwires != 6)
+       if (cpu_class_is_omap1() && nwires != 6)
                USB_TRANSCEIVER_CTRL_REG &= ~CONF_USB2_UNI_R;
 
        switch (nwires) {
        case 3:
                syscon1 = 2;
+               if (cpu_is_omap24xx())
+                       CONTROL_DEVCONF_REG |= USBT0WRMODEI(USB_BIDIR);
                break;
        case 4:
                syscon1 = 1;
+               if (cpu_is_omap24xx())
+                       CONTROL_DEVCONF_REG |= USBT0WRMODEI(USB_BIDIR);
                break;
        case 6:
                syscon1 = 3;
-               omap_cfg_reg(AA9_USB0_VP);
-               omap_cfg_reg(R9_USB0_VM);
-               USB_TRANSCEIVER_CTRL_REG |= CONF_USB2_UNI_R;
+               if (cpu_is_omap24xx()) {
+                       omap_cfg_reg(J19_24XX_USB0_VP);
+                       omap_cfg_reg(K20_24XX_USB0_VM);
+                       CONTROL_DEVCONF_REG |= USBT0WRMODEI(USB_UNIDIR);
+               } else {
+                       omap_cfg_reg(AA9_USB0_VP);
+                       omap_cfg_reg(R9_USB0_VM);
+                       USB_TRANSCEIVER_CTRL_REG |= CONF_USB2_UNI_R;
+               }
                break;
        default:
                printk(KERN_ERR "illegal usb%d %d-wire transceiver\n",
@@ -171,14 +217,22 @@ static u32 __init omap_usb1_init(unsigned nwires)
 {
        u32     syscon1 = 0;
 
-       if (nwires != 6 && !cpu_is_omap15xx())
+       if (cpu_class_is_omap1() && !cpu_is_omap15xx() && nwires != 6)
                USB_TRANSCEIVER_CTRL_REG &= ~CONF_USB1_UNI_R;
+       if (cpu_is_omap24xx())
+               CONTROL_DEVCONF_REG &= ~USBT1WRMODEI(USB_BIDIR_TLL);
+
        if (nwires == 0)
                return 0;
 
        /* external transceiver */
-       omap_cfg_reg(USB1_TXD);
-       omap_cfg_reg(USB1_TXEN);
+       if (cpu_class_is_omap1()) {
+               omap_cfg_reg(USB1_TXD);
+               omap_cfg_reg(USB1_TXEN);
+               if (nwires != 3)
+                       omap_cfg_reg(USB1_RCV);
+       }
+
        if (cpu_is_omap15xx()) {
                omap_cfg_reg(USB1_SEO);
                omap_cfg_reg(USB1_SPEED);
@@ -190,20 +244,38 @@ static u32 __init omap_usb1_init(unsigned nwires)
        } else if (cpu_is_omap1710()) {
                omap_cfg_reg(R13_1710_USB1_SE0);
                // SUSP
+       } else if (cpu_is_omap24xx()) {
+               /* NOTE:  board-specific code must set up pin muxing for usb1,
+                * since each signal could come out on either of two balls.
+                */
        } else {
-               pr_debug("usb unrecognized\n");
+               pr_debug("usb%d cpu unrecognized\n", 1);
+               return 0;
        }
-       if (nwires != 3)
-               omap_cfg_reg(USB1_RCV);
 
        switch (nwires) {
+       case 2:
+               if (!cpu_is_omap24xx())
+                       goto bad;
+               /* NOTE: board-specific code must override this setting if
+                * this TLL link is not using DP/DM
+                */
+               syscon1 = 1;
+               CONTROL_DEVCONF_REG |= USBT1WRMODEI(USB_BIDIR_TLL);
+               break;
        case 3:
                syscon1 = 2;
+               if (cpu_is_omap24xx())
+                       CONTROL_DEVCONF_REG |= USBT1WRMODEI(USB_BIDIR);
                break;
        case 4:
                syscon1 = 1;
+               if (cpu_is_omap24xx())
+                       CONTROL_DEVCONF_REG |= USBT1WRMODEI(USB_BIDIR);
                break;
        case 6:
+               if (cpu_is_omap24xx())
+                       goto bad;
                syscon1 = 3;
                omap_cfg_reg(USB1_VP);
                omap_cfg_reg(USB1_VM);
@@ -211,6 +283,7 @@ static u32 __init omap_usb1_init(unsigned nwires)
                        USB_TRANSCEIVER_CTRL_REG |= CONF_USB1_UNI_R;
                break;
        default:
+bad:
                printk(KERN_ERR "illegal usb%d %d-wire transceiver\n",
                        1, nwires);
        }
@@ -221,10 +294,17 @@ static u32 __init omap_usb2_init(unsigned nwires, unsigned alt_pingroup)
 {
        u32     syscon1 = 0;
 
-       /* NOTE erratum: must leave USB2_UNI_R set if usb0 in use */
+       if (cpu_is_omap24xx()) {
+               CONTROL_DEVCONF_REG &= ~(USBT2WRMODEI(USB_BIDIR_TLL)
+                                       | USBT2TLL5PI);
+               alt_pingroup = 0;
+       }
+
+       /* NOTE omap1 erratum: must leave USB2_UNI_R set if usb0 in use */
        if (alt_pingroup || nwires == 0)
                return 0;
-       if (nwires != 6 && !cpu_is_omap15xx())
+
+       if (cpu_class_is_omap1() && !cpu_is_omap15xx() && nwires != 6)
                USB_TRANSCEIVER_CTRL_REG &= ~CONF_USB2_UNI_R;
 
        /* external transceiver */
@@ -242,19 +322,54 @@ static u32 __init omap_usb2_init(unsigned nwires, unsigned alt_pingroup)
                if (nwires != 3)
                        omap_cfg_reg(Y5_USB2_RCV);
                // FIXME omap_cfg_reg(USB2_SPEED);
+       } else if (cpu_is_omap24xx()) {
+               omap_cfg_reg(Y11_24XX_USB2_DAT);
+               omap_cfg_reg(AA10_24XX_USB2_SE0);
+               if (nwires > 2)
+                       omap_cfg_reg(AA12_24XX_USB2_TXEN);
+               if (nwires > 3)
+                       omap_cfg_reg(AA6_24XX_USB2_RCV);
        } else {
-               pr_debug("usb unrecognized\n");
+               pr_debug("usb%d cpu unrecognized\n", 1);
+               return 0;
        }
-       // omap_cfg_reg(USB2_SUSP);
+       // if (cpu_class_is_omap1()) omap_cfg_reg(USB2_SUSP);
 
        switch (nwires) {
+       case 2:
+               if (!cpu_is_omap24xx())
+                       goto bad;
+               /* NOTE: board-specific code must override this setting if
+                * this TLL link is not using DP/DM
+                */
+               syscon1 = 1;
+               CONTROL_DEVCONF_REG |= USBT2WRMODEI(USB_BIDIR_TLL);
+               break;
        case 3:
                syscon1 = 2;
+               if (cpu_is_omap24xx())
+                       CONTROL_DEVCONF_REG |= USBT2WRMODEI(USB_BIDIR);
                break;
        case 4:
                syscon1 = 1;
+               if (cpu_is_omap24xx())
+                       CONTROL_DEVCONF_REG |= USBT2WRMODEI(USB_BIDIR);
+               break;
+       case 5:
+               if (!cpu_is_omap24xx())
+                       goto bad;
+               omap_cfg_reg(AA4_24XX_USB2_TLLSE0);
+               /* NOTE: board-specific code must override this setting if
+                * this TLL link is not using DP/DM.  Something must also
+                * set up OTG_SYSCON2.HMC_TLL{ATTACH,SPEED}
+                */
+               syscon1 = 3;
+               CONTROL_DEVCONF_REG |= USBT2WRMODEI(USB_UNIDIR_TLL)
+                                       | USBT2TLL5PI;
                break;
        case 6:
+               if (cpu_is_omap24xx())
+                       goto bad;
                syscon1 = 3;
                if (cpu_is_omap15xx()) {
                        omap_cfg_reg(USB2_VP);
@@ -266,6 +381,7 @@ static u32 __init omap_usb2_init(unsigned nwires, unsigned alt_pingroup)
                }
                break;
        default:
+bad:
                printk(KERN_ERR "illegal usb%d %d-wire transceiver\n",
                        2, nwires);
        }
@@ -294,13 +410,13 @@ static struct resource udc_resources[] = {
                .end            = UDC_BASE + 0xff,
                .flags          = IORESOURCE_MEM,
        }, {            /* general IRQ */
-               .start          = IH2_BASE + 20,
+               .start          = INT_USB_IRQ_GEN,
                .flags          = IORESOURCE_IRQ,
        }, {            /* PIO IRQ */
-               .start          = IH2_BASE + 30,
+               .start          = INT_USB_IRQ_NISO,
                .flags          = IORESOURCE_IRQ,
        }, {            /* SOF IRQ */
-               .start          = IH2_BASE + 29,
+               .start          = INT_USB_IRQ_ISO,
                .flags          = IORESOURCE_IRQ,
        },
 };
@@ -329,11 +445,11 @@ static u64 ohci_dmamask = ~(u32)0;
 static struct resource ohci_resources[] = {
        {
                .start  = OMAP_OHCI_BASE,
-               .end    = OMAP_OHCI_BASE + 4096 - 1,
+               .end    = OMAP_OHCI_BASE + 0xff,
                .flags  = IORESOURCE_MEM,
        },
        {
-               .start  = INT_USB_HHC_1,
+               .start  = INT_USB_IRQ_HGEN,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -361,7 +477,7 @@ static struct resource otg_resources[] = {
                .end            = OTG_BASE + 0xff,
                .flags          = IORESOURCE_MEM,
        }, {
-               .start          = IH2_BASE + 8,
+               .start          = INT_USB_IRQ_OTG,
                .flags          = IORESOURCE_IRQ,
        },
 };
@@ -385,7 +501,7 @@ static struct platform_device otg_device = {
 
 
 // FIXME correct answer depends on hmc_mode,
-// as does any nonzero value for config->otg port number
+// as does (on omap1) any nonzero value for config->otg port number
 #ifdef CONFIG_USB_GADGET_OMAP
 #define        is_usb0_device(config)  1
 #else
@@ -426,12 +542,13 @@ omap_otg_init(struct omap_usb_config *config)
        if (config->otg)
                syscon |= OTG_EN;
 #endif
-       pr_debug("USB_TRANSCEIVER_CTRL_REG = %03x\n", USB_TRANSCEIVER_CTRL_REG);
+       if (cpu_class_is_omap1())
+               pr_debug("USB_TRANSCEIVER_CTRL_REG = %03x\n", USB_TRANSCEIVER_CTRL_REG);
        pr_debug("OTG_SYSCON_2_REG = %08x\n", syscon);
        OTG_SYSCON_2_REG = syscon;
 
        printk("USB: hmc %d", config->hmc_mode);
-       if (alt_pingroup)
+       if (!alt_pingroup)
                printk(", usb2 alt %d wires", config->pins[2]);
        else if (config->pins[0])
                printk(", usb0 %d wires%s", config->pins[0],
@@ -444,10 +561,12 @@ omap_otg_init(struct omap_usb_config *config)
                printk(", Mini-AB on usb%d", config->otg - 1);
        printk("\n");
 
-       /* leave USB clocks/controllers off until needed */
-       ULPD_SOFT_REQ_REG &= ~SOFT_USB_CLK_REQ;
-       ULPD_CLOCK_CTRL_REG &= ~USB_MCLK_EN;
-       ULPD_CLOCK_CTRL_REG |= DIS_USB_PVCI_CLK;
+       if (cpu_class_is_omap1()) {
+               /* leave USB clocks/controllers off until needed */
+               ULPD_SOFT_REQ_REG &= ~SOFT_USB_CLK_REQ;
+               ULPD_CLOCK_CTRL_REG &= ~USB_MCLK_EN;
+               ULPD_CLOCK_CTRL_REG |= DIS_USB_PVCI_CLK;
+       }
        syscon = OTG_SYSCON_1_REG;
        syscon |= HST_IDLE_EN|DEV_IDLE_EN|OTG_IDLE_EN;
 
@@ -585,7 +704,7 @@ omap_usb_init(void)
        }
        platform_data = *config;
 
-       if (cpu_is_omap730() || cpu_is_omap16xx())
+       if (cpu_is_omap730() || cpu_is_omap16xx() || cpu_is_omap24xx())
                omap_otg_init(&platform_data);
        else if (cpu_is_omap15xx())
                omap_1510_usb_init(&platform_data);
index e7da9fa724ec5f50aa70040df67c10c2d7cbf2fe..bc33d90b3764a30f2c7e97938a76eff4ef4aece5 100644 (file)
@@ -82,4 +82,6 @@ source "drivers/dma/Kconfig"
 
 source "drivers/kvm/Kconfig"
 
+source "drivers/ssi/Kconfig"
+
 endmenu
index 0dd96d1afd39246bb3e625c60b9f30bd386305a4..1dc8aba48ea99e47bcc17047d81a6eccda23ef81 100644 (file)
@@ -25,9 +25,14 @@ obj-$(CONFIG_CONNECTOR)              += connector/
 obj-$(CONFIG_FB_I810)           += video/i810/
 obj-$(CONFIG_FB_INTEL)          += video/intelfb/
 
+# we also need input/serio early so serio bus is initialized by the time
+# serial drivers start registering their serio ports
+obj-$(CONFIG_SERIO)            += input/serio/
 obj-y                          += serial/
 obj-$(CONFIG_PARPORT)          += parport/
 obj-y                          += base/ block/ misc/ mfd/ net/ media/
+obj-$(CONFIG_I2C)              += i2c/
+obj-y                          += media/ ssi/ cbus/
 obj-$(CONFIG_NUBUS)            += nubus/
 obj-$(CONFIG_ATM)              += atm/
 obj-$(CONFIG_PPC_PMAC)         += macintosh/
@@ -50,14 +55,13 @@ obj-$(CONFIG_ATA_OVER_ETH)  += block/aoe/
 obj-$(CONFIG_PARIDE)           += block/paride/
 obj-$(CONFIG_TC)               += tc/
 obj-$(CONFIG_USB)              += usb/
+obj-$(CONFIG_USB_MUSB_HDRC)    += usb/musb/
 obj-$(CONFIG_PCI)              += usb/
 obj-$(CONFIG_USB_GADGET)       += usb/gadget/
-obj-$(CONFIG_SERIO)            += input/serio/
 obj-$(CONFIG_GAMEPORT)         += input/gameport/
 obj-$(CONFIG_INPUT)            += input/
 obj-$(CONFIG_I2O)              += message/
 obj-$(CONFIG_RTC_LIB)          += rtc/
-obj-$(CONFIG_I2C)              += i2c/
 obj-$(CONFIG_W1)               += w1/
 obj-$(CONFIG_HWMON)            += hwmon/
 obj-$(CONFIG_PHONE)            += telephony/
index b9fbe6e7f9ae6e6fd9da5e78990efd5e87229bc4..9abcd6206ac321c9306854f6ced36008ffceb911 100644 (file)
@@ -147,6 +147,17 @@ config BT_HCIBTUART
          Say Y here to compile support for HCI UART devices into the
          kernel or say M to compile it as module (btuart_cs).
 
+config BT_HCIBRF6150
+       tristate "HCI TI BRF6150 driver with H4 extensions"
+       depends on BT && ARCH_OMAP
+       help
+         Bluetooth HCI driver for TI BRF6150 with H4 extensions.
+         This driver provides support for BRF6150 Bluetooth chip 
+         with vendor-specific H4 extensions.
+
+         Say Y here to compile support for TI BRF6150 devices into the
+         kernel or say M to compile it as module (brf6150).
+
 config BT_HCIVHCI
        tristate "HCI VHCI (Virtual HCI device) driver"
        help
index 08c10e178e02400fd3aae0027943a94b6c91daea..18aa038db1367d655d98b810c3bc8ba22f8862cb 100644 (file)
@@ -12,6 +12,7 @@ obj-$(CONFIG_BT_HCIDTL1)      += dtl1_cs.o
 obj-$(CONFIG_BT_HCIBT3C)       += bt3c_cs.o
 obj-$(CONFIG_BT_HCIBLUECARD)   += bluecard_cs.o
 obj-$(CONFIG_BT_HCIBTUART)     += btuart_cs.o
+obj-$(CONFIG_BT_HCIBRF6150)    += brf6150.o
 
 hci_uart-y                             := hci_ldisc.o
 hci_uart-$(CONFIG_BT_HCIUART_H4)       += hci_h4.o
diff --git a/drivers/bluetooth/brf6150.c b/drivers/bluetooth/brf6150.c
new file mode 100644 (file)
index 0000000..4bb38d9
--- /dev/null
@@ -0,0 +1,1041 @@
+/*
+ *  linux/drivers/bluetooth/brf6150/brf6150.c
+ *
+ *  Copyright (C) 2005 Nokia Corporation
+ *  Written by Ville Tervo <ville.tervo@nokia.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version. 
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/serial_reg.h>
+#include <linux/skbuff.h>
+#include <linux/firmware.h>
+#include <linux/irq.h>
+#include <linux/timer.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/board.h>
+#include <asm/arch/irqs.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/hci.h>
+
+#include "brf6150.h"
+
+#if 0
+#define NBT_DBG(fmt, arg...)  printk("%s: " fmt "" , __FUNCTION__ , ## arg)
+#else
+#define NBT_DBG(...)
+#endif
+
+#if 0
+#define NBT_DBG_FW(fmt, arg...)  printk("%s: " fmt "" , __FUNCTION__ , ## arg)
+#else
+#define NBT_DBG_FW(...)
+#endif
+
+#if 0
+#define NBT_DBG_POWER(fmt, arg...)  printk("%s: " fmt "" , __FUNCTION__ , ## arg)
+#else
+#define NBT_DBG_POWER(...)
+#endif
+
+#if 0
+#define NBT_DBG_TRANSFER(fmt, arg...)  printk("%s: " fmt "" , __FUNCTION__ , ## arg)
+#else
+#define NBT_DBG_TRANSFER(...)
+#endif
+
+#if 0
+#define NBT_DBG_TRANSFER_NF(fmt, arg...)  printk(fmt "" , ## arg)
+#else
+#define NBT_DBG_TRANSFER_NF(...)
+#endif
+
+#define PM_TIMEOUT (2000)
+
+static void brf6150_device_release(struct device *dev);
+static struct brf6150_info *exit_info;
+
+static struct platform_device brf6150_device = {
+       .name           = BT_DEVICE,
+       .id             = -1,
+       .num_resources  = 0,
+       .dev = {
+               .release = brf6150_device_release,
+       }
+};
+
+static struct device_driver brf6150_driver = {
+       .name           = BT_DRIVER,
+       .bus            = &platform_bus_type,
+};
+
+static inline void brf6150_outb(struct brf6150_info *info, unsigned int offset, u8 val)
+{
+       outb(val, info->uart_base + (offset << 2));
+}
+
+static inline u8 brf6150_inb(struct brf6150_info *info, unsigned int offset)
+{
+       return inb(info->uart_base + (offset << 2));
+}
+
+static void brf6150_set_rts(struct brf6150_info *info, int active)
+{
+       u8 b;
+
+       b = brf6150_inb(info, UART_MCR);
+       if (active)
+               b |= UART_MCR_RTS;
+       else
+               b &= ~UART_MCR_RTS;
+       brf6150_outb(info, UART_MCR, b);
+}
+
+static void brf6150_wait_for_cts(struct brf6150_info *info, int active,
+                                int timeout_ms)
+{
+       int okay;
+       unsigned long timeout;
+
+       okay = 0;
+       timeout = jiffies + msecs_to_jiffies(timeout_ms);
+       for (;;) {
+               int state;
+
+               state = brf6150_inb(info, UART_MSR) & UART_MSR_CTS;
+               if (active) {
+                       if (state)
+                               break;
+               } else {
+                       if (!state)
+                               break;
+               }
+               if (jiffies > timeout)
+                       break;
+       }
+}
+
+static inline void brf6150_set_auto_ctsrts(struct brf6150_info *info, int on)
+{
+       u8 lcr, b;
+
+       lcr = brf6150_inb(info, UART_LCR);
+       brf6150_outb(info, UART_LCR, 0xbf);
+       b = brf6150_inb(info, UART_EFR);
+       if (on)
+               b |= UART_EFR_CTS | UART_EFR_RTS;
+       else
+               b &= ~(UART_EFR_CTS | UART_EFR_RTS);
+       brf6150_outb(info, UART_EFR, b);
+       brf6150_outb(info, UART_LCR, lcr);
+}
+
+static inline void brf6150_enable_pm_rx(struct brf6150_info *info)
+{
+       if (info->pm_enabled) {
+               info->rx_pm_enabled = 1;
+       }
+}
+
+static inline void brf6150_disable_pm_rx(struct brf6150_info *info)
+{
+       if (info->pm_enabled) {
+               info->rx_pm_enabled = 0;
+       }
+}
+
+static void brf6150_enable_pm_tx(struct brf6150_info *info)
+{
+       if (info->pm_enabled) {
+               mod_timer(&info->pm_timer, jiffies + msecs_to_jiffies(PM_TIMEOUT));
+               info->tx_pm_enabled = 1;
+       }
+}
+
+static void brf6150_disable_pm_tx(struct brf6150_info *info)
+{
+       if (info->pm_enabled) {
+               info->tx_pm_enabled = 0;
+               omap_set_gpio_dataout(info->btinfo->bt_wakeup_gpio, 1);
+       }
+       if (omap_get_gpio_datain(info->btinfo->host_wakeup_gpio))
+               tasklet_schedule(&info->tx_task);
+}
+
+static void brf6150_pm_timer(unsigned long data)
+{
+       struct brf6150_info *info;
+
+       info = (struct brf6150_info *)data;
+       if (info->tx_pm_enabled && info->rx_pm_enabled && !test_bit(HCI_INQUIRY, &info->hdev->flags))
+               omap_set_gpio_dataout(info->btinfo->bt_wakeup_gpio, 0);
+       else
+               mod_timer(&info->pm_timer, jiffies + msecs_to_jiffies(PM_TIMEOUT));
+}
+
+static int brf6150_change_speed(struct brf6150_info *info, unsigned long speed)
+{
+       unsigned int divisor;
+       u8 lcr, mdr1;
+
+       NBT_DBG("Setting speed %lu\n", speed);
+
+       if (speed >= 460800) {
+               divisor = UART_CLOCK / 13 / speed;
+               mdr1 = 3;
+       } else {
+               divisor = UART_CLOCK / 16 / speed;
+               mdr1 = 0;
+       }
+
+       brf6150_outb(info, UART_OMAP_MDR1, 7); /* Make sure UART mode is disabled */
+       lcr = brf6150_inb(info, UART_LCR);
+       brf6150_outb(info, UART_LCR, UART_LCR_DLAB);     /* Set DLAB */
+       brf6150_outb(info, UART_DLL, divisor & 0xff);    /* Set speed */
+       brf6150_outb(info, UART_DLM, divisor >> 8);
+       brf6150_outb(info, UART_LCR, lcr);
+       brf6150_outb(info, UART_OMAP_MDR1, mdr1); /* Make sure UART mode is enabled */
+
+       return 0;
+}
+
+/* Firmware handling */
+static int brf6150_open_firmware(struct brf6150_info *info)
+{
+       int err;
+
+       info->fw_pos = 0;
+       err = request_firmware(&info->fw_entry, "brf6150fw.bin", &brf6150_device.dev);
+
+       return err;
+}
+
+static struct sk_buff *brf6150_read_fw_cmd(struct brf6150_info *info, int how)
+{
+       struct sk_buff *skb;
+       unsigned int cmd_len;
+
+       if (info->fw_pos >= info->fw_entry->size) {
+               return NULL;
+       }
+
+       cmd_len = info->fw_entry->data[info->fw_pos++];
+       if (!cmd_len)
+               return NULL;
+
+       if (info->fw_pos + cmd_len > info->fw_entry->size) {
+               printk(KERN_WARNING "Corrupted firmware image\n");
+               return NULL;
+       }
+
+       skb = bt_skb_alloc(cmd_len, how);
+       if (!skb) {
+               printk(KERN_WARNING "Cannot reserve memory for buffer\n");
+               return NULL;
+       }
+       memcpy(skb_put(skb, cmd_len), &info->fw_entry->data[info->fw_pos], cmd_len);
+
+       info->fw_pos += cmd_len;
+
+       return skb;
+}
+
+static int brf6150_close_firmware(struct brf6150_info *info)
+{
+       release_firmware(info->fw_entry);
+       return 0;
+}
+
+static int brf6150_send_alive_packet(struct brf6150_info *info)
+{
+       struct sk_buff *skb;
+
+       NBT_DBG("Sending alive packet\n");
+       skb = brf6150_read_fw_cmd(info, GFP_ATOMIC);
+       if (!skb) {
+               printk(KERN_WARNING "Cannot read alive command");
+               return -1;
+       }
+
+       clk_enable(info->uart_ck);
+       skb_queue_tail(&info->txq, skb);
+       tasklet_schedule(&info->tx_task);
+
+       NBT_DBG("Alive packet sent\n");
+       return 0;
+}
+
+static void brf6150_alive_packet(struct brf6150_info *info, struct sk_buff *skb)
+{
+       NBT_DBG("Received alive packet\n");
+       if (skb->data[1] == 0xCC) {
+               complete(&info->init_completion);
+       }
+
+       kfree_skb(skb);
+}
+
+static int brf6150_send_negotiation(struct brf6150_info *info)
+{
+       struct sk_buff *skb;
+       NBT_DBG("Sending negotiation..\n");
+
+       brf6150_change_speed(info, INIT_SPEED);
+
+       skb = brf6150_read_fw_cmd(info, GFP_KERNEL);
+
+       if (!skb) {
+               printk(KERN_WARNING "Cannot read negoatiation message");
+               return -1;
+       }
+
+       clk_enable(info->uart_ck);
+       skb_queue_tail(&info->txq, skb);
+       tasklet_schedule(&info->tx_task);
+
+
+       NBT_DBG("Negotiation sent\n");
+       return 0;
+}
+
+static void brf6150_negotiation_packet(struct brf6150_info *info,
+                                      struct sk_buff *skb)
+{
+       if (skb->data[1] == 0x20) {
+               /* Change to operational settings */
+               brf6150_set_rts(info, 0);
+               brf6150_wait_for_cts(info, 0, 100);
+               brf6150_change_speed(info, MAX_BAUD_RATE);
+               brf6150_set_rts(info, 1);
+               brf6150_wait_for_cts(info, 1, 100);
+               brf6150_set_auto_ctsrts(info, 1);
+               brf6150_send_alive_packet(info);
+       } else {
+               printk(KERN_WARNING "Could not negotiate brf6150 settings\n");
+       }
+       kfree_skb(skb);
+}
+
+static int brf6150_get_hdr_len(u8 pkt_type)
+{
+       long retval;
+
+       switch (pkt_type) {
+       case H4_EVT_PKT:
+               retval = HCI_EVENT_HDR_SIZE;
+               break;
+       case H4_ACL_PKT:
+               retval = HCI_ACL_HDR_SIZE;
+               break;
+       case H4_SCO_PKT:
+               retval = HCI_SCO_HDR_SIZE;
+               break;
+       case H4_NEG_PKT:
+               retval = 9;
+               break;
+       case H4_ALIVE_PKT:
+               retval = 3;
+               break;
+       default:
+               printk(KERN_ERR "brf6150: Unknown H4 packet");
+               retval = -1;
+               break;
+       }
+
+       return retval;
+}
+
+static unsigned int brf6150_get_data_len(struct brf6150_info *info,
+                                        struct sk_buff *skb)
+{
+       long retval = -1;
+       struct hci_event_hdr *evt_hdr;
+       struct hci_acl_hdr *acl_hdr;
+       struct hci_sco_hdr *sco_hdr;
+
+       switch (bt_cb(skb)->pkt_type) {
+       case H4_EVT_PKT:
+               evt_hdr = (struct hci_event_hdr *)skb->data;
+               retval = evt_hdr->plen;
+               break;
+       case H4_ACL_PKT:
+               acl_hdr = (struct hci_acl_hdr *)skb->data;
+               retval = le16_to_cpu(acl_hdr->dlen);
+               break;
+       case H4_SCO_PKT:
+               sco_hdr = (struct hci_sco_hdr *)skb->data;
+               retval = sco_hdr->dlen;
+               break;
+       case H4_NEG_PKT:
+               retval = 0;
+               break;
+       case H4_ALIVE_PKT:
+               retval = 0;
+               break;
+       }
+
+       return retval;
+}
+
+static void brf6150_parse_fw_event(struct brf6150_info *info)
+{
+       struct hci_fw_event *ev;
+
+       if (bt_cb(info->rx_skb)->pkt_type != H4_EVT_PKT) {
+               printk(KERN_WARNING "Got non event fw packet.\n");
+               info->fw_error = 1;
+               return;
+       }
+
+       ev = (struct hci_fw_event *)info->rx_skb->data;
+       if (ev->hev.evt != HCI_EV_CMD_COMPLETE) {
+               printk(KERN_WARNING "Got non cmd complete fw event\n");
+               info->fw_error = 1;
+               return;
+       }
+
+       if (ev->status != 0) {
+               printk(KERN_WARNING "Got error status from fw command\n");
+               info->fw_error = 1;
+               return;
+       }
+
+       complete(&info->fw_completion);
+}
+
+static inline void brf6150_recv_frame(struct brf6150_info *info,
+                                     struct sk_buff *skb)
+{
+       if (unlikely(!test_bit(HCI_RUNNING, &info->hdev->flags))) {
+               NBT_DBG("fw_event\n");
+               brf6150_parse_fw_event(info);
+               kfree_skb(skb);
+       } else {
+               hci_recv_frame(skb);
+               if (!(brf6150_inb(info, UART_LSR) & UART_LSR_DR))
+                       brf6150_enable_pm_rx(info);
+               NBT_DBG("Frame sent to upper layer\n");
+       }
+
+}
+
+static inline void brf6150_rx(struct brf6150_info *info)
+{
+       u8 byte;
+
+       NBT_DBG_TRANSFER("rx_tasklet woke up\ndata ");
+
+       while (brf6150_inb(info, UART_LSR) & UART_LSR_DR) {
+               if (info->rx_skb == NULL) {
+                       info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
+                       if (!info->rx_skb) {
+                               printk(KERN_WARNING "brf6150: Can't allocate memory for new packet\n");
+                               return;
+                       }
+                       info->rx_state = WAIT_FOR_PKT_TYPE;
+                       info->rx_skb->dev = (void *)info->hdev;
+                       brf6150_disable_pm_rx(info);
+                       clk_enable(info->uart_ck);
+               }
+
+               byte = brf6150_inb(info, UART_RX);
+               if (info->garbage_bytes) {
+                       info->garbage_bytes--;
+                       info->hdev->stat.err_rx++;
+                       continue;
+               }
+               info->hdev->stat.byte_rx++;
+               NBT_DBG_TRANSFER_NF("0x%.2x  ", byte);
+               switch (info->rx_state) {
+               case WAIT_FOR_PKT_TYPE:
+                       bt_cb(info->rx_skb)->pkt_type = byte;
+                       info->rx_count = brf6150_get_hdr_len(byte);
+                       if (info->rx_count >= 0) {
+                               info->rx_state = WAIT_FOR_HEADER;
+                       } else {
+                               info->hdev->stat.err_rx++;
+                               kfree_skb(info->rx_skb);
+                               info->rx_skb = NULL;
+                               clk_disable(info->uart_ck);
+                       }
+                       break;
+               case WAIT_FOR_HEADER:
+                       info->rx_count--;
+                       *skb_put(info->rx_skb, 1) = byte;
+                       if (info->rx_count == 0) {
+                               info->rx_count = brf6150_get_data_len(info, info->rx_skb);
+                               if (info->rx_count > skb_tailroom(info->rx_skb)) {
+                                       printk(KERN_WARNING "brf6150: Frame is %ld bytes too long.\n",
+                                              info->rx_count - skb_tailroom(info->rx_skb));
+                                       info->rx_skb = NULL;
+                                       info->garbage_bytes = info->rx_count - skb_tailroom(info->rx_skb);
+                                       clk_disable(info->uart_ck);
+                                       break;
+                               }
+                               info->rx_state = WAIT_FOR_DATA;
+                               if (bt_cb(info->rx_skb)->pkt_type == H4_NEG_PKT) {
+                                       brf6150_negotiation_packet(info, info->rx_skb);
+                                       info->rx_skb = NULL;
+                                       clk_disable(info->uart_ck);
+                                       return;
+                               }
+                               if (bt_cb(info->rx_skb)->pkt_type == H4_ALIVE_PKT) {
+                                       brf6150_alive_packet(info, info->rx_skb);
+                                       info->rx_skb = NULL;
+                                       clk_disable(info->uart_ck);
+                                       return;
+                               }
+                       }
+                       break;
+               case WAIT_FOR_DATA:
+                       info->rx_count--;
+                       *skb_put(info->rx_skb, 1) = byte;
+                       if (info->rx_count == 0) {
+                               brf6150_recv_frame(info, info->rx_skb);
+                               info->rx_skb = NULL;
+                               clk_disable(info->uart_ck);
+                       }
+                       break;
+               default:
+                       WARN_ON(1);
+                       break;
+               }
+       }
+
+       NBT_DBG_TRANSFER_NF("\n");
+}
+
+static void brf6150_tx_tasklet(unsigned long data)
+{
+       unsigned int sent = 0;
+       unsigned long flags;
+       struct sk_buff *skb;
+       struct brf6150_info *info = (struct brf6150_info *)data;
+
+       NBT_DBG_TRANSFER("tx_tasklet woke up\n data ");
+
+       skb = skb_dequeue(&info->txq);
+       if (!skb) {
+               /* No data in buffer */
+               brf6150_enable_pm_tx(info);
+               return;
+       }
+
+       /* Copy data to tx fifo */
+       while (!(brf6150_inb(info, UART_OMAP_SSR) & UART_OMAP_SSR_TXFULL) &&
+              (sent < skb->len)) {
+               NBT_DBG_TRANSFER_NF("0x%.2x ", skb->data[sent]);
+               brf6150_outb(info, UART_TX, skb->data[sent]);
+               sent++;
+       }
+
+       info->hdev->stat.byte_tx += sent;
+       NBT_DBG_TRANSFER_NF("\n");
+       if (skb->len == sent) {
+               kfree_skb(skb);
+               clk_disable(info->uart_ck);
+       } else {
+               skb_pull(skb, sent);
+               skb_queue_head(&info->txq, skb);
+       }
+
+       spin_lock_irqsave(&info->lock, flags);
+       brf6150_outb(info, UART_IER, brf6150_inb(info, UART_IER) | UART_IER_THRI);
+       spin_unlock_irqrestore(&info->lock, flags);
+}
+
+static irqreturn_t brf6150_interrupt(int irq, void *data)
+{
+       struct brf6150_info *info = (struct brf6150_info *)data;
+       u8 iir, msr;
+       int ret;
+       unsigned long flags;
+
+       ret = IRQ_NONE;
+
+       clk_enable(info->uart_ck);
+       iir = brf6150_inb(info, UART_IIR);
+       if (iir & UART_IIR_NO_INT) {
+               printk("Interrupt but no reason irq 0x%.2x\n", iir);
+               clk_disable(info->uart_ck);
+               return IRQ_HANDLED;
+       }
+
+       NBT_DBG("In interrupt handler iir 0x%.2x\n", iir);
+
+       iir &= UART_IIR_ID;
+
+       if (iir == UART_IIR_MSI) {
+               msr = brf6150_inb(info, UART_MSR);
+               ret = IRQ_HANDLED;
+       }
+       if (iir == UART_IIR_RLSI) {
+               brf6150_inb(info, UART_RX);
+               brf6150_inb(info, UART_LSR);
+               ret = IRQ_HANDLED;
+       }
+
+       if (iir == UART_IIR_RDI) {
+               brf6150_rx(info);
+               ret = IRQ_HANDLED;
+       }
+
+       if (iir == UART_IIR_THRI) {
+               spin_lock_irqsave(&info->lock, flags);
+               brf6150_outb(info, UART_IER, brf6150_inb(info, UART_IER) & ~UART_IER_THRI);
+               spin_unlock_irqrestore(&info->lock, flags);
+               tasklet_schedule(&info->tx_task);
+               ret = IRQ_HANDLED;
+       }
+
+       clk_disable(info->uart_ck);
+       return ret;
+}
+
+static irqreturn_t brf6150_wakeup_interrupt(int irq, void *dev_inst)
+{
+       struct brf6150_info *info = dev_inst;
+       int should_wakeup;
+       unsigned long flags;
+
+       spin_lock_irqsave(&info->lock, flags);
+       should_wakeup = omap_get_gpio_datain(info->btinfo->host_wakeup_gpio);
+       NBT_DBG_POWER("gpio interrupt %d\n", should_wakeup);
+       if (should_wakeup) {
+               clk_enable(info->uart_ck);
+               brf6150_set_auto_ctsrts(info, 1);
+               brf6150_rx(info);
+               tasklet_schedule(&info->tx_task);
+       } else {
+               brf6150_set_auto_ctsrts(info, 0);
+               brf6150_set_rts(info, 0);
+               clk_disable(info->uart_ck);
+       }
+
+       spin_unlock_irqrestore(&info->lock, flags);
+       return IRQ_HANDLED;
+}
+
+static int brf6150_init_uart(struct brf6150_info *info)
+{
+       int count = 0;
+
+       /* Reset the  UART */
+       brf6150_outb(info, UART_OMAP_SYSC, UART_SYSC_OMAP_RESET);
+       while (!(brf6150_inb(info, UART_OMAP_SYSS) & UART_SYSS_RESETDONE)) {
+               if (count++ > 100) {
+                       printk(KERN_ERR "brf6150: UART reset timeout\n");
+                       return -1;
+               }
+               udelay(1);
+       }
+
+       /* Enable and setup FIFO */
+       brf6150_outb(info, UART_LCR, UART_LCR_WLEN8);
+       brf6150_outb(info, UART_OMAP_MDR1, 0x00); /* Make sure UART mode is enabled */
+       brf6150_outb(info, UART_OMAP_SCR, 0x00);
+       brf6150_outb(info, UART_EFR, brf6150_inb(info, UART_EFR) | UART_EFR_ECB);
+       brf6150_outb(info, UART_MCR, brf6150_inb(info, UART_MCR) | UART_MCR_TCRTLR);
+       brf6150_outb(info, UART_TI752_TLR, 0xff);
+       brf6150_outb(info, UART_TI752_TCR, 0x1f);
+       brf6150_outb(info, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
+       brf6150_outb(info, UART_IER, UART_IER_RDI);
+
+       return 0;
+}
+
+static int brf6150_reset(struct brf6150_info *info)
+{
+       omap_set_gpio_dataout(info->btinfo->bt_wakeup_gpio, 0);
+       omap_set_gpio_dataout(info->btinfo->reset_gpio, 0);
+       current->state = TASK_UNINTERRUPTIBLE;
+       schedule_timeout(msecs_to_jiffies(10));
+       omap_set_gpio_dataout(info->btinfo->bt_wakeup_gpio, 1);
+       current->state = TASK_UNINTERRUPTIBLE;
+       schedule_timeout(msecs_to_jiffies(100));
+       omap_set_gpio_dataout(info->btinfo->reset_gpio, 1);
+       current->state = TASK_UNINTERRUPTIBLE;
+       schedule_timeout(msecs_to_jiffies(100));
+
+       return 0;
+}
+
+static int brf6150_send_firmware(struct brf6150_info *info)
+{
+       struct sk_buff *skb;
+
+       init_completion(&info->fw_completion);
+       info->fw_error = 0;
+
+       while ((skb = brf6150_read_fw_cmd(info, GFP_KERNEL)) != NULL) {
+               clk_enable(info->uart_ck);
+               skb_queue_tail(&info->txq, skb);
+               tasklet_schedule(&info->tx_task);
+
+               if (!wait_for_completion_timeout(&info->fw_completion, HZ)) {
+                       return -1;
+               }
+
+               if (info->fw_error) {
+                       return -1;
+               }
+       }
+       NBT_DBG_FW("Firmware sent\n");
+
+       return 0;
+
+}
+
+/* hci callback functions */
+static int brf6150_hci_flush(struct hci_dev *hdev)
+{
+       struct brf6150_info *info;
+       info = hdev->driver_data;
+
+       skb_queue_purge(&info->txq);
+
+       return 0;
+}
+
+static int brf6150_hci_open(struct hci_dev *hdev)
+{
+       struct brf6150_info *info;
+       int err;
+
+       info = hdev->driver_data;
+
+       if (test_bit(HCI_RUNNING, &hdev->flags))
+               return 0;
+
+       if (brf6150_open_firmware(info) < 0) {
+               printk("Cannot open firmware\n");
+               return -1;
+       }
+
+       info->rx_state = WAIT_FOR_PKT_TYPE;
+       info->rx_count = 0;
+       info->garbage_bytes = 0;
+       info->rx_skb = NULL;
+       info->pm_enabled = 0;
+       set_irq_type(OMAP_GPIO_IRQ(info->btinfo->host_wakeup_gpio), IRQT_NOEDGE);
+       init_completion(&info->fw_completion);
+
+       clk_enable(info->uart_ck);
+
+       brf6150_init_uart(info);
+       brf6150_set_auto_ctsrts(info, 0);
+       brf6150_set_rts(info, 0);
+       brf6150_reset(info);
+       brf6150_wait_for_cts(info, 1, 10);
+       brf6150_set_rts(info, 1);
+       if (brf6150_send_negotiation(info)) {
+               brf6150_close_firmware(info);
+               return -1;
+       }
+
+       if (!wait_for_completion_interruptible_timeout(&info->init_completion, HZ)) {
+               brf6150_close_firmware(info);
+               clk_disable(info->uart_ck);
+               clear_bit(HCI_RUNNING, &hdev->flags);
+               return -1;
+       }
+       brf6150_set_auto_ctsrts(info, 1);
+
+       err = brf6150_send_firmware(info);
+       brf6150_close_firmware(info);
+       if (err < 0)
+               printk(KERN_ERR "brf6150: Sending firmware failed. Bluetooth won't work properly\n");
+
+       set_irq_type(OMAP_GPIO_IRQ(info->btinfo->host_wakeup_gpio), IRQT_BOTHEDGE);
+       info->pm_enabled = 1;
+       set_bit(HCI_RUNNING, &hdev->flags);
+       return 0;
+}
+
+static int brf6150_hci_close(struct hci_dev *hdev)
+{
+       struct brf6150_info *info = hdev->driver_data;
+       if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
+               return 0;
+
+       brf6150_hci_flush(hdev);
+       clk_disable(info->uart_ck);
+       del_timer_sync(&info->pm_timer);
+       omap_set_gpio_dataout(info->btinfo->bt_wakeup_gpio, 0);
+       set_irq_type(OMAP_GPIO_IRQ(info->btinfo->host_wakeup_gpio), IRQT_NOEDGE);
+
+       return 0;
+}
+
+static void brf6150_hci_destruct(struct hci_dev *hdev)
+{
+}
+
+static int brf6150_hci_send_frame(struct sk_buff *skb)
+{
+       struct brf6150_info *info;
+       struct hci_dev *hdev = (struct hci_dev *)skb->dev;
+
+       if (!hdev) {
+               printk(KERN_WARNING "brf6150: Frame for unknown device\n");
+               return -ENODEV;
+       }
+
+       if (!test_bit(HCI_RUNNING, &hdev->flags)) {
+               printk(KERN_WARNING "brf6150: Frame for non-running device\n");
+               return -EIO;
+       }
+
+       info = hdev->driver_data;
+
+       switch (bt_cb(skb)->pkt_type) {
+               case HCI_COMMAND_PKT:
+                       hdev->stat.cmd_tx++;
+                       break;
+               case HCI_ACLDATA_PKT:
+                       hdev->stat.acl_tx++;
+                       break;
+               case HCI_SCODATA_PKT:
+                       hdev->stat.sco_tx++;
+                       break;
+       };
+
+       /* Push frame type to skb */
+       clk_enable(info->uart_ck);
+       *skb_push(skb, 1) = bt_cb(skb)->pkt_type;
+       skb_queue_tail(&info->txq, skb);
+
+       brf6150_disable_pm_tx(info);
+
+       return 0;
+}
+
+static int brf6150_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
+{
+       return -ENOIOCTLCMD;
+}
+
+static void brf6150_device_release(struct device *dev)
+{
+}
+
+static int brf6150_register_hdev(struct brf6150_info *info)
+{
+       struct hci_dev *hdev;
+
+       /* Initialize and register HCI device */
+
+       hdev = hci_alloc_dev();
+       if (!hdev) {
+               printk(KERN_WARNING "brf6150: Can't allocate memory for device\n");
+               return -ENOMEM;
+       }
+       info->hdev = hdev;
+
+       hdev->type = HCI_UART;
+       hdev->driver_data = info;
+
+       hdev->open = brf6150_hci_open;
+       hdev->close = brf6150_hci_close;
+       hdev->destruct = brf6150_hci_destruct;
+       hdev->flush = brf6150_hci_flush;
+       hdev->send = brf6150_hci_send_frame;
+       hdev->destruct = brf6150_hci_destruct;
+       hdev->ioctl = brf6150_hci_ioctl;
+
+       hdev->owner = THIS_MODULE;
+
+       if (hci_register_dev(hdev) < 0) {
+               printk(KERN_WARNING "brf6150: Can't register HCI device %s.\n", hdev->name);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static int __init brf6150_init(void)
+{
+       struct brf6150_info *info;
+       int irq, err;
+
+       info = kmalloc(sizeof(struct brf6150_info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+       memset(info, 0, sizeof(struct brf6150_info));
+
+       brf6150_device.dev.driver_data = info;
+       init_completion(&info->init_completion);
+       init_completion(&info->fw_completion);
+       info->pm_enabled = 0;
+       info->rx_pm_enabled = 0;
+       info->tx_pm_enabled = 0;
+       info->garbage_bytes = 0;
+       tasklet_init(&info->tx_task, brf6150_tx_tasklet, (unsigned long)info);
+       spin_lock_init(&info->lock);
+       skb_queue_head_init(&info->txq);
+       init_timer(&info->pm_timer);
+       info->pm_timer.function = brf6150_pm_timer;
+       info->pm_timer.data = (unsigned long)info;
+       exit_info = NULL;
+
+       info->btinfo = omap_get_config(OMAP_TAG_NOKIA_BT, struct omap_bluetooth_config);
+       if (info->btinfo == NULL)
+               return -1;
+
+       NBT_DBG("RESET gpio: %d\n", info->btinfo->reset_gpio);
+       NBT_DBG("BTWU gpio: %d\n", info->btinfo->bt_wakeup_gpio);
+       NBT_DBG("HOSTWU gpio: %d\n", info->btinfo->host_wakeup_gpio);
+       NBT_DBG("Uart: %d\n", info->btinfo->bt_uart);
+       NBT_DBG("sysclk: %d\n", info->btinfo->bt_sysclk);
+
+       err = omap_request_gpio(info->btinfo->reset_gpio);
+       if (err < 0)
+       {
+               printk(KERN_WARNING "Cannot get GPIO line %d", 
+                      info->btinfo->reset_gpio);
+               kfree(info);
+               return err;
+       }
+
+       err = omap_request_gpio(info->btinfo->bt_wakeup_gpio);
+       if (err < 0)
+       {
+               printk(KERN_WARNING "Cannot get GPIO line 0x%d",
+                      info->btinfo->bt_wakeup_gpio);
+               omap_free_gpio(info->btinfo->reset_gpio);
+               kfree(info);
+               return err;
+       }
+
+       err = omap_request_gpio(info->btinfo->host_wakeup_gpio);
+       if (err < 0)
+       {
+               printk(KERN_WARNING "Cannot get GPIO line %d",
+                      info->btinfo->host_wakeup_gpio);
+               omap_free_gpio(info->btinfo->reset_gpio);
+               omap_free_gpio(info->btinfo->bt_wakeup_gpio);
+               kfree(info);
+               return err;
+       }
+
+       omap_set_gpio_direction(info->btinfo->reset_gpio, 0);
+       omap_set_gpio_direction(info->btinfo->bt_wakeup_gpio, 0);
+       omap_set_gpio_direction(info->btinfo->host_wakeup_gpio, 1);
+       set_irq_type(OMAP_GPIO_IRQ(info->btinfo->host_wakeup_gpio), IRQT_NOEDGE);
+
+       switch (info->btinfo->bt_uart) {
+       case 1:
+               irq = INT_UART1;
+               info->uart_ck = clk_get(NULL, "uart1_ck");
+               info->uart_base = io_p2v((unsigned long)OMAP_UART1_BASE);
+               break;
+       case 2:
+               irq = INT_UART2;
+               info->uart_ck = clk_get(NULL, "uart2_ck");
+               info->uart_base = io_p2v((unsigned long)OMAP_UART2_BASE);
+               break;
+       case 3:
+               irq = INT_UART3;
+               info->uart_ck = clk_get(NULL, "uart3_ck");
+               info->uart_base = io_p2v((unsigned long)OMAP_UART3_BASE);
+               break;
+       default:
+               printk(KERN_ERR "No uart defined\n");
+               goto cleanup;
+       }
+
+       info->irq = irq;
+       err = request_irq(irq, brf6150_interrupt, 0, "brf6150", (void *)info);
+       if (err < 0) {
+               printk(KERN_ERR "brf6150: unable to get IRQ %d\n", irq);
+               goto cleanup;
+       }
+
+       err = request_irq(OMAP_GPIO_IRQ(info->btinfo->host_wakeup_gpio),
+                       brf6150_wakeup_interrupt, 0, "brf6150_wkup", (void *)info);
+       if (err < 0) {
+               printk(KERN_ERR "brf6150: unable to get wakeup IRQ %d\n",
+                               OMAP_GPIO_IRQ(info->btinfo->host_wakeup_gpio));
+               free_irq(irq, (void *)info);
+               goto cleanup;
+       }
+
+       /* Register with LDM */
+       if (platform_device_register(&brf6150_device)) {
+               printk(KERN_ERR "failed to register brf6150 device\n");
+               err = -ENODEV;
+               goto cleanup_irq;
+       }
+       /* Register the driver with LDM */
+       if (driver_register(&brf6150_driver)) {
+               printk(KERN_WARNING "failed to register brf6150 driver\n");
+               platform_device_unregister(&brf6150_device);
+               err = -ENODEV;
+               goto cleanup_irq;
+       }
+
+       if (brf6150_register_hdev(info) < 0) {
+               printk(KERN_WARNING "failed to register brf6150 hci device\n");
+               platform_device_unregister(&brf6150_device);
+               driver_unregister(&brf6150_driver);
+               goto cleanup_irq;
+       }
+
+       exit_info = info;
+       return 0;
+
+cleanup_irq:
+       free_irq(irq, (void *)info);
+       free_irq(OMAP_GPIO_IRQ(info->btinfo->host_wakeup_gpio), (void *)info);
+cleanup:
+       omap_free_gpio(info->btinfo->reset_gpio);
+       omap_free_gpio(info->btinfo->bt_wakeup_gpio);
+       omap_free_gpio(info->btinfo->host_wakeup_gpio);
+       kfree(info);
+
+       return err;
+}
+
+static void __exit brf6150_exit(void)
+{
+       brf6150_hci_close(exit_info->hdev);
+       hci_free_dev(exit_info->hdev);
+       omap_free_gpio(exit_info->btinfo->reset_gpio);
+       omap_free_gpio(exit_info->btinfo->bt_wakeup_gpio);
+       omap_free_gpio(exit_info->btinfo->host_wakeup_gpio);
+       free_irq(exit_info->irq, (void *)exit_info);
+       free_irq(OMAP_GPIO_IRQ(exit_info->btinfo->host_wakeup_gpio), (void *)exit_info);
+       kfree(exit_info);
+}
+
+module_init(brf6150_init);
+module_exit(brf6150_exit);
+
+MODULE_DESCRIPTION("brf6150 hci driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ville Tervo <ville.tervo@nokia.com>");
diff --git a/drivers/bluetooth/brf6150.h b/drivers/bluetooth/brf6150.h
new file mode 100644 (file)
index 0000000..334a72e
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ *  linux/drivers/bluetooth/brf6150/brf6150.h
+ *
+ *  Copyright (C) 2005 Nokia Corporation
+ *  Written by Ville Tervo <ville.tervo@nokia.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version. 
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <asm/arch/board.h>
+
+#ifndef __DRIVERS_BLUETOOTH_BRF6150_H
+#define __DRIVERS_BLUETOOTH_BRF6150_H
+
+#define UART_SYSC_OMAP_RESET   0x02
+#define UART_SYSS_RESETDONE    0x01
+#define UART_OMAP_SCR_EMPTY_THR        0x08
+#define UART_OMAP_SCR_WAKEUP   0x10
+#define UART_OMAP_SSR_WAKEUP   0x02
+#define UART_OMAP_SSR_TXFULL   0x01
+
+struct brf6150_info {
+       struct hci_dev *hdev;
+       spinlock_t lock;
+
+       struct clk *uart_ck;
+       unsigned long uart_base;
+       unsigned int irq;
+
+       struct sk_buff_head txq;
+       struct sk_buff *rx_skb;
+       const struct omap_bluetooth_config *btinfo;
+       const struct firmware *fw_entry;
+       int fw_pos;
+       int fw_error;
+       struct completion fw_completion;
+       struct completion init_completion;
+       struct tasklet_struct tx_task;
+       long rx_count;
+       unsigned long garbage_bytes;
+       unsigned long rx_state;
+       int pm_enabled;
+       int rx_pm_enabled;
+       int tx_pm_enabled;
+       struct timer_list pm_timer;
+};
+
+#define BT_DEVICE "nokia_btuart"
+#define BT_DRIVER "nokia_btuart"
+
+#define MAX_BAUD_RATE          921600
+#define UART_CLOCK             48000000
+#define BT_INIT_DIVIDER                320
+#define BT_BAUDRATE_DIVIDER    384000000
+#define BT_SYSCLK_DIV          1000
+#define INIT_SPEED             120000
+
+#define H4_TYPE_SIZE           1
+
+/* H4+ packet types */
+#define H4_CMD_PKT             0x01
+#define H4_ACL_PKT             0x02
+#define H4_SCO_PKT             0x03
+#define H4_EVT_PKT             0x04
+#define H4_NEG_PKT             0x06
+#define H4_ALIVE_PKT           0x07
+
+/* TX states */
+#define WAIT_FOR_PKT_TYPE      1
+#define WAIT_FOR_HEADER                2
+#define WAIT_FOR_DATA          3
+
+struct hci_fw_event {
+       struct hci_event_hdr hev;
+       struct hci_ev_cmd_complete cmd;
+       __u8 status;
+} __attribute__ ((packed));
+
+#endif /* __DRIVERS_BLUETOOTH_BRF6150_H */
diff --git a/drivers/cbus/Kconfig b/drivers/cbus/Kconfig
new file mode 100644 (file)
index 0000000..008d193
--- /dev/null
@@ -0,0 +1,81 @@
+#
+# CBUS device configuration
+#
+
+menu "CBUS support"
+
+config CBUS
+       depends on ARCH_OMAP
+       bool "CBUS support on OMAP"
+       ---help---
+         CBUS is a proprietary serial protocol by Nokia.  It is mainly
+         used for accessing Energy Management auxiliary chips.
+
+         If you want CBUS support, you should say Y here.
+
+config CBUS_TAHVO
+       depends on CBUS
+       bool "Support for Tahvo"
+       ---help---
+         Tahvo is a mixed signal ASIC with some system features
+
+         If you want Tahvo support, you should say Y here.
+
+config CBUS_TAHVO_USER
+       depends on CBUS_TAHVO
+       bool "Support for Tahvo user space functions"
+       ---help---
+         If you want support for Tahvo's user space read/write etc. functions, 
+         you should say Y here.
+
+config CBUS_TAHVO_USB
+       depends on CBUS_TAHVO && USB
+       tristate "Support for Tahvo USB transceiver"
+       ---help---
+         If you want Tahvo support for USB transceiver, say Y or M here. 
+
+config CBUS_TAHVO_USB_HOST_BY_DEFAULT
+       depends on CBUS_TAHVO_USB && USB_OTG
+       boolean "Device in USB host mode by default"
+       ---help---
+         Say Y here, if you want the device to enter USB host mode
+         by default on bootup.
+
+config CBUS_RETU
+       depends on CBUS
+       bool "Support for Retu"
+       ---help---
+         Retu is a mixed signal ASIC with some system features
+
+         If you want Retu support, you should say Y here.
+
+config CBUS_RETU_USER
+       depends on CBUS_RETU
+       bool "Support for Retu user space functions"
+       ---help---
+         If you want support for Retu's user space read/write etc. functions, 
+         you should say Y here.
+
+config CBUS_RETU_POWERBUTTON
+       depends on CBUS_RETU
+       bool "Support for Retu power button"
+       ---help---
+         The power button on Nokia 770 is connected to the Retu ASIC.
+
+         If you want support for the Retu power button, you should say Y here.
+
+config CBUS_RETU_RTC
+       depends on CBUS_RETU && SYSFS
+       tristate "Support for Retu pseudo-RTC"
+       ---help---
+         Say Y here if you want support for the device that alleges to be an
+         RTC in Retu. This will expose a sysfs interface for it.
+
+config CBUS_RETU_WDT
+       depends on CBUS_RETU && SYSFS
+       tristate "Support for Retu watchdog timer"
+       ---help---
+         Say Y here if you want support for the watchdog in Retu. This will
+         expose a sysfs interface to grok it.
+
+endmenu
diff --git a/drivers/cbus/Makefile b/drivers/cbus/Makefile
new file mode 100644 (file)
index 0000000..6390139
--- /dev/null
@@ -0,0 +1,13 @@
+#
+# 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
diff --git a/drivers/cbus/cbus.c b/drivers/cbus/cbus.c
new file mode 100644 (file)
index 0000000..eff38be
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+ * drivers/cbus/cbus.c
+ *
+ * Support functions for CBUS serial protocol
+ *
+ * Copyright (C) 2004, 2005 Nokia Corporation
+ *
+ * Written by Juha Yrjölä <juha.yrjola@nokia.com>,
+ *           David Weinehall <david.weinehall@nokia.com>, and
+ *           Mikko Ylinen <mikko.k.ylinen@nokia.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/board.h>
+
+#include <asm/io.h>
+
+#include "cbus.h"
+
+struct cbus_host *cbus_host = NULL;
+
+#ifdef CONFIG_ARCH_OMAP1
+/* We use our own MPUIO functions to get closer to 1MHz bus speed */
+
+static inline void cbus_set_gpio_direction(u32 base, int mpuio, int is_input)
+{
+       u16 w;
+
+       mpuio &= 0x0f;
+       w = __raw_readw(base + OMAP_MPUIO_IO_CNTL);
+       if (is_input)
+               w |= 1 << mpuio;
+       else
+               w &= ~(1 << mpuio);
+       __raw_writew(w, base + OMAP_MPUIO_IO_CNTL);
+
+}
+
+static inline void cbus_set_gpio_dataout(u32 base, int mpuio, int enable)
+{
+       u16 w;
+
+       mpuio &= 0x0f;
+       w = __raw_readw(base + OMAP_MPUIO_OUTPUT);
+       if (enable)
+               w |= 1 << mpuio;
+       else
+               w &= ~(1 << mpuio);
+       __raw_writew(w, base + OMAP_MPUIO_OUTPUT);
+}
+
+static inline int cbus_get_gpio_datain(u32 base, int mpuio)
+{
+       mpuio &= 0x0f;
+
+       return (__raw_readw(base + OMAP_MPUIO_INPUT_LATCH) & (1 << mpuio)) != 0;
+}
+
+static void cbus_send_bit(struct cbus_host *host, u32 base, int bit,
+                         int set_to_input)
+{
+       cbus_set_gpio_dataout(base, host->dat_gpio, bit ? 1 : 0);
+       cbus_set_gpio_dataout(base, host->clk_gpio, 1);
+
+       /* The data bit is read on the rising edge of CLK */
+       if (set_to_input)
+               cbus_set_gpio_direction(base, host->dat_gpio, 1);
+
+       cbus_set_gpio_dataout(base, host->clk_gpio, 0);
+}
+
+static u8 cbus_receive_bit(struct cbus_host *host, u32 base)
+{
+       u8 ret;
+
+       cbus_set_gpio_dataout(base, host->clk_gpio, 1);
+       ret = cbus_get_gpio_datain(base, host->dat_gpio);
+       cbus_set_gpio_dataout(base, host->clk_gpio, 0);
+
+       return ret;
+}
+
+#else
+
+#define cbus_set_gpio_direction(base, gpio, is_input) omap_set_gpio_direction(gpio, is_input)
+#define cbus_set_gpio_dataout(base, gpio, enable) omap_set_gpio_dataout(gpio, enable)
+#define cbus_get_gpio_datain(base, int, gpio) omap_get_gpio_datain(gpio)
+
+static void _cbus_send_bit(struct cbus_host *host, int bit, int set_to_input)
+{
+       omap_set_gpio_dataout(host->dat_gpio, bit ? 1 : 0);
+       omap_set_gpio_dataout(host->clk_gpio, 1);
+
+       /* The data bit is read on the rising edge of CLK */
+       if (set_to_input)
+               omap_set_gpio_direction(host->dat_gpio, 1);
+
+       omap_set_gpio_dataout(host->clk_gpio, 0);
+}
+
+static u8 _cbus_receive_bit(struct cbus_host *host)
+{
+       u8 ret;
+
+       omap_set_gpio_dataout(host->clk_gpio, 1);
+       ret = omap_get_gpio_datain(host->dat_gpio);
+       omap_set_gpio_dataout(host->clk_gpio, 0);
+
+       return ret;
+}
+
+#define cbus_send_bit(host, base, bit, set_to_input) _cbus_send_bit(host, bit, set_to_input)
+#define cbus_receive_bit(host, base) _cbus_receive_bit(host)
+
+#endif
+
+static int cbus_transfer(struct cbus_host *host, int dev, int reg, int data)
+{
+       int i;
+       int is_read = 0;
+       unsigned long flags;
+       u32 base;
+
+#ifdef CONFIG_ARCH_OMAP1
+       base = (u32) io_p2v(OMAP_MPUIO_BASE);
+#else
+       base = 0;
+#endif
+
+       if (data < 0)
+               is_read = 1;
+
+       /* We don't want interrupts disturbing our transfer */
+       spin_lock_irqsave(&host->lock, flags);
+
+       /* Reset state and start of transfer, SEL stays down during transfer */
+       cbus_set_gpio_dataout(base, host->sel_gpio, 0);
+
+       /* Set the DAT pin to output */
+       cbus_set_gpio_direction(base, host->dat_gpio, 0);
+
+       /* Send the device address */
+       for (i = 3; i > 0; i--)
+               cbus_send_bit(host, base, dev & (1 << (i - 1)), 0);
+
+       /* Send the rw flag */
+       cbus_send_bit(host, base, is_read, 0);
+
+       /* Send the register address */
+       for (i = 5; i > 0; i--) {
+               int set_to_input = 0;
+
+               if (is_read && i == 1)
+                       set_to_input = 1;
+
+               cbus_send_bit(host, base, reg & (1 << (i - 1)), set_to_input);
+       }
+
+       if (!is_read) {
+               for (i = 16; i > 0; i--)
+                       cbus_send_bit(host, base, data & (1 << (i - 1)), 0);
+       } else {
+               cbus_set_gpio_dataout(base, host->clk_gpio, 1);
+               data = 0;
+
+               for (i = 16; i > 0; i--) {
+                       u8 bit = cbus_receive_bit(host, base);
+
+                       if (bit)
+                               data |= 1 << (i - 1);
+               }
+       }
+
+       /* Indicate end of transfer, SEL goes up until next transfer */
+       cbus_set_gpio_dataout(base, host->sel_gpio, 1);
+       cbus_set_gpio_dataout(base, host->clk_gpio, 1);
+       cbus_set_gpio_dataout(base, host->clk_gpio, 0);
+
+       spin_unlock_irqrestore(&host->lock, flags);
+
+       return is_read ? data : 0;
+}
+
+/*
+ * Read a given register from the device
+ */
+int cbus_read_reg(struct cbus_host *host, int dev, int reg)
+{
+       return cbus_host ? cbus_transfer(host, dev, reg, -1) : -ENODEV;
+}
+
+/*
+ * Write to a given register of the device
+ */
+int cbus_write_reg(struct cbus_host *host, int dev, int reg, u16 val)
+{
+       return cbus_host ? cbus_transfer(host, dev, reg, (int)val) : -ENODEV;
+}
+
+int __init cbus_bus_init(void)
+{
+       const struct omap_cbus_config * cbus_config;
+       struct cbus_host *chost;
+       int ret;
+
+       chost = kmalloc(sizeof (*chost), GFP_KERNEL);
+       if (chost == NULL)
+               return -ENOMEM;
+
+       memset(chost, 0, sizeof (*chost));
+
+       spin_lock_init(&chost->lock);
+
+       cbus_config = omap_get_config(OMAP_TAG_CBUS, struct omap_cbus_config);
+
+       if (cbus_config == NULL) {
+               printk(KERN_ERR "cbus: Unable to retrieve config data\n");
+               return -ENODATA;
+       }
+
+       chost->clk_gpio = cbus_config->clk_gpio;
+       chost->dat_gpio = cbus_config->dat_gpio;
+       chost->sel_gpio = cbus_config->sel_gpio;
+
+#ifdef CONFIG_ARCH_OMAP1
+       if (!OMAP_GPIO_IS_MPUIO(chost->clk_gpio) ||
+           !OMAP_GPIO_IS_MPUIO(chost->dat_gpio) ||
+           !OMAP_GPIO_IS_MPUIO(chost->sel_gpio)) {
+               printk(KERN_ERR "cbus: Only MPUIO pins supported\n");
+               ret = -ENODEV;
+               goto exit1;
+       }
+#endif
+
+       if ((ret = omap_request_gpio(chost->clk_gpio)) < 0)
+               goto exit1;
+
+       if ((ret = omap_request_gpio(chost->dat_gpio)) < 0)
+               goto exit2;
+
+       if ((ret = omap_request_gpio(chost->sel_gpio)) < 0)
+               goto exit3;
+
+       omap_set_gpio_dataout(chost->clk_gpio, 0);
+       omap_set_gpio_dataout(chost->sel_gpio, 1);
+
+       omap_set_gpio_direction(chost->clk_gpio, 0);
+       omap_set_gpio_direction(chost->dat_gpio, 1);
+       omap_set_gpio_direction(chost->sel_gpio, 0);
+
+       omap_set_gpio_dataout(chost->clk_gpio, 1);
+       omap_set_gpio_dataout(chost->clk_gpio, 0);
+
+       cbus_host = chost;
+
+       return 0;
+exit3:
+       omap_free_gpio(chost->dat_gpio);
+exit2:
+       omap_free_gpio(chost->clk_gpio);
+exit1:
+       kfree(chost);
+       return ret;
+}
+
+subsys_initcall(cbus_bus_init);
+
+EXPORT_SYMBOL(cbus_host);
+EXPORT_SYMBOL(cbus_read_reg);
+EXPORT_SYMBOL(cbus_write_reg);
+
+MODULE_DESCRIPTION("CBUS serial protocol");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Juha Yrjölä, David Weinehall, and Mikko Ylinen");
diff --git a/drivers/cbus/cbus.h b/drivers/cbus/cbus.h
new file mode 100644 (file)
index 0000000..957224c
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * 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 */
diff --git a/drivers/cbus/retu-pwrbutton.c b/drivers/cbus/retu-pwrbutton.c
new file mode 100644 (file)
index 0000000..7a7469f
--- /dev/null
@@ -0,0 +1,119 @@
+/**
+ * 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 "retu.h"
+
+#define RETU_STATUS_PWRONX     (1 << 5)
+
+#define PWRBTN_DELAY           20
+#define PWRBTN_UP              0
+#define PWRBTN_PRESSED         1
+
+static int pwrbtn_state;
+static struct input_dev *pwrbtn_dev;
+static struct timer_list pwrbtn_timer;
+
+static void retubutton_timer_func(unsigned long arg)
+{
+       int state;
+
+       if (retu_read_reg(RETU_REG_STATUS) & RETU_STATUS_PWRONX)
+               state = PWRBTN_UP;
+       else
+               state = PWRBTN_PRESSED;
+
+       if (pwrbtn_state != state) {
+               input_report_key(pwrbtn_dev, KEY_POWER, state);
+               pwrbtn_state = state;
+       }
+}
+
+/**
+ * Interrupt function is called whenever power button key is pressed
+ * or released.
+ */
+static void retubutton_irq(unsigned long arg)
+{
+       retu_ack_irq(RETU_INT_PWR);
+       mod_timer(&pwrbtn_timer, jiffies + msecs_to_jiffies(PWRBTN_DELAY));
+}
+
+/**
+ * Init function.
+ * Allocates interrupt for power button and registers itself to input layer.
+ */
+static int __init retubutton_init(void)
+{
+       int irq;
+
+       printk(KERN_INFO "Retu power button driver initialized\n");
+       irq = RETU_INT_PWR;
+
+       init_timer(&pwrbtn_timer);
+       pwrbtn_timer.function = retubutton_timer_func;
+
+       if (retu_request_irq(irq, &retubutton_irq, 0, "PwrOnX") < 0) {
+               printk(KERN_ERR "%s@%s: Cannot allocate irq\n",
+                      __FUNCTION__, __FILE__);
+               return -EBUSY;
+       }
+
+       pwrbtn_dev = input_allocate_device();
+       if (!pwrbtn_dev)
+               return -ENOMEM;
+       
+       pwrbtn_dev->evbit[0] = BIT(EV_KEY);
+       pwrbtn_dev->keybit[LONG(KEY_POWER)] = BIT(KEY_POWER);
+       pwrbtn_dev->name = "retu-pwrbutton";
+
+       input_register_device(pwrbtn_dev);
+
+       return 0;
+}
+
+/**
+ * Cleanup function which is called when driver is unloaded
+ */
+static void __exit retubutton_exit(void)
+{
+       retu_free_irq(RETU_INT_PWR);
+       del_timer_sync(&pwrbtn_timer);
+       input_unregister_device(pwrbtn_dev);
+}
+
+module_init(retubutton_init);
+module_exit(retubutton_exit);
+
+MODULE_DESCRIPTION("Retu Power Button");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ari Saastamoinen");
diff --git a/drivers/cbus/retu-rtc.c b/drivers/cbus/retu-rtc.c
new file mode 100644 (file)
index 0000000..b36fd06
--- /dev/null
@@ -0,0 +1,477 @@
+/**
+ * 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 device_driver retu_rtc_driver;
+
+static void retu_rtca_disable(void)
+{
+       retu_disable_irq(RETU_INT_RTCA);
+       retu_rtc_alarm_expired = 1;
+       retu_rtc_barrier();
+       retu_write_reg(RETU_REG_RTCHMAR, (24 << 8) | 60);
+}
+
+static void retu_rtca_expired(struct work_struct *unused)
+{
+       retu_rtca_disable();
+       sysfs_notify(&retu_rtc_driver.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(&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");
diff --git a/drivers/cbus/retu-user.c b/drivers/cbus/retu-user.c
new file mode 100644 (file)
index 0000000..74a7d61
--- /dev/null
@@ -0,0 +1,423 @@
+/**
+ * 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");
diff --git a/drivers/cbus/retu-wdt.c b/drivers/cbus/retu-wdt.c
new file mode 100644 (file)
index 0000000..63194d8
--- /dev/null
@@ -0,0 +1,198 @@
+/**
+ * drivers/cbus/retu-wdt.c
+ *
+ * Driver for Retu watchdog
+ *
+ * Copyright (C) 2004, 2005 Nokia Corporation
+ *
+ * Written by Amit Kucheria <amit.kucheria@nokia.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/init.h>
+
+#include <linux/completion.h>
+#include <linux/errno.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+
+#include "cbus.h"
+#include "retu.h"
+
+/* Watchdog timeout in seconds */
+#define RETU_WDT_MIN_TIMER 0
+#define RETU_WDT_DEFAULT_TIMER 32
+#define RETU_WDT_MAX_TIMER 63
+
+static struct completion retu_wdt_completion;
+static DECLARE_MUTEX(retu_wdt_mutex);  /* Avoid simultaneous writes to watchdog register */
+
+static unsigned int period_val = RETU_WDT_DEFAULT_TIMER;       /* Current period of watchdog */
+static int counter_param = RETU_WDT_MAX_TIMER;
+
+static int retu_modify_counter(unsigned int new)
+{
+       int ret = 0;
+
+       if (new < RETU_WDT_MIN_TIMER || new > RETU_WDT_MAX_TIMER)
+               return -EINVAL;
+
+       down_interruptible(&retu_wdt_mutex);
+
+       period_val = new;
+       retu_write_reg(RETU_REG_WATCHDOG, (u16)period_val);
+
+       up(&retu_wdt_mutex);
+       return ret;
+}
+
+static ssize_t retu_wdt_period_show(struct device *dev, struct device_attribute *attr,
+                                   char *buf)
+{
+       /* Show current max counter */
+       return sprintf(buf, "%u\n", (u16)period_val);
+}
+
+static ssize_t retu_wdt_period_store(struct device *dev, struct device_attribute *attr,
+                                    const char *buf, size_t count)
+{
+       unsigned int new_period;
+       int ret;
+
+       if (sscanf(buf, "%u", &new_period) != 1) {
+               printk(KERN_ALERT "retu_wdt_period_store: Invalid input\n");
+               return -EINVAL;
+       }
+
+       ret = retu_modify_counter(new_period);
+       if (ret < 0)
+               return ret;
+
+       return strnlen(buf, count);
+}
+
+static ssize_t retu_wdt_counter_show(struct device *dev, struct device_attribute *attr,
+                                    char *buf)
+{
+       u16 counter;
+
+       /* Show current value in watchdog counter */
+       counter = retu_read_reg(RETU_REG_WATCHDOG);
+
+       /* Only the 5 LSB are important */
+       return snprintf(buf, PAGE_SIZE, "%u\n", (counter & 0x3F));
+}
+
+static DEVICE_ATTR(period, S_IRUGO | S_IWUSR, retu_wdt_period_show, \
+                   retu_wdt_period_store);
+static DEVICE_ATTR(counter, S_IRUGO, retu_wdt_counter_show, NULL);
+
+static int __devinit retu_wdt_probe(struct device *dev)
+{
+       int ret;
+
+       ret = device_create_file(dev, &dev_attr_period);
+       if (ret) {
+               printk(KERN_ERR "retu_wdt_probe: Error creating sys device file: period\n");
+               return ret;
+       }
+
+       ret = device_create_file(dev, &dev_attr_counter);
+       if (ret) {
+               device_remove_file(dev, &dev_attr_period);
+               printk(KERN_ERR "retu_wdt_probe: Error creating sys device file: counter\n");
+       }
+
+       return ret;
+}
+
+static int __devexit retu_wdt_remove(struct device *dev)
+{
+       device_remove_file(dev, &dev_attr_period);
+       device_remove_file(dev, &dev_attr_counter);
+       return 0;
+}
+
+static void retu_wdt_device_release(struct device *dev)
+{
+       complete(&retu_wdt_completion);
+}
+
+static struct platform_device retu_wdt_device = {
+       .name = "retu-watchdog",
+       .id = -1,
+       .dev = {
+               .release = retu_wdt_device_release,
+       },
+};
+
+static struct device_driver retu_wdt_driver = {
+       .name = "retu-watchdog",
+       .bus = &platform_bus_type,
+       .probe = retu_wdt_probe,
+       .remove = __devexit_p(retu_wdt_remove),
+};
+
+static int __init retu_wdt_init(void)
+{
+       int ret;
+
+       init_completion(&retu_wdt_completion);
+
+       ret = driver_register(&retu_wdt_driver);
+       if (ret)
+               return ret;
+
+       ret = platform_device_register(&retu_wdt_device);
+       if (ret)
+               goto exit1;
+
+       /* passed as module parameter? */
+       ret = retu_modify_counter(counter_param);
+       if (ret == -EINVAL) {
+               ret = retu_modify_counter(RETU_WDT_DEFAULT_TIMER);
+               printk(KERN_INFO
+                      "retu_wdt_init: Intializing to default value\n");
+       }
+
+       printk(KERN_INFO "Retu watchdog driver initialized\n");
+       return ret;
+
+exit1:
+       driver_unregister(&retu_wdt_driver);
+       wait_for_completion(&retu_wdt_completion);
+
+       return ret;
+}
+
+static void __exit retu_wdt_exit(void)
+{
+       platform_device_unregister(&retu_wdt_device);
+       driver_unregister(&retu_wdt_driver);
+
+       wait_for_completion(&retu_wdt_completion);
+}
+
+module_init(retu_wdt_init);
+module_exit(retu_wdt_exit);
+module_param(counter_param, int, 0);
+
+MODULE_DESCRIPTION("Retu WatchDog");
+MODULE_AUTHOR("Amit Kucheria");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/cbus/retu.c b/drivers/cbus/retu.c
new file mode 100644 (file)
index 0000000..417273a
--- /dev/null
@@ -0,0 +1,454 @@
+/**
+ * drivers/cbus/retu.c
+ *
+ * Support functions for Retu ASIC
+ *
+ * Copyright (C) 2004, 2005 Nokia Corporation
+ *
+ * Written by Juha Yrjölä <juha.yrjola@nokia.com>,
+ *           David Weinehall <david.weinehall@nokia.com>, and
+ *           Mikko Ylinen <mikko.k.ylinen@nokia.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/miscdevice.h>
+#include <linux/poll.h>
+#include <linux/fs.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+
+#include <asm/uaccess.h>
+
+#include <asm/arch/mux.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/board.h>
+
+#include "cbus.h"
+#include "retu.h"
+
+#define RETU_ID                        0x01
+#define PFX                    "retu: "
+
+static int retu_initialized;
+static int retu_irq_pin;
+static int retu_is_vilma;
+
+static struct tasklet_struct retu_tasklet;
+spinlock_t retu_lock = SPIN_LOCK_UNLOCKED;
+
+static struct completion device_release;
+
+struct retu_irq_handler_desc {
+       int (*func)(unsigned long);
+       unsigned long arg;
+       char name[8];
+};
+
+static struct retu_irq_handler_desc retu_irq_handlers[MAX_RETU_IRQ_HANDLERS];
+
+/**
+ * retu_read_reg - Read a value from a register in Retu
+ * @reg: the register to read from
+ *
+ * This function returns the contents of the specified register
+ */
+int retu_read_reg(int reg)
+{
+       BUG_ON(!retu_initialized);
+       return cbus_read_reg(cbus_host, RETU_ID, reg);
+}
+
+/**
+ * retu_write_reg - Write a value to a register in Retu
+ * @reg: the register to write to
+ * @reg: the value to write to the register
+ *
+ * This function writes a value to the specified register
+ */
+void retu_write_reg(int reg, u16 val)
+{
+       BUG_ON(!retu_initialized);
+       cbus_write_reg(cbus_host, RETU_ID, reg, val);
+}
+
+void retu_set_clear_reg_bits(int reg, u16 set, u16 clear)
+{
+       unsigned long flags;
+       u16 w;
+
+       spin_lock_irqsave(&retu_lock, flags);
+       w = retu_read_reg(reg);
+       w &= ~clear;
+       w |= set;
+       retu_write_reg(reg, w);
+       spin_unlock_irqrestore(&retu_lock, flags);
+}
+
+#define ADC_MAX_CHAN_NUMBER    13
+
+int retu_read_adc(int channel)
+{
+       unsigned long flags;
+       int res;
+
+       if (channel < 0 || channel > ADC_MAX_CHAN_NUMBER)
+               return -EINVAL;
+
+       spin_lock_irqsave(&retu_lock, flags);
+       /* Select the channel and read result */
+       retu_write_reg(RETU_REG_ADCR, channel << 10);
+       res = retu_read_reg(RETU_REG_ADCR) & 0x3ff;
+       /* Unlock retu */
+       spin_unlock_irqrestore(&retu_lock, flags);
+
+       return res;
+}
+
+
+static u16 retu_disable_bogus_irqs(u16 mask)
+{
+       int i;
+
+       for (i = 0; i < MAX_RETU_IRQ_HANDLERS; i++) {
+               if (mask & (1 << i))
+                       continue;
+               if (retu_irq_handlers[i].func != NULL)
+                       continue;
+               /* an IRQ was enabled but we don't have a handler for it */
+               printk(KERN_INFO PFX "disabling bogus IRQ %d\n", i);
+               mask |= (1 << i);
+       }
+       return mask;
+}
+
+/*
+ * Disable given RETU interrupt
+ */
+void retu_disable_irq(int id)
+{
+       unsigned long flags;
+       u16 mask;
+
+       spin_lock_irqsave(&retu_lock, flags);
+       mask = retu_read_reg(RETU_REG_IMR);
+       mask |= 1 << id;
+       mask = retu_disable_bogus_irqs(mask);
+       retu_write_reg(RETU_REG_IMR, mask);
+       spin_unlock_irqrestore(&retu_lock, flags);
+}
+
+/*
+ * Enable given RETU interrupt
+ */
+void retu_enable_irq(int id)
+{
+       unsigned long flags;
+       u16 mask;
+
+       if (id == 3) {
+               printk("Enabling Retu IRQ %d\n", id);
+               dump_stack();
+       }
+       spin_lock_irqsave(&retu_lock, flags);
+       mask = retu_read_reg(RETU_REG_IMR);
+       mask &= ~(1 << id);
+       mask = retu_disable_bogus_irqs(mask);
+       retu_write_reg(RETU_REG_IMR, mask);
+       spin_unlock_irqrestore(&retu_lock, flags);
+}
+
+/*
+ * Acknowledge given RETU interrupt
+ */
+void retu_ack_irq(int id)
+{
+       retu_write_reg(RETU_REG_IDR, 1 << id);
+}
+
+/*
+ * RETU interrupt handler. Only schedules the tasklet.
+ */
+static irqreturn_t retu_irq_handler(int irq, void *dev_id)
+{
+       tasklet_schedule(&retu_tasklet);
+       return IRQ_HANDLED;
+}
+
+/*
+ * Tasklet handler
+ */
+static void retu_tasklet_handler(unsigned long data)
+{
+       struct retu_irq_handler_desc *hnd;
+       u16 id;
+       u16 im;
+       int i;
+
+       for (;;) {
+               id = retu_read_reg(RETU_REG_IDR);
+               im = ~retu_read_reg(RETU_REG_IMR);
+               id &= im;
+
+               if (!id)
+                       break;
+
+               for (i = 0; id != 0; i++, id >>= 1) {
+                       if (!(id & 1))
+                               continue;
+                       hnd = &retu_irq_handlers[i];
+                       if (hnd->func == NULL) {
+                               /* Spurious retu interrupt - disable and ack it */
+                               printk(KERN_INFO "Spurious Retu interrupt "
+                                                "(id %d)\n", i);
+                               retu_disable_irq(i);
+                               retu_ack_irq(i);
+                               continue;
+                       }
+                       hnd->func(hnd->arg);
+                       /*
+                        * Don't acknowledge the interrupt here
+                        * It must be done explicitly
+                        */
+               }
+       }
+}
+
+/*
+ * Register the handler for a given RETU interrupt source.
+ */
+int retu_request_irq(int id, void *irq_handler, unsigned long arg, char *name)
+{
+       struct retu_irq_handler_desc *hnd;
+
+       if (irq_handler == NULL || id >= MAX_RETU_IRQ_HANDLERS ||
+           name == NULL) {
+               printk(KERN_ERR PFX "Invalid arguments to %s\n",
+                      __FUNCTION__);
+               return -EINVAL;
+       }
+       hnd = &retu_irq_handlers[id];
+       if (hnd->func != NULL) {
+               printk(KERN_ERR PFX "IRQ %d already reserved\n", id);
+               return -EBUSY;
+       }
+       printk(KERN_INFO PFX "Registering interrupt %d for device %s\n",
+              id, name);
+       hnd->func = irq_handler;
+       hnd->arg = arg;
+       strlcpy(hnd->name, name, sizeof(hnd->name));
+
+       retu_ack_irq(id);
+       retu_enable_irq(id);
+
+       return 0;
+}
+
+/*
+ * Unregister the handler for a given RETU interrupt source.
+ */
+void retu_free_irq(int id)
+{
+       struct retu_irq_handler_desc *hnd;
+
+       if (id >= MAX_RETU_IRQ_HANDLERS) {
+               printk(KERN_ERR PFX "Invalid argument to %s\n",
+                      __FUNCTION__);
+               return;
+       }
+       hnd = &retu_irq_handlers[id];
+       if (hnd->func == NULL) {
+               printk(KERN_ERR PFX "IRQ %d already freed\n", id);
+               return;
+       }
+
+       retu_disable_irq(id);
+       hnd->func = NULL;
+}
+
+/**
+ * retu_power_off - Shut down power to system
+ *
+ * This function puts the system in power off state
+ */
+static void retu_power_off(void)
+{
+       /* Ignore power button state */
+       retu_write_reg(RETU_REG_CC1, retu_read_reg(RETU_REG_CC1) | 2);
+       /* Expire watchdog immediately */
+       retu_write_reg(RETU_REG_WATCHDOG, 0);
+       /* Wait for poweroff*/
+       for (;;);
+}
+
+/**
+ * retu_probe - Probe for Retu ASIC
+ * @dev: the Retu device
+ *
+ * Probe for the Retu ASIC and allocate memory
+ * for its device-struct if found
+ */
+static int __devinit retu_probe(struct device *dev)
+{
+       const struct omap_em_asic_bb5_config * em_asic_config;
+       int rev, ret;
+
+       /* Prepare tasklet */
+       tasklet_init(&retu_tasklet, retu_tasklet_handler, 0);
+
+       em_asic_config = omap_get_config(OMAP_TAG_EM_ASIC_BB5,
+                                        struct omap_em_asic_bb5_config);
+       if (em_asic_config == NULL) {
+               printk(KERN_ERR PFX "Unable to retrieve config data\n");
+               return -ENODATA;
+       }
+
+       retu_irq_pin = em_asic_config->retu_irq_gpio;
+
+       if ((ret = omap_request_gpio(retu_irq_pin)) < 0) {
+               printk(KERN_ERR PFX "Unable to reserve IRQ GPIO\n");
+               return ret;
+       }
+
+       /* Set the pin as input */
+       omap_set_gpio_direction(retu_irq_pin, 1);
+
+       /* Rising edge triggers the IRQ */
+       set_irq_type(OMAP_GPIO_IRQ(retu_irq_pin), IRQT_RISING);
+
+       retu_initialized = 1;
+
+       rev = retu_read_reg(RETU_REG_ASICR) & 0xff;
+       if (rev & (1 << 7))
+               retu_is_vilma = 1;
+
+       printk(KERN_INFO "%s v%d.%d found\n", retu_is_vilma ? "Vilma" : "Retu",
+              (rev >> 4) & 0x07, rev & 0x0f);
+
+       /* Mask all RETU interrupts */
+       retu_write_reg(RETU_REG_IMR, 0xffff);
+
+       ret = request_irq(OMAP_GPIO_IRQ(retu_irq_pin), retu_irq_handler, 0,
+                         "retu", 0);
+       if (ret < 0) {
+               printk(KERN_ERR PFX "Unable to register IRQ handler\n");
+               omap_free_gpio(retu_irq_pin);
+               return ret;
+       }
+       set_irq_wake(OMAP_GPIO_IRQ(retu_irq_pin), 1);
+
+       /* Register power off function */
+       pm_power_off = retu_power_off;
+
+#ifdef CONFIG_CBUS_RETU_USER
+       /* Initialize user-space interface */
+       if (retu_user_init() < 0) {
+               printk(KERN_ERR "Unable to initialize driver\n");
+               free_irq(OMAP_GPIO_IRQ(retu_irq_pin), 0);
+               omap_free_gpio(retu_irq_pin);
+               return ret;
+       }
+#endif
+
+       return 0;
+}
+
+static int retu_remove(struct device *dev)
+{
+#ifdef CONFIG_CBUS_RETU_USER
+       retu_user_cleanup();
+#endif
+       /* Mask all RETU interrupts */
+       retu_write_reg(RETU_REG_IMR, 0xffff);
+       free_irq(OMAP_GPIO_IRQ(retu_irq_pin), 0);
+       omap_free_gpio(retu_irq_pin);
+       tasklet_kill(&retu_tasklet);
+
+       return 0;
+}
+
+static void retu_device_release(struct device *dev)
+{
+       complete(&device_release);
+}
+
+static struct device_driver retu_driver = {
+       .name           = "retu",
+       .bus            = &platform_bus_type,
+       .probe          = retu_probe,
+       .remove         = retu_remove,
+};
+
+static struct platform_device retu_device = {
+       .name           = "retu",
+       .id             = -1,
+       .dev = {
+               .release = retu_device_release,
+       }
+};
+
+/**
+ * retu_init - initialise Retu driver
+ *
+ * Initialise the Retu driver and return 0 if everything worked ok
+ */
+static int __init retu_init(void)
+{
+       int ret = 0;
+
+       printk(KERN_INFO "Retu/Vilma driver initialising\n");
+
+       init_completion(&device_release);
+
+       if ((ret = driver_register(&retu_driver)) < 0)
+               return ret;
+
+       if ((ret = platform_device_register(&retu_device)) < 0) {
+               driver_unregister(&retu_driver);
+               return ret;
+       }
+       return 0;
+}
+
+/*
+ * Cleanup
+ */
+static void __exit retu_exit(void)
+{
+       platform_device_unregister(&retu_device);
+       driver_unregister(&retu_driver);
+       wait_for_completion(&device_release);
+}
+
+EXPORT_SYMBOL(retu_request_irq);
+EXPORT_SYMBOL(retu_free_irq);
+EXPORT_SYMBOL(retu_enable_irq);
+EXPORT_SYMBOL(retu_disable_irq);
+EXPORT_SYMBOL(retu_ack_irq);
+EXPORT_SYMBOL(retu_read_reg);
+EXPORT_SYMBOL(retu_write_reg);
+
+subsys_initcall(retu_init);
+module_exit(retu_exit);
+
+MODULE_DESCRIPTION("Retu ASIC control");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Juha Yrjölä, David Weinehall, and Mikko Ylinen");
diff --git a/drivers/cbus/retu.h b/drivers/cbus/retu.h
new file mode 100644 (file)
index 0000000..02be6d4
--- /dev/null
@@ -0,0 +1,73 @@
+/**
+ * drivers/cbus/retu.h
+ *
+ * Copyright (C) 2004, 2005 Nokia Corporation
+ *
+ * Written by Juha Yrjölä <juha.yrjola@nokia.com> and
+ *           David Weinehall <david.weinehall@nokia.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __DRIVERS_CBUS_RETU_H
+#define __DRIVERS_CBUS_RETU_H
+
+#include <linux/types.h>
+
+/* Registers */
+#define RETU_REG_ASICR         0x00    /* ASIC ID & revision */
+#define RETU_REG_IDR           0x01    /* Interrupt ID */
+#define RETU_REG_IMR           0x02    /* Interrupt mask */
+#define RETU_REG_RTCDSR                0x03    /* RTC seconds register */
+#define RETU_REG_RTCHMR                0x04    /* RTC hours and minutes register */
+#define RETU_REG_RTCHMAR       0x05    /* RTC hours and minutes alarm and time set register */
+#define RETU_REG_RTCCALR       0x06    /* RTC calibration register */
+#define RETU_REG_ADCR          0x08    /* ADC result */
+#define RETU_REG_CC1           0x0d    /* Common control register 1 */
+#define RETU_REG_CC2           0x0e    /* Common control register 2 */
+#define RETU_REG_CTRL_CLR      0x0f    /* Regulator clear register */
+#define RETU_REG_CTRL_SET      0x10    /* Regulator set register */
+#define RETU_REG_STATUS                0x16    /* Status register */
+#define RETU_REG_WATCHDOG      0x17    /* Watchdog register */
+#define RETU_REG_MAX           0x1f
+
+/* Interrupt sources */
+#define RETU_INT_PWR           0
+#define RETU_INT_CHAR          1
+#define RETU_INT_RTCS          2
+#define RETU_INT_RTCM          3
+#define RETU_INT_RTCD          4
+#define RETU_INT_RTCA          5
+#define RETU_INT_ADCS          8
+
+#define        MAX_RETU_IRQ_HANDLERS   16
+
+int retu_read_reg(int reg);
+void retu_write_reg(int reg, u16 val);
+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 */
diff --git a/drivers/cbus/tahvo-usb.c b/drivers/cbus/tahvo-usb.c
new file mode 100644 (file)
index 0000000..934400f
--- /dev/null
@@ -0,0 +1,745 @@
+/**
+ * drivers/cbus/tahvo-usb.c
+ *
+ * Tahvo USB transeiver
+ *
+ * Copyright (C) 2005-2006 Nokia Corporation
+ *
+ * Parts copied from drivers/i2c/chips/isp1301_omap.c
+ * Copyright (C) 2004 Texas Instruments
+ * Copyright (C) 2004 David Brownell
+ *
+ * Written by Juha Yrjölä <juha.yrjola@nokia.com>,
+ *           Tony Lindgren <tony@atomide.com>, and
+ *           Timo Teräs <timo.teras@nokia.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/usb_ch9.h>
+#include <linux/usb_gadget.h>
+#include <linux/usb.h>
+#include <linux/usb/otg.h>
+#include <linux/i2c.h>
+#include <linux/workqueue.h>
+#include <linux/kobject.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+
+#include <asm/irq.h>
+#include <asm/arch/usb.h>
+
+#include "cbus.h"
+#include "tahvo.h"
+
+#define DRIVER_NAME     "tahvo-usb"
+
+#define USBR_SLAVE_CONTROL     (1 << 8)
+#define USBR_VPPVIO_SW         (1 << 7)
+#define USBR_SPEED             (1 << 6)
+#define USBR_REGOUT            (1 << 5)
+#define USBR_MASTER_SW2                (1 << 4)
+#define USBR_MASTER_SW1                (1 << 3)
+#define USBR_SLAVE_SW          (1 << 2)
+#define USBR_NSUSPEND          (1 << 1)
+#define USBR_SEMODE            (1 << 0)
+
+/* bits in OTG_CTRL_REG */
+
+/* Bits that are controlled by OMAP OTG and are read-only */
+#define OTG_CTRL_OMAP_MASK     (OTG_PULLDOWN|OTG_PULLUP|OTG_DRV_VBUS|\
+                               OTG_PD_VBUS|OTG_PU_VBUS|OTG_PU_ID)
+/* Bits that are controlled by transceiver */
+#define OTG_CTRL_XCVR_MASK     (OTG_ASESSVLD|OTG_BSESSEND|\
+                               OTG_BSESSVLD|OTG_VBUSVLD|OTG_ID)
+/* Bits that are controlled by system */
+#define OTG_CTRL_SYS_MASK      (OTG_A_BUSREQ|OTG_A_SETB_HNPEN|OTG_B_BUSREQ|\
+                               OTG_B_HNPEN|OTG_BUSDROP)
+
+#if defined(CONFIG_USB_OHCI_HCD) && !defined(CONFIG_USB_OTG)
+#error tahvo-otg.c does not work with OCHI yet!
+#endif
+
+#define TAHVO_MODE_HOST                0
+#define TAHVO_MODE_PERIPHERAL  1
+
+#ifdef CONFIG_USB_OTG
+#define TAHVO_MODE(tu)         (tu)->tahvo_mode
+#elif defined(CONFIG_USB_GADGET_OMAP)
+#define TAHVO_MODE(tu)         TAHVO_MODE_PERIPHERAL
+#else
+#define TAHVO_MODE(tu)         TAHVO_MODE_HOST
+#endif
+
+struct tahvo_usb {
+       struct platform_device *pt_dev;
+       struct otg_transceiver otg;
+       int vbus_state;
+       struct work_struct irq_work;
+       struct mutex serialize;
+#ifdef CONFIG_USB_OTG
+       int tahvo_mode;
+#endif
+};
+static struct platform_device tahvo_usb_device;
+
+/*
+ * ---------------------------------------------------------------------------
+ * OTG related functions
+ *
+ * These shoud be separated into omap-otg.c driver module, as they are used
+ * by various transceivers. These functions are needed in the UDC-only case 
+ * as well. These functions are copied from GPL isp1301_omap.c
+ * ---------------------------------------------------------------------------
+ */
+static struct platform_device *tahvo_otg_dev;
+
+static irqreturn_t omap_otg_irq(int irq, void *arg)
+{
+       struct platform_device *otg_dev = (struct platform_device *) arg;
+       struct tahvo_usb *tu = (struct tahvo_usb *) otg_dev->dev.driver_data;
+       u16 otg_irq;
+
+       otg_irq = OTG_IRQ_SRC_REG;
+       if (otg_irq & OPRT_CHG) {
+               OTG_IRQ_SRC_REG = OPRT_CHG;
+       } else if (otg_irq & B_SRP_TMROUT) {
+               OTG_IRQ_SRC_REG = B_SRP_TMROUT;
+       } else if (otg_irq & B_HNP_FAIL) {
+               OTG_IRQ_SRC_REG = B_HNP_FAIL;
+       } else if (otg_irq & A_SRP_DETECT) {
+               OTG_IRQ_SRC_REG = A_SRP_DETECT;
+       } else if (otg_irq & A_REQ_TMROUT) {
+               OTG_IRQ_SRC_REG = A_REQ_TMROUT;
+       } else if (otg_irq & A_VBUS_ERR) {
+               OTG_IRQ_SRC_REG = A_VBUS_ERR;
+       } else if (otg_irq & DRIVER_SWITCH) {
+               if ((!(OTG_CTRL_REG & OTG_DRIVER_SEL)) &&
+                  tu->otg.host && tu->otg.state == OTG_STATE_A_HOST) {
+                       /* role is host */
+                       usb_bus_start_enum(tu->otg.host,
+                                          tu->otg.host->otg_port);
+               }
+               OTG_IRQ_SRC_REG = DRIVER_SWITCH;
+       } else
+               return IRQ_NONE;
+
+       return IRQ_HANDLED;
+
+}
+
+static int omap_otg_init(void)
+{
+
+#ifdef CONFIG_USB_OTG
+       if (!tahvo_otg_dev) {
+               printk("tahvo-usb: no tahvo_otg_dev\n");
+               return -ENODEV;
+       }
+#endif
+       OTG_SYSCON_1_REG &= ~OTG_IDLE_EN;
+       udelay(100);
+
+       /* some of these values are board-specific... */
+       OTG_SYSCON_2_REG |= OTG_EN
+               /* for B-device: */
+               | SRP_GPDATA            /* 9msec Bdev D+ pulse */
+               | SRP_GPDVBUS           /* discharge after VBUS pulse */
+               // | (3 << 24)          /* 2msec VBUS pulse */
+               /* for A-device: */
+               | (0 << 20)             /* 200ms nominal A_WAIT_VRISE timer */
+               | SRP_DPW               /* detect 167+ns SRP pulses */
+               | SRP_DATA | SRP_VBUS;  /* accept both kinds of SRP pulse */
+
+       OTG_IRQ_EN_REG = DRIVER_SWITCH | OPRT_CHG
+                       | B_SRP_TMROUT | B_HNP_FAIL
+                       | A_VBUS_ERR | A_SRP_DETECT | A_REQ_TMROUT;
+       OTG_SYSCON_2_REG |= OTG_EN;
+
+       return 0;
+}
+
+static int omap_otg_probe(struct device *dev)
+{
+       int ret;
+
+       tahvo_otg_dev = to_platform_device(dev);
+       ret = omap_otg_init();
+       if (ret != 0) {
+               printk(KERN_ERR "tahvo-usb: omap_otg_init failed\n");
+               return ret;
+       }
+
+       return request_irq(tahvo_otg_dev->resource[1].start,
+                          omap_otg_irq, IRQF_DISABLED, DRIVER_NAME,
+                          &tahvo_usb_device);
+}
+
+static int omap_otg_remove(struct device *dev)
+{
+       free_irq(tahvo_otg_dev->resource[1].start, &tahvo_usb_device);
+       tahvo_otg_dev = NULL;
+
+       return 0;
+}
+
+struct device_driver omap_otg_driver = {
+       .name           = "omap_otg",
+       .bus            = &platform_bus_type,
+       .probe          = omap_otg_probe,
+       .remove         = omap_otg_remove,
+};
+
+/*
+ * ---------------------------------------------------------------------------
+ * Tahvo related functions
+ * These are Nokia proprietary code, except for the OTG register settings,
+ * which are copied from isp1301.c
+ * ---------------------------------------------------------------------------
+ */
+static ssize_t vbus_state_show(struct device *device,
+                              struct device_attribute *attr, char *buf)
+{
+       struct tahvo_usb *tu = (struct tahvo_usb*) device->driver_data;
+       return sprintf(buf, "%d\n", tu->vbus_state);
+}
+static DEVICE_ATTR(vbus_state, 0444, vbus_state_show, NULL);
+
+int vbus_active = 0;
+
+#if 0
+
+static int host_suspend(struct tahvo_usb *tu)
+{
+       struct device   *dev;
+
+       if (!tu->otg.host)
+               return -ENODEV;
+
+       /* Currently ASSUMES only the OTG port matters;
+        * other ports could be active...
+        */
+       dev = tu->otg.host->controller;
+       return dev->driver->suspend(dev, PMSG_SUSPEND);
+}
+
+static int host_resume(struct tahvo_usb *tu)
+{
+       struct device   *dev;
+
+       if (!tu->otg.host)
+               return -ENODEV;
+
+       dev = tu->otg.host->controller;
+       return dev->driver->resume(dev);
+}
+
+#else
+
+static int host_suspend(struct tahvo_usb *tu)
+{
+       return 0;
+}
+
+static int host_resume(struct tahvo_usb *tu)
+{
+       return 0;
+}
+
+#endif
+
+static void check_vbus_state(struct tahvo_usb *tu)
+{
+       int reg, prev_state;
+
+       reg = tahvo_read_reg(TAHVO_REG_IDSR);
+       if (reg & 0x01) {
+               vbus_active = 1;
+               switch (tu->otg.state) {
+               case OTG_STATE_B_IDLE:
+                       /* Enable the gadget driver */
+                       if (tu->otg.gadget)
+                               usb_gadget_vbus_connect(tu->otg.gadget);
+                       /* Set B-session valid and not B-sessio ended to indicate
+                        * Vbus to be ok. */
+                       OTG_CTRL_REG = (OTG_CTRL_REG & ~OTG_BSESSEND) | OTG_BSESSVLD;
+
+                       tu->otg.state = OTG_STATE_B_PERIPHERAL;
+                       break;
+               case OTG_STATE_A_IDLE:
+                       /* Session is now valid assuming the USB hub is driving Vbus */
+                       tu->otg.state = OTG_STATE_A_HOST;
+                       host_resume(tu);
+                       break;
+               default:
+                       break;
+               }
+               printk("USB cable connected\n");
+       } else {
+               switch (tu->otg.state) {
+               case OTG_STATE_B_PERIPHERAL:
+                       if (tu->otg.gadget)
+                               usb_gadget_vbus_disconnect(tu->otg.gadget);
+                       tu->otg.state = OTG_STATE_B_IDLE;
+                       break;
+               case OTG_STATE_A_HOST:
+                       tu->otg.state = OTG_STATE_A_IDLE;
+                       break;
+               default:
+                       break;
+               }
+               printk("USB cable disconnected\n");
+               vbus_active = 0;
+       }
+
+       prev_state = tu->vbus_state;
+       tu->vbus_state = reg & 0x01;
+       if (prev_state != tu->vbus_state)
+               sysfs_notify(&tu->pt_dev->dev.kobj, NULL, "vbus_state");
+}
+
+static void tahvo_usb_become_host(struct tahvo_usb *tu)
+{
+       u32 l;
+
+       /* Clear system and transceiver controlled bits
+        * also mark the A-session is always valid */
+       omap_otg_init();
+
+       l = OTG_CTRL_REG;
+       l &= ~(OTG_CTRL_XCVR_MASK|OTG_CTRL_SYS_MASK);
+       l |= OTG_ASESSVLD;
+       OTG_CTRL_REG = l;
+
+       /* Power up the transceiver in USB host mode */
+       tahvo_write_reg(TAHVO_REG_USBR, USBR_REGOUT | USBR_NSUSPEND |
+                       USBR_MASTER_SW2 | USBR_MASTER_SW1);
+       tu->otg.state = OTG_STATE_A_IDLE;
+
+       check_vbus_state(tu);
+}
+
+static void tahvo_usb_stop_host(struct tahvo_usb *tu)
+{
+       host_suspend(tu);
+       tu->otg.state = OTG_STATE_A_IDLE;
+}
+
+static void tahvo_usb_become_peripheral(struct tahvo_usb *tu)
+{
+       /* Clear system and transceiver controlled bits
+        * and enable ID to mark peripheral mode and
+        * BSESSEND to mark no Vbus */
+       omap_otg_init();
+       OTG_CTRL_REG = (OTG_CTRL_REG & ~(OTG_CTRL_XCVR_MASK|OTG_CTRL_SYS_MASK|OTG_BSESSVLD))
+               | OTG_ID | OTG_BSESSEND;
+
+       /* Power up transceiver and set it in USB perhiperal mode */
+       tahvo_write_reg(TAHVO_REG_USBR, USBR_SLAVE_CONTROL | USBR_REGOUT | USBR_NSUSPEND | USBR_SLAVE_SW);
+       tu->otg.state = OTG_STATE_B_IDLE;
+
+       check_vbus_state(tu);
+}
+
+static void tahvo_usb_stop_peripheral(struct tahvo_usb *tu)
+{
+       OTG_CTRL_REG = (OTG_CTRL_REG & ~OTG_BSESSVLD) | OTG_BSESSEND;
+       if (tu->otg.gadget)
+               usb_gadget_vbus_disconnect(tu->otg.gadget);
+       tu->otg.state = OTG_STATE_B_IDLE;
+
+}
+
+static void tahvo_usb_power_off(struct tahvo_usb *tu)
+{
+       u32 l;
+       int id;
+
+       /* Disable gadget controller if any */
+       if (tu->otg.gadget)
+               usb_gadget_vbus_disconnect(tu->otg.gadget);
+
+       host_suspend(tu);
+
+       /* Disable OTG and interrupts */
+       if (TAHVO_MODE(tu) == TAHVO_MODE_PERIPHERAL)
+               id = OTG_ID;
+       else
+               id = 0;
+       l = OTG_CTRL_REG;
+       l &= ~(OTG_CTRL_XCVR_MASK | OTG_CTRL_SYS_MASK | OTG_BSESSVLD);
+       l |= id | OTG_BSESSEND;
+       OTG_CTRL_REG = l;
+       OTG_IRQ_EN_REG = 0;
+
+       OTG_SYSCON_2_REG &= ~OTG_EN;
+
+       OTG_SYSCON_1_REG |= OTG_IDLE_EN;
+
+       /* Power off transceiver */
+       tahvo_write_reg(TAHVO_REG_USBR, 0);
+       tu->otg.state = OTG_STATE_UNDEFINED;
+}
+
+
+static int tahvo_usb_set_power(struct otg_transceiver *dev, unsigned mA)
+{
+       struct tahvo_usb *tu = container_of(dev, struct tahvo_usb, otg);
+
+       dev_dbg(&tu->pt_dev->dev, "set_power %d mA\n", mA);
+
+       if (dev->state == OTG_STATE_B_PERIPHERAL) {
+               /* REVISIT: Can Tahvo charge battery from VBUS? */
+       }
+       return 0;
+}
+
+static int tahvo_usb_set_suspend(struct otg_transceiver *dev, int suspend)
+{
+       struct tahvo_usb *tu = container_of(dev, struct tahvo_usb, otg);
+       u16 w;
+
+       dev_dbg(&tu->pt_dev->dev, "set_suspend\n");
+
+       w = tahvo_read_reg(TAHVO_REG_USBR);
+       if (suspend)
+               w &= ~USBR_NSUSPEND;
+       else
+               w |= USBR_NSUSPEND;
+       tahvo_write_reg(TAHVO_REG_USBR, w);
+
+       return 0;
+}
+
+static int tahvo_usb_start_srp(struct otg_transceiver *dev)
+{
+       struct tahvo_usb *tu = container_of(dev, struct tahvo_usb, otg);
+       u32 otg_ctrl;
+
+       dev_dbg(&tu->pt_dev->dev, "start_srp\n");
+
+       if (!dev || tu->otg.state != OTG_STATE_B_IDLE)
+               return -ENODEV;
+
+       otg_ctrl = OTG_CTRL_REG;
+       if (!(otg_ctrl & OTG_BSESSEND))
+               return -EINVAL;
+
+       otg_ctrl |= OTG_B_BUSREQ;
+       otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_SYS_MASK;
+       OTG_CTRL_REG = otg_ctrl;
+       tu->otg.state = OTG_STATE_B_SRP_INIT;
+
+       return 0;
+}
+
+static int tahvo_usb_start_hnp(struct otg_transceiver *otg)
+{
+       struct tahvo_usb *tu = container_of(otg, struct tahvo_usb, otg);
+
+       dev_dbg(&tu->pt_dev->dev, "start_hnp\n");
+#ifdef CONFIG_USB_OTG
+       /* REVISIT: Add this for OTG */
+#endif
+       return -EINVAL;
+}
+
+static int tahvo_usb_set_host(struct otg_transceiver *otg, struct usb_bus *host)
+{
+       struct tahvo_usb *tu = container_of(otg, struct tahvo_usb, otg);
+
+       dev_dbg(&tu->pt_dev->dev, "set_host %p\n", host);
+
+       if (otg == NULL)
+               return -ENODEV;
+
+#if defined(CONFIG_USB_OTG) || !defined(CONFIG_USB_GADGET_OMAP)
+
+       mutex_lock(&tu->serialize);
+
+       if (host == NULL) {
+               if (TAHVO_MODE(tu) == TAHVO_MODE_HOST)
+                       tahvo_usb_power_off(tu);
+               tu->otg.host = NULL;
+               mutex_unlock(&tu->serialize);
+               return 0;
+       }
+
+       OTG_SYSCON_1_REG &= ~(OTG_IDLE_EN | HST_IDLE_EN | DEV_IDLE_EN);
+
+       if (TAHVO_MODE(tu) == TAHVO_MODE_HOST) {
+               tu->otg.host = NULL;
+               tahvo_usb_become_host(tu);
+       } else
+               host_suspend(tu);
+
+       tu->otg.host = host;
+
+       mutex_unlock(&tu->serialize);
+#else
+       /* No host mode configured, so do not allow host controlled to be set */
+       return -EINVAL;
+#endif
+
+       return 0;
+}
+
+static int tahvo_usb_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *gadget)
+{
+       struct tahvo_usb *tu = container_of(otg, struct tahvo_usb, otg);
+
+       dev_dbg(&tu->pt_dev->dev, "set_peripheral %p\n", gadget);
+
+       if (!otg)
+               return -ENODEV;
+
+#if defined(CONFIG_USB_OTG) || defined(CONFIG_USB_GADGET_OMAP)
+
+       mutex_lock(&tu->serialize);
+
+       if (!gadget) {
+               if (TAHVO_MODE(tu) == TAHVO_MODE_PERIPHERAL)
+                       tahvo_usb_power_off(tu);
+               tu->otg.gadget = NULL;
+               mutex_unlock(&tu->serialize);
+               return 0;
+       }
+
+       tu->otg.gadget = gadget;
+       if (TAHVO_MODE(tu) == TAHVO_MODE_PERIPHERAL)
+               tahvo_usb_become_peripheral(tu);
+
+       mutex_unlock(&tu->serialize);
+#else
+       /* No gadget mode configured, so do not allow host controlled to be set */
+       return -EINVAL;
+#endif
+
+       return 0;
+}
+
+static void tahvo_usb_irq_work(struct work_struct *work)
+{
+       struct tahvo_usb *tu = container_of(work, struct tahvo_usb, irq_work);
+
+       mutex_lock(&tu->serialize);
+       check_vbus_state(tu);
+       mutex_unlock(&tu->serialize);
+}
+
+static void tahvo_usb_vbus_interrupt(unsigned long arg)
+{
+       struct tahvo_usb *tu = (struct tahvo_usb *) arg;
+
+       tahvo_ack_irq(TAHVO_INT_VBUSON);
+       /* Seems we need this to acknowledge the interrupt */
+       tahvo_read_reg(TAHVO_REG_IDSR);
+       schedule_work(&tu->irq_work);
+}
+
+#ifdef CONFIG_USB_OTG
+static ssize_t otg_mode_show(struct device *device,
+                            struct device_attribute *attr, char *buf)
+{
+       struct tahvo_usb *tu = (struct tahvo_usb*) device->driver_data;
+       switch (tu->tahvo_mode) {
+       case TAHVO_MODE_HOST:
+               return sprintf(buf, "host\n");
+       case TAHVO_MODE_PERIPHERAL:
+               return sprintf(buf, "peripheral\n");
+       }
+       return sprintf(buf, "unknown\n");
+}
+
+static ssize_t otg_mode_store(struct device *device,
+                             struct device_attribute *attr,
+                             const char *buf, size_t count)
+{
+       struct tahvo_usb *tu = (struct tahvo_usb*) device->driver_data;
+       int r;
+
+       r = strlen(buf);
+       mutex_lock(&tu->serialize);
+       if (strncmp(buf, "host", 4) == 0) {
+               if (tu->tahvo_mode == TAHVO_MODE_PERIPHERAL)
+                       tahvo_usb_stop_peripheral(tu);
+               tu->tahvo_mode = TAHVO_MODE_HOST;
+               if (tu->otg.host) {
+                       printk(KERN_INFO "Selected HOST mode: host controller present.\n");
+                       tahvo_usb_become_host(tu);
+               } else {
+                       printk(KERN_INFO "Selected HOST mode: no host controller, powering off.\n");
+                       tahvo_usb_power_off(tu);
+               }
+       } else if (strncmp(buf, "peripheral", 10) == 0) {
+               if (tu->tahvo_mode == TAHVO_MODE_HOST)
+                       tahvo_usb_stop_host(tu);
+               tu->tahvo_mode = TAHVO_MODE_PERIPHERAL;
+               if (tu->otg.gadget) {
+                       printk(KERN_INFO "Selected PERIPHERAL mode: gadget driver present.\n");
+                       tahvo_usb_become_peripheral(tu);
+               } else {
+                       printk(KERN_INFO "Selected PERIPHERAL mode: no gadget driver, powering off.\n");
+                       tahvo_usb_power_off(tu);
+               }
+       } else
+               r = -EINVAL;
+
+       mutex_unlock(&tu->serialize);
+       return r;
+}
+
+static DEVICE_ATTR(otg_mode, 0644, otg_mode_show, otg_mode_store);
+#endif
+
+static int tahvo_usb_probe(struct device *dev)
+{
+       struct tahvo_usb *tu;
+       int ret;
+
+       dev_dbg(dev, "probe\n");
+
+       /* Create driver data */
+       tu = kmalloc(sizeof(*tu), GFP_KERNEL);
+       if (!tu)
+               return -ENOMEM;
+       memset(tu, 0, sizeof(*tu));
+       tu->pt_dev = container_of(dev, struct platform_device, dev);
+#ifdef CONFIG_USB_OTG
+       /* Default mode */
+#ifdef CONFIG_CBUS_TAHVO_USB_HOST_BY_DEFAULT
+       tu->tahvo_mode = TAHVO_MODE_HOST;
+#else
+       tu->tahvo_mode = TAHVO_MODE_PERIPHERAL;
+#endif
+#endif
+
+       INIT_WORK(&tu->irq_work, tahvo_usb_irq_work);
+       mutex_init(&tu->serialize);
+
+       /* Set initial state, so that we generate kevents only on
+        * state changes */
+       tu->vbus_state = tahvo_read_reg(TAHVO_REG_IDSR) & 0x01;
+
+       /* We cannot enable interrupt until omap_udc is initialized */
+       ret = tahvo_request_irq(TAHVO_INT_VBUSON, tahvo_usb_vbus_interrupt,
+                               (unsigned long) tu, "vbus_interrupt");
+       if (ret != 0) {
+               kfree(tu);
+               printk(KERN_ERR "Could not register Tahvo interrupt for VBUS\n");
+               return ret;
+       }
+
+       /* Attributes */
+       ret = device_create_file(dev, &dev_attr_vbus_state);
+#ifdef CONFIG_USB_OTG
+       ret |= device_create_file(dev, &dev_attr_otg_mode);
+#endif
+       if (ret)
+               printk(KERN_ERR "attribute creation failed: %d\n", ret);
+
+       /* Create OTG interface */
+       tahvo_usb_power_off(tu);
+       tu->otg.state = OTG_STATE_UNDEFINED;
+       tu->otg.label = DRIVER_NAME;
+       tu->otg.set_host = tahvo_usb_set_host;
+       tu->otg.set_peripheral = tahvo_usb_set_peripheral;
+       tu->otg.set_power = tahvo_usb_set_power;
+       tu->otg.set_suspend = tahvo_usb_set_suspend;
+       tu->otg.start_srp = tahvo_usb_start_srp;
+       tu->otg.start_hnp = tahvo_usb_start_hnp;
+
+       ret = otg_set_transceiver(&tu->otg);
+       if (ret < 0) {
+               printk(KERN_ERR "Cannot register USB transceiver\n");
+               kfree(tu);
+               tahvo_free_irq(TAHVO_INT_VBUSON);
+               return ret;
+       }
+
+       dev->driver_data = tu;
+
+       /* Act upon current vbus state once at startup. A vbus state irq may or
+        * may not be generated in addition to this. */
+       schedule_work(&tu->irq_work);
+       return 0;
+}
+
+static int tahvo_usb_remove(struct device *dev)
+{
+       dev_dbg(dev, "remove\n");
+
+       tahvo_free_irq(TAHVO_INT_VBUSON);
+       flush_scheduled_work();
+       otg_set_transceiver(0);
+       device_remove_file(dev, &dev_attr_vbus_state);
+#ifdef CONFIG_USB_OTG
+       device_remove_file(dev, &dev_attr_otg_mode);
+#endif
+       return 0;
+}
+
+static struct device_driver tahvo_usb_driver = {
+       .name           = "tahvo-usb",
+       .bus            = &platform_bus_type,
+       .probe          = tahvo_usb_probe,
+       .remove         = tahvo_usb_remove,
+};
+
+static struct platform_device tahvo_usb_device = {
+       .name           = "tahvo-usb",
+       .id             = -1,
+};
+
+static int __init tahvo_usb_init(void)
+{
+       int ret = 0;
+
+       printk(KERN_INFO "Tahvo USB transceiver driver initializing\n");
+       ret = driver_register(&tahvo_usb_driver);
+       if (ret)
+               return ret;
+       ret = platform_device_register(&tahvo_usb_device);
+       if (ret < 0) {
+               driver_unregister(&tahvo_usb_driver);
+               return ret;
+       }
+       ret = driver_register(&omap_otg_driver);
+       if (ret) {
+               platform_device_unregister(&tahvo_usb_device);
+               driver_unregister(&tahvo_usb_driver);
+               return ret;
+       }
+       return 0;
+}
+
+subsys_initcall(tahvo_usb_init);
+
+static void __exit tahvo_usb_exit(void)
+{
+       driver_unregister(&omap_otg_driver);
+       platform_device_unregister(&tahvo_usb_device);
+       driver_unregister(&tahvo_usb_driver);
+}
+module_exit(tahvo_usb_exit);
+
+MODULE_DESCRIPTION("Tahvo USB OTG Transceiver Driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Juha Yrjölä, Tony Lindgren, and Timo Teräs");
diff --git a/drivers/cbus/tahvo-user.c b/drivers/cbus/tahvo-user.c
new file mode 100644 (file)
index 0000000..873d648
--- /dev/null
@@ -0,0 +1,405 @@
+/**
+ * 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");
diff --git a/drivers/cbus/tahvo.c b/drivers/cbus/tahvo.c
new file mode 100644 (file)
index 0000000..edf7082
--- /dev/null
@@ -0,0 +1,441 @@
+/**
+ * drivers/cbus/tahvo.c
+ *
+ * Support functions for Tahvo ASIC
+ *
+ * Copyright (C) 2004, 2005 Nokia Corporation
+ *
+ * Written by Juha Yrjölä <juha.yrjola@nokia.com>,
+ *           David Weinehall <david.weinehall@nokia.com>, and
+ *           Mikko Ylinen <mikko.k.ylinen@nokia.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/miscdevice.h>
+#include <linux/poll.h>
+#include <linux/fs.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+
+#include <asm/uaccess.h>
+
+#include <asm/arch/mux.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/board.h>
+
+#include "cbus.h"
+#include "tahvo.h"
+
+#define TAHVO_ID               0x02
+#define PFX                    "tahvo: "
+
+static int tahvo_initialized;
+static int tahvo_irq_pin;
+static int tahvo_is_betty;
+
+static struct tasklet_struct tahvo_tasklet;
+spinlock_t tahvo_lock = SPIN_LOCK_UNLOCKED;
+
+static struct completion device_release;
+
+struct tahvo_irq_handler_desc {
+       int (*func)(unsigned long);
+       unsigned long arg;
+       char name[8];
+};
+
+static struct tahvo_irq_handler_desc tahvo_irq_handlers[MAX_TAHVO_IRQ_HANDLERS];
+
+/**
+ * tahvo_read_reg - Read a value from a register in Tahvo
+ * @reg: the register to read from
+ *
+ * This function returns the contents of the specified register
+ */
+int tahvo_read_reg(int reg)
+{
+       BUG_ON(!tahvo_initialized);
+       return cbus_read_reg(cbus_host, TAHVO_ID, reg);
+}
+
+/**
+ * tahvo_write_reg - Write a value to a register in Tahvo
+ * @reg: the register to write to
+ * @reg: the value to write to the register
+ *
+ * This function writes a value to the specified register
+ */
+void tahvo_write_reg(int reg, u16 val)
+{
+       BUG_ON(!tahvo_initialized);
+       cbus_write_reg(cbus_host, TAHVO_ID, reg, val);
+}
+
+/**
+ * tahvo_set_clear_reg_bits - set and clear register bits atomically
+ * @reg: the register to write to
+ * @bits: the bits to set
+ *
+ * This function sets and clears the specified Tahvo register bits atomically
+ */
+void tahvo_set_clear_reg_bits(int reg, u16 set, u16 clear)
+{
+       unsigned long flags;
+       u16 w;
+
+       spin_lock_irqsave(&tahvo_lock, flags);
+       w = tahvo_read_reg(reg);
+       w &= ~clear;
+       w |= set;
+       tahvo_write_reg(reg, w);
+       spin_unlock_irqrestore(&tahvo_lock, flags);
+}
+
+/*
+ * Disable given TAHVO interrupt
+ */
+void tahvo_disable_irq(int id)
+{
+       unsigned long flags;
+       u16 mask;
+
+       spin_lock_irqsave(&tahvo_lock, flags);
+       mask = tahvo_read_reg(TAHVO_REG_IMR);
+       mask |= 1 << id;
+       tahvo_write_reg(TAHVO_REG_IMR, mask);
+       spin_unlock_irqrestore(&tahvo_lock, flags);
+}
+
+/*
+ * Enable given TAHVO interrupt
+ */
+void tahvo_enable_irq(int id)
+{
+       unsigned long flags;
+       u16 mask;
+
+       spin_lock_irqsave(&tahvo_lock, flags);
+       mask = tahvo_read_reg(TAHVO_REG_IMR);
+       mask &= ~(1 << id);
+       tahvo_write_reg(TAHVO_REG_IMR, mask);
+       spin_unlock_irqrestore(&tahvo_lock, flags);
+}
+
+/*
+ * Acknowledge given TAHVO interrupt
+ */
+void tahvo_ack_irq(int id)
+{
+       tahvo_write_reg(TAHVO_REG_IDR, 1 << id);
+}
+
+static int tahvo_7bit_backlight;
+
+int tahvo_get_backlight_level(void)
+{
+       int mask;
+
+       if (tahvo_7bit_backlight)
+               mask = 0x7f;
+       else
+               mask = 0x0f;
+       return tahvo_read_reg(TAHVO_REG_LEDPWMR) & mask;
+}
+
+int tahvo_get_max_backlight_level(void)
+{
+       if (tahvo_7bit_backlight)
+               return 0x7f;
+       else
+               return 0x0f;
+}
+
+void tahvo_set_backlight_level(int level)
+{
+       int max_level;
+
+       max_level = tahvo_get_max_backlight_level();
+       if (level > max_level)
+               level = max_level;
+       tahvo_write_reg(TAHVO_REG_LEDPWMR, level);
+}
+
+/*
+ * TAHVO interrupt handler. Only schedules the tasklet.
+ */
+static irqreturn_t tahvo_irq_handler(int irq, void *dev_id)
+{
+       tasklet_schedule(&tahvo_tasklet);
+       return IRQ_HANDLED;
+}
+
+/*
+ * Tasklet handler
+ */
+static void tahvo_tasklet_handler(unsigned long data)
+{
+       struct tahvo_irq_handler_desc *hnd;
+       u16 id;
+       u16 im;
+       int i;
+
+       for (;;) {
+               id = tahvo_read_reg(TAHVO_REG_IDR);
+               im = ~tahvo_read_reg(TAHVO_REG_IMR);
+               id &= im;
+
+               if (!id)
+                       break;
+
+               for (i = 0; id != 0; i++, id >>= 1) {
+                       if (!(id & 1))
+                               continue;
+                       hnd = &tahvo_irq_handlers[i];
+                       if (hnd->func == NULL) {
+                               /* Spurious tahvo interrupt - just ack it */
+                               printk(KERN_INFO "Spurious Tahvo interrupt "
+                                                "(id %d)\n", i);
+                               tahvo_disable_irq(i);
+                               tahvo_ack_irq(i);
+                               continue;
+                       }
+                       hnd->func(hnd->arg);
+                       /*
+                        * Don't acknowledge the interrupt here
+                        * It must be done explicitly
+                        */
+               }
+       }
+}
+
+/*
+ * Register the handler for a given TAHVO interrupt source.
+ */
+int tahvo_request_irq(int id, void *irq_handler, unsigned long arg, char *name)
+{
+       struct tahvo_irq_handler_desc *hnd;
+
+       if (irq_handler == NULL || id >= MAX_TAHVO_IRQ_HANDLERS ||
+           name == NULL) {
+               printk(KERN_ERR PFX "Invalid arguments to %s\n",
+                      __FUNCTION__);
+               return -EINVAL;
+       }
+       hnd = &tahvo_irq_handlers[id];
+       if (hnd->func != NULL) {
+               printk(KERN_ERR PFX "IRQ %d already reserved\n", id);
+               return -EBUSY;
+       }
+       printk(KERN_INFO PFX "Registering interrupt %d for device %s\n",
+              id, name);
+       hnd->func = irq_handler;
+       hnd->arg = arg;
+       strlcpy(hnd->name, name, sizeof(hnd->name));
+
+       tahvo_ack_irq(id);
+       tahvo_enable_irq(id);
+
+       return 0;
+}
+
+/*
+ * Unregister the handler for a given TAHVO interrupt source.
+ */
+void tahvo_free_irq(int id)
+{
+       struct tahvo_irq_handler_desc *hnd;
+
+       if (id >= MAX_TAHVO_IRQ_HANDLERS) {
+               printk(KERN_ERR PFX "Invalid argument to %s\n",
+                      __FUNCTION__);
+               return;
+       }
+       hnd = &tahvo_irq_handlers[id];
+       if (hnd->func == NULL) {
+               printk(KERN_ERR PFX "IRQ %d already freed\n", id);
+               return;
+       }
+
+       tahvo_disable_irq(id);
+       hnd->func = NULL;
+}
+
+/**
+ * tahvo_probe - Probe for Tahvo ASIC
+ * @dev: the Tahvo device
+ *
+ * Probe for the Tahvo ASIC and allocate memory
+ * for its device-struct if found
+ */
+static int __devinit tahvo_probe(struct device *dev)
+{
+       const struct omap_em_asic_bb5_config * em_asic_config;
+       int rev, id, ret;
+
+       /* Prepare tasklet */
+       tasklet_init(&tahvo_tasklet, tahvo_tasklet_handler, 0);
+
+       em_asic_config = omap_get_config(OMAP_TAG_EM_ASIC_BB5,
+                                        struct omap_em_asic_bb5_config);
+       if (em_asic_config == NULL) {
+               printk(KERN_ERR PFX "Unable to retrieve config data\n");
+               return -ENODATA;
+       }
+
+       tahvo_initialized = 1;
+
+       rev = tahvo_read_reg(TAHVO_REG_ASICR);
+
+       id = (rev >> 8) & 0xff;
+       if (id == 0x03) {
+               if ((rev & 0xff) >= 0x50)
+                       tahvo_7bit_backlight = 1;
+       } else if (id == 0x0b) {
+               tahvo_is_betty = 1;
+               tahvo_7bit_backlight = 1;
+       } else {
+               printk(KERN_ERR "Tahvo/Betty chip not found");
+               return -ENODEV;
+       }
+
+       printk(KERN_INFO "%s v%d.%d found\n", tahvo_is_betty ? "Betty" : "Tahvo",
+              (rev >> 4) & 0x0f, rev & 0x0f);
+
+       tahvo_irq_pin = em_asic_config->tahvo_irq_gpio;
+
+       if ((ret = omap_request_gpio(tahvo_irq_pin)) < 0) {
+               printk(KERN_ERR PFX "Unable to reserve IRQ GPIO\n");
+               return ret;
+       }
+
+       /* Set the pin as input */
+       omap_set_gpio_direction(tahvo_irq_pin, 1);
+
+       /* Rising edge triggers the IRQ */
+       set_irq_type(OMAP_GPIO_IRQ(tahvo_irq_pin), IRQT_RISING);
+
+       /* Mask all TAHVO interrupts */
+       tahvo_write_reg(TAHVO_REG_IMR, 0xffff);
+
+       ret = request_irq(OMAP_GPIO_IRQ(tahvo_irq_pin), tahvo_irq_handler, 0,
+                         "tahvo", 0);
+       if (ret < 0) {
+               printk(KERN_ERR PFX "Unable to register IRQ handler\n");
+               omap_free_gpio(tahvo_irq_pin);
+               return ret;
+       }
+#ifdef CONFIG_CBUS_TAHVO_USER
+       /* Initialize user-space interface */
+       if (tahvo_user_init() < 0) {
+               printk(KERN_ERR "Unable to initialize driver\n");
+               free_irq(OMAP_GPIO_IRQ(tahvo_irq_pin), 0);
+               omap_free_gpio(tahvo_irq_pin);
+               return ret;
+       }
+#endif
+       return 0;
+}
+
+static int tahvo_remove(struct device *dev)
+{
+#ifdef CONFIG_CBUS_TAHVO_USER
+       tahvo_user_cleanup();
+#endif
+       /* Mask all TAHVO interrupts */
+       tahvo_write_reg(TAHVO_REG_IMR, 0xffff);
+       free_irq(OMAP_GPIO_IRQ(tahvo_irq_pin), 0);
+       omap_free_gpio(tahvo_irq_pin);
+       tasklet_kill(&tahvo_tasklet);
+
+       return 0;
+}
+
+static void tahvo_device_release(struct device *dev)
+{
+       complete(&device_release);
+}
+
+static struct device_driver tahvo_driver = {
+       .name           = "tahvo",
+       .bus            = &platform_bus_type,
+       .probe          = tahvo_probe,
+       .remove         = tahvo_remove,
+};
+
+static struct platform_device tahvo_device = {
+       .name           = "tahvo",
+       .id             = -1,
+       .dev = {
+               .release = tahvo_device_release,
+       }
+};
+
+/**
+ * tahvo_init - initialise Tahvo driver
+ *
+ * Initialise the Tahvo driver and return 0 if everything worked ok
+ */
+static int __init tahvo_init(void)
+{
+       int ret = 0;
+
+       printk(KERN_INFO "Tahvo/Betty driver initialising\n");
+
+       init_completion(&device_release);
+
+       if ((ret = driver_register(&tahvo_driver)) < 0)
+               return ret;
+
+       if ((ret = platform_device_register(&tahvo_device)) < 0) {
+               driver_unregister(&tahvo_driver);
+               return ret;
+       }
+       return 0;
+}
+
+/*
+ * Cleanup
+ */
+static void __exit tahvo_exit(void)
+{
+       platform_device_unregister(&tahvo_device);
+       driver_unregister(&tahvo_driver);
+       wait_for_completion(&device_release);
+}
+
+EXPORT_SYMBOL(tahvo_request_irq);
+EXPORT_SYMBOL(tahvo_free_irq);
+EXPORT_SYMBOL(tahvo_enable_irq);
+EXPORT_SYMBOL(tahvo_disable_irq);
+EXPORT_SYMBOL(tahvo_ack_irq);
+EXPORT_SYMBOL(tahvo_read_reg);
+EXPORT_SYMBOL(tahvo_write_reg);
+EXPORT_SYMBOL(tahvo_get_backlight_level);
+EXPORT_SYMBOL(tahvo_get_max_backlight_level);
+EXPORT_SYMBOL(tahvo_set_backlight_level);
+
+subsys_initcall(tahvo_init);
+module_exit(tahvo_exit);
+
+MODULE_DESCRIPTION("Tahvo ASIC control");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Juha Yrjölä, David Weinehall, and Mikko Ylinen");
diff --git a/drivers/cbus/tahvo.h b/drivers/cbus/tahvo.h
new file mode 100644 (file)
index 0000000..b7a8ee1
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * 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 */
diff --git a/drivers/cbus/user_retu_tahvo.h b/drivers/cbus/user_retu_tahvo.h
new file mode 100644 (file)
index 0000000..a5c2190
--- /dev/null
@@ -0,0 +1,75 @@
+/**
+ * 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
index 9e43e39dc35c09dc25efafa0c56555bfeabf4dea..ba2157b1e9a13a8cf8613602a8b83e9b2b4a8568 100644 (file)
@@ -696,6 +696,16 @@ config NWFLASH
 
 source "drivers/char/hw_random/Kconfig"
 
+config OMAP_RNG
+       tristate "OMAP Random Number Generator support"
+       depends on ARCH_OMAP16XX || ARCH_OMAP24XX
+       ---help---
+         This driver provides kernel-side support for the Random Number
+         Generator hardware found on OMAP16xx and OMAP24xx multimedia
+         processors.
+
+         If unsure, say N.
+
 config NVRAM
        tristate "/dev/nvram support"
        depends on ATARI || X86 || ARM || GENERIC_NVRAM
@@ -798,6 +808,11 @@ config GEN_RTC_X
 config EFI_RTC
        bool "EFI Real Time Clock Services"
        depends on IA64
+config OMAP_RTC
+       bool "TI OMAP Real Time Clock"
+       depends on ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP730
+       help
+         Support for TI OMAP RTC
 
 config DS1302
        tristate "DS1302 RTC support"
index fc110637ced6ad4b4f6ae8b70bc3365d69110540..611cdc12afb8672b7c2ec999a5677f1c1e217155 100644 (file)
@@ -69,6 +69,7 @@ obj-$(CONFIG_GEN_RTC)         += genrtc.o
 obj-$(CONFIG_EFI_RTC)          += efirtc.o
 obj-$(CONFIG_SGI_DS1286)       += ds1286.o
 obj-$(CONFIG_SGI_IP27_RTC)     += ip27-rtc.o
+obj-$(CONFIG_OMAP_RTC)         += omap-rtc.o
 obj-$(CONFIG_DS1302)           += ds1302.o
 ifeq ($(CONFIG_GENERIC_NVRAM),y)
   obj-$(CONFIG_NVRAM)  += generic_nvram.o
index e13dd1892bfdf95bb8c8e731528c12eab1a4fb4d..773d8a87510ba9799dd6a048b1a7e596672578a5 100644 (file)
@@ -179,7 +179,6 @@ static struct platform_driver omap_rng_driver = {
                .name           = "omap_rng",
                .owner          = THIS_MODULE,
        },
-       .probe          = omap_rng_probe,
        .remove         = __exit_p(omap_rng_remove),
        .suspend        = omap_rng_suspend,
        .resume         = omap_rng_resume
@@ -190,7 +189,7 @@ static int __init omap_rng_init(void)
        if (!cpu_is_omap16xx() && !cpu_is_omap24xx())
                return -ENODEV;
 
-       return platform_driver_register(&omap_rng_driver);
+       return platform_driver_probe(&omap_rng_driver, omap_rng_probe);
 }
 
 static void __exit omap_rng_exit(void)
diff --git a/drivers/char/omap-rng.c b/drivers/char/omap-rng.c
new file mode 100644 (file)
index 0000000..cc3290e
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * drivers/char/omap-rng.c
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ * Author: Juha Yrjölä <juha.yrjola@nokia.com>
+ *
+ * OMAP16xx and OMAP24xx Random Number Generator driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/random.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+
+#if defined (CONFIG_ARCH_OMAP16XX)
+#define RNG_BASE               0xfffe5000
+#endif
+#if defined (CONFIG_ARCH_OMAP24XX)
+#define RNG_BASE               0x480A0000
+#endif
+
+#define RNG_OUT_REG            0x00            /* Output register */
+#define RNG_STAT_REG           0x04            /* Status register
+                                                       [0] = STAT_BUSY */
+#define RNG_ALARM_REG          0x24            /* Alarm register
+                                                       [7:0] = ALARM_COUNTER */
+#define RNG_CONFIG_REG         0x28            /* Configuration register
+                                                       [11:6] = RESET_COUNT
+                                                       [5:3]  = RING2_DELAY 
+                                                       [2:0]  = RING1_DELAY */
+#define RNG_REV_REG            0x3c            /* Revision register
+                                                       [7:0] = REV_NB */
+#define RNG_MASK_REG           0x40            /* Mask and reset register
+                                                       [2] = IT_EN
+                                                       [1] = SOFTRESET
+                                                       [0] = AUTOIDLE */
+#define RNG_SYSSTATUS          0x44            /* System status
+                                                       [0] = RESETDONE */
+
+#define ENTROPY_WORD_COUNT     128
+
+static u32 rng_base = io_p2v(RNG_BASE);
+
+static struct clk *rng_ick = NULL;
+
+static u32 rng_read_reg(int reg)
+{
+       return __raw_readl(rng_base + reg);
+}
+
+static void rng_write_reg(int reg, u32 val)
+{
+       __raw_writel(val, rng_base + reg);
+}
+
+static void rng_feed_entropy(int count)
+{
+       u32 l;
+
+       while (count--) {
+               while (rng_read_reg(RNG_STAT_REG));
+               l = rng_read_reg(RNG_OUT_REG);
+               add_input_randomness(0, 0, l);
+       }
+}
+
+static int __init rng_init(void)
+{
+       if (!cpu_is_omap16xx() && !cpu_is_omap24xx())
+               return -ENODEV;
+
+       if (cpu_is_omap24xx()) {
+               rng_ick = clk_get(NULL, "rng_ick");
+               if (IS_ERR(rng_ick)) {
+                       printk(KERN_ERR "omap-rng.c: Could not get rng_ick\n");
+                       return PTR_ERR(rng_ick);
+               }
+               clk_enable(rng_ick);
+       }
+
+       printk("OMAP Random Number Generator ver. %02x\n",
+       rng_read_reg(RNG_REV_REG));
+       rng_write_reg(RNG_MASK_REG, 0x00000001);
+       rng_feed_entropy(ENTROPY_WORD_COUNT);
+       rng_write_reg(RNG_MASK_REG, 0x00000000);
+       printk("%d words of entropy generated\n", ENTROPY_WORD_COUNT);
+
+       return 0;
+}
+late_initcall(rng_init);
diff --git a/drivers/char/omap-rtc.c b/drivers/char/omap-rtc.c
new file mode 100644 (file)
index 0000000..f1b3fa3
--- /dev/null
@@ -0,0 +1,788 @@
+/*
+ *     TI OMAP Real Time Clock interface for Linux     
+ *
+ *     Copyright (C) 2003 MontaVista Software, Inc.
+ *      Author: George G. Davis <gdavis@mvista.com> or <source@mvista.com>
+ *
+ *     Initially based on linux-2.4.20/drivers/char/rtc.c
+ *     Copyright (C) 1996 Paul Gortmaker
+ *
+ *     This driver allows use of the real time clock (built into
+ *     nearly all computers) from user space. It exports the /dev/rtc
+ *     interface supporting various ioctl() and also the
+ *     /proc/driver/rtc pseudo-file for status information.
+ *
+ *     The ioctls can be used to set the interrupt behaviour from the
+ *     RTC via IRQs. Then the /dev/rtc interface can be used to make
+ *     use of RTC interrupts, be they time update or alarm based.
+ *
+ *     The /dev/rtc interface will block on reads until an interrupt
+ *     has been received. If a RTC interrupt has already happened,
+ *     it will output an unsigned long and then block. The output value
+ *     contains the interrupt status in the low byte and the number of
+ *     interrupts since the last read in the remaining high bytes. The 
+ *     /dev/rtc interface can also be used with the select(2) call.
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     as published by the Free Software Foundation; either version
+ *     2 of the License, or (at your option) any later version.
+ *
+ *     Based on other minimal char device drivers, like Alan's
+ *     watchdog, Ted's random, etc. etc.
+ *
+ * Change Log :
+ *      v1.0    <gdavis@mvista.com> Initial version based on rtc.c v1.10e
+ *              <ramakrishnan@india.ti.com> Added support for 2.6 kernel, 
+ *                  - changed the return value of the interrupt handler
+ */
+
+/*
+ *     Note that *all* calls to CMOS_READ and CMOS_WRITE are done with
+ *     interrupts disabled.
+ *     REVISIT: Elaborate on OMAP1510 TRM 15uS BUSY access rule.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/rtc.h>
+#include <asm/mach/time.h>
+
+#include "omap-rtc.h"
+
+extern spinlock_t rtc_lock;
+
+static int omap_rtc_alarm = NO_IRQ;
+static int omap_rtc_timer = NO_IRQ;
+
+
+/* OMAP RTC register access macros: */
+
+#define CMOS_READ(addr)                omap_readb(addr)
+#define CMOS_WRITE(val, addr)  omap_writeb(val, addr)
+
+static struct fasync_struct *rtc_async_queue;
+
+static DECLARE_WAIT_QUEUE_HEAD(rtc_wait);
+
+static void get_rtc_time (struct rtc_time *rtc_tm);
+static void get_rtc_alm_time (struct rtc_time *alm_tm);
+
+static void set_rtc_irq_bit(unsigned char bit);
+static void mask_rtc_irq_bit(unsigned char bit);
+
+static int rtc_read_proc(char *page, char **start, off_t off,
+                         int count, int *eof, void *data);
+
+/*
+ *     Bits in rtc_status. (7 bits of room for future expansion)
+ */
+
+#define RTC_IS_OPEN            0x01    /* means /dev/rtc is in use     */
+
+/*
+ * REVISIT: fix this comment:
+ * rtc_status is never changed by rtc_interrupt, and ioctl/open/close is
+ * protected by the big kernel lock.
+ */
+static unsigned long rtc_status = 0;   /* bitmapped status byte.       */
+static unsigned long rtc_irq_data = 0; /* our output to the world      */
+
+/*
+ *     If this driver ever becomes modularised, it will be really nice
+ *     to make the epoch retain its value across module reload...
+ */
+
+static unsigned long epoch = 1900;     /* year corresponding to 0x00   */
+
+static const unsigned char days_in_mo[] = 
+{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+/*
+ *     A very tiny interrupt handler. It runs with IRQF_DISABLED set.
+ */
+
+irqreturn_t rtc_interrupt(int irq, void *dev_id)
+{
+       /*
+        *      Either an alarm interrupt or update complete interrupt.
+        *      We store the status in the low byte and the number of
+        *      interrupts received since the last read in the remainder
+        *      of rtc_irq_data.
+        */
+
+       spin_lock (&rtc_lock);
+
+       rtc_irq_data += 0x100;
+       rtc_irq_data &= ~0xff;
+       rtc_irq_data |= CMOS_READ(OMAP_RTC_STATUS_REG);
+
+       if (rtc_irq_data & OMAP_RTC_STATUS_ALARM)
+               CMOS_WRITE(OMAP_RTC_STATUS_ALARM, OMAP_RTC_STATUS_REG);
+
+       spin_unlock (&rtc_lock);
+
+       /* Now do the rest of the actions */
+       wake_up_interruptible(&rtc_wait);       
+
+       kill_fasync (&rtc_async_queue, SIGIO, POLL_IN);
+       return IRQ_HANDLED;
+}
+
+/*
+ *     Now all the various file operations that we export.
+ */
+
+static ssize_t rtc_read(struct file *file, char __user *buf,
+                       size_t count, loff_t *ppos)
+{
+       DECLARE_WAITQUEUE(wait, current);
+       unsigned long data;
+       ssize_t retval;
+       
+       if (count < sizeof(unsigned long))
+               return -EINVAL;
+
+       add_wait_queue(&rtc_wait, &wait);
+       set_current_state(TASK_INTERRUPTIBLE);
+
+       for (;;) {
+               spin_lock_irq (&rtc_lock);
+               data = rtc_irq_data;
+               if (data != 0) {
+                       rtc_irq_data = 0;
+                       break;
+               }
+               spin_unlock_irq (&rtc_lock);
+
+               if (file->f_flags & O_NONBLOCK) {
+                       retval = -EAGAIN;
+                       goto out;
+               }
+               if (signal_pending(current)) {
+                       retval = -ERESTARTSYS;
+                       goto out;
+               }
+               schedule();
+       }
+
+       spin_unlock_irq (&rtc_lock);
+       retval = put_user(data, (unsigned long __user *)buf);
+       if (!retval)
+               retval = sizeof(unsigned long); 
+ out:
+       set_current_state(TASK_RUNNING);
+       remove_wait_queue(&rtc_wait, &wait);
+
+       return retval;
+}
+
+/* convert from userspace struct to hardware BCD-encoded version,
+ * or return error code
+ */
+static int utm2bcd(struct rtc_time __user *arg, struct rtc_time *tm)
+{
+       unsigned char leap_yr;
+
+       if (copy_from_user(tm, arg, sizeof(struct rtc_time)))
+               return -EFAULT;
+
+       tm->tm_year += 1900;
+       tm->tm_mon++;
+
+       if (tm->tm_year < 1970)
+               return -EINVAL;
+
+       leap_yr = (!(tm->tm_year % 4) && (tm->tm_year % 100))
+                       || !(tm->tm_year % 400);
+
+       if ((tm->tm_mon > 12) || (tm->tm_mday == 0))
+               return -EINVAL;
+
+       if (tm->tm_mday > (days_in_mo[tm->tm_mon] + ((tm->tm_mon == 2) && leap_yr)))
+               return -EINVAL;
+
+       if ((tm->tm_hour >= 24) || (tm->tm_min >= 60) || (tm->tm_sec >= 60))
+               return -EINVAL;
+
+       if ((tm->tm_year -= epoch) > 255)    /* They are unsigned */
+               return -EINVAL;
+
+       if (tm->tm_year > 169)
+               return -EINVAL;
+
+       if (tm->tm_year >= 100)
+               tm->tm_year -= 100;
+
+       BIN_TO_BCD(tm->tm_sec);
+       BIN_TO_BCD(tm->tm_min);
+       BIN_TO_BCD(tm->tm_hour);
+       BIN_TO_BCD(tm->tm_mday);
+       BIN_TO_BCD(tm->tm_mon);
+       BIN_TO_BCD(tm->tm_year);
+
+       return 0;
+}
+
+static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+                    unsigned long arg)
+{
+       struct rtc_time wtime; 
+       int status = 0;
+       u8 save_control;
+
+       switch (cmd) {
+       case RTC_AIE_OFF:       /* Mask alarm int. enab. bit    */
+               mask_rtc_irq_bit(OMAP_RTC_INTERRUPTS_IT_ALARM);
+               break;
+       case RTC_AIE_ON:        /* Allow alarm interrupts.      */
+               set_rtc_irq_bit(OMAP_RTC_INTERRUPTS_IT_ALARM);
+               break;
+       case RTC_UIE_OFF:       /* Mask ints from RTC updates.  */
+               mask_rtc_irq_bit(OMAP_RTC_INTERRUPTS_IT_TIMER);
+               break;
+       case RTC_UIE_ON:        /* Allow ints for RTC updates.  */
+               set_rtc_irq_bit(OMAP_RTC_INTERRUPTS_IT_TIMER);
+               break;
+       case RTC_ALM_READ:      /* Read the present alarm time */
+               /*
+                * This returns a struct rtc_time. Reading >= 0xc0
+                * means "don't care" or "match all". Only the tm_hour,
+                * tm_min, and tm_sec values are filled in.
+                */
+               memset(&wtime, 0, sizeof(struct rtc_time));
+               get_rtc_alm_time(&wtime);
+               goto return_wtime;
+       case RTC_ALM_SET:       /* Store a time into the alarm */
+               status = utm2bcd((void __user *)arg, &wtime);
+               if (status != 0)
+                       return status;
+
+               spin_lock_irq(&rtc_lock);
+               CMOS_WRITE(wtime.tm_year, OMAP_RTC_ALARM_YEARS_REG);
+               CMOS_WRITE(wtime.tm_mon, OMAP_RTC_ALARM_MONTHS_REG);
+               CMOS_WRITE(wtime.tm_mday, OMAP_RTC_ALARM_DAYS_REG);
+               CMOS_WRITE(wtime.tm_hour, OMAP_RTC_ALARM_HOURS_REG);
+               CMOS_WRITE(wtime.tm_min, OMAP_RTC_ALARM_MINUTES_REG);
+               CMOS_WRITE(wtime.tm_sec, OMAP_RTC_ALARM_SECONDS_REG);
+               spin_unlock_irq(&rtc_lock);
+
+               break;
+       case RTC_RD_TIME:       /* Read the time/date from RTC  */
+               memset(&wtime, 0, sizeof(struct rtc_time));
+               get_rtc_time(&wtime);
+               goto return_wtime;
+       case RTC_SET_TIME:      /* Set the RTC */
+               if (!capable(CAP_SYS_TIME))
+                       return -EACCES;
+
+               status = utm2bcd((void __user *)arg, &wtime);
+               if (status != 0)
+                       return status;
+
+               spin_lock_irq(&rtc_lock);
+               save_control = CMOS_READ(OMAP_RTC_CTRL_REG);
+               CMOS_WRITE((save_control & ~OMAP_RTC_CTRL_STOP),
+                          OMAP_RTC_CTRL_REG);
+               CMOS_WRITE(wtime.tm_year, OMAP_RTC_YEARS_REG);
+               CMOS_WRITE(wtime.tm_mon, OMAP_RTC_MONTHS_REG);
+               CMOS_WRITE(wtime.tm_mday, OMAP_RTC_DAYS_REG);
+               CMOS_WRITE(wtime.tm_hour, OMAP_RTC_HOURS_REG);
+               CMOS_WRITE(wtime.tm_min, OMAP_RTC_MINUTES_REG);
+               CMOS_WRITE(wtime.tm_sec, OMAP_RTC_SECONDS_REG);
+               CMOS_WRITE((save_control | OMAP_RTC_CTRL_STOP),
+                          OMAP_RTC_CTRL_REG);
+               spin_unlock_irq(&rtc_lock);
+
+               break;
+       case RTC_EPOCH_READ:    /* Read the epoch.      */
+               status = put_user (epoch, (unsigned long  __user *)arg);
+               break;
+       case RTC_EPOCH_SET:     /* Set the epoch.       */
+               if (!capable(CAP_SYS_TIME))
+                       return -EACCES;
+
+               /* 
+                * There were no RTC clocks before 1900.
+                */
+               if (arg < 1900)
+                       status = -EINVAL;
+               else
+                       epoch = arg;
+               break;
+       default:
+               status = -ENOTTY;
+       }
+       return status;
+
+return_wtime:
+       return copy_to_user((void  __user *)arg, &wtime, sizeof wtime)
+               ? -EFAULT
+               : 0;
+}
+
+/*
+ *     We enforce only one user at a time here with the open/close.
+ *     Also clear the previous interrupt data on an open, and clean
+ *     up things on a close.
+ */
+
+/* We use rtc_lock to protect against concurrent opens. So the BKL is not
+ * needed here. Or anywhere else in this driver. */
+static int rtc_open(struct inode *inode, struct file *file)
+{
+       spin_lock_irq (&rtc_lock);
+
+       if (rtc_status & RTC_IS_OPEN)
+               goto out_busy;
+
+       rtc_status |= RTC_IS_OPEN;
+
+       rtc_irq_data = 0;
+       spin_unlock_irq (&rtc_lock);
+       return 0;
+
+out_busy:
+       spin_unlock_irq (&rtc_lock);
+       return -EBUSY;
+}
+
+static int rtc_fasync(int fd, struct file *filp, int on)
+{
+       return fasync_helper (fd, filp, on, &rtc_async_queue);
+}
+
+static int rtc_release(struct inode *inode, struct file *file)
+{
+       unsigned char tmp;
+
+       /*
+        * Turn off all interrupts once the device is no longer
+        * in use, and clear the data.
+        */
+
+       spin_lock_irq(&rtc_lock);
+       tmp = CMOS_READ(OMAP_RTC_INTERRUPTS_REG);
+       tmp &=  ~OMAP_RTC_INTERRUPTS_IT_ALARM;
+       tmp &=  ~OMAP_RTC_INTERRUPTS_IT_TIMER;
+       CMOS_WRITE(tmp, OMAP_RTC_INTERRUPTS_REG);
+       spin_unlock_irq(&rtc_lock);
+
+       if (file->f_flags & FASYNC) {
+               rtc_fasync (-1, file, 0);
+       }
+
+       spin_lock_irq (&rtc_lock);
+       rtc_irq_data = 0;
+       spin_unlock_irq (&rtc_lock);
+
+       /* No need for locking -- nobody else can do anything until this rmw
+        * is committed, and we don't implement timer support in omap-rtc.
+        */
+       rtc_status &= ~RTC_IS_OPEN;
+       return 0;
+}
+
+/* Called without the kernel lock - fine */
+static unsigned int rtc_poll(struct file *file, poll_table *wait)
+{
+       unsigned long l;
+
+       poll_wait(file, &rtc_wait, wait);
+
+       spin_lock_irq (&rtc_lock);
+       l = rtc_irq_data;
+       spin_unlock_irq (&rtc_lock);
+
+       if (l != 0)
+               return POLLIN | POLLRDNORM;
+       return 0;
+}
+
+/*
+ *     The various file operations we support.
+ */
+
+static struct file_operations rtc_fops = {
+       .owner          = THIS_MODULE,
+       .llseek         = no_llseek,
+       .read           = rtc_read,
+       .poll           = rtc_poll,
+       .ioctl          = rtc_ioctl,
+       .open           = rtc_open,
+       .release        = rtc_release,
+       .fasync         = rtc_fasync,
+};
+
+static struct miscdevice rtc_dev = {
+       .minor          = RTC_MINOR,
+       .name           = "rtc",
+       .fops           = &rtc_fops,
+};
+
+static int __init omap_rtc_probe(struct platform_device *pdev)
+{
+       struct resource         *res, *mem;
+
+       /* find the IRQs */
+
+       omap_rtc_timer = platform_get_irq(pdev, 0);
+       if (omap_rtc_timer <= 0) {
+               dev_err(&pdev->dev, "no irq for rtc timer\n");
+               return -ENOENT;
+       }
+
+       omap_rtc_alarm = platform_get_irq(pdev, 1);
+       if (omap_rtc_alarm <= 0) {
+               dev_err(&pdev->dev, "no irq for alarm\n");
+               return -ENOENT;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res)
+               mem = request_mem_region(res->start,
+                               res->end - res->start + 1,
+                               pdev->name);
+       else
+               mem = NULL;
+       if (!mem) {
+               pr_debug("%s: RTC registers at %x are not free.\n",
+                       pdev->name, OMAP_RTC_BASE);
+               return -EBUSY;
+       }
+       platform_set_drvdata(pdev, mem);
+
+       if (CMOS_READ(OMAP_RTC_STATUS_REG) & OMAP_RTC_STATUS_POWER_UP) {
+               pr_info("%s: RTC power up reset detected.\n",
+                       pdev->name);
+               /* Clear OMAP_RTC_STATUS_POWER_UP */
+               CMOS_WRITE(OMAP_RTC_STATUS_POWER_UP, OMAP_RTC_STATUS_REG);
+       }
+
+       if (CMOS_READ(OMAP_RTC_STATUS_REG) & OMAP_RTC_STATUS_ALARM) {
+               pr_debug("%s: Clearing RTC ALARM interrupt.\n",
+                       pdev->name);
+               /* Clear OMAP_RTC_STATUS_ALARM */
+               CMOS_WRITE(OMAP_RTC_STATUS_ALARM, OMAP_RTC_STATUS_REG);
+       }
+
+       if (request_irq(omap_rtc_timer, rtc_interrupt, IRQF_DISABLED,
+                       pdev->name, NULL)) {
+               pr_debug("%s: RTC timer interrupt IRQ%d is not free.\n",
+                       pdev->name, omap_rtc_timer);
+               goto fail;
+       }
+
+       if (request_irq(omap_rtc_alarm, rtc_interrupt, IRQF_DISABLED,
+                       pdev->name, NULL)) {
+               pr_debug("%s: RTC alarm interrupt IRQ%d is not free.\n",
+                       pdev->name, omap_rtc_alarm);
+               free_irq(omap_rtc_timer, NULL);
+               goto fail;
+       }
+
+       /* On boards with split power, RTC_ON_NOFF resets all but the RTC */
+       if (!(CMOS_READ(OMAP_RTC_CTRL_REG) & OMAP_RTC_CTRL_STOP)) {
+               pr_info("%s: Enabling RTC.\n", pdev->name);
+               CMOS_WRITE(OMAP_RTC_CTRL_STOP, OMAP_RTC_CTRL_REG);
+       } else
+               pr_info("%s: RTC already running.\n", pdev->name);
+
+       spin_lock_init(&rtc_lock);
+       misc_register(&rtc_dev);
+       create_proc_read_entry("driver/rtc", 0, NULL, rtc_read_proc, NULL);
+
+       return 0;
+
+fail:
+       release_resource(mem);
+       return -EIO;
+}
+
+static int omap_rtc_remove(struct platform_device *pdev)
+{
+       free_irq (omap_rtc_timer, NULL);
+       free_irq (omap_rtc_alarm, NULL);
+
+       remove_proc_entry ("driver/rtc", NULL);
+       misc_deregister(&rtc_dev);
+
+       release_resource(platform_get_drvdata(pdev));
+       return 0;
+}
+
+/*
+ *     Info exported via "/proc/driver/rtc".
+ */
+
+static int rtc_proc_output (char *buf)
+{
+#define YN(value) ((value) ? "yes" : "no")
+       char *p;
+       struct rtc_time tm;
+
+       p = buf;
+
+       get_rtc_time(&tm);
+
+       /*
+        * There is no way to tell if the luser has the RTC set for local
+        * time or for Universal Standard Time (GMT). Probably local though.
+        */
+       p += sprintf(p,
+                    "rtc_time\t: %02d:%02d:%02d\n"
+                    "rtc_date\t: %04d-%02d-%02d\n"
+                    "rtc_epoch\t: %04lu\n",
+                    tm.tm_hour, tm.tm_min, tm.tm_sec,
+                    tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, epoch);
+
+       get_rtc_alm_time(&tm);
+
+       /*
+        * We implicitly assume 24hr mode here. Alarm values >= 0xc0 will
+        * match any value for that particular field. Values that are
+        * greater than a valid time, but less than 0xc0 shouldn't appear.
+        */
+       p += sprintf(p,
+                    "alarm_time\t: %02d:%02d:%02d\n"
+                    "alarm_date\t: %04d-%02d-%02d\n",
+                    tm.tm_hour, tm.tm_min, tm.tm_sec,
+                    tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
+
+       p += sprintf(p,
+                    "BCD\t\t: %s\n"
+                    "24hr\t\t: %s\n"
+                    "alarm_IRQ\t: %s\n"
+                    "update_IRQ\t: %s\n"
+                    "update_rate\t: %ud\n",
+                    YN(1),
+                    YN(1),
+                    YN(CMOS_READ(OMAP_RTC_INTERRUPTS_REG) &
+                       OMAP_RTC_INTERRUPTS_IT_ALARM),
+                    YN(CMOS_READ(OMAP_RTC_INTERRUPTS_REG) &
+                       OMAP_RTC_INTERRUPTS_IT_TIMER),
+                    CMOS_READ(OMAP_RTC_INTERRUPTS_REG) & 3 /* REVISIT */);
+
+       return  p - buf;
+#undef YN
+}
+
+static int rtc_read_proc(char *page, char **start, off_t off,
+                         int count, int *eof, void *data)
+{
+        int len = rtc_proc_output (page);
+
+       if (len <= off+count)
+               *eof = 1;
+        *start = page + off;
+        len -= off;
+       if (len > count)
+               len = count;
+       if (len < 0)
+               len = 0;
+        return len;
+}
+
+/*
+ * Returns true if a clock update is in progress
+ */
+static inline unsigned char rtc_is_updating(void)
+{
+       unsigned char uip;
+
+       spin_lock_irq(&rtc_lock);
+       uip = (CMOS_READ(OMAP_RTC_STATUS_REG) & OMAP_RTC_STATUS_BUSY);
+       spin_unlock_irq(&rtc_lock);
+       return uip;
+}
+
+static void bcd2tm(struct rtc_time *tm)
+{
+       BCD_TO_BIN(tm->tm_sec);
+       BCD_TO_BIN(tm->tm_min);
+       BCD_TO_BIN(tm->tm_hour);
+       BCD_TO_BIN(tm->tm_mday);
+       BCD_TO_BIN(tm->tm_mon);
+       BCD_TO_BIN(tm->tm_year);
+
+       /*
+        * Account for differences between how the RTC uses the values
+        * and how they are defined in a struct rtc_time;
+        */
+       if ((tm->tm_year += (epoch - 1900)) <= 69)
+               tm->tm_year += 100;
+
+       tm->tm_mon--;
+}
+
+
+static void get_rtc_time(struct rtc_time *rtc_tm)
+{
+       unsigned char ctrl;
+
+       /* REVISIT: Fix this comment!!!
+        * read RTC once any update in progress is done. The update
+        * can take just over 2ms. We wait 10 to 20ms. There is no need to
+        * to poll-wait (up to 1s - eeccch) for the falling edge of OMAP_RTC_STATUS_BUSY.
+        * If you need to know *exactly* when a second has started, enable
+        * periodic update complete interrupts, (via ioctl) and then 
+        * immediately read /dev/rtc which will block until you get the IRQ.
+        * Once the read clears, read the RTC time (again via ioctl). Easy.
+        */
+
+#if    0 /* REVISIT: This need to do as the TRM says. */
+       unsigned long uip_watchdog = jiffies;
+       if (rtc_is_updating() != 0)
+               while (jiffies - uip_watchdog < 2*HZ/100) {
+                       barrier();
+                       cpu_relax();
+               }
+#endif
+
+       /*
+        * Only the values that we read from the RTC are set. We leave
+        * tm_wday, tm_yday and tm_isdst untouched. Even though the
+        * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated
+        * by the RTC when initially set to a non-zero value.
+        */
+       spin_lock_irq(&rtc_lock);
+       rtc_tm->tm_sec = CMOS_READ(OMAP_RTC_SECONDS_REG);
+       rtc_tm->tm_min = CMOS_READ(OMAP_RTC_MINUTES_REG);
+       rtc_tm->tm_hour = CMOS_READ(OMAP_RTC_HOURS_REG);
+       rtc_tm->tm_mday = CMOS_READ(OMAP_RTC_DAYS_REG);
+       rtc_tm->tm_mon = CMOS_READ(OMAP_RTC_MONTHS_REG);
+       rtc_tm->tm_year = CMOS_READ(OMAP_RTC_YEARS_REG);
+       ctrl = CMOS_READ(OMAP_RTC_CTRL_REG);
+       spin_unlock_irq(&rtc_lock);
+
+       bcd2tm(rtc_tm);
+}
+
+static void get_rtc_alm_time(struct rtc_time *alm_tm)
+{
+       unsigned char ctrl;
+
+       spin_lock_irq(&rtc_lock);
+       alm_tm->tm_sec = CMOS_READ(OMAP_RTC_ALARM_SECONDS_REG);
+       alm_tm->tm_min = CMOS_READ(OMAP_RTC_ALARM_MINUTES_REG);
+       alm_tm->tm_hour = CMOS_READ(OMAP_RTC_ALARM_HOURS_REG);
+       alm_tm->tm_mday = CMOS_READ(OMAP_RTC_ALARM_DAYS_REG);
+       alm_tm->tm_mon = CMOS_READ(OMAP_RTC_ALARM_MONTHS_REG);
+       alm_tm->tm_year = CMOS_READ(OMAP_RTC_ALARM_YEARS_REG);
+       ctrl = CMOS_READ(OMAP_RTC_CTRL_REG);
+       spin_unlock_irq(&rtc_lock);
+
+       bcd2tm(alm_tm);
+}
+
+/*
+ * Used to disable/enable UIE and AIE interrupts.
+ */
+
+static void mask_rtc_irq_bit(unsigned char bit)
+{
+       unsigned char val;
+
+       spin_lock_irq(&rtc_lock);
+       val = CMOS_READ(OMAP_RTC_INTERRUPTS_REG);
+       val &=  ~bit;
+       CMOS_WRITE(val, OMAP_RTC_INTERRUPTS_REG);
+       rtc_irq_data = 0;
+       spin_unlock_irq(&rtc_lock);
+}
+
+static void set_rtc_irq_bit(unsigned char bit)
+{
+       unsigned char val;
+
+       spin_lock_irq(&rtc_lock);
+       val = CMOS_READ(OMAP_RTC_INTERRUPTS_REG);
+       val |= bit;
+       CMOS_WRITE(val, OMAP_RTC_INTERRUPTS_REG);
+       rtc_irq_data = 0;
+       spin_unlock_irq(&rtc_lock);
+}
+
+#ifdef CONFIG_PM
+static struct timespec rtc_delta;
+
+static int omap_rtc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct rtc_time rtc_tm;
+       struct timespec time;
+
+       time.tv_nsec = 0;
+       get_rtc_time(&rtc_tm);
+       rtc_tm_to_time(&rtc_tm, &time.tv_sec);
+
+       save_time_delta(&rtc_delta, &time);
+
+       return 0;
+}
+
+static int omap_rtc_resume(struct platform_device *pdev)
+{
+       struct rtc_time rtc_tm;
+       struct timespec time;
+
+       time.tv_nsec = 0;
+       get_rtc_time(&rtc_tm);
+       rtc_tm_to_time(&rtc_tm, &time.tv_sec);
+
+       restore_time_delta(&rtc_delta, &time);
+
+       return 0;
+}
+#else
+#define omap_rtc_suspend NULL
+#define omap_rtc_resume  NULL
+#endif
+
+static struct platform_driver omap_rtc_driver = {
+       .probe          = omap_rtc_probe,
+       .remove         = omap_rtc_remove,
+       .suspend        = omap_rtc_suspend,
+       .resume         = omap_rtc_resume,
+       .driver         = {
+               .name   = "omap_rtc",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static char __initdata banner[] = KERN_INFO "OMAP RTC Driver\n";
+
+static int __init rtc_init(void)
+{
+       printk(banner);
+       return platform_driver_register(&omap_rtc_driver);
+}
+
+static void __exit rtc_exit(void)
+{
+       platform_driver_unregister(&omap_rtc_driver);
+}
+
+module_init(rtc_init);
+module_exit(rtc_exit);
+
+MODULE_AUTHOR("George G. Davis (and others)");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(RTC_MINOR);
diff --git a/drivers/char/omap-rtc.h b/drivers/char/omap-rtc.h
new file mode 100644 (file)
index 0000000..d8acb56
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ *  TI OMAP Real Time Clock header file
+ *
+ *  Copyright (C) 2003 TI
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
+ */
+
+#define OMAP_RTC_BASE                  0xfffb4800
+#define OMAP_RTC_SIZE                  128
+
+#define OMAP_RTC_VIRT_BASE             IO_ADDRESS(OMAP_RTC_BASE)
+
+/*
+ * Real-Time Clock
+ */
+
+#define OMAP_RTC_SECONDS_REG            (OMAP_RTC_BASE + 0x00)
+#define OMAP_RTC_MINUTES_REG            (OMAP_RTC_BASE + 0x04)
+#define OMAP_RTC_HOURS_REG              (OMAP_RTC_BASE + 0x08)
+#define OMAP_RTC_DAYS_REG               (OMAP_RTC_BASE + 0x0C)
+#define OMAP_RTC_MONTHS_REG             (OMAP_RTC_BASE + 0x10)
+#define OMAP_RTC_YEARS_REG              (OMAP_RTC_BASE + 0x14)
+#define OMAP_RTC_WEEKS_REG              (OMAP_RTC_BASE + 0x18)
+#define OMAP_RTC_ALARM_SECONDS_REG      (OMAP_RTC_BASE + 0x20)
+#define OMAP_RTC_ALARM_MINUTES_REG      (OMAP_RTC_BASE + 0x24)
+#define OMAP_RTC_ALARM_HOURS_REG        (OMAP_RTC_BASE + 0x28)
+#define OMAP_RTC_ALARM_DAYS_REG         (OMAP_RTC_BASE + 0x2c)
+#define OMAP_RTC_ALARM_MONTHS_REG       (OMAP_RTC_BASE + 0x30)
+#define OMAP_RTC_ALARM_YEARS_REG        (OMAP_RTC_BASE + 0x34)
+#define OMAP_RTC_CTRL_REG               (OMAP_RTC_BASE + 0x40)
+#define OMAP_RTC_STATUS_REG             (OMAP_RTC_BASE + 0x44)
+#define OMAP_RTC_INTERRUPTS_REG         (OMAP_RTC_BASE + 0x48)
+#define OMAP_RTC_COMP_LSB_REG           (OMAP_RTC_BASE + 0x4c)
+#define OMAP_RTC_COMP_MSB_REG           (OMAP_RTC_BASE + 0x50)
+
+/* RTC Control Register bit fields: */
+
+#define OMAP_RTC_CTRL_STOP              (1<<0)
+
+/* RTC Status Register bit fields: */
+
+#define OMAP_RTC_STATUS_POWER_UP        (1<<7)
+#define OMAP_RTC_STATUS_ALARM           (1<<6)
+#define OMAP_RTC_STATUS_1D_EVENT        (1<<5)
+#define OMAP_RTC_STATUS_1H_EVENT        (1<<4)
+#define OMAP_RTC_STATUS_1M_EVENT        (1<<3)
+#define OMAP_RTC_STATUS_1S_EVENT        (1<<2)
+#define OMAP_RTC_STATUS_RUN             (1<<1)
+#define OMAP_RTC_STATUS_BUSY            (1<<0)
+
+/* RTC Interrupt Register bit fields: */
+
+#define OMAP_RTC_INTERRUPTS_IT_ALARM    (1<<3)
+#define OMAP_RTC_INTERRUPTS_IT_TIMER    (1<<2)
index 2cd8ff8d10ac839b1e251c51225521dd89d76ef3..b15f99e83bd13368d1d417c90943a498f7d3844d 100644 (file)
@@ -29,6 +29,7 @@ obj-$(CONFIG_21285_WATCHDOG) += wdt285.o
 obj-$(CONFIG_977_WATCHDOG) += wdt977.o
 obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o
 obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o
+obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o
 obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o
 obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o
 obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o
index 106fa01cdb6069717c61ee6a596e94d1ad38bf98..affcc00764d3d207cf2225240802a5255b2a7d9c 100644 (file)
@@ -101,7 +101,7 @@ static void __exit hwmon_exit(void)
        class_destroy(hwmon_class);
 }
 
-module_init(hwmon_init);
+subsys_initcall(hwmon_init);
 module_exit(hwmon_exit);
 
 EXPORT_SYMBOL_GPL(hwmon_device_register);
index 11935f66fcd8fcf839bafc73c74fbb1eb1a9f009..13721f2afaa5f9242aa2378a41d8e2fa3e7b90c9 100644 (file)
@@ -6,6 +6,7 @@ menu "I2C support"
 
 config I2C
        tristate "I2C support"
+       default y if MACH_OMAP_H3 || MACH_OMAP_OSK
        ---help---
          I2C (pronounce: I-square-C) is a slow serial bus protocol used in
          many micro controller applications and developed by Philips.  SMBus,
index 37196c1d0794e830b34b7c16f41ea68774a38940..a0c423351cebeb7c3e4a5266350b397779d7aeec 100644 (file)
@@ -46,6 +46,7 @@ obj-$(CONFIG_I2C_VIAPRO)      += i2c-viapro.o
 obj-$(CONFIG_I2C_VOODOO3)      += i2c-voodoo3.o
 obj-$(CONFIG_SCx200_ACB)       += scx200_acb.o
 obj-$(CONFIG_SCx200_I2C)       += scx200_i2c.o
+obj-$(CONFIG_I2C_OMAP)          += i2c-omap.o
 
 ifeq ($(CONFIG_I2C_DEBUG_BUS),y)
 EXTRA_CFLAGS += -DDEBUG
index bcd8367cede1aa0dc13b221d14266166c1e9e346..5308d672255e7fb75cbd3c61e6187288ed438771 100644 (file)
 
 #include <asm/io.h>
 
+/* Hack to enable zero length transfers and smbus quick until clean fix
+   is available */
+#define OMAP_HACK
+
 /* timeout waiting for the controller to respond */
 #define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000))
 
@@ -285,12 +289,16 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
                             struct i2c_msg *msg, int stop)
 {
        struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
+#ifdef OMAP_HACK
+       u8 zero_byte = 0;
+#endif
        int r;
        u16 w;
 
        dev_dbg(dev->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
                msg->addr, msg->len, msg->flags, stop);
 
+#ifndef OMAP_HACK
        if (msg->len == 0)
                return -EINVAL;
 
@@ -300,6 +308,27 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
        dev->buf = msg->buf;
        dev->buf_len = msg->len;
 
+#else
+
+       omap_i2c_write_reg(dev, OMAP_I2C_SA_REG, msg->addr);
+       /* REVISIT: Remove this hack when we can get I2C chips from board-*.c
+        *          files
+        * Sigh, seems we can't do zero length transactions. Thus, we
+        * can't probe for devices w/o actually sending/receiving at least
+        * a single byte. So we'll set count to 1 for the zero length
+        * transaction case and hope we don't cause grief for some
+        * arbitrary device due to random byte write/read during
+        * probes.
+        */
+       if (msg->len == 0) {
+               dev->buf = &zero_byte;
+               dev->buf_len = 1;
+       } else {
+               dev->buf = msg->buf;
+               dev->buf_len = msg->len;
+       }
+#endif
+
        omap_i2c_write_reg(dev, OMAP_I2C_CNT_REG, dev->buf_len);
 
        init_completion(&dev->cmd_complete);
@@ -314,8 +343,8 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
                w |= OMAP_I2C_CON_STP;
        omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
 
-       r = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
-                                                     OMAP_I2C_TIMEOUT);
+       r = wait_for_completion_timeout(&dev->cmd_complete,
+                                       OMAP_I2C_TIMEOUT);
        dev->buf_len = 0;
        if (r < 0)
                return r;
@@ -383,7 +412,11 @@ out:
 static u32
 omap_i2c_func(struct i2c_adapter *adap)
 {
+#ifndef OMAP_HACK
        return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
+#else
+       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+#endif
 }
 
 static inline void
@@ -478,9 +511,14 @@ omap_i2c_isr(int this_irq, void *dev_id)
                        if (dev->buf_len) {
                                *dev->buf++ = w;
                                dev->buf_len--;
-                               if (dev->buf_len) {
-                                       *dev->buf++ = w >> 8;
-                                       dev->buf_len--;
+                               /*
+                                * Data reg in 2430 is 8 bit wide,
+                                */
+                               if (!cpu_is_omap2430()) {
+                                       if (dev->buf_len) {
+                                               *dev->buf++ = w >> 8;
+                                               dev->buf_len--;
+                                       }
                                }
                        } else
                                dev_err(dev->dev, "RRDY IRQ while no data"
@@ -493,9 +531,14 @@ omap_i2c_isr(int this_irq, void *dev_id)
                        if (dev->buf_len) {
                                w = *dev->buf++;
                                dev->buf_len--;
-                               if (dev->buf_len) {
-                                       w |= *dev->buf++ << 8;
-                                       dev->buf_len--;
+                               /*
+                                * Data reg in 2430 is 8 bit wide,
+                                */
+                               if (!cpu_is_omap2430()) {
+                                       if (dev->buf_len) {
+                                               w |= *dev->buf++ << 8;
+                                               dev->buf_len--;
+                                       }
                                }
                        } else
                                dev_err(dev->dev, "XRDY IRQ while no"
index 87ee3ce58618b7c3ed7a519859b042023be325fb..3f54badd49a761efe156c683131f883bf2a0a3a5 100644 (file)
@@ -101,6 +101,32 @@ config TPS65010
          This driver can also be built as a module.  If so, the module
          will be called tps65010.
 
+config SENSORS_TLV320AIC23
+       tristate "Texas Instruments TLV320AIC23 Codec"
+       depends on I2C && I2C_OMAP
+       help
+         If you say yes here you get support for the I2C control
+         interface for Texas Instruments TLV320AIC23 audio codec.
+
+config GPIOEXPANDER_OMAP
+       bool "GPIO Expander PCF8574PWR for OMAP"
+       depends on I2C && (ARCH_OMAP16XX || ARCH_OMAP24XX)
+       help
+         If you say yes here you get support for I/O expander calls
+         to configure IrDA, Camera and audio devices.
+
+config MENELAUS
+       bool "Menelaus PM chip"
+       depends on I2C=y && ARCH_OMAP24XX
+       help
+         Say yes here if you have Menelaus chip on your board
+
+config TWL4030_CORE
+       bool "TI's TWL4030 companion chip Core Driver Support"
+       depends on I2C=y && ARCH_OMAP24XX
+       help
+         Say yes here if you have TWL4030 chip on your board
+
 config SENSORS_M41T00
        tristate "ST M41T00 RTC chip"
        depends on I2C && PPC32
index 779868ef2e268c6a4520625acadcd21823ceb50b..2ea4a4a09c19cad26b918907805cb1320bebdb67 100644 (file)
@@ -12,6 +12,11 @@ obj-$(CONFIG_SENSORS_PCF8574)        += pcf8574.o
 obj-$(CONFIG_SENSORS_PCF8591)  += pcf8591.o
 obj-$(CONFIG_ISP1301_OMAP)     += isp1301_omap.o
 obj-$(CONFIG_TPS65010)         += tps65010.o
+obj-$(CONFIG_SENSORS_TLV320AIC23) += tlv320aic23.o
+obj-$(CONFIG_GPIOEXPANDER_OMAP)        += gpio_expander_omap.o
+obj-$(CONFIG_MENELAUS)         += menelaus.o
+obj-$(CONFIG_TWL4030_CORE)      += twl4030_core.o
+obj-$(CONFIG_RTC_X1205_I2C)    += x1205.o
 
 ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
 EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/i2c/chips/gpio_expander_omap.c b/drivers/i2c/chips/gpio_expander_omap.c
new file mode 100644 (file)
index 0000000..d63a6ee
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * drivers/i2c/chips/gpio_expander_omap.c
+ *
+ * Copyright (C) 2004 Texas Instruments Inc
+ * Author:
+ *
+ * gpio expander is used to configure IrDA, camera and audio devices on omap 1710 processor.
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/errno.h>
+
+int read_gpio_expa(u8 * val, int addr);
+int write_gpio_expa(u8 val, int addr);
+
+int write_gpio_expa(u8 val, int addr)
+{
+       struct i2c_adapter *adap;
+       int err;
+       struct i2c_msg msg[1];
+       unsigned char data[1];
+
+       adap = i2c_get_adapter(0);
+       if (!adap)
+               return -ENODEV;
+       msg->addr = addr;       /* I2C address of GPIO EXPA */
+       msg->flags = 0;
+       msg->len = 1;
+       msg->buf = data;
+       data[0] = val;
+       err = i2c_transfer(adap, msg, 1);
+       if (err >= 0)
+               return 0;
+       return err;
+}
+
+/* Read from I/O EXPANDER on the H3 board.
+ * The IO expanders need an independent I2C client driver.
+ */
+
+int read_gpio_expa(u8 * val, int addr)
+{
+       struct i2c_adapter *adap;
+       int err;
+       struct i2c_msg msg[1];
+       unsigned char data[1];
+
+       adap = i2c_get_adapter(0);
+       if (!adap)
+               return -ENODEV;
+       msg->addr = addr;       /* I2C address of GPIO EXPA */
+       msg->flags = I2C_M_RD;
+       msg->len = 2;
+       msg->buf = data;
+       err = i2c_transfer(adap, msg, 1);
+       *val = data[0];
+
+       if (err >= 0)
+               return 0;
+       return err;
+}
+
+EXPORT_SYMBOL(read_gpio_expa);
+EXPORT_SYMBOL(write_gpio_expa);
+
index ccdf3e90862ba4b979736b6955113067c69c248f..e2717542e0ea940bc9c56e69a202dd594db08d37 100644 (file)
 #include <linux/workqueue.h>
 
 #include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/gpio.h>
 #include <asm/arch/usb.h>
+#include <asm/arch/mux.h>
 
 
 #ifndef        DEBUG
@@ -44,7 +48,7 @@
 
 
 #define        DRIVER_VERSION  "24 August 2004"
-#define        DRIVER_NAME     (isp1301_driver.name)
+#define        DRIVER_NAME     (isp1301_driver.driver.name)
 
 MODULE_DESCRIPTION("ISP1301 USB OTG Transceiver Driver");
 MODULE_LICENSE("GPL");
@@ -55,6 +59,7 @@ struct isp1301 {
        void                    (*i2c_release)(struct device *dev);
 
        int                     irq;
+       int                     irq_type;
 
        u32                     last_otg_ctrl;
        unsigned                working:1;
@@ -63,7 +68,7 @@ struct isp1301 {
 
        /* use keventd context to change the state for us */
        struct work_struct      work;
-       
+
        unsigned long           todo;
 #              define WORK_UPDATE_ISP  0       /* update ISP from OTG */
 #              define WORK_UPDATE_OTG  1       /* update OTG from ISP */
@@ -90,14 +95,11 @@ struct isp1301 {
 
 /*-------------------------------------------------------------------------*/
 
-#ifdef CONFIG_MACH_OMAP_H2
+#if    defined(CONFIG_MACH_OMAP_H2) || \
+       defined(CONFIG_MACH_OMAP_H3)
 
 /* board-specific PM hooks */
 
-#include <asm/arch/gpio.h>
-#include <asm/arch/mux.h>
-#include <asm/mach-types.h>
-
 
 #if    defined(CONFIG_TPS65010) || defined(CONFIG_TPS65010_MODULE)
 
@@ -128,17 +130,30 @@ static void enable_vbus_source(struct isp1301 *isp)
 }
 
 
-/* products will deliver OTG messages with LEDs, GUI, etc */
-static inline void notresponding(struct isp1301 *isp)
+#else
+
+static void enable_vbus_draw(struct isp1301 *isp, unsigned mA)
 {
-       printk(KERN_NOTICE "OTG device not responding.\n");
+       pr_debug("%s UNIMPL\n", __FUNCTION__);
 }
 
+static void enable_vbus_source(struct isp1301 *isp)
+{
+       pr_debug("%s UNIMPL\n", __FUNCTION__);
+}
 
 #endif
 
 /*-------------------------------------------------------------------------*/
 
+/* products will deliver OTG messages with LEDs, GUI, etc */
+static inline void notresponding(struct isp1301 *isp)
+{
+       printk(KERN_NOTICE "OTG device not responding.\n");
+}
+
+/*-------------------------------------------------------------------------*/
+
 /* only two addresses possible */
 #define        ISP_BASE                0x2c
 static unsigned short normal_i2c[] = {
@@ -291,7 +306,7 @@ static void power_up(struct isp1301 *isp)
 {
        // isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_2, MC2_GLOBAL_PWR_DN);
        isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, MC1_SUSPEND_REG);
-       
+
        /* do this only when cpu is driving transceiver,
         * so host won't see a low speed device...
         */
@@ -514,6 +529,7 @@ static inline void check_state(struct isp1301 *isp, const char *tag) { }
 static void update_otg1(struct isp1301 *isp, u8 int_src)
 {
        u32     otg_ctrl;
+       u8      int_id;
 
        otg_ctrl = OTG_CTRL_REG
                        & OTG_CTRL_MASK
@@ -527,7 +543,10 @@ static void update_otg1(struct isp1301 *isp, u8 int_src)
        }
        if (int_src & INTR_VBUS_VLD)
                otg_ctrl |= OTG_VBUSVLD;
-       if (int_src & INTR_ID_GND) {            /* default-A */
+
+       int_id = isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE);
+
+       if (int_id & INTR_ID_GND) {             /* default-A */
                if (isp->otg.state == OTG_STATE_B_IDLE
                                || isp->otg.state == OTG_STATE_UNDEFINED) {
                        a_idle(isp, "init");
@@ -799,7 +818,7 @@ static irqreturn_t omap_otg_irq(int irq, void *_isp)
                /* role is host */
                } else {
                        if (!(otg_ctrl & OTG_ID)) {
-                               otg_ctrl &= OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS;
+                               otg_ctrl &= OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS;
                                OTG_CTRL_REG = otg_ctrl | OTG_A_BUSREQ;
                        }
 
@@ -1082,7 +1101,7 @@ static void isp_update_otg(struct isp1301 *isp, u8 stat)
        /* update the OTG controller state to match the isp1301; may
         * trigger OPRT_CHG irqs for changes going to the isp1301.
         */
-       update_otg1(isp, isp_stat);
+       update_otg1(isp, stat); // pass the actual interrupt latch status
        update_otg2(isp, isp_bstat);
        check_state(isp, __FUNCTION__);
 #endif
@@ -1100,9 +1119,9 @@ static u8 isp1301_clear_latch(struct isp1301 *isp)
 }
 
 static void
-isp1301_work(void *data)
+isp1301_work(struct work_struct *work)
 {
-       struct isp1301  *isp = data;
+       struct isp1301  *isp = container_of(work, struct isp1301, work);
        int             stop;
 
        /* implicit lock:  we're the only task using this device */
@@ -1223,6 +1242,12 @@ static int isp1301_detach_client(struct i2c_client *i2c)
        if (machine_is_omap_h2())
                omap_free_gpio(2);
 
+       if (machine_is_omap_h3())
+               omap_free_gpio(14);
+
+       if (machine_is_omap_h4())
+               omap_free_gpio(125);
+
        isp->timer.data = 0;
        set_bit(WORK_STOP, &isp->todo);
        del_timer_sync(&isp->timer);
@@ -1244,7 +1269,7 @@ static int isp1301_detach_client(struct i2c_client *i2c)
  *  - DEVICE mode, for when there's a B/Mini-B (device) connector
  *
  * As a rule, you won't have an isp1301 chip unless it's there to
- * support the OTG mode.  Other modes help testing USB controllers 
+ * support the OTG mode.  Other modes help testing USB controllers
  * in isolation from (full) OTG support, or maybe so later board
  * revisions can help to support those feature.
  */
@@ -1260,9 +1285,9 @@ static int isp1301_otg_enable(struct isp1301 *isp)
         * a few more interrupts than are strictly needed.
         */
        isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING,
-               INTR_VBUS_VLD | INTR_SESS_VLD | INTR_ID_GND);
+               INTR_VBUS_VLD | INTR_SESS_VLD | INTR_ID_GND);
        isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
-               INTR_VBUS_VLD | INTR_SESS_VLD | INTR_ID_GND);
+               INTR_VBUS_VLD | INTR_SESS_VLD | INTR_ID_GND);
 
        dev_info(&isp->client.dev, "ready for dual-role USB ...\n");
 
@@ -1301,14 +1326,15 @@ isp1301_set_host(struct otg_transceiver *otg, struct usb_bus *host)
 
        power_up(isp);
 
-       if (machine_is_omap_h2())
+// XXX h4 too?
+       if (machine_is_omap_h2() || machine_is_omap_h3())
                isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0);
 
        dev_info(&isp->client.dev, "A-Host sessions ok\n");
        isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING,
-               INTR_ID_GND);
+               INTR_ID_GND);
        isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
-               INTR_ID_GND);
+               INTR_ID_GND);
 
        /* If this has a Mini-AB connector, this mode is highly
         * nonstandard ... but can be handy for testing, especially with
@@ -1364,13 +1390,14 @@ isp1301_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *gadget)
        power_up(isp);
        isp->otg.state = OTG_STATE_B_IDLE;
 
-       if (machine_is_omap_h2())
+// XXX h4 too?
+       if (machine_is_omap_h2() || machine_is_omap_h3())
                isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0);
 
        isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING,
-               INTR_SESS_VLD);
+               INTR_SESS_VLD | INTR_VBUS_VLD);
        isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
-               INTR_VBUS_VLD);
+               INTR_VBUS_VLD | INTR_SESS_VLD);
        dev_info(&isp->client.dev, "B-Peripheral sessions ok\n");
        dump_regs(isp, __FUNCTION__);
 
@@ -1447,6 +1474,10 @@ isp1301_start_hnp(struct otg_transceiver *dev)
         * So do this part as early as possible...
         */
        switch (isp->otg.state) {
+       case OTG_STATE_B_PERIPHERAL:
+               isp->otg.state = OTG_STATE_B_WAIT_ACON;
+               isp1301_defer_work(isp, WORK_UPDATE_ISP);
+               break;
        case OTG_STATE_B_HOST:
                isp->otg.state = OTG_STATE_B_PERIPHERAL;
                /* caller will suspend next */
@@ -1494,12 +1525,13 @@ static int isp1301_probe(struct i2c_adapter *bus, int address, int kind)
        if (!isp)
                return 0;
 
-       INIT_WORK(&isp->work, isp1301_work, isp);
+       INIT_WORK(&isp->work, isp1301_work);
        init_timer(&isp->timer);
        isp->timer.function = isp1301_timer;
        isp->timer.data = (unsigned long) isp;
 
        isp->irq = -1;
+       isp->irq_type = 0;
        isp->client.addr = address;
        i2c_set_clientdata(&isp->client, isp);
        isp->client.adapter = bus;
@@ -1562,23 +1594,44 @@ fail1:
        }
 #endif
 
-       if (machine_is_omap_h2()) {
+// XXX h4 too?
+       if (machine_is_omap_h2() || machine_is_omap_h3()) {
                /* full speed signaling by default */
                isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1,
                        MC1_SPEED_REG);
                isp1301_set_bits(isp, ISP1301_MODE_CONTROL_2,
                        MC2_SPD_SUSP_CTRL);
+       }
 
+       if (machine_is_omap_h2()) {
                /* IRQ wired at M14 */
                omap_cfg_reg(M14_1510_GPIO2);
                isp->irq = OMAP_GPIO_IRQ(2);
                omap_request_gpio(2);
                omap_set_gpio_direction(2, 1);
-               omap_set_gpio_edge_ctrl(2, OMAP_GPIO_FALLING_EDGE);
+               isp->irq_type = IRQF_TRIGGER_FALLING;
+       }
+
+       if (machine_is_omap_h3()) {
+               /* IRQ wired at N21 */
+               omap_cfg_reg(N21_1710_GPIO14);
+               isp->irq = OMAP_GPIO_IRQ(14);
+               omap_request_gpio(14);
+               omap_set_gpio_direction(14, 1);
+               isp->irq_type = IRQF_TRIGGER_FALLING;
+       }
+
+       if (machine_is_omap_h4()) {
+               /* IRQ wired at P14 */
+               omap_cfg_reg(P14_24XX_GPIO125);
+               isp->irq = OMAP_GPIO_IRQ(125);
+               omap_request_gpio(125);
+               omap_set_gpio_direction(125, 1);
+               isp->irq_type = IRQF_TRIGGER_LOW;
        }
 
        status = request_irq(isp->irq, isp1301_irq,
-                       IRQF_SAMPLE_RANDOM, DRIVER_NAME, isp);
+                       isp->irq_type, DRIVER_NAME, isp);
        if (status < 0) {
                dev_dbg(&i2c->dev, "can't get IRQ %d, err %d\n",
                                isp->irq, status);
diff --git a/drivers/i2c/chips/menelaus.c b/drivers/i2c/chips/menelaus.c
new file mode 100644 (file)
index 0000000..b9510f3
--- /dev/null
@@ -0,0 +1,959 @@
+/*
+ * drivers/i2c/chips/menelaus.c
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *
+ * Some parts based tps65010.c:
+ * Copyright (C) 2004 Texas Instruments and
+ * Copyright (C) 2004-2005 David Brownell
+ *
+ * Some parts based on tlv320aic24.c:
+ * Copyright (C) by Kai Svahn <kai.svahn@nokia.com>
+ *
+ * Changes for interrupt handling and clean-up by
+ * Tony Lindgren <tony@atomide.com> and Imre Deak <imre.deak@nokia.com>
+ * 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 <asm/mach-types.h>
+#include <asm/mach/irq.h>
+
+#include <asm/arch/mux.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/menelaus.h>
+
+#define DEBUG
+
+#define DRIVER_NAME                    "menelaus"
+
+#define pr_err(fmt, arg...)    printk(KERN_ERR DRIVER_NAME ": ", ## arg);
+
+#define MENELAUS_I2C_ADDRESS           0x72
+
+#define MENELAUS_REV                   0x01
+#define MENELAUS_VCORE_CTRL1           0x02
+#define MENELAUS_VCORE_CTRL2           0x03
+#define MENELAUS_VCORE_CTRL3           0x04
+#define MENELAUS_VCORE_CTRL4           0x05
+#define MENELAUS_VCORE_CTRL5           0x06
+#define MENELAUS_DCDC_CTRL1            0x07
+#define MENELAUS_DCDC_CTRL2            0x08
+#define MENELAUS_DCDC_CTRL3            0x09
+#define MENELAUS_LDO_CTRL1             0x0A
+#define MENELAUS_LDO_CTRL2             0x0B
+#define MENELAUS_LDO_CTRL3             0x0C
+#define MENELAUS_LDO_CTRL4             0x0D
+#define MENELAUS_LDO_CTRL5             0x0E
+#define MENELAUS_LDO_CTRL6             0x0F
+#define MENELAUS_LDO_CTRL7             0x10
+#define MENELAUS_LDO_CTRL8             0x11
+#define MENELAUS_SLEEP_CTRL1           0x12
+#define MENELAUS_SLEEP_CTRL2           0x13
+#define MENELAUS_DEVICE_OFF            0x14
+#define MENELAUS_OSC_CTRL              0x15
+#define MENELAUS_DETECT_CTRL           0x16
+#define MENELAUS_INT_MASK1             0x17
+#define MENELAUS_INT_MASK2             0x18
+#define MENELAUS_INT_STATUS1           0x19
+#define MENELAUS_INT_STATUS2           0x1A
+#define MENELAUS_INT_ACK1              0x1B
+#define MENELAUS_INT_ACK2              0x1C
+#define MENELAUS_GPIO_CTRL             0x1D
+#define MENELAUS_GPIO_IN               0x1E
+#define MENELAUS_GPIO_OUT              0x1F
+#define MENELAUS_BBSMS                 0x20
+#define MENELAUS_RTC_CTRL              0x21
+#define MENELAUS_RTC_UPDATE            0x22
+#define MENELAUS_RTC_SEC               0x23
+#define MENELAUS_RTC_MIN               0x24
+#define MENELAUS_RTC_HR                        0x25
+#define MENELAUS_RTC_DAY               0x26
+#define MENELAUS_RTC_MON               0x27
+#define MENELAUS_RTC_YR                        0x28
+#define MENELAUS_RTC_WKDAY             0x29
+#define MENELAUS_RTC_AL_SEC            0x2A
+#define MENELAUS_RTC_AL_MIN            0x2B
+#define MENELAUS_RTC_AL_HR             0x2C
+#define MENELAUS_RTC_AL_DAY            0x2D
+#define MENELAUS_RTC_AL_MON            0x2E
+#define MENELAUS_RTC_AL_YR             0x2F
+#define MENELAUS_RTC_COMP_MSB          0x30
+#define MENELAUS_RTC_COMP_LSB          0x31
+#define MENELAUS_S1_PULL_EN            0x32
+#define MENELAUS_S1_PULL_DIR           0x33
+#define MENELAUS_S2_PULL_EN            0x34
+#define MENELAUS_S2_PULL_DIR           0x35
+#define MENELAUS_MCT_CTRL1             0x36
+#define MENELAUS_MCT_CTRL2             0x37
+#define MENELAUS_MCT_CTRL3             0x38
+#define MENELAUS_MCT_PIN_ST            0x39
+#define MENELAUS_DEBOUNCE1             0x3A
+
+#define IH_MENELAUS_IRQS               12
+#define MENELAUS_MMC_S1CD_IRQ          0       /* MMC slot 1 card change */
+#define MENELAUS_MMC_S2CD_IRQ          1       /* MMC slot 2 card change */
+#define MENELAUS_MMC_S1D1_IRQ          2       /* MMC DAT1 low in slot 1 */
+#define MENELAUS_MMC_S2D1_IRQ          3       /* MMC DAT1 low in slot 2 */
+#define MENELAUS_LOWBAT_IRQ            4       /* Low battery */
+#define MENELAUS_HOTDIE_IRQ            5       /* Hot die detect */
+#define MENELAUS_UVLO_IRQ              6       /* UVLO detect */
+#define MENELAUS_TSHUT_IRQ             7       /* Thermal shutdown */
+#define MENELAUS_RTCTMR_IRQ            8       /* RTC timer */
+#define MENELAUS_RTCALM_IRQ            9       /* RTC alarm */
+#define MENELAUS_RTCERR_IRQ            10      /* RTC error */
+#define MENELAUS_PSHBTN_IRQ            11      /* Push button */
+#define MENELAUS_RESERVED12_IRQ                12      /* Reserved */
+#define MENELAUS_RESERVED13_IRQ                13      /* Reserved */
+#define MENELAUS_RESERVED14_IRQ                14      /* Reserved */
+#define MENELAUS_RESERVED15_IRQ                15      /* Reserved */
+
+static void menelaus_work(struct work_struct *_menelaus);
+
+/* Initialized by menelaus_init */
+static unsigned short normal_i2c[] = { MENELAUS_I2C_ADDRESS, I2C_CLIENT_END };
+
+I2C_CLIENT_INSMOD;
+
+struct menelaus_chip {
+       unsigned long           initialized;
+       struct mutex            lock;
+       struct i2c_client       client;
+       struct work_struct      work;
+       int                     irq;
+       unsigned                vcore_hw_mode:1;
+       void                    *handlers[16];
+       void                    (*mmc_callback)(void *data, u8 mask);
+       void                    *mmc_callback_data;
+};
+
+static struct menelaus_chip menelaus;
+static struct menelaus_platform_data *menelaus_pdata;
+
+static int menelaus_write_reg(int reg, u8 value)
+{
+       int val = i2c_smbus_write_byte_data(&menelaus.client, reg, value);
+
+       if (val < 0) {
+               pr_err("write error");
+               return val;
+       }
+
+       return 0;
+}
+
+static int menelaus_read_reg(int reg)
+{
+       int val = i2c_smbus_read_byte_data(&menelaus.client, reg);
+
+       if (val < 0)
+               pr_err("read error");
+
+       return val;
+}
+
+static int menelaus_enable_irq(int irq)
+{
+       if (irq > 7)
+               return menelaus_write_reg(MENELAUS_INT_MASK2,
+                                         menelaus_read_reg(MENELAUS_INT_MASK2)
+                                         & ~(1 << (irq - 8)));
+       else
+               return menelaus_write_reg(MENELAUS_INT_MASK1,
+                                         menelaus_read_reg(MENELAUS_INT_MASK1)
+                                         & ~(1 << irq));
+}
+
+static int menelaus_disable_irq(int irq)
+{
+       if (irq > 7)
+               return menelaus_write_reg(menelaus_read_reg(MENELAUS_INT_MASK2)
+                                         | (1 << (irq - 8)),
+                                         MENELAUS_INT_MASK2);
+       else
+               return menelaus_write_reg(MENELAUS_INT_MASK1,
+                                         menelaus_read_reg(MENELAUS_INT_MASK1)
+                                         | (1 << irq));
+}
+
+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)
+{
+       int ret = 0;
+
+       mutex_lock(&menelaus.lock);
+       menelaus.handlers[irq] = handler;
+       ret = menelaus_enable_irq(irq);
+       mutex_unlock(&menelaus.lock);
+
+       return ret;
+}
+
+/* Removes handler for an interrupt */
+static int menelaus_remove_irq_work(int irq)
+{
+       int ret = 0;
+
+       mutex_lock(&menelaus.lock);
+       ret = menelaus_disable_irq(irq);
+       menelaus.handlers[irq] = NULL;
+       mutex_unlock(&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 int 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 reg;
+
+       if (!(reg & 0x1))
+               card_mask |= (1 << 0);
+
+       if (!(reg & 0x2))
+               card_mask |= (1 << 1);
+
+       if (menelaus_hw->mmc_callback)
+               menelaus_hw->mmc_callback(menelaus_hw->mmc_callback_data,
+                                         card_mask);
+
+       return 0;
+}
+
+/*
+ * 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(&menelaus.lock);
+       ret = menelaus_read_reg(MENELAUS_MCT_CTRL1);
+       if (ret < 0) {
+               mutex_unlock(&menelaus.lock);
+               return ret;
+       }
+       val = ret;
+       if (slot == 1) {
+               if (enable)
+                       val |= 1 << 2;
+               else
+                       val &= ~(1 << 2);
+       } else {
+               if (enable)
+                       val |= 1 << 3;
+               else
+                       val &= ~(1 << 3);
+       }
+       ret = menelaus_write_reg(MENELAUS_MCT_CTRL1, val);
+       mutex_unlock(&menelaus.lock);
+
+       return ret;
+}
+EXPORT_SYMBOL(menelaus_set_mmc_opendrain);
+
+int menelaus_set_slot_sel(int enable)
+{
+       int ret;
+
+       mutex_lock(&menelaus.lock);
+       ret = menelaus_read_reg(MENELAUS_GPIO_CTRL);
+       if (ret < 0)
+               goto out;
+       ret |= 0x02;
+       if (enable)
+               ret |= 1 << 5;
+       else
+               ret &= ~(1 << 5);
+       ret = menelaus_write_reg(MENELAUS_GPIO_CTRL, ret);
+out:
+       mutex_unlock(&menelaus.lock);
+       return ret;
+}
+EXPORT_SYMBOL(menelaus_set_slot_sel);
+
+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(&menelaus.lock);
+
+       ret = menelaus_read_reg(MENELAUS_MCT_CTRL2);
+       if (ret < 0)
+               goto out;
+       val = ret;
+       if (slot == 1) {
+               if (cd_en)
+                       val |= (1 << 4) | (1 << 6);
+               else
+                       val &= ~((1 << 4) | (1 << 6));
+       } else {
+               if (cd_en)
+                       val |= (1 << 5) | (1 << 7);
+               else
+                       val &= ~((1 << 5) | (1 << 7));
+       }
+       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 |= 1 << 0;
+               else
+                       val &= ~(1 << 0);
+       } else {
+               int b;
+
+               if (enable)
+                       ret |= 1 << 1;
+               else
+                       ret &= ~(1 << 1);
+               b = menelaus_read_reg(MENELAUS_MCT_CTRL2);
+               b &= ~0x03;
+               b |= power;
+               ret = menelaus_write_reg(MENELAUS_MCT_CTRL2, b);
+               if (ret < 0)
+                       goto out;
+       }
+       /* Disable autonomous shutdown */
+       val &= ~(0x03 << 2);
+       ret = menelaus_write_reg(MENELAUS_MCT_CTRL3, val);
+out:
+       mutex_unlock(&menelaus.lock);
+       return ret;
+}
+EXPORT_SYMBOL(menelaus_set_mmc_slot);
+
+#include <linux/delay.h>
+
+int menelaus_register_mmc_callback(void (*callback)(void *data, u8 card_mask),
+                                  void *data)
+{
+       int ret = 0;
+
+       menelaus.mmc_callback_data = data;
+       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);
+
+       menelaus.mmc_callback = NULL;
+       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;
+
+       mutex_lock(&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;
+#ifdef DEBUG
+       printk("menelaus: Setting voltage '%s' to %d mV (reg 0x%02x, val 0x%02x)\n",
+              vtg->name, mV, vtg->vtg_reg, val);
+#endif
+       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(&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;
+
+       val = menelaus_get_vtg_value(mV, vcore_values, ARRAY_SIZE(vcore_values));
+       if (val < 0)
+               return -EINVAL;
+#ifdef DEBUG
+       printk("menelaus: Setting VCORE to %d mV (val 0x%02x)\n", mV, val);
+#endif
+
+       /* Set SW mode and the voltage in one go. */
+       mutex_lock(&menelaus.lock);
+       ret = menelaus_write_reg(MENELAUS_VCORE_CTRL1, val);
+       if (ret == 0)
+               menelaus.vcore_hw_mode = 0;
+       mutex_unlock(&menelaus.lock);
+       msleep(1);
+
+       return ret;
+}
+
+int menelaus_set_vcore_hw(unsigned int roof_mV, unsigned int floor_mV)
+{
+       int fval, rval, val, ret;
+
+       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;
+
+#ifdef DEBUG
+       printk("menelaus: Setting VCORE FLOOR to %d mV and ROOF to %d mV\n",
+              floor_mV, roof_mV);
+#endif
+
+       mutex_lock(&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 (!menelaus.vcore_hw_mode) {
+               val = menelaus_read_reg(MENELAUS_VCORE_CTRL1);
+               val |= ((1 << 7) | (1 << 5)); /* HW mode, turn OFF byte comparator */
+               ret = menelaus_write_reg(MENELAUS_VCORE_CTRL1, val);
+               menelaus.vcore_hw_mode = 1;
+       }
+       msleep(1);
+out:
+       mutex_unlock(&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;
+
+        mutex_lock(&menelaus.lock);
+       ret = menelaus_write_reg(MENELAUS_SLEEP_CTRL2, val);
+       if (ret < 0)
+               goto out;
+#ifdef DEBUG
+       printk("menelaus: regulator sleep configuration: %02x\n", val);
+#endif
+       ret = menelaus_read_reg(MENELAUS_GPIO_CTRL);
+       if (ret < 0)
+               goto out;
+       t = ((1 << 6) | 0x04);
+       if (enable)
+               ret |= t;
+       else
+               ret &= ~t;
+       ret = menelaus_write_reg(MENELAUS_GPIO_CTRL, ret);
+out:
+       mutex_unlock(&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);
+       int (*handler)(struct menelaus_chip *menelaus);
+
+       while (1) {
+               int i;
+               unsigned char isr;
+
+               isr = menelaus_read_reg(MENELAUS_INT_STATUS1) |
+                     (menelaus_read_reg(MENELAUS_INT_STATUS2) << 8);
+
+               if (!isr)
+                       break;
+
+               for (i = 0; i < IH_MENELAUS_IRQS; i++) {
+                       if (isr & (1 << i)) {
+                               mutex_lock(&menelaus->lock);
+                               menelaus_disable_irq(i);
+                               menelaus_ack_irq(i);
+                               if (menelaus->handlers[i]) {
+                                       handler = menelaus->handlers[i];
+                                       handler(menelaus);
+                               }
+                               menelaus_enable_irq(i);
+                               mutex_unlock(&menelaus->lock);
+                       }
+               }
+       }
+       enable_irq(menelaus->irq);
+}
+
+/*
+ * We cannot use I2C in interrupt context, so we just schedule work.
+ */
+static irqreturn_t menelaus_irq(int irq, void *_menelaus)
+{
+       struct menelaus_chip *menelaus = _menelaus;
+
+       disable_irq_nosync(irq);
+       (void)schedule_work(&menelaus->work);
+
+       return IRQ_HANDLED;
+}
+
+static struct i2c_driver menelaus_i2c_driver;
+
+static int menelaus_probe(struct i2c_adapter *adapter, int address, int kind)
+{
+       struct i2c_client       *c;
+       int                     rev = 0, val;
+       int                     err = 0;
+
+       if (test_and_set_bit(0, &menelaus.initialized))
+               return -EBUSY;
+
+       c = &menelaus.client;
+       strncpy(c->name, DRIVER_NAME, sizeof(c->name));
+       c->addr         = address;
+       c->adapter      = adapter;
+       c->driver       = &menelaus_i2c_driver;
+       c->flags        = 0;
+
+       if ((err = i2c_attach_client(c)) < 0) {
+               pr_err("couldn't attach\n");
+               goto fail1;
+       }
+
+       /* If a true probe check the device */
+       if (kind < 0 && (rev = menelaus_read_reg(MENELAUS_REV)) < 0) {
+               pr_err("device not found");
+               err = -ENODEV;
+               goto fail2;
+       }
+
+       /* Most likely Menelaus interrupt is at SYS_NIRQ */
+       omap_cfg_reg(W19_24XX_SYS_NIRQ);
+       menelaus.irq = INT_24XX_SYS_NIRQ;
+
+       /* 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);
+
+       /* Set output buffer strengths */
+       menelaus_write_reg(MENELAUS_MCT_CTRL1, 0x73);
+
+       err = request_irq(menelaus.irq, menelaus_irq, IRQF_DISABLED,
+                         DRIVER_NAME, &menelaus);
+       if (err) {
+               printk(KERN_ERR "Could not get Menelaus IRQ\n");
+               goto fail2;
+       }
+
+       mutex_init(&menelaus.lock);
+       INIT_WORK(&menelaus.work, menelaus_work);
+
+       if (kind < 0)
+               pr_info("Menelaus rev %d.%d\n", rev >> 4, rev & 0x0f);
+
+       val = menelaus_read_reg(MENELAUS_VCORE_CTRL1);
+       if (val < 0)
+               goto fail3;
+       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(&c->dev);
+               if (err < 0)
+                       goto fail3;
+       }
+
+       return 0;
+fail3:
+       free_irq(menelaus.irq, &menelaus);
+       flush_scheduled_work();
+fail2:
+       i2c_detach_client(c);
+fail1:
+       clear_bit(0, &menelaus.initialized);
+       return err;
+}
+
+static int menelaus_remove(struct i2c_client *client)
+{
+       int err;
+
+       free_irq(menelaus.irq, &menelaus);
+
+       if ((err = i2c_detach_client(client))) {
+               pr_err("client deregistration failed\n");
+               return err;
+       }
+
+       clear_bit(0, &menelaus.initialized);
+
+       return 0;
+}
+
+/*-----------------------------------------------------------------------*/
+
+static int menelaus_scan_bus(struct i2c_adapter *bus)
+{
+       if (!i2c_check_functionality(bus, I2C_FUNC_SMBUS_BYTE_DATA |
+                                         I2C_FUNC_SMBUS_WRITE_BYTE)) {
+               pr_err("invalid i2c bus functionality\n");
+               return -EINVAL;
+       }
+
+       return i2c_probe(bus, &addr_data, menelaus_probe);
+}
+
+static struct i2c_driver menelaus_i2c_driver = {
+       .driver = {
+               .name           = DRIVER_NAME,
+       },
+       .id             = I2C_DRIVERID_MISC, /*FIXME:accroding to i2c-ids.h */
+       .class          = I2C_CLASS_HWMON,
+       .attach_adapter = menelaus_scan_bus,
+       .detach_client  = menelaus_remove,
+};
+
+static int __init menelaus_init(void)
+{
+       int res;
+
+       if ((res = i2c_add_driver(&menelaus_i2c_driver)) < 0) {
+               pr_err("driver registration failed\n");
+               return res;
+       }
+
+       return 0;
+}
+
+static void __exit menelaus_exit(void)
+{
+       if (i2c_del_driver(&menelaus_i2c_driver) < 0)
+               pr_err("driver remove failed\n");
+
+       /* FIXME: Shutdown menelaus parts that can be shut down */
+}
+
+void __init menelaus_set_platform_data(struct menelaus_platform_data *pdata)
+{
+       menelaus_pdata = pdata;
+}
+
+MODULE_AUTHOR("Texas Instruments, Inc.");
+MODULE_DESCRIPTION("I2C interface for Menelaus.");
+MODULE_LICENSE("GPL");
+
+module_init(menelaus_init);
+module_exit(menelaus_exit);
diff --git a/drivers/i2c/chips/tlv320aic23.c b/drivers/i2c/chips/tlv320aic23.c
new file mode 100644 (file)
index 0000000..c1e27f1
--- /dev/null
@@ -0,0 +1,674 @@
+/*
+ *   Texas Instrumens TLV320AIC23 audio codec's i2c interface.
+ *
+ *   Copyright (c) by Kai Svahn <kai.svahn@nokia.com>
+ *   Copyright (c) by Jussi Laako <jussi.laako@nokia.com>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <asm/io.h>
+#include <asm/arch/aic23.h>
+#include <asm/arch/mcbsp.h>
+
+#define TLV320AIC23_VERSION    "1.8"
+#define TLV320AIC23_DATE       "10-Feb-2006"
+#define MAX_VOL                        100
+#define MIN_VOL                        0
+#define MAX_GAIN               100
+#define MIN_GAIN               0
+#define OUTPUT_VOLUME_MIN       LHV_MIN
+#define OUTPUT_VOLUME_MAX       LHV_MAX
+#define OUTPUT_VOLUME_RANGE     (OUTPUT_VOLUME_MAX - OUTPUT_VOLUME_MIN)
+#define INPUT_VOLUME_MIN       LIV_MIN
+#define INPUT_VOLUME_MAX       LIV_MAX
+#define INPUT_VOLUME_RANGE     (INPUT_VOLUME_MAX - INPUT_VOLUME_MIN)
+
+/* I2C Addresses to scan */
+static unsigned short normal_i2c[] = { TLV320AIC23ID1, TLV320AIC23ID2, \
+                                      I2C_CLIENT_END };
+/*static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };*/
+
+/* This makes all addr_data:s */
+I2C_CLIENT_INSMOD;
+
+static struct i2c_driver aic23_driver;
+static struct i2c_client *new_client;
+static int selftest;
+
+static struct aic23_info {
+       u16 volume_reg_left;
+       u16 volume_reg_right;
+       u16 input_gain_reg_left;
+       u16 input_gain_reg_right;
+       u16 power;                      /* For POWER_DOWN_CONTROL_ADDR */
+       u16 mask;                       /* For ANALOG_AUDIO_CONTROL_ADDR */
+       int mic_loopback;
+       int mic_enable;
+       int sta;
+       int power_down;
+       int initialized;
+} aic23_info_l;
+
+static int _aic23_write_value(struct i2c_client *client, u8 reg, u16 value)
+{
+       u8 val, wreg;
+
+       /* TLV320AIC23 has 7 bit address and 9 bits of data
+        * so we need to switch one data bit into reg and rest
+        * of data into val
+        */
+
+       wreg = (reg << 1);
+       val = (0x01 & (value >> 8));
+       wreg = (wreg | val);
+       val = (0x00ff & value);
+
+       return i2c_smbus_write_byte_data(client, wreg, val);
+}
+
+int aic23_write_value(u8 reg, u16 value)
+{
+       static struct i2c_client *client;
+       client = new_client;
+       _aic23_write_value(client, reg, value);
+
+       return 0;
+}
+
+static int aic23_detect_client(struct i2c_adapter *adapter, int address,
+                                    int kind)
+{
+       int err = 0;
+       const char *client_name = "TLV320AIC23 Audio Codec";
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA |
+                                    I2C_FUNC_SMBUS_WRITE_BYTE)) {
+               printk(KERN_WARNING "%s functinality check failed\n", 
+                      client_name);
+               return err;
+       }
+
+       if (!(new_client = kmalloc(sizeof(struct i2c_client),
+                                  GFP_KERNEL))) {
+               err = -ENOMEM;
+               printk(KERN_WARNING "Couldn't allocate memory for %s\n", 
+                      client_name);
+               return err;
+       }
+
+       memset(new_client, 0x00, sizeof(struct i2c_client));
+       new_client->addr = address;
+       new_client->adapter = adapter;
+       new_client->driver = &aic23_driver;
+       new_client->flags = 0;
+       strlcpy(new_client->name, client_name, I2C_NAME_SIZE);
+
+       if ((err = i2c_attach_client(new_client))) {
+               printk(KERN_WARNING "Couldn't attach %s\n", client_name);
+               kfree(new_client);
+               return err;
+       }
+       return 0;
+}
+
+static int aic23_detach_client(struct i2c_client *client)
+{
+       int err;
+
+       if ((err = i2c_detach_client(client))) {
+               printk("aic23.o: Client deregistration failed, \
+                      client not detached.\n");
+               return err;
+       }
+       kfree(client);
+       return 0;
+}
+
+static int aic23_attach_adapter(struct i2c_adapter *adapter)
+{
+       int res;
+
+       res = i2c_probe(adapter, &addr_data, &aic23_detect_client);
+       return res;
+}
+
+static struct i2c_driver aic23_driver = {
+       .driver = {
+               .name   = "OMAP+TLV320AIC23 codec",
+               /*.flags        = I2C_DF_NOTIFY,*/
+       },
+       .id             = I2C_DRIVERID_MISC, /* Experimental ID */
+       .attach_adapter = aic23_attach_adapter,
+       .detach_client  = aic23_detach_client,
+};
+
+/*
+ * Configures the McBSP3 which is used to send clock to the AIC23 codec.
+ * The input clock rate from DSP is 12MHz.
+ * The DSP clock must be on before this is called. 
+ */
+static int omap_mcbsp3_aic23_clock_init(void)
+{
+       u16 w;
+
+       /* enable 12MHz clock to mcbsp 1 & 3 */
+       __raw_writew(__raw_readw(DSP_IDLECT2) | (1<<1), DSP_IDLECT2);
+       __raw_writew(__raw_readw(DSP_RSTCT2) | 1 | 1<<1, DSP_RSTCT2);
+
+       /* disable sample rate generator */
+       OMAP_MCBSP_WRITE(OMAP1610_MCBSP3_BASE, SPCR1, 0x0000);
+       OMAP_MCBSP_WRITE(OMAP1610_MCBSP3_BASE, SPCR2, 0x0000);
+
+       /* pin control register */
+       OMAP_MCBSP_WRITE(OMAP1610_MCBSP3_BASE, PCR0,(CLKXM | CLKXP | CLKRP));
+
+       /* configure srg to send 12MHz pulse from dsp peripheral clock */
+       OMAP_MCBSP_WRITE(OMAP1610_MCBSP3_BASE, SRGR1, 0x0000);
+       OMAP_MCBSP_WRITE(OMAP1610_MCBSP3_BASE, SRGR2, CLKSM);
+
+       /* enable sample rate generator */
+       w = OMAP_MCBSP_READ(OMAP1610_MCBSP3_BASE, SPCR2);
+       OMAP_MCBSP_WRITE(OMAP1610_MCBSP3_BASE, SPCR2, (w | FREE | GRST));
+       printk("Clock enabled to MCBSP1 & 3 \n");
+
+       return 0;
+}
+
+static void update_volume_left(int volume)
+{
+       u16 val = 0;
+       val = ((volume * OUTPUT_VOLUME_RANGE) / 100) + OUTPUT_VOLUME_MIN;
+       aic23_write_value(LEFT_CHANNEL_VOLUME_ADDR, val);
+       aic23_info_l.volume_reg_left = volume;
+}
+
+static void update_volume_right(int volume)
+{
+       u16 val = 0;
+       val = ((volume * OUTPUT_VOLUME_RANGE) / 100) + OUTPUT_VOLUME_MIN;
+       aic23_write_value(RIGHT_CHANNEL_VOLUME_ADDR, val);
+       aic23_info_l.volume_reg_right = volume;
+}
+
+static void set_mic(int mic_en)
+{
+       u16 dg_ctrl;
+
+       if (mic_en) {
+               aic23_info_l.power = OSC_OFF | LINE_OFF;
+               dg_ctrl = ADCHP_ON;
+               aic23_info_l.mask &= ~MICM_MUTED;
+               aic23_info_l.mask |= MICB_20DB; /* STE_ENABLED */
+       } else {
+               aic23_info_l.power =
+                       OSC_OFF | ADC_OFF | MIC_OFF | LINE_OFF;
+               dg_ctrl = 0x00;
+               aic23_info_l.mask = 
+                       DAC_SELECTED | INSEL_MIC | MICM_MUTED;
+       }
+       aic23_write_value(POWER_DOWN_CONTROL_ADDR,
+                               aic23_info_l.power);
+       aic23_write_value(DIGITAL_AUDIO_CONTROL_ADDR, dg_ctrl);
+       aic23_write_value(ANALOG_AUDIO_CONTROL_ADDR,
+                               aic23_info_l.mask);
+       aic23_info_l.mic_enable = mic_en;
+
+       printk(KERN_INFO "aic23 mic state: %i\n", mic_en);
+}
+
+static void aic23_init_power(void)
+{
+       aic23_write_value(RESET_CONTROL_ADDR, 0x00);
+       
+       if (aic23_info_l.initialized == 0) {
+               aic23_write_value(LEFT_CHANNEL_VOLUME_ADDR, LHV_MIN);
+               aic23_write_value(RIGHT_CHANNEL_VOLUME_ADDR, LHV_MIN);
+       }
+       else {
+               update_volume_left(aic23_info_l.volume_reg_left);
+               update_volume_right(aic23_info_l.volume_reg_right);
+       }
+       
+       aic23_info_l.mask = DAC_SELECTED | INSEL_MIC | MICM_MUTED;
+       aic23_write_value(ANALOG_AUDIO_CONTROL_ADDR,
+                               aic23_info_l.mask);
+       aic23_write_value(DIGITAL_AUDIO_CONTROL_ADDR, 0x00);
+       aic23_write_value(DIGITAL_AUDIO_FORMAT_ADDR, LRP_ON | FOR_DSP);
+       aic23_write_value(SAMPLE_RATE_CONTROL_ADDR, USB_CLK_ON);
+       aic23_write_value(DIGITAL_INTERFACE_ACT_ADDR, ACT_ON);
+       aic23_info_l.power = OSC_OFF | ADC_OFF | MIC_OFF | LINE_OFF;
+       aic23_write_value(POWER_DOWN_CONTROL_ADDR,
+                               aic23_info_l.power);
+
+       /* enable mic input */
+       if (aic23_info_l.mic_enable)
+               set_mic(aic23_info_l.mic_enable);
+
+       printk(KERN_INFO "aic23_init_power() done\n");
+}
+
+void aic23_power_down(void)
+{
+       if (aic23_info_l.initialized) {
+               printk("aic23 powering down\n");
+               aic23_write_value(POWER_DOWN_CONTROL_ADDR, 0xff);
+       }
+       aic23_info_l.power_down = 1;
+}
+
+void aic23_power_up(void)
+{
+       if (aic23_info_l.initialized) {
+               printk("aic23 powering up\n");
+               aic23_init_power();
+       }
+       aic23_info_l.power_down = 0;
+}
+
+/*----------------------------------------------------------------------*/
+/*                     sysfs initializations                           */
+/*----------------------------------------------------------------------*/
+
+static ssize_t store_volume_left(struct device *dev,
+                                struct device_attribute *attr,
+                                const char *buf, size_t count)
+{
+       signed volume;
+
+       sscanf(buf, "%i", &volume);
+
+       if (volume < MIN_VOL) {
+               aic23_power_down();
+               return count;
+       } else if (volume > MIN_VOL && aic23_info_l.power_down) {
+               aic23_info_l.volume_reg_left = volume;
+               aic23_power_up();
+               return count;
+       }
+       if (volume > MAX_VOL)
+               volume = MAX_VOL;
+
+       update_volume_left(volume);
+       return count;
+}
+
+static ssize_t show_volume_left(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%u\n", aic23_info_l.volume_reg_left);
+}
+
+static DEVICE_ATTR(volume_left, S_IRUGO | S_IWUGO,
+                  show_volume_left, store_volume_left);
+
+static ssize_t store_volume_right(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t count)
+{
+       signed volume;
+
+       sscanf(buf, "%i", &volume);
+       if (volume < MIN_VOL) {
+               aic23_power_down();
+               return count;
+       } else if (volume > MIN_VOL && aic23_info_l.power_down) {
+               aic23_info_l.volume_reg_right = volume;
+               aic23_power_up();
+               return count;
+       }
+       if (volume > MAX_VOL)
+               volume = MAX_VOL;
+
+       update_volume_right(volume);
+       return count;
+}
+
+static ssize_t show_volume_right(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%u\n", aic23_info_l.volume_reg_right);
+}
+
+static DEVICE_ATTR(volume_right, S_IRUGO | S_IWUGO,
+                  show_volume_right, store_volume_right);
+
+static ssize_t store_gain_left(struct device *dev,
+                              struct device_attribute *attr,
+                              const char *buf, size_t count)
+{
+       u16 val = 0;
+       unsigned gain;
+
+       sscanf(buf, "%u", &gain);
+       if (gain > MAX_VOL)
+               gain = MAX_VOL;
+
+       val = ((gain * INPUT_VOLUME_RANGE) / 100) + INPUT_VOLUME_MIN;
+       aic23_write_value(LEFT_LINE_VOLUME_ADDR, val);
+       aic23_info_l.input_gain_reg_left = gain;
+
+       return count;
+}
+
+static ssize_t show_gain_left(struct device *dev,
+                             struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%u\n", aic23_info_l.input_gain_reg_left);
+}
+
+static DEVICE_ATTR(gain_left, S_IRUGO | S_IWUSR, show_gain_left,
+                  store_gain_left);
+
+static ssize_t store_gain_right(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf, size_t count)
+{
+       u16 val = 0;
+       unsigned gain;
+
+       sscanf(buf, "%u", &gain);
+       if (gain > MAX_VOL)
+               gain = MAX_VOL;
+
+       val = ((gain * INPUT_VOLUME_RANGE) / 100) + INPUT_VOLUME_MIN;
+       aic23_write_value(RIGHT_LINE_VOLUME_ADDR, val);
+       aic23_info_l.input_gain_reg_right = gain;
+
+       return count;
+}
+
+static ssize_t show_gain_right(struct device *dev,
+                              struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%u\n", aic23_info_l.input_gain_reg_right);
+}
+
+static DEVICE_ATTR(gain_right, S_IRUGO | S_IWUSR, show_gain_right,
+                  store_gain_right);
+
+static ssize_t store_mic_loopback(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t count)
+{
+       int mic;
+
+       sscanf(buf, "%i", &mic);
+       if (mic > 0) {
+               aic23_write_value(POWER_DOWN_CONTROL_ADDR, \
+                                       OSC_OFF | ADC_OFF | LINE_OFF);
+               aic23_info_l.mask = STE_ENABLED | DAC_SELECTED \
+                                         | INSEL_MIC | MICB_20DB;
+               aic23_write_value(ANALOG_AUDIO_CONTROL_ADDR, 
+                                       aic23_info_l.mask);
+               mic = 1;
+       }
+       else {
+               aic23_write_value(POWER_DOWN_CONTROL_ADDR, \
+                                       OSC_OFF | ADC_OFF | MIC_OFF | LINE_OFF);
+               mic = 0;
+       }
+       aic23_info_l.mic_loopback = mic;
+
+       return count;
+}
+
+static ssize_t show_mic_loopback(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%i\n", aic23_info_l.mic_loopback);
+}
+
+static DEVICE_ATTR(mic_loopback, S_IRUGO | S_IWUSR,
+                  show_mic_loopback, store_mic_loopback);
+
+static ssize_t store_st_attenuation(struct device *dev,
+                                   struct device_attribute *attr,
+                                   const char *buf, size_t count)
+{
+       unsigned sta;
+       u16 tmp;
+
+       sscanf(buf, "%u", &sta);
+       if (sta > 3)
+               sta = 3;
+
+       tmp = aic23_info_l.mask;
+       tmp &= 0x3f;
+
+       aic23_info_l.mask =  tmp | STA_REG(sta);
+       aic23_write_value(ANALOG_AUDIO_CONTROL_ADDR,
+                               aic23_info_l.mask);
+       aic23_info_l.sta = sta;
+
+       return count;
+}
+
+static ssize_t show_st_attenuation(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%i\n", aic23_info_l.sta);
+}
+
+static DEVICE_ATTR(st_attenuation, S_IRUGO | S_IWUSR,
+                  show_st_attenuation, store_st_attenuation);
+
+static ssize_t store_mic_enable(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf, size_t count)
+{
+       int mic;
+
+       sscanf(buf, "%i", &mic);
+       set_mic(mic);
+
+       return count;
+}
+
+static ssize_t show_mic_enable(struct device *dev,
+                              struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%i\n", aic23_info_l.mic_enable);
+}
+
+static DEVICE_ATTR(mic_enable, S_IRUGO | S_IWUSR,
+       show_mic_enable, store_mic_enable);
+
+static ssize_t show_audio_selftest(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%i\n", selftest);
+}
+
+static DEVICE_ATTR(audio_selftest, S_IRUGO | S_IWUSR,
+               show_audio_selftest, NULL);
+
+static int audio_i2c_probe(struct platform_device *dev)
+{
+       int r;
+
+       if ((r = device_create_file(&dev->dev, &dev_attr_volume_left)) != 0)
+               return r;
+       else if ((r = device_create_file(&dev->dev,
+               &dev_attr_volume_right)) != 0)
+               goto err_volume_left;
+       else if ((r = device_create_file(&dev->dev,
+               &dev_attr_gain_right)) != 0)
+               goto err_volume_right;
+       else if ((r = device_create_file(&dev->dev,
+               &dev_attr_gain_left)) != 0)
+               goto err_gain_right;
+       else if ((r = device_create_file(&dev->dev,
+               &dev_attr_mic_loopback)) != 0)
+               goto err_gain_left;
+       else if ((r = device_create_file(&dev->dev,
+               &dev_attr_mic_enable)) != 0)
+               goto err_mic_loopback;
+       else if ((r = device_create_file(&dev->dev,
+               &dev_attr_st_attenuation)) != 0)
+               goto err_mic_enable;
+       else if ((r = device_create_file(&dev->dev,
+               &dev_attr_audio_selftest)) != 0)
+               goto err_st_attenuation;
+       else
+               return r;
+
+err_st_attenuation:
+       device_remove_file(&dev->dev, &dev_attr_st_attenuation);
+err_mic_enable:
+       device_remove_file(&dev->dev, &dev_attr_mic_enable);
+err_mic_loopback:
+       device_remove_file(&dev->dev, &dev_attr_mic_loopback);
+err_gain_left:
+       device_remove_file(&dev->dev, &dev_attr_gain_left);
+err_gain_right:
+       device_remove_file(&dev->dev, &dev_attr_gain_right);
+err_volume_right:
+       device_remove_file(&dev->dev, &dev_attr_volume_right);
+err_volume_left:
+       device_remove_file(&dev->dev, &dev_attr_volume_left);
+
+       return r;
+}
+
+static int audio_i2c_remove(struct platform_device *dev)
+{
+       device_remove_file(&dev->dev, &dev_attr_st_attenuation);
+       device_remove_file(&dev->dev, &dev_attr_mic_enable);
+       device_remove_file(&dev->dev, &dev_attr_mic_loopback);
+       device_remove_file(&dev->dev, &dev_attr_gain_left);
+       device_remove_file(&dev->dev, &dev_attr_gain_right);
+       device_remove_file(&dev->dev, &dev_attr_volume_right);
+       device_remove_file(&dev->dev, &dev_attr_volume_left);
+
+       return 0;
+}
+
+/*----------------------------------------------------------------*/
+/*                     PM functions                              */
+/*----------------------------------------------------------------*/
+
+static void audio_i2c_shutdown(struct platform_device *dev)
+{
+       /* Let's mute the codec before powering off to prevent
+       * glitch in the sound
+       */
+       aic23_write_value(LEFT_CHANNEL_VOLUME_ADDR, LHV_MIN);
+       aic23_write_value(RIGHT_CHANNEL_VOLUME_ADDR, LHV_MIN);
+       aic23_power_down();
+}
+
+static int audio_i2c_suspend(struct platform_device *dev, pm_message_t state)
+{
+       /* Let's mute the codec before powering off to prevent
+        * glitch in the sound
+        */
+       aic23_write_value(LEFT_CHANNEL_VOLUME_ADDR, LHV_MIN);
+       aic23_write_value(RIGHT_CHANNEL_VOLUME_ADDR, LHV_MIN);
+       aic23_power_down();
+
+       return 0;
+}
+
+static int audio_i2c_resume(struct platform_device *dev)
+{
+       aic23_power_up();
+
+       return 0;
+}
+
+static struct platform_driver audio_i2c_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "audio-i2c",
+       },
+       .shutdown       = audio_i2c_shutdown,
+       .probe          = audio_i2c_probe,
+       .remove         = audio_i2c_remove,
+       .suspend        = audio_i2c_suspend,
+       .resume         = audio_i2c_resume,
+};
+
+static struct platform_device audio_i2c_device = {
+       .name           = "audio-i2c",
+       .id             = -1,
+};
+
+/*----------------------------------------------------------------*/
+
+static int __init aic23_init(void)
+{
+       selftest =  0;
+       aic23_info_l.initialized = 0;
+
+       if (i2c_add_driver(&aic23_driver)) {
+               printk("aic23 i2c: Driver registration failed, \
+                     module not inserted.\n");
+               selftest = -ENODEV;
+               return selftest;
+       }
+
+       if (platform_driver_register(&audio_i2c_driver)) {
+               printk(KERN_WARNING "Failed to register audio i2c driver\n");
+               selftest = -ENODEV;
+               return selftest;
+       }
+
+       if (platform_device_register(&audio_i2c_device)) {
+               printk(KERN_WARNING "Failed to register audio i2c device\n");
+               platform_driver_unregister(&audio_i2c_driver);
+               selftest = -ENODEV;
+               return selftest;
+       }
+       /* FIXME: Do in board-specific file */
+       omap_mcbsp3_aic23_clock_init();
+       if (!aic23_info_l.power_down)
+               aic23_power_up();
+       aic23_info_l.initialized = 1;
+       printk("TLV320AIC23 I2C version %s (%s)\n", 
+              TLV320AIC23_VERSION, TLV320AIC23_DATE);
+
+       return selftest;
+}
+
+static void __exit aic23_exit(void)
+{
+       int res;
+
+       aic23_power_down();
+       if ((res = i2c_del_driver(&aic23_driver))) 
+               printk("aic23 i2c: Driver remove failed, module not removed.\n");
+
+       platform_device_unregister(&audio_i2c_device);
+       platform_driver_unregister(&audio_i2c_driver);
+}
+
+MODULE_AUTHOR("Kai Svahn <kai.svahn@nokia.com>");
+MODULE_DESCRIPTION("I2C interface for TLV320AIC23 codec.");
+MODULE_LICENSE("GPL");
+
+module_init(aic23_init)
+module_exit(aic23_exit)
+
+EXPORT_SYMBOL(aic23_write_value);
+EXPORT_SYMBOL(aic23_power_up);
+EXPORT_SYMBOL(aic23_power_down);
diff --git a/drivers/i2c/chips/twl4030_core.c b/drivers/i2c/chips/twl4030_core.c
new file mode 100644 (file)
index 0000000..3134064
--- /dev/null
@@ -0,0 +1,910 @@
+/*
+ * twl4030_core.c - driver for TWL4030 PM and audio CODEC device
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * Modifications to defer interrupt handling to a kernel thread:
+ * Copyright (C) 2006 MontaVista Software, Inc.
+ *
+ * Based on tlv320aic23.c:
+ * Copyright (c) by Kai Svahn <kai.svahn@nokia.com>
+ *
+ * Code cleanup and modifications to IRQ handler.
+ * by syed khasim <x0khasim@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel_stat.h>
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/interrupt.h>
+#include <linux/random.h>
+#include <linux/syscalls.h>
+#include <linux/kthread.h>
+
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+
+#include <asm/irq.h>
+#include <asm/mach/irq.h>
+
+#include <asm/arch/twl4030.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/mux.h>
+
+/**** Macro Definitions */
+#define TWL_CLIENT_STRING              "TWL4030-ID"
+#define TWL_CLIENT_USED                        1
+#define TWL_CLIENT_FREE                        0
+
+/* IRQ Flags */
+#define FREE                           0
+#define USED                           1
+
+/** Primary Interrupt Handler on TWL4030 Registers */
+
+/**** Register Definitions */
+
+#define REG_PIH_ISR_P1                 (0x1)
+#define REG_PIH_ISR_P2                 (0x2)
+#define REG_PIH_SIR                    (0x3)
+
+/* Triton Core internal information (BEGIN) */
+
+/* Last - for index max*/
+#define TWL4030_MODULE_LAST            TWL4030_MODULE_SECURED_REG
+
+/* Slave address */
+#define TWL4030_NUM_SLAVES             0x04
+#define TWL4030_SLAVENUM_NUM0          0x00
+#define TWL4030_SLAVENUM_NUM1          0x01
+#define TWL4030_SLAVENUM_NUM2          0x02
+#define TWL4030_SLAVENUM_NUM3          0x03
+#define TWL4030_SLAVEID_ID0            0x48
+#define TWL4030_SLAVEID_ID1            0x49
+#define TWL4030_SLAVEID_ID2            0x4A
+#define TWL4030_SLAVEID_ID3            0x4B
+
+/* Base Address defns */
+/* USB ID */
+#define TWL4030_BASEADD_USB            0x0000
+/* AUD ID */
+#define TWL4030_BASEADD_AUDIO_VOICE    0x0000
+#define TWL4030_BASEADD_GPIO           0x0098
+
+#define TWL4030_BASEADD_INTBR          0x0085
+#define TWL4030_BASEADD_PIH            0x0080
+#define TWL4030_BASEADD_TEST           0x004C
+/* AUX ID */
+#define TWL4030_BASEADD_INTERRUPTS     0x00B9
+#define TWL4030_BASEADD_LED            0x00EE
+#define TWL4030_BASEADD_MADC           0x0000
+#define TWL4030_BASEADD_MAIN_CHARGE    0x0074
+#define TWL4030_BASEADD_PRECHARGE      0x00AA
+#define TWL4030_BASEADD_PWM0           0x00F8
+#define TWL4030_BASEADD_PWM1           0x00FB
+#define TWL4030_BASEADD_PWMA           0x00EF
+#define TWL4030_BASEADD_PWMB           0x00F1
+#define TWL4030_BASEADD_KEYPAD         0x00D2
+/* POWER ID */
+#define TWL4030_BASEADD_BACKUP         0x0014
+#define TWL4030_BASEADD_INT            0x002E
+#define TWL4030_BASEADD_PM_MASTER      0x0036
+#define TWL4030_BASEADD_PM_RECIEVER    0x005B
+#define TWL4030_BASEADD_RTC            0x001C
+#define TWL4030_BASEADD_SECURED_REG    0x0000
+
+/* Triton Core internal information (END) */
+
+/* Few power values */
+#define R_CFG_BOOT                     0x05
+#define R_PROTECT_KEY                  0x0E
+
+/* access control */
+#define KEY_UNLOCK1                    0xce
+#define KEY_UNLOCK2                    0xec
+#define KEY_LOCK                       0x00
+
+#define HFCLK_FREQ_19p2_MHZ            (1 << 0)
+#define HFCLK_FREQ_26_MHZ              (2 << 0)
+#define HFCLK_FREQ_38p4_MHZ            (3 << 0)
+#define HIGH_PERF_SQ                   (1 << 3)
+
+/* on I2C-1 for 2430SDP */
+#define CONFIG_I2C_TWL4030_ID          1
+
+/**** Helper functions */
+static int
+twl4030_detect_client(struct i2c_adapter *adapter, unsigned char sid);
+static int twl4030_attach_adapter(struct i2c_adapter *adapter);
+static int twl4030_detach_client(struct i2c_client *client);
+static void do_twl4030_irq(unsigned int irq, irq_desc_t *desc);
+
+static void twl_init_irq(void);
+
+/**** Data Structures */
+/* To have info on T2 IRQ substem activated or not */
+static unsigned char twl_irq_used = FREE;
+
+/* Structure to define on TWL4030 Slave ID */
+struct twl4030_client {
+       struct i2c_client client;
+       const char client_name[sizeof(TWL_CLIENT_STRING) + 1];
+       const unsigned char address;
+       const char adapter_index;
+       unsigned char inuse;
+
+       /* max numb of i2c_msg required is for read =2 */
+       struct i2c_msg xfer_msg[2];
+
+       /* To lock access to xfer_msg */
+       struct semaphore xfer_lock;
+};
+
+/* Module Mapping */
+struct twl4030mapping {
+       unsigned char sid;      /* Slave ID */
+       unsigned char base;     /* base address */
+};
+
+/* mapping the module id to slave id and base address */
+static struct twl4030mapping twl4030_map[TWL4030_MODULE_LAST + 1] = {
+       { TWL4030_SLAVENUM_NUM0, TWL4030_BASEADD_USB },
+       { TWL4030_SLAVENUM_NUM1, TWL4030_BASEADD_AUDIO_VOICE },
+       { TWL4030_SLAVENUM_NUM1, TWL4030_BASEADD_GPIO },
+       { TWL4030_SLAVENUM_NUM1, TWL4030_BASEADD_INTBR },
+       { TWL4030_SLAVENUM_NUM1, TWL4030_BASEADD_PIH },
+       { TWL4030_SLAVENUM_NUM1, TWL4030_BASEADD_TEST },
+       { TWL4030_SLAVENUM_NUM2, TWL4030_BASEADD_KEYPAD },
+       { TWL4030_SLAVENUM_NUM2, TWL4030_BASEADD_MADC },
+       { TWL4030_SLAVENUM_NUM2, TWL4030_BASEADD_INTERRUPTS },
+       { TWL4030_SLAVENUM_NUM2, TWL4030_BASEADD_LED },
+       { TWL4030_SLAVENUM_NUM2, TWL4030_BASEADD_MAIN_CHARGE },
+       { TWL4030_SLAVENUM_NUM2, TWL4030_BASEADD_PRECHARGE },
+       { TWL4030_SLAVENUM_NUM2, TWL4030_BASEADD_PWM0 },
+       { TWL4030_SLAVENUM_NUM2, TWL4030_BASEADD_PWM1 },
+       { TWL4030_SLAVENUM_NUM2, TWL4030_BASEADD_PWMA },
+       { TWL4030_SLAVENUM_NUM2, TWL4030_BASEADD_PWMB },
+       { TWL4030_SLAVENUM_NUM3, TWL4030_BASEADD_BACKUP },
+       { TWL4030_SLAVENUM_NUM3, TWL4030_BASEADD_INT },
+       { TWL4030_SLAVENUM_NUM3, TWL4030_BASEADD_PM_MASTER },
+       { TWL4030_SLAVENUM_NUM3, TWL4030_BASEADD_PM_RECIEVER },
+       { TWL4030_SLAVENUM_NUM3, TWL4030_BASEADD_RTC },
+       { TWL4030_SLAVENUM_NUM3, TWL4030_BASEADD_SECURED_REG },
+};
+
+static struct twl4030_client twl4030_modules[TWL4030_NUM_SLAVES] = {
+       {
+               .address        = TWL4030_SLAVEID_ID0,
+               .client_name    = TWL_CLIENT_STRING "0",
+               .adapter_index  = CONFIG_I2C_TWL4030_ID,
+       },
+       {
+               .address        = TWL4030_SLAVEID_ID1,
+               .client_name    = TWL_CLIENT_STRING "1",
+               .adapter_index  = CONFIG_I2C_TWL4030_ID,
+       },
+       {
+               .address        = TWL4030_SLAVEID_ID2,
+               .client_name    = TWL_CLIENT_STRING "2",
+               .adapter_index  = CONFIG_I2C_TWL4030_ID,
+       },
+       {
+               .address        = TWL4030_SLAVEID_ID3,
+               .client_name    = TWL_CLIENT_STRING "3",
+               .adapter_index  = CONFIG_I2C_TWL4030_ID,
+       },
+};
+
+/* One Client Driver , 4 Clients */
+static struct i2c_driver twl4030_driver = {
+       .driver.name    = "TWL4030 I2C",
+       .attach_adapter = twl4030_attach_adapter,
+       .detach_client  = twl4030_detach_client,
+};
+
+/*
+ * TWL4030 doesn't have PIH mask, hence dummy function for mask
+ * and unmask.
+ */
+
+static void twl4030_i2c_ackirq(unsigned int irq) {}
+static void twl4030_i2c_disableint(unsigned int irq) {}
+static void twl4030_i2c_enableint(unsigned int irq) {}
+
+/* information for processing in the Work Item */
+static struct irq_chip twl4030_irq_chip = {
+       .ack    = twl4030_i2c_ackirq,
+       .mask   = twl4030_i2c_disableint,
+       .unmask = twl4030_i2c_enableint,
+};
+
+/* Global Functions */
+/*
+ * @brief twl4030_i2c_write - Writes a n bit register in TWL4030
+ *
+ * @param mod_no - module number
+ * @param *value - an array of num_bytes+1 containing data to write
+ * IMPORTANT - Allocate value num_bytes+1 and valid data starts at
+ *              Offset 1.
+ * @param reg - register address (just offset will do)
+ * @param num_bytes - number of bytes to transfer
+ *
+ * @return result of operation - 0 is success
+ */
+int twl4030_i2c_write(u8 mod_no, u8 * value, u8 reg, u8 num_bytes)
+{
+       int ret;
+       int sid;
+       struct twl4030_client *client;
+       struct i2c_msg *msg;
+
+       if (unlikely(mod_no > TWL4030_MODULE_LAST)) {
+               printk(KERN_ERR "TWL4030: Invalid module Number\n");
+               return -EPERM;
+       }
+       sid = twl4030_map[mod_no].sid;
+       client = &(twl4030_modules[sid]);
+
+       if (unlikely(client->inuse != TWL_CLIENT_USED)) {
+               printk(KERN_ERR
+                       "TWL4030: I2C Client[%d] is not initialized[%d]\n",
+                       sid, __LINE__);
+               return -EPERM;
+       }
+       down(&(client->xfer_lock));
+       /*
+        * [MSG1]: fill the register address data
+        * fill the data Tx buffer
+        */
+       msg = &(client->xfer_msg[0]);
+       msg->addr = client->address;
+       msg->len = num_bytes + 1;
+       msg->flags = 0;
+       msg->buf = value;
+       /* over write the first byte of buffer with the register address */
+       *value = twl4030_map[mod_no].base + reg;
+       ret = i2c_transfer(client->client.adapter, client->xfer_msg, 1);
+       up(&(client->xfer_lock));
+
+       /* i2cTransfer returns num messages.translate it pls.. */
+       if (ret >= 0)
+               ret = 0;
+       return ret;
+}
+
+/**
+ * @brief twl4030_i2c_read - Reads a n bit register in TWL4030
+ *
+ * @param mod_no - module number
+ * @param *value - an array of num_bytes containing data to be read
+ * @param reg - register address (just offset will do)
+ * @param num_bytes - number of bytes to transfer
+ *
+ * @return result of operation - num_bytes is success else failure.
+ */
+int twl4030_i2c_read(u8 mod_no, u8 * value, u8 reg, u8 num_bytes)
+{
+       int ret;
+       u8 val;
+       int sid;
+       struct twl4030_client *client;
+       struct i2c_msg *msg;
+       if (unlikely(mod_no > TWL4030_MODULE_LAST)) {
+               printk(KERN_ERR "TWL4030: Invalid module Number\n");
+               return -EPERM;
+       }
+       sid = twl4030_map[mod_no].sid;
+       client = &(twl4030_modules[sid]);
+
+       if (unlikely(client->inuse != TWL_CLIENT_USED)) {
+               printk(KERN_ERR
+                       "TWL4030: I2C Client[%d] is not initialized[%d]\n",
+                       sid, __LINE__);
+               return -EPERM;
+       }
+       down(&(client->xfer_lock));
+       /* [MSG1] fill the register address data */
+       msg = &(client->xfer_msg[0]);
+       msg->addr = client->address;
+       msg->len = 1;
+       val = twl4030_map[mod_no].base + reg;
+       msg->buf = &val;
+       /* [MSG2] fill the data rx buffer */
+       msg = &(client->xfer_msg[1]);
+       msg->addr = client->address;
+       msg->flags = I2C_M_RD;  /* Read the register value */
+       msg->len = num_bytes;   /* only n bytes */
+       msg->buf = value;
+       ret = i2c_transfer(client->client.adapter, client->xfer_msg, 2);
+       up(&(client->xfer_lock));
+
+       /* i2cTransfer returns num messages.translate it pls.. */
+       if (ret >= 0)
+               ret = 0;
+       return ret;
+}
+
+/**
+ * @brief twl4030_i2c_write_u8 - Writes a 8 bit register in TWL4030
+ *
+ * @param mod_no - module number
+ * @param value - the value to be written 8 bit
+ * @param reg - register address (just offset will do)
+ *
+ * @return result of operation - 0 is success
+ */
+int twl4030_i2c_write_u8(u8 mod_no, u8 value, u8 reg)
+{
+       int ret;
+       /* 2 bytes offset 1 contains the data offset 0 is used by i2c_write */
+       u8 temp_buffer[2] = { 0 };
+       /* offset 1 contains the data */
+       temp_buffer[1] = value;
+       ret = twl4030_i2c_write(mod_no, temp_buffer, reg, 1);
+       return ret;
+}
+
+/**
+ * @brief twl4030_i2c_read_u8 - Reads a 8 bit register from TWL4030
+ *
+ * @param mod_no - module number
+ * @param *value - the value read 8 bit
+ * @param reg - register address (just offset will do)
+ *
+ * @return result of operation - 0 is success
+ */
+int twl4030_i2c_read_u8(u8 mod_no, u8 * value, u8 reg)
+{
+       int ret = 0;
+       ret = twl4030_i2c_read(mod_no, value, reg, 1);
+       return ret;
+}
+
+/**** Helper Functions */
+
+/*
+ * do_twl4030_module_irq() is the desc->handle method for each of the twl4030
+ * module interrupts.  It executes in kernel thread context.
+ * On entry, cpu interrupts are disabled.
+ */
+static void do_twl4030_module_irq(unsigned int irq, irq_desc_t *desc)
+{
+       struct irqaction *action;
+       const unsigned int cpu = smp_processor_id();
+
+       /*
+        * Earlier this was desc->triggered = 1;
+        */
+       desc->status = IRQ_INPROGRESS;
+
+       /*
+        * The desc->handle method would normally call the desc->chip->ack
+        * method here, but we won't bother since our ack method is NULL.
+        */
+
+       if (!desc->depth) {
+               kstat_cpu(cpu).irqs[irq]++;
+
+               action = desc->action;
+               if (action) {
+                       int ret;
+                       int status = 0;
+                       int retval = 0;
+
+                       local_irq_enable();
+
+                       do {
+                               /* Call the ISR with cpu interrupts enabled */
+                               ret = action->handler(irq, action->dev_id);
+                               if (ret == IRQ_HANDLED)
+                                       status |= action->flags;
+                               retval |= ret;
+                               action = action->next;
+                       } while (action);
+
+                       if (status & IRQF_SAMPLE_RANDOM)
+                               add_interrupt_randomness(irq);
+
+                       local_irq_disable();
+
+                       if (retval != IRQ_HANDLED)
+                               printk(KERN_ERR "ISR for TWL4030 module"
+                                       " irq %d can't handle interrupt\n", irq);
+
+                       /*
+                        * Here is where we should call the unmask method, but
+                        * again we won't bother since it is NULL.
+                        */
+               } else
+                       printk(KERN_CRIT "TWL4030 module irq %d has no ISR"
+                                       " but can't be masked!\n", irq);
+       } else
+               printk(KERN_CRIT "TWL4030 module irq %d is disabled but can't"
+                               " be masked!\n", irq);
+}
+
+/*
+ * twl4030_irq_thread() runs as a kernel thread.  It queries the twl4030
+ * interrupt controller to see which modules are generating interrupt requests
+ * and then calls the desc->handle method for each module requesting service.
+ */
+static int twl4030_irq_thread(void *data)
+{
+       int irq = (int)data;
+       irq_desc_t *desc = irq_desc + irq;
+       static unsigned i2c_errors;
+       const static unsigned max_i2c_errors = 100;
+
+       while (!kthread_should_stop()) {
+               int ret;
+               int module_irq;
+               u8 pih_isr;
+
+               ret = twl4030_i2c_read_u8(TWL4030_MODULE_PIH, &pih_isr,
+                                         REG_PIH_ISR_P1);
+               if (ret) {
+                       printk(KERN_WARNING "I2C error %d while reading TWL4030"
+                                       " PIH ISR register.\n", ret);
+                       if (++i2c_errors >= max_i2c_errors) {
+                               printk(KERN_ERR "Maximum I2C error count"
+                                               " exceeded.  Terminating %s.\n",
+                                               __FUNCTION__);
+                               break;
+                       }
+                       continue;
+               }
+
+               for (module_irq = IH_TWL4030_BASE; 0 != pih_isr;
+                        pih_isr >>= 1, module_irq++) {
+                       if (pih_isr & 0x1) {
+                               irq_desc_t *d = irq_desc + module_irq;
+
+                               local_irq_disable();
+
+                               d->handle_irq(module_irq, d);
+
+                               local_irq_enable();
+                       }
+               }
+
+               local_irq_disable();
+
+               set_current_state(TASK_INTERRUPTIBLE);
+               desc->chip->unmask(irq);
+
+               local_irq_enable();
+
+               schedule();
+       }
+       set_current_state(TASK_RUNNING);
+       return 0;
+}
+
+/*
+ * do_twl4030_irq() is the desc->handle method for the twl4030 interrupt.
+ * This is a chained interrupt, so there is no desc->action method for it.
+ * Now we need to query the interrupt controller in the twl4030 to determine
+ * which module is generating the interrupt request.  However, we can't do i2c
+ * transactions in interrupt context, so we must defer that work to a kernel
+ * thread.  All we do here is acknowledge and mask the interrupt and wakeup
+ * the kernel thread.
+ */
+static void do_twl4030_irq(unsigned int irq, irq_desc_t *desc)
+{
+       const unsigned int cpu = smp_processor_id();
+       struct task_struct *thread = (struct task_struct *)desc->chip_data;
+
+       /*
+        * Earlier this was desc->triggered = 1;
+        */
+       desc->status = IRQ_INPROGRESS;
+
+       /*
+        * Acknowledge, clear _AND_ disable the interrupt.
+        */
+       desc->chip->ack(irq);
+
+       if (!desc->depth) {
+               kstat_cpu(cpu).irqs[irq]++;
+
+               if (thread && thread->state != TASK_RUNNING)
+                       wake_up_process(thread);
+       }
+}
+
+/* attach a client to the adapter */
+static int twl4030_detect_client(struct i2c_adapter *adapter, unsigned char sid)
+{
+       int err = 0;
+       struct twl4030_client *client;
+       if (unlikely(sid >= TWL4030_NUM_SLAVES)) {
+               printk(KERN_ERR "TWL4030: sid[%d] >MOD_LAST[%d]\n", sid,
+                               TWL4030_NUM_SLAVES);
+               return -EPERM;
+       }
+
+       /* Check basic functionality */
+       if (!(err = i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA |
+                                               I2C_FUNC_SMBUS_WRITE_BYTE))) {
+               printk(KERN_WARNING
+                       "TWL4030: SlaveID=%d functionality check failed\n", sid);
+               return err;
+       }
+       client = &(twl4030_modules[sid]);
+       if (unlikely(client->inuse)) {
+               printk(KERN_ERR "TWL4030: Client is already in Use.....\n");
+               printk("%s[ID=0x%x] NOT attached to I2c Adapter %s\n",
+                       client->client_name, client->address, adapter->name);
+               return -EPERM;
+       }
+
+       memset(&(client->client), 0, sizeof(struct i2c_client));
+
+       client->client.addr     = client->address;
+       client->client.adapter  = adapter;
+       client->client.driver   = &twl4030_driver;
+
+       memcpy(&(client->client.name), client->client_name,
+                       sizeof(TWL_CLIENT_STRING) + 1);
+       printk("TWL4030: TRY attach Slave %s on Adapter %s[%d][%x]\n",
+                               client->client_name, adapter->name, err, err);
+       if ((err = i2c_attach_client(&(client->client))))
+               printk(KERN_WARNING
+                       "TWL4030: Couldn't attach Slave %s on Adapter "
+                       "%s[%d][%x]\n",
+                       client->client_name, adapter->name, err, err);
+       else {
+               client->inuse = TWL_CLIENT_USED;
+               init_MUTEX(&client->xfer_lock);
+       }
+       return err;
+}
+
+/* adapter callback */
+static int twl4030_attach_adapter(struct i2c_adapter *adapter)
+{
+       int i;
+       int ret = 0;
+       static int twl_i2c_adapter = 1;
+       for (i = 0; i < TWL4030_NUM_SLAVES; i++) {
+               /* Check if I need to hook on to this adapter or not */
+               if (twl4030_modules[i].adapter_index == twl_i2c_adapter) {
+                       if ((ret = twl4030_detect_client(adapter, i)))
+                               goto free_client;
+               }
+       }
+       twl_i2c_adapter++;
+
+       /*
+        * Check if the PIH module is initialized, if yes, then init
+        * the T2 Interrupt subsystem
+        */
+       if ((twl4030_modules[twl4030_map[TWL4030_MODULE_PIH].sid].inuse ==
+               TWL_CLIENT_USED) && (twl_irq_used != USED)) {
+               twl_init_irq();
+               twl_irq_used = USED;
+       }
+       return 0;
+
+free_client:
+       printk(KERN_ERR
+               "TWL4030: TWL_CLIENT(Idx=%d] REGISTRATION FAILED=%d[0x%x]\n", i,
+                       ret, ret);
+
+       /* ignore current slave..it never got registered */
+       i--;
+       while (i >= 0) {
+               /* now remove all those from the current adapter... */
+               if (twl4030_modules[i].adapter_index == twl_i2c_adapter)
+                       (void)twl4030_detach_client(&(twl4030_modules[i].client));
+               i--;
+       }
+       return ret;
+}
+
+/* adapter's callback */
+static int twl4030_detach_client(struct i2c_client *iclient)
+{
+       int err;
+       if ((err = i2c_detach_client(iclient))) {
+               printk(KERN_ERR
+                               "TWL4030: Client deregistration failed, client not detached.\n");
+               return err;
+       }
+       return 0;
+}
+
+struct task_struct *start_twl4030_irq_thread(int irq)
+{
+       struct task_struct *thread;
+
+       thread = kthread_create(twl4030_irq_thread, (void *)irq,
+                               "twl4030 irq %d", irq);
+       if (!thread)
+               printk(KERN_ERR "%s: could not create twl4030 irq %d thread!\n",
+                       __FUNCTION__, irq);
+
+       return thread;
+}
+
+/*
+ * These three functions should be part of Voltage frame work
+ * added here to complete the functionality for now.
+ */
+static int protect_pm_master(void)
+{
+       int e = 0;
+       e = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_LOCK,
+                       R_PROTECT_KEY);
+       return e;
+}
+
+static int unprotect_pm_master(void)
+{
+       int e = 0;
+       e |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_UNLOCK1,
+                       R_PROTECT_KEY);
+       e |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_UNLOCK2,
+                       R_PROTECT_KEY);
+       return e;
+}
+
+int power_companion_init(void)
+{
+       struct clk *osc;
+       u32 rate, ctrl = HFCLK_FREQ_26_MHZ;
+       int e = 0;
+
+       osc = clk_get(NULL,"osc_ck");
+       rate = clk_get_rate(osc);
+       clk_put(osc);
+
+       switch(rate) {
+               case 19200000 : ctrl = HFCLK_FREQ_19p2_MHZ; break;
+               case 26000000 : ctrl = HFCLK_FREQ_26_MHZ; break;
+               case 38400000 : ctrl = HFCLK_FREQ_38p4_MHZ; break;
+       }
+
+       ctrl |= HIGH_PERF_SQ;
+       e |= unprotect_pm_master();
+                       /* effect->MADC+USB ck en */
+       e |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, ctrl, R_CFG_BOOT);
+       e |= protect_pm_master();
+
+       return e;
+}
+
+static void twl_init_irq(void)
+{
+       int i = 0;
+       int res = 0;
+       int line = 0;
+       /*
+        * We end up with interrupts from other modules before
+        * they get a chance to handle them...
+        */
+       /* PWR_ISR1 */
+       res = twl4030_i2c_write_u8(TWL4030_MODULE_INT, 0xFF, 0x00);
+       if (res < 0) {
+               line = __LINE__;
+               goto irq_exit_path;
+       }
+
+       /* PWR_ISR2 */
+       res = twl4030_i2c_write_u8(TWL4030_MODULE_INT, 0xFF, 0x02);
+       if (res < 0) {
+               line = __LINE__;
+               goto irq_exit_path;
+       }
+
+       /* PWR_IMR1 */
+       res = twl4030_i2c_write_u8(TWL4030_MODULE_INT, 0xFF, 0x1);
+       if (res < 0) {
+               line = __LINE__;
+               goto irq_exit_path;
+       }
+
+       /* PWR_IMR2 */
+       res = twl4030_i2c_write_u8(TWL4030_MODULE_INT, 0xFF, 0x3);
+       if (res < 0) {
+               line = __LINE__;
+               goto irq_exit_path;
+       }
+
+       /* Clear off any other pending interrupts on power */
+       /* PWR_ISR1 */
+       res = twl4030_i2c_write_u8(TWL4030_MODULE_INT, 0xFF, 0x00);
+       if (res < 0) {
+               line = __LINE__;
+               goto irq_exit_path;
+       }
+
+       /* PWR_ISR2 */
+       res = twl4030_i2c_write_u8(TWL4030_MODULE_INT, 0xFF, 0x02);
+       if (res < 0) {
+               line = __LINE__;
+               goto irq_exit_path;
+       }
+       /* POWER HACK (END) */
+       /* Slave address 0x4A */
+
+       /* BCIIMR1_1 */
+       res = twl4030_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xFF, 0x3);
+       if (res < 0) {
+               line = __LINE__;
+               goto irq_exit_path;
+       }
+
+       /* BCIIMR1_2 */
+       res = twl4030_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xFF, 0x4);
+       if (res < 0) {
+               line = __LINE__;
+               goto irq_exit_path;
+       }
+
+       /* BCIIMR2_1 */
+       res = twl4030_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xFF, 0x7);
+       if (res < 0) {
+               line = __LINE__;
+               goto irq_exit_path;
+       }
+
+       /* BCIIMR2_2 */
+       res = twl4030_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xFF, 0x8);
+       if (res < 0) {
+               line = __LINE__;
+               goto irq_exit_path;
+       }
+
+       /* MAD C */
+       /* MADC_IMR1 */
+       res = twl4030_i2c_write_u8(TWL4030_MODULE_MADC, 0xFF, 0x62);
+       if (res < 0) {
+               line = __LINE__;
+               goto irq_exit_path;
+       }
+
+       /* MADC_IMR2 */
+       res = twl4030_i2c_write_u8(TWL4030_MODULE_MADC, 0xFF, 0x64);
+       if (res < 0) {
+               line = __LINE__;
+               goto irq_exit_path;
+       }
+
+       /* key Pad */
+       /* KEYPAD - IMR1 */
+       res = twl4030_i2c_write_u8(TWL4030_MODULE_KEYPAD, 0xFF, (0x12));
+       if (res < 0) {
+               line = __LINE__;
+               goto irq_exit_path;
+       }
+       {
+               u8 clear;
+               /* Clear ISR */
+               twl4030_i2c_read_u8(TWL4030_MODULE_KEYPAD, &clear, 0x11);
+               twl4030_i2c_read_u8(TWL4030_MODULE_KEYPAD, &clear, 0x11);
+       }
+
+       /* KEYPAD - IMR2 */
+       res = twl4030_i2c_write_u8(TWL4030_MODULE_KEYPAD, 0xFF, (0x14));
+       if (res < 0) {
+               line = __LINE__;
+               goto irq_exit_path;
+       }
+
+       /* Slave address 0x49 */
+       /* GPIO_IMR1A */
+       res = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xFF, (0x1C));
+       if (res < 0) {
+               line = __LINE__;
+               goto irq_exit_path;
+       }
+
+       /* GPIO_IMR2A */
+       res = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xFF, (0x1D));
+       if (res < 0) {
+               line = __LINE__;
+               goto irq_exit_path;
+       }
+
+       /* GPIO_IMR3A */
+       res = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xFF, (0x1E));
+       if (res < 0) {
+               line = __LINE__;
+               goto irq_exit_path;
+       }
+
+       /* GPIO_IMR1B */
+       res = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xFF, (0x22));
+       if (res < 0) {
+               line = __LINE__;
+               goto irq_exit_path;
+       }
+
+       /* GPIO_IMR2B */
+       res = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xFF, (0x23));
+       if (res < 0) {
+               line = __LINE__;
+               goto irq_exit_path;
+       }
+
+       /* GPIO_IMR3B */
+       res = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xFF, (0x24));
+       if (res < 0) {
+               line = __LINE__;
+               goto irq_exit_path;
+       }
+
+       /* install an irq handler for each of the PIH modules */
+       for (i = IH_TWL4030_BASE; i < IH_TWL4030_END; i++) {
+               set_irq_chip(i, &twl4030_irq_chip);
+               set_irq_handler(i, do_twl4030_module_irq);
+               set_irq_flags(i, IRQF_VALID);
+       }
+
+       /* install an irq handler to demultiplex the TWL4030 interrupt */
+       set_irq_data(TWL4030_IRQNUM, start_twl4030_irq_thread(TWL4030_IRQNUM));
+       set_irq_type(TWL4030_IRQNUM, IRQT_FALLING);
+       set_irq_chained_handler(TWL4030_IRQNUM, do_twl4030_irq);
+
+       res = power_companion_init();
+       if (res < 0) {
+               line = __LINE__;
+               goto irq_exit_path;
+       }
+
+irq_exit_path:
+       if (res)
+               printk(KERN_ERR
+                       "TWL4030: Unable to register interrupt "
+                       "subsystem[%d][%d]\n", res, line);
+}
+
+static int __init twl4030_init(void)
+{
+       int res;
+       if ((res = i2c_register_driver(THIS_MODULE, &twl4030_driver))) {
+               printk(KERN_ERR "TWL4030: Driver registration failed \n");
+               return res;
+       }
+       printk(KERN_INFO "TWL4030: Driver registration complete.\n");
+       return res;
+}
+
+static void __exit twl4030_exit(void)
+{
+       if (i2c_del_driver(&twl4030_driver))
+               printk(KERN_ERR
+                       "TWL4030: Driver remove failed, module not removed\n");
+       twl_irq_used = FREE;
+}
+
+subsys_initcall(twl4030_init);
+module_exit(twl4030_exit);
+
+EXPORT_SYMBOL(twl4030_i2c_write_u8);
+EXPORT_SYMBOL(twl4030_i2c_read_u8);
+EXPORT_SYMBOL(twl4030_i2c_read);
+EXPORT_SYMBOL(twl4030_i2c_write);
+
+MODULE_AUTHOR("Texas Instruments, Inc.");
+MODULE_DESCRIPTION("I2C Core interface for TWL4030");
+MODULE_LICENSE("GPL");
index 049f2f544e75e94a9d40aee991df4cf8d45510f4..d3e5f7f74648d09d13585ca361dfb25390f8468e 100644 (file)
@@ -203,6 +203,16 @@ config KEYBOARD_OMAP
          To compile this driver as a module, choose M here: the
          module will be called omap-keypad.
 
+config OMAP_PS2
+       tristate "TI OMAP Innovator 1510 PS/2 keyboard & mouse support"
+       depends on ARCH_OMAP15XX && MACH_OMAP_INNOVATOR
+       help
+         Say Y here if you want to use the OMAP Innovator 1510 PS/2
+         keyboard and mouse.
+
+         To compile this driver as a module, choose M here: the
+         module will be called innovator_ps2.
+
 config KEYBOARD_AAED2000
        tristate "AAED-2000 keyboard"
        depends on MACH_AAED2000
index 568797907347b9e0ace4898ab425e8a9ba16683d..8b5429d8366e6231eac4575ab3ec2f216620c9ec 100644 (file)
@@ -17,5 +17,6 @@ obj-$(CONFIG_KEYBOARD_SPITZ)          += spitzkbd.o
 obj-$(CONFIG_KEYBOARD_HIL)             += hil_kbd.o
 obj-$(CONFIG_KEYBOARD_HIL_OLD)         += hilkbd.o
 obj-$(CONFIG_KEYBOARD_OMAP)             += omap-keypad.o
+obj-$(CONFIG_OMAP_PS2)                 += innovator_ps2.o
 obj-$(CONFIG_KEYBOARD_AAED2000)         += aaed2000_kbd.o
 
diff --git a/drivers/input/keyboard/innovator_ps2.c b/drivers/input/keyboard/innovator_ps2.c
new file mode 100644 (file)
index 0000000..0f95f9f
--- /dev/null
@@ -0,0 +1,1280 @@
+/*
+ * drivers/char/innovator_ps2.c
+ *
+ * Basic PS/2 keyboard/mouse driver for the Juno® USAR HID controller
+ * present on the TI Innovator/OMAP1510 Break-out-board.
+ *
+ *
+ * Author: MontaVista Software, Inc.
+ *         <gdavis@mvista.com> or <source@mvista.com>
+ *
+ *
+ * 2003 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ *
+ *
+ * REFERENCES:
+ *
+ * 1.  Technical Reference Manual
+ *     Juno® 01
+ *     Multi-function ICs family
+ *     UR8HC007-001 HID & Power management controller
+ *     Document Number: DOC8-007-001-TR-075
+ *     Date: February 2002
+ *     Copyright Â©1998-2002 Semtech Corporation
+ *     http://www.semtech.com/pdf/doc8-007-001-tr.pdf
+ *
+ * 2.  Juno® 01 UR8HC007-001 Data Sheet
+ *     Extremely Low-power Input Device and Power Management IC
+ *     Copyright Â©1998-2002 Semtech Corporation
+ *     DOC8-007-001-DS-112
+ *     http://www.semtech.com/pdf/doc8-007-001-ds.pdf
+ *
+ *
+ * HISTORY:
+ *
+ * 20030626: George G. Davis <gdavis@mvista.com>
+ *      Initially based on the following RidgeRun DSPlinux Version 1.6 files:
+ *             linux-2.4.15-rmk1-dsplinux/arch/arm/dsplinux/hid/omap1510_hid.c
+ *             linux-2.4.15-rmk1-dsplinux/arch/arm/dsplinux/hid/omap1510_hid.h
+ *             linux-2.4.15-rmk1-dsplinux/arch/arm/dsplinux/hid/omap1510_ps2.c
+ *             linux-2.4.15-rmk1-dsplinux/arch/arm/dsplinux/hid/omap1510_spi.c
+ *     All original files above are
+ *             Copyright (C) 2001 RidgeRun, Inc.
+ *             Author: Alex McMains <aam@ridgerun.com>
+ *
+ * 20040812: Thiago Radicchi <trr@dcc.ufmg.br>
+ *      Cleanup of old code from 2.4 driver and some debug code.
+ *      Minor changes in interrupt handling code.
+ *
+ * NOTES:
+ *
+ * 1. This driver does not provide support for setting keyboard/mouse
+ *    configuration parameters. Both devices are managed directly by
+ *    the Juno UR8HC007-001 on behalf of the host. This minimises the
+ *    amount of host processing required to manage HID events and state
+ *    changes, e.g. both keyboard and mouse devices are hot pluggable
+ *    with no host intervention required. However, we cannot customise
+ *    keyboard/mouse settings in this case. So we live with the defaults
+ *    as setup by the Juno UR8HC007-001 whatever they may be.
+ * 2. Keyboard auto repeat does not work. See 1 above. : )
+ *
+ *
+ * TODO:
+ *
+ * 1. Complete DPM/LDM stubs and test.
+ * 2. Add SPI error handling support, i.e. resend, etc.,.
+ * 3. Determine why innovator_hid_interrupt() is called for every
+ *    invocation of Innovator FPGA IRQ demux. It appears that the
+ *    missed Innovator ethernet workaround may be to blame. However,
+ *    it does not adversely affect operation of this driver since we
+ *    check for assertion of ATN prior to servicing the interrupt. If
+ *    ATN is negated, we bug out right away.
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/stddef.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/poll.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/arch/fpga.h>
+
+#undef INNOVATOR_KEYB_DEBUG
+#ifdef INNOVATOR_KEYB_DEBUG
+#define        dbg(format, arg...) printk(KERN_DEBUG "%s:%d: " format , \
+                                  __FUNCTION__ , __LINE__ , ## arg)
+#define        entry() printk(KERN_DEBUG "%s:%d: Entry\n" , __FUNCTION__ , __LINE__)
+#define        exit()  printk(KERN_DEBUG "%s:%d: Exit\n" , __FUNCTION__ , __LINE__)
+#define dump_packet(p, n)                                      \
+       {                                                       \
+               int i;                                          \
+               printk(KERN_DEBUG "%s:%d: %08x:" ,              \
+                      __FUNCTION__ , __LINE__ , (int) p);      \
+               for (i = 0; i < n; i += 1) {                    \
+                       printk(" %02x", (int) p[i]);            \
+               }                                               \
+               printk("\n");                                   \
+       }
+#else
+#define        dbg(format, arg...) do {} while (0)
+#define        entry() do {} while (0)
+#define        exit()  do {} while (0)
+#define dump_packet(p, n) do {} while (0)
+#endif
+
+
+#define        PFX     "innovator_ps2"
+#define err(format, arg...)    printk(KERN_ERR PFX ": " format , ## arg)
+#define info(format, arg...)   printk(KERN_INFO PFX ": " format , ## arg)
+#define warn(format, arg...)   printk(KERN_WARNING PFX ": " format , ## arg)
+
+
+/****************************************************************************/
+
+/*
+ * Synchronous communications timing parameters (Reference [1] pg 7-7)
+ */
+
+#define tMSA   5000    /* -/5ms        _SS to _ATN (master transfer) */
+#define tMAC   100     /* 100us/5ms    _ATN to first clock pulse (master
+                                       transfer) */
+#define tMIB   150     /* 150us/5ms    Beginning of byte transfer to beginning
+                                       of next byte transfer */
+#define tSIB   150     /* 150us/5ms    Beginning of byte transfer to beginning
+                                       of next byte transfer */
+#define tMSP   100     /* -/100us      Last clock pulse of packet to _SS
+                                       de-assertion */
+#define tMNSA  100     /* -/100us      _SS de-assertion to _ATN de-assertion */
+#define tMNEXT 120     /* 120uS/-      _ATN release to _SS re-assertion
+                                       (master transfer) */
+#define        tSAS    5000    /* -/5ms        _ATN to _SS (slave transfer) */
+#define tSSC   100     /* 100us/5ms    _SS to first clock pulse (slave
+                                       transfer) */
+#define tSNA   100     /* -/100us      Last clock pulse of packet to _ATN
+                                       de-assertion */
+#define tSNAS  100     /* -/100us      _ATN release to _SS de-assertion */
+#define tSNEXT 120     /* 120us/-      _SS release to _ATN re-assertion
+                                       (slave transfer) */
+#define tSCK   4       /* 4us/-        Clock period */
+#define tSLOW  2       /* 2us/-        Clock LOW period */
+#define tHOLD  200     /* 200ns/-      Master data hold time */
+#define tSETUP 100     /* 100ns/-      Master data setup Time */
+#define tSSETUP        500     /* -/500ns      Slave data setup time from clock
+                                       falling edge */
+
+
+/*
+ * Protocol Headers (Reference [1], pg. 5-1):
+ */
+
+
+/* Protocols used in commands issued by the host: */
+#define SIMPLE                 0x80    /* Simple commands
+                                        * Common for both host and controller
+                                        * protocol headers.
+                                        */
+#define WRITE_REGISTER_BIT     0x81    /* Write register bit */
+#define READ_REGISTER_BIT      0x82    /* Read register bit */
+#define WRITE_REGISTER         0x83    /* Write register */
+#define READ_REGISTER          0x84    /* Read register */
+#define WRITE_BLOCK            0x85    /* Write block */
+#define READ_BLOCK             0x86    /* Read block */
+
+
+/* Protocols used in responses, reports and alerts issued by the controller: */
+#define REPORT_REGISTER_BIT    0x81    /* Report register bit & event alerts */
+#define REPORT_REGISTER                0x83    /* Report register */
+#define REPORT_BLOCK           0x85    /* Report block */
+#define POINTING_REPORT                0x87    /* Pointing device data report */
+#define KEYBOARD_REPORT                0x88    /* Keyboard device data report */
+
+
+/* Simple Commands (Reference [1], pg 5-3): */
+#define INITIALIZE             0x00    /* Forces the recipient to enter the
+                                        * known default power-on state.
+                                        */
+#define INITIALIZATION_COMPLETE        0x01    /* Issued as a hand-shake response only
+                                        * to the "Initialize" command.
+                                        */
+#define RESEND_REQUEST         0x05    /* Issued upon error in the reception
+                                        * of a package. The recipient resends
+                                        * the last transmitted packet.
+                                        */
+
+/* Register offsets (Reference [1], pg 6-1 thru 6-9): */
+
+#define REG_PM_COMM            0
+#define REG_PM_STATUS          1
+#define REG_PAGENO             255
+
+/* Power management bits ((Reference [1], pg 6-10): */
+
+#define SUS_STATE              0x2     /* in REG_PM_COMM */
+
+/* Miscellaneous constants: */
+
+#define X_MSB_SHIFT    (8-4)
+#define X_MSB_MASK     (3<<4)
+#define Y_MSB_SHIFT    (8-6)
+#define Y_MSB_MASK     (3<<6)
+
+
+#define JUNO_BLOCK_SIZE     32
+#define JUNO_BUFFER_SIZE    256
+
+
+/*
+ * Errors:
+ */
+
+#define E_BAD_HEADER   1
+#define E_BAD_LRC      2
+#define E_ZERO_BYTES   3
+#define E_BAD_VALUE    4
+#define E_BAD_MODE     5
+#define E_REPORT_MODE  6
+#define E_BAD_ACK      7
+#define E_BAD_DEVICE_ID        8
+#define E_PKT_SZ       9
+
+
+/*
+ * Host/Controller Command/Response Formats:
+ */
+
+typedef struct _simple_t {
+       u8 header;
+       u8 cmd_code;
+       u8 LRC;
+} __attribute__ ((packed)) simple_t;
+
+typedef struct _write_bit_t {
+       u8 header;
+       u8 offset;
+       u8 value_bit;
+       u8 LRC;
+} __attribute__ ((packed)) write_bit_t;
+
+typedef struct _read_bit_t {
+       u8 header;
+       u8 offset;
+       u8 bit;
+       u8 LRC;
+} __attribute__ ((packed)) read_bit_t;
+
+typedef struct _write_reg_t {
+       u8 header;
+       u8 offset;
+       u8 value;
+       u8 LRC;
+} __attribute__ ((packed)) write_reg_t;
+
+typedef struct _read_reg_t {
+       u8 header;
+       u8 offset;
+       u8 LRC;
+} __attribute__ ((packed)) read_reg_t;
+
+typedef struct _write_block_t {
+       u8 header;
+       u8 offset;
+       u8 length;
+       u8 block[JUNO_BLOCK_SIZE + 1]; /* Hack: LRC is last element of block[] */
+} __attribute__ ((packed)) write_block_t;
+
+typedef struct _read_block_t {
+       u8 header;
+       u8 offset;
+       u8 length;
+       u8 LRC;
+} __attribute__ ((packed)) read_block_t;
+
+typedef struct _report_bit_t {
+       u8 header;
+       u8 offset;
+       u8 value_bit;
+       u8 LRC;
+} __attribute__ ((packed)) report_bit_t;
+
+typedef struct _report_reg_t {
+       u8 header;
+       u8 offset;
+       u8 value;
+       u8 LRC;
+} __attribute__ ((packed)) report_reg_t;
+
+typedef struct _report_block_t {
+       u8 header;
+       u8 offset;
+       u8 length;
+       u8 block[32];
+       u8 LRC;
+} __attribute__ ((packed)) report_block_t;
+
+typedef struct _mse_report_t {
+       u8 header;
+       u8 buttons;
+       u8 Xdisplacement;
+       u8 Ydisplacement;
+       u8 Zdisplacement;
+       u8 LRC;
+} __attribute__ ((packed)) mse_report_t;
+
+typedef struct _kdb_report_t {
+       u8 header;
+       u8 keynum;              /* up > 0x80, down < 0x7E, all keys up 0x00 */
+       u8 LRC;
+} __attribute__ ((packed)) kdb_report_t;
+
+
+static u8 buffer[JUNO_BUFFER_SIZE];
+
+static void do_hid_tasklet(unsigned long);
+DECLARE_TASKLET(hid_tasklet, do_hid_tasklet, 0);
+static struct innovator_hid_dev *hid;
+
+struct innovator_hid_dev {
+       struct input_dev *mouse, *keyboard;
+       int open;
+       int irq_enabled;
+};
+
+/****************************************************************************/
+
+/*
+ * Low-level TI Innovator/OMAP1510 FPGA HID SPI interface helper functions:
+ */
+
+static u8
+innovator_fpga_hid_rd(void)
+{
+       u8 val = inb(INNOVATOR_FPGA_HID_SPI);
+       return val;
+}
+
+static void
+innovator_fpga_hid_wr(u8 val)
+{
+       outb(val, INNOVATOR_FPGA_HID_SPI);
+}
+
+static void
+innovator_fpga_hid_frob(u8 mask, u8 val)
+{
+       unsigned long flags;
+       local_irq_save(flags);
+       innovator_fpga_hid_wr((innovator_fpga_hid_rd() & ~mask) | val);
+       local_irq_restore(flags);
+}
+
+static void
+innovator_fpga_hid_set_bits(u8 x)
+{
+       innovator_fpga_hid_frob(x, x);
+}
+
+static void
+SS(int value)
+{
+       innovator_fpga_hid_frob(OMAP1510_FPGA_HID_nSS, value ? OMAP1510_FPGA_HID_nSS : 0);
+}
+
+static void
+SCLK(int value)
+{
+       innovator_fpga_hid_frob(OMAP1510_FPGA_HID_SCLK, value ? OMAP1510_FPGA_HID_SCLK : 0);
+}
+
+static void
+MOSI(int value)
+{
+       innovator_fpga_hid_frob(OMAP1510_FPGA_HID_MOSI, value ? OMAP1510_FPGA_HID_MOSI : 0);
+}
+
+static u8
+MISO(void)
+{
+       return ((innovator_fpga_hid_rd() & OMAP1510_FPGA_HID_MISO) ? 1 : 0);
+}
+
+static u8 
+ATN(void)
+{
+       return ((innovator_fpga_hid_rd() & OMAP1510_FPGA_HID_ATN) ? 1 : 0);
+}
+
+static int
+wait_for_ATN(int assert, int timeout)
+{
+       do {
+               if (ATN() == assert)
+                       return 0;
+               udelay(1);
+       } while (timeout -= 1);
+       return -1;
+}
+
+static u8
+innovator_fpga_hid_xfer_byte(u8 xbyte)
+{
+       int i;
+       u8 rbyte;
+
+       for (rbyte = 0, i = 7; i >= 0; i -= 1) {
+               SCLK(0);
+               MOSI((xbyte >> i) & 1);
+               udelay(tSLOW);
+               SCLK(1);
+               rbyte = (rbyte << 1) | MISO();
+               udelay(tSLOW);
+       }
+
+       return rbyte;
+}
+
+static void
+innovator_fpga_hid_reset(void)
+{
+       innovator_fpga_hid_wr(OMAP1510_FPGA_HID_SCLK | OMAP1510_FPGA_HID_MOSI);
+       mdelay(1);
+       innovator_fpga_hid_set_bits(OMAP1510_FPGA_HID_RESETn);
+}
+
+
+/*****************************************************************************
+
+  Refer to Reference [1], Chapter 7 / Low-level communications, Serial
+  Peripheral Interface (SPI) implementation Host (master) packet
+  transmission timing, pg. 7-3, for timing and implementation details
+  for spi_xmt().
+
+ *****************************************************************************/
+
+int
+spi_xmt(u8 * p, u8 n)
+{
+       unsigned long flags;
+
+       dump_packet(p, n);
+       local_irq_save(flags);
+       disable_irq(OMAP1510_INT_FPGA_ATN);
+
+       if (ATN()) {
+               /* Oops, we have a collision. */
+               enable_irq(OMAP1510_INT_FPGA_ATN);
+               local_irq_restore(flags);
+               dbg("Protocol error: ATN is asserted\n");
+               return -EAGAIN;
+       }
+
+       SS(1);
+
+       if (wait_for_ATN(1, tMSA) < 0) {
+               SS(0);
+               enable_irq(OMAP1510_INT_FPGA_ATN);
+               local_irq_restore(flags);
+               dbg("timeout waiting for ATN assertion\n");
+               return -EREMOTEIO;
+       }
+
+       udelay(tMAC);
+
+       while (n--) {
+               innovator_fpga_hid_xfer_byte(*p++);
+               if (n) {
+                       udelay(tMIB - 8 * tSCK);
+               }
+       }
+
+       MOSI(1);        /* Set MOSI to idle high. */
+
+       /* NOTE: The data sheet does not specify a minimum delay
+        * here. But innovator_fpga_hid_xfer_byte() gives us a half-clock
+        * delay (tSLOW) after the last bit is sent. So I'm happy with
+        * that.
+        */
+
+       SS(0);
+
+       if (wait_for_ATN(0, tMNSA) < 0) {
+               enable_irq(OMAP1510_INT_FPGA_ATN);
+               local_irq_restore(flags);
+               dbg("timeout waiting for ATN negation\n");
+               return -EREMOTEIO;
+       }
+
+       udelay(tMNEXT);
+       enable_irq(OMAP1510_INT_FPGA_ATN);
+       local_irq_restore(flags);
+       return 0;
+}
+
+
+/*****************************************************************************
+
+  Refer to Reference [1],  Chapter 7 / Low-level communications, Serial
+  Peripheral Interface (SPI) implementation, Slave packet transmission
+  timing, pg. 7-5, for timing and implementation details for spi_rcv().
+
+ *****************************************************************************/
+
+int
+spi_rcv(u8 * p, int len)
+{
+       unsigned long flags;
+       int ret = 0;
+
+       if (len > 256) {
+               /* Limit packet size to something reasonable */
+               return -1;
+       }
+
+       local_irq_save(flags);
+
+       if (wait_for_ATN(1, tMSA) < 0) {
+               local_irq_restore(flags);
+               dbg("Protocol error: ATN is not asserted\n");
+               return -EREMOTEIO;
+       }
+
+       SS(1);
+
+       udelay(tSSC);
+
+       while (ATN()) {
+               if (ret >= len) {
+                       err("over run error\n");
+                       ret = -1;
+                       break;
+               }
+               p[ret++] = innovator_fpga_hid_xfer_byte(0xff);
+               udelay(tSNA);   /* Wait long enough to detect negation of ATN
+                                * after last clock pulse of packet.
+                                *
+                                * NOTE: Normally, we need a minimum delay of
+                                *       tSIB between the start of one byte
+                                *       and the start of the next. However,
+                                *       we also need to wait long enough
+                                *       for the USAR to negate ATN before
+                                *       starting the next byte. So we use
+                                *       max(tSIB - 8 * tSCK, tSNA) here to
+                                *       satisfy both constraints.
+                                */
+       }
+
+       SS(0);  /* NOTE: The data sheet does not specify a minimum delay
+                * here. But innovator_fpga_hid_xfer_byte() gives us a
+                * half-clock delay (tSLOW) after the last bit is sent. So
+                * I'm happy with that (rather than no delay at all : ).
+                */
+
+
+       udelay(tSNEXT); /* This isn't quite right. Assertion of ATN after
+                        * negation of SS is an USAR timing constraint.
+                        * What we need here is a spec for the minimum
+                        * delay from SS negation to SS assertion. But
+                        * for now, just use this brain dead delay.
+                        */
+
+       local_irq_restore(flags);
+
+       if (ret > 0) {
+               dump_packet(p, ret);
+       }
+
+       return ret;
+}
+
+
+/*****************************************************************************
+  Calculate Host/Controller Command/Response Longitudinal Redundancy Check (LRC)
+
+  The algorithm implemented in calculate_LRC() below is taken directly from
+  the reference [1], Chapter 7 / Low-level communications, LRC (Longitudinal
+  Redundancy Check), pg 5-10.
+
+ *****************************************************************************/
+
+static u8
+calculate_LRC(u8 * p, int n)
+{
+       u8 LRC;
+       int i;
+
+       /*
+        * Init the LRC using the first two message bytes.
+        */
+       LRC = p[0] ^ p[1];
+
+       /*
+        * Update the LRC using the remainder of the p.
+        */
+       for (i = 2; i < n; i++)
+               LRC ^= p[i];
+
+       /*
+        * If the MSB is set then clear the MSB and change the next
+        * most significant bit
+        */
+       if (LRC & 0x80)
+               LRC ^= 0xC0;
+
+       return LRC;
+}
+
+
+/*
+ * Controller response helper functions:
+ */
+
+static inline int
+report_mouse(mse_report_t * p, int n)
+{
+       if (p->header != POINTING_REPORT)
+               return -E_BAD_HEADER;
+
+       if (n != sizeof(mse_report_t))
+               return -E_PKT_SZ;
+
+       return (p->LRC != calculate_LRC((u8 *) p, sizeof(mse_report_t) - 1)) ?
+               -E_BAD_LRC : POINTING_REPORT;
+}
+
+static inline int
+report_keyboard(kdb_report_t * p, int n)
+{
+       if (p->header != KEYBOARD_REPORT)
+               return -E_BAD_HEADER;
+
+       if (n != sizeof(kdb_report_t))
+               return -E_PKT_SZ;
+
+       return (p->LRC != calculate_LRC((u8 *) p, sizeof(kdb_report_t) - 1)) ?
+               -E_BAD_LRC : KEYBOARD_REPORT;
+}
+
+
+/*
+ * Miscellaneous helper functions:
+ */
+
+static inline int
+report_type(u8 * type)
+{
+       /* check the header to find out what kind of report it is */
+       if ((*type) == KEYBOARD_REPORT)
+               return KEYBOARD_REPORT;
+       else if ((*type) == POINTING_REPORT)
+               return POINTING_REPORT;
+       else
+               return -E_BAD_HEADER;
+}
+
+static inline int
+report_async(void * p, int n)
+{
+       int ret;
+
+       if ((ret = spi_rcv((u8 *) p, n)) < 0)
+               return ret;
+
+       if (report_type((u8 *) p) == POINTING_REPORT)
+               ret = report_mouse((mse_report_t *) p, ret);
+       else if (report_type((u8 *) p) == KEYBOARD_REPORT)
+               ret = report_keyboard((kdb_report_t *) p, ret);
+
+       return ret;
+}
+
+/*
+ * Host command helper functions:
+ */
+
+#if    0
+/* REVISIT/TODO: Wrapper for command/response with resend handing. */
+static int
+spi_xfer(u8 * optr, u8 osz, u8 * iptr, u8 isz)
+{
+       static u8 buf[256];
+       int ret;
+       int xretries = 3;
+
+       do {
+               if (optr != NULL && osz) {
+                       do {
+                               ret = spi_xmt((u8 *) optr, osz);
+                       } while (ret < 0);
+               }
+
+               ret = spi_rcv((u8 *) buf, 256);
+
+               if (ret == -EREMOTEIO) {
+                       if (iptr == NULL) {
+                               break;
+                       }
+               }
+       } while (xretries--);
+
+       return ret;
+}
+#endif
+
+/* REVISIT: Enable these when/if additional Juno features are required. */
+static inline int
+simple(u8 cmd)
+{
+       static simple_t p;
+       int ret;
+
+       p.header = SIMPLE;
+       p.cmd_code = cmd;
+       p.LRC = calculate_LRC((u8 *) & p, sizeof(p) - 1);
+
+       if ((ret = spi_xmt((u8 *) & p, sizeof(p))) < 0)
+               return ret;
+
+       if ((ret = spi_rcv((u8 *) & p, sizeof(p))) < 0)
+               return ret;
+
+       if (ret == 0)
+               return -E_ZERO_BYTES;
+
+       if (ret != sizeof(p))
+               return -E_PKT_SZ;
+
+       if (p.header != SIMPLE)
+               return -E_BAD_HEADER;
+
+       if (p.LRC != calculate_LRC((u8 *) & p, sizeof(p) - 1))
+               return -E_BAD_LRC;
+
+       /* REVISIT: Need to check or return response code here? */
+}
+
+static inline int
+write_bit(u8 offset, u8 bit, u8 value)
+{
+       static write_bit_t p;
+
+       p.header = WRITE_REGISTER_BIT;
+       p.offset = offset;
+       p.value_bit = (bit << 1) | (value & 1);
+       p.LRC = calculate_LRC((u8 *) & p, sizeof(p) - 1);
+
+       return spi_xmt((u8 *) & p, sizeof(p));
+}
+
+static inline int
+read_bit(u8 offset, u8 bit, u8 * data)
+{
+       static read_bit_t p;
+       static report_bit_t q;
+       int ret;
+
+       p.header = READ_REGISTER_BIT;
+       p.offset = offset;
+       p.bit = bit;
+       p.LRC = calculate_LRC((u8 *) & p, sizeof(p) - 1);
+
+       if ((ret = spi_xmt((u8 *) & p, sizeof(p))) < 0)
+               return ret;
+
+       if ((ret = spi_rcv((u8 *) & q, sizeof(q))) < 0)
+               return ret;
+
+       if (ret == 0)
+               return -E_ZERO_BYTES;
+
+       if (ret != sizeof(q))
+               return -E_PKT_SZ;
+
+       if (q.header != REPORT_REGISTER_BIT)
+               return -E_BAD_HEADER;
+
+       if (q.LRC != calculate_LRC((u8 *) & q, sizeof(q) - 1))
+               return -E_BAD_LRC;
+
+       *data = q.value_bit;
+
+       return 0;
+}
+
+static inline int
+write_reg(u8 offset, u8 value)
+{
+       static write_reg_t p;
+
+       p.header = WRITE_REGISTER;
+       p.offset = offset;
+       p.value = value;
+       p.LRC = calculate_LRC((u8 *) & p, sizeof(p) - 1);
+
+       return spi_xmt((u8 *) & p, sizeof(p));
+}
+
+static inline int
+read_reg(u8 offset, u8 * data)
+{
+       static read_reg_t p;
+       static report_reg_t q;
+       int ret;
+
+       p.header = READ_REGISTER;
+       p.offset = offset;
+       p.LRC = calculate_LRC((u8 *) & p, sizeof(p) - 1);
+
+       if ((ret = spi_xmt((u8 *) & p, sizeof(p))) < 0)
+               return ret;
+
+       if ((ret = spi_rcv((u8 *) & q, sizeof(q))) < 0)
+               return ret;
+
+       if (ret == 0)
+               return -E_ZERO_BYTES;
+
+       if (ret != sizeof(q))
+               return -E_PKT_SZ;
+
+       if (q.header != REPORT_REGISTER)
+               return -E_BAD_HEADER;
+
+       if (q.LRC != calculate_LRC((u8 *) & q, sizeof(q) - 1))
+               return -E_BAD_LRC;
+
+       *data = q.value;
+
+       return 0;
+}
+
+static inline int
+write_block(u8 offset, u8 length, u8 * block)
+{
+       static write_block_t p;
+
+       p.header = WRITE_BLOCK;
+       p.offset = offset;
+       p.length = length;
+       memcpy(&p.block, block, length);
+       p.block[length] = calculate_LRC((u8 *) & p, 3 + length);
+
+       return spi_xmt((u8 *) & p, 4 + length);
+}
+
+static inline int
+read_block(u8 offset, u8 length, u8 * buf)
+{
+       static read_block_t p;
+       static report_block_t q;
+       int ret;
+
+       p.header = READ_BLOCK;
+       p.offset = offset;
+       p.length = length;
+       p.LRC = calculate_LRC((u8 *) & p, sizeof(p) - 1);
+
+       if ((ret = spi_xmt((u8 *) & p, sizeof(p))) < 0)
+               return ret;
+
+       if ((ret = spi_rcv((u8 *) & q, sizeof(q))) < 0)
+               return ret;
+
+       if (ret == 0)
+               return -E_ZERO_BYTES;
+
+       if (ret != sizeof(4 + q.length))
+               return -E_PKT_SZ;
+
+       if (q.header != REPORT_BLOCK)
+               return -E_BAD_HEADER;
+
+       if (q.block[q.length] != calculate_LRC((u8 *) & q, 3 + q.length))
+               return -E_BAD_LRC;
+
+       if (length != q.length)
+               return -E_PKT_SZ;
+
+       memcpy(buf, &q.block, length);
+
+       return 0;
+}
+
+#ifdef INNOVATOR_KEYB_DEBUG
+static void
+ctrl_dump_regs(void)
+{
+       int i;
+       int n;
+
+       for (i = 0; i < 256; i += 8) {
+               read_block(i, 16, buffer);
+               mdelay(1);
+       }
+}
+#endif
+
+/*****************************************************************************/
+
+static void
+process_pointing_report(struct innovator_hid_dev *hid, u8 * buffer)
+{
+       static int prev_x, prev_y, prev_btn;
+       int x, y, btn;
+       hid->keyboard = input_allocate_device();
+       hid->mouse = input_allocate_device();
+
+       if (buffer[1] & (1 << 3)) {
+               /* relative pointing device report */
+               x = buffer[2];
+               y = buffer[3];
+
+               /* check the sign and convert from 2's complement if negative */
+               if (buffer[1] & (1<<4))
+                       x = ~(-x) - 255;
+
+               /* input driver wants -y */
+               if (buffer[1] & (1<<5))
+                       y = -(~(-y) - 255);
+               else
+                       y = -y;
+
+               input_report_key(hid->mouse,
+                                BTN_LEFT, buffer[1] & (1<<0));
+               input_report_key(hid->mouse,
+                                BTN_RIGHT, buffer[1] & (1<<1));
+               input_report_key(hid->mouse,
+                                BTN_MIDDLE, buffer[1] & (1<<2));
+               input_report_rel(hid->mouse, REL_X, x);
+               input_report_rel(hid->mouse, REL_Y, y);
+       } else {
+               /* REVISIT: Does this work? */
+               /* absolute pointing device report */
+               x = buffer[2] + ((buffer[1] & X_MSB_MASK) << X_MSB_SHIFT);
+               y = buffer[3] + ((buffer[1] & Y_MSB_MASK) << Y_MSB_SHIFT);
+               btn = buffer[1] & (1<<0);
+
+               if ((prev_x == x) && (prev_y == y)
+                   && (prev_btn == btn))
+                       return;
+
+               input_report_key(hid->mouse, BTN_LEFT, btn);
+               input_report_abs(hid->mouse, ABS_X, x);
+               input_report_abs(hid->mouse, ABS_Y, y);
+               prev_x = x;
+               prev_y = y;
+               prev_btn = btn;
+       }
+       input_sync(hid->mouse);
+       dbg("HID X: %d Y: %d Functions: %x\n", x, y, buffer[1]);
+}
+
+/*
+ * Reference [1], Appendix A, Semtech standard PS/2 key number definitions,
+ * pgs. A-1 through A-3. The following table lists standard PS/2 key numbers
+ * used by the Juno® 01 keyboard manager.
+ *
+ * NOTES:
+ * 1. The following table indices are E0 codes which require special handling:
+ *     53..62, 77..78, 94, 96, 100, 102..104, 108..110
+ * 2. The following table indices are E1 codes which require special handling:
+ *     101
+ */
+
+static unsigned char usar2scancode[128] = {
+       0x00, 0x29, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+       0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+       0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+       0x18, 0x19, 0x1a, 0x1b, 0x2b, 0x1e, 0x1f, 0x20,
+       0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+       0x1c, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32,
+       0x33, 0x34, 0x35, 0x39, 0x01, 0x52, 0x53, 0x4b,
+       0x47, 0x4f, 0x48, 0x50, 0x49, 0x51, 0x4d, 0x37,
+       0x4e, 0x4f, 0x50, 0x51, 0x4b, 0x4c, 0x4d, 0x47,
+       0x48, 0x49, 0x52, 0x53, 0x4a, 0x1c, 0x35, 0x3b,
+       0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43,
+       0x44, 0x57, 0x58, 0x2a, 0x36, 0x38, 0x38, 0x1d,
+       0x1d, 0x3a, 0x45, 0x46, 0x2a, 0x1d, 0x5b, 0x5c,
+       0x5d, 0xff, 0x00, 0x00, 0x5e, 0x5f, 0x63, 0x70,
+       0x7b, 0x79, 0x7d, 0x73, 0x5b, 0x5c, 0x5d, 0x63,
+       0x65, 0x66, 0x68, 0x69, 0x6b, 0x56, 0x54, 0x00
+};
+
+/*
+ * The following are bit masks used to encode E0 scan codes which
+ * require special handling. However, scan codes 100 and 101 are
+ * excludable here since they each require unique multi-byte scan
+ * code translations and are therefore dealt with individually via
+ * handle_print_scr() and handle_pause() respectively below.
+ */
+
+static unsigned long int e0_codes1 = 0x030003ff; /* scan codes 53..84 */
+static unsigned long int e0_codes2 = 0x038e0a00; /* scan codes 85..116 */
+
+static void
+handle_print_scr(int up)
+{
+       if (up) {
+               input_report_key(hid->keyboard, 0xe0, 1);
+               input_report_key(hid->keyboard, 0xb7, 1);
+               input_report_key(hid->keyboard, 0xe0, 1);
+               input_report_key(hid->keyboard, 0xaa, 1);
+       } else {
+               input_report_key(hid->keyboard, 0xe0, 0);
+               input_report_key(hid->keyboard, 0x2a, 0);
+               input_report_key(hid->keyboard, 0xe0, 0);
+               input_report_key(hid->keyboard, 0x37, 0);
+       }
+}
+
+static void
+handle_pause(void)
+{
+       input_report_key(hid->keyboard, 0xe1, 0);
+       input_report_key(hid->keyboard, 0x1d, 0);
+       input_report_key(hid->keyboard, 0x45, 0);
+       input_report_key(hid->keyboard, 0xe1, 0);
+       input_report_key(hid->keyboard, 0x9d, 0);
+       input_report_key(hid->keyboard, 0xc5, 0);
+}
+
+static void
+process_keyboard_report(struct innovator_hid_dev *hid, u8 * buffer)
+{
+       unsigned char ch = buffer[1] & 0x7f;
+       int up = buffer[1] & 0x80 ? 1 : 0;
+       int is_e0 = 0;
+       hid->keyboard = input_allocate_device();
+       hid->mouse = input_allocate_device();
+
+       if ((ch == 106) || (ch == 107))
+               return;         /* no code */
+
+       if (ch == 100) {
+               handle_print_scr(up);
+               return;
+       }
+
+       if (ch == 101) {
+               handle_pause();
+               return;
+       }
+
+       if ((ch >= 53) && (ch <= 84)) {
+               /* first block of e0 codes */
+               is_e0 = e0_codes1 & (1 << (ch - 53));
+       } else if ((ch >= 85) && (ch <= 116)) {
+               /* second block of e0 codes */
+               is_e0 = e0_codes2 & (1 << (ch - 85));
+       }
+
+       if (is_e0) {
+               input_report_key(hid->keyboard, 0xe0, !up);
+       }
+       input_report_key(hid->keyboard, usar2scancode[ch], !up);
+       input_sync(hid->keyboard);
+}
+
+static irqreturn_t
+innovator_hid_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       if (ATN()) {
+               disable_irq(OMAP1510_INT_FPGA_ATN);
+               tasklet_schedule(&hid_tasklet);
+       }
+       return IRQ_HANDLED;
+}
+
+static void
+do_hid_tasklet(unsigned long unused)
+{
+       int ret;
+       if ((ret = report_async(buffer, 256)) == -1) {
+               dbg("Error: Bad Juno return value: %d\n", ret);
+       } else if (ret == KEYBOARD_REPORT) {
+               process_keyboard_report(hid, buffer);
+       } else if (ret == POINTING_REPORT) {
+               process_pointing_report(hid, buffer);
+       } else {
+               dbg("ERROR: bad report\n");
+       }
+       enable_irq(OMAP1510_INT_FPGA_ATN);
+}
+
+static int
+innovator_hid_open(struct input_dev *dev)
+{
+       if (hid->open++)
+               return 0;
+
+       if (request_irq(OMAP1510_INT_FPGA_ATN, (void *) innovator_hid_interrupt,
+                       IRQF_DISABLED, PFX, hid) < 0)
+               return -EINVAL;
+
+       return 0;
+}
+
+static void
+innovator_hid_close(struct input_dev *dev)
+{
+       if (!--hid->open)
+               return;
+
+       if (hid == NULL)
+               return;
+
+       kfree(hid);
+}
+
+static int innovator_ps2_remove(struct device *dev)
+{
+       return 0;
+}
+
+static void innovator_ps2_device_release(struct device *dev)
+{
+       /* Nothing */
+}
+
+static int innovator_ps2_suspend(struct device *dev, pm_message_t state)
+{
+       u8 pmcomm = 0;
+
+       /*
+        * Set SUS_STATE in REG_PM_COMM (Page 0 R0).  This will cause
+        * PM_MOD bits of REG_PM_STATUS to show suspended state,
+        * but the SUS_STAT bit of REG_PM_STATUS will continue to
+        * reflect the state of the _HSUS pin.
+        */
+
+       if (write_reg(REG_PAGENO, 0) < 0)
+               printk("ps2 suspend: write_reg REG_PAGENO error\n");
+
+       if (read_reg(REG_PM_COMM, &pmcomm) < 0)
+               printk("ps2 suspend: read_reg REG_PM_COMM error\n");
+               
+       if (write_reg(REG_PM_COMM, pmcomm | SUS_STATE) < 0)
+               printk("ps2 suspend: write_reg REG_PM_COMM error\n");
+
+       return 0;
+}
+
+static int innovator_ps2_resume(struct device *dev)
+{
+       u8 pmcomm = 0;
+
+       /*
+        * Clear SUS_STATE from REG_PM_COMM (Page 0 R0).
+        */
+
+       if (write_reg(REG_PAGENO, 0) < 0)
+               printk("ps2 resume: write_reg REG_PAGENO error\n");
+
+       if (read_reg(REG_PM_COMM, &pmcomm) < 0)
+               printk("ps2 resume: read_reg REG_PM_COMM error\n");
+
+       if (write_reg(REG_PM_COMM, pmcomm & ~SUS_STATE) < 0)
+               printk("ps2 resume: write_reg REG_PM_COMM error\n");
+
+       return 0;
+}
+
+static struct device_driver innovator_ps2_driver = {
+       .name           = "innovator_ps2",
+       .bus            = &platform_bus_type,
+       .remove         = innovator_ps2_remove,
+       .suspend        = innovator_ps2_suspend,
+       .resume         = innovator_ps2_resume,
+};
+
+static struct platform_device innovator_ps2_device = {
+       .name           = "ps2",
+       .id             = -1,
+       .dev = {
+               .driver         = &innovator_ps2_driver,
+               .release        = innovator_ps2_device_release,
+       },
+};
+
+static int __init
+innovator_kbd_init(void)
+{
+       int i;
+       info("Innovator PS/2 keyboard/mouse driver v1.0\n");
+
+       innovator_fpga_hid_reset();
+
+       if ((hid = kmalloc(sizeof(struct innovator_hid_dev),
+            GFP_KERNEL)) == NULL) {
+               warn("unable to allocate space for HID device\n");
+               return -ENOMEM;
+       }
+
+       /* setup the mouse */
+       memset(hid, 0, sizeof(struct innovator_hid_dev));
+       hid->mouse = input_allocate_device();
+       hid->mouse->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+       hid->mouse->keybit[LONG(BTN_MOUSE)] =
+           BIT(BTN_LEFT) | BIT(BTN_RIGHT) |
+           BIT(BTN_MIDDLE) | BIT(BTN_TOUCH);
+       hid->mouse->relbit[0] = BIT(REL_X) | BIT(REL_Y);
+       hid->mouse->private = hid;
+       hid->mouse->open = innovator_hid_open;
+       hid->mouse->close = innovator_hid_close;
+       hid->mouse->name = "innovator_mouse";
+       hid->mouse->id.bustype = 0;
+       hid->mouse->id.vendor = 0;
+       hid->mouse->id.product = 0;
+       hid->mouse->id.version = 0;
+       hid->keyboard = input_allocate_device();
+       hid->keyboard->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+       hid->keyboard->keycodesize = sizeof(unsigned char);
+       hid->keyboard->keycodemax = ARRAY_SIZE(usar2scancode);
+       for(i = 0; i < 128; i++)
+               set_bit(usar2scancode[i], hid->keyboard->keybit);
+       hid->keyboard->private = hid;
+       hid->keyboard->open = innovator_hid_open;
+       hid->keyboard->close = innovator_hid_close;
+       hid->keyboard->name = "innovator_keyboard";
+       hid->keyboard->id.bustype = 0;
+       hid->keyboard->id.vendor = 0;
+       hid->keyboard->id.product = 0;
+       hid->keyboard->id.version = 0;
+       input_register_device(hid->mouse);
+       input_register_device(hid->keyboard);
+       innovator_hid_open(hid->mouse);
+       innovator_hid_open(hid->keyboard);
+
+       if (driver_register(&innovator_ps2_driver) != 0)
+               printk(KERN_ERR "Driver register failed for innovator_ps2\n");
+
+       if (platform_device_register(&innovator_ps2_device) != 0) {
+               printk(KERN_ERR "Device register failed for ps2\n");
+               driver_unregister(&innovator_ps2_driver);
+       }
+
+#ifdef INNOVATOR_KEYB_DEBUG
+       ctrl_dump_regs();
+#endif
+       return 0;
+}
+
+static void __exit
+innovator_kbd_exit(void)
+{
+       input_unregister_device(hid->mouse);
+       input_unregister_device(hid->keyboard);
+       free_irq(OMAP1510_INT_FPGA_ATN, hid);
+       if (hid != NULL)
+               kfree(hid);
+       driver_unregister(&innovator_ps2_driver);
+       platform_device_unregister(&innovator_ps2_device);
+       return;
+}
+
+module_init(innovator_kbd_init);
+module_exit(innovator_kbd_exit);
+
+MODULE_AUTHOR("George G. Davis <gdavis@mvista.com>");
+MODULE_DESCRIPTION("Innovator PS/2 Driver");
+MODULE_LICENSE("GPL");
index 5680a6d95b2b335c36c8bd6eed067ee87d2d085e..794bf4a25b7437135774d5bb9e97c54c4d4a47ef 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/delay.h>
 #include <linux/platform_device.h>
 #include <linux/mutex.h>
+#include <linux/spinlock.h>
 #include <linux/errno.h>
 #include <asm/arch/gpio.h>
 #include <asm/arch/keypad.h>
@@ -61,6 +62,8 @@ struct omap_kp {
        unsigned int cols;
        unsigned long delay;
        unsigned int debounce;
+       int suspended;
+       spinlock_t suspend_lock;
 };
 
 DECLARE_TASKLET_DISABLED(kp_tasklet, omap_kp_tasklet, 0);
@@ -100,6 +103,14 @@ static u8 get_row_gpio_val(struct omap_kp *omap_kp)
 static irqreturn_t omap_kp_interrupt(int irq, void *dev_id)
 {
        struct omap_kp *omap_kp = dev_id;
+       unsigned long flags;
+
+       spin_lock_irqsave(&omap_kp->suspend_lock, flags);
+       if (omap_kp->suspended) {
+               spin_unlock_irqrestore(&omap_kp->suspend_lock, flags);
+               return IRQ_HANDLED;
+       }
+       spin_unlock_irqrestore(&omap_kp->suspend_lock, flags);
 
        /* disable keyboard interrupt and schedule for handling */
        if (cpu_is_omap24xx()) {
@@ -271,15 +282,29 @@ static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, omap_kp_enable_show, omap_kp_enabl
 #ifdef CONFIG_PM
 static int omap_kp_suspend(struct platform_device *dev, pm_message_t state)
 {
-       /* Nothing yet */
+       struct omap_kp *omap_kp = platform_get_drvdata(dev);
+       unsigned long flags;
+       spin_lock_irqsave(&omap_kp->suspend_lock, flags);
+
+       /*
+        * Re-enable the interrupt in case it has been masked by the
+        * handler and a key is still pressed.  We need the interrupt
+        * to wake us up from suspended.
+        */
+       if (cpu_class_is_omap1())
+               omap_writew(0, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
+
+       omap_kp->suspended = 1;
 
+       spin_unlock_irqrestore(&omap_kp->suspend_lock, flags);
        return 0;
 }
 
 static int omap_kp_resume(struct platform_device *dev)
 {
-       /* Nothing yet */
+       struct omap_kp *omap_kp = platform_get_drvdata(dev);
 
+       omap_kp->suspended = 0;
        return 0;
 }
 #else
@@ -292,7 +317,7 @@ static int __init omap_kp_probe(struct platform_device *pdev)
        struct omap_kp *omap_kp;
        struct input_dev *input_dev;
        struct omap_kp_platform_data *pdata =  pdev->dev.platform_data;
-       int i, col_idx, row_idx, irq_idx, ret;
+       int i, col_idx = 0, row_idx = 0, irq_idx, ret;
 
        if (!pdata->rows || !pdata->cols || !pdata->keymap) {
                printk(KERN_ERR "No rows, cols or keymap from pdata\n");
@@ -309,7 +334,9 @@ static int __init omap_kp_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, omap_kp);
 
+       spin_lock_init(&omap_kp->suspend_lock);
        omap_kp->input = input_dev;
+       omap_kp->suspended = 0;
 
        /* Disable the interrupt for the MPUIO keyboard */
        if (!cpu_is_omap24xx())
index 6b46c9bf1d2045c7bf79a1c2c977bdf92a6db27e..8b3a3715e0b216ff16cf597b2d651738e9c70b10 100644 (file)
@@ -14,10 +14,13 @@ if INPUT_TOUCHSCREEN
 config TOUCHSCREEN_ADS7846
        tristate "ADS 7846 based touchscreens"
        depends on SPI_MASTER
+       select HWMON
        help
          Say Y here if you have a touchscreen interface using the
          ADS7846 controller, and your board-specific initialization
-         code includes that in its table of SPI devices.
+         code includes that in its table of SPI devices.  You will
+         also get hwmon interfaces for the temperature and voltage
+         sensors this chip provides.
 
          If unsure, say N (but it's safe to say "Y").
 
@@ -159,4 +162,32 @@ config TOUCHSCREEN_UCB1400
          To compile this driver as a module, choose M here: the
          module will be called ucb1400_ts.
 
+config TOUCHSCREEN_TSC2102
+       tristate "TSC 2102 based touchscreens"
+       depends on SPI_MASTER
+       select TSC2102
+       help
+         Say Y here if you have a touchscreen interface using the
+         TI TSC 2102 controller, and your board-specific initialization
+         code includes that in its table of SPI devices.  Also make
+         sure the proper SPI controller is selected.
+
+         If unsure, say N (but it's safe to say "Y").
+
+         To compile this driver as a module, choose M here: the
+         module will be called tsc2102_ts.
+
+config TOUCHSCREEN_OMAP
+       tristate "OMAP touchscreen input driver"
+       depends on INPUT && INPUT_TOUCHSCREEN && (MACH_OMAP_H2 || MACH_OMAP_H3)
+       help
+         Say Y here if you have an OMAP based board with touchscreen
+         attached to it, e.g. OMAP H2 or H3
+
+         If unsure, or you're using drivers in the newer SPI
+         framework (as with Innovator or OSK/Mistral), say N.
+
+         To compile this driver as a module, choose M here: the
+         module will be called omap_ts.
+
 endif
index 30e6e2217a15d86d72f153ca2fa3af9086f7ca70..061bc14aeda41dcce8c9f9311adb17055ab1dba3 100644 (file)
@@ -1,5 +1,5 @@
 #
-# Makefile for the mouse drivers.
+# Makefile for the touchscreen input drivers.
 #
 
 # Each configuration option enables a list of files.
@@ -16,3 +16,5 @@ obj-$(CONFIG_TOUCHSCREEN_PENMOUNT)    += penmount.o
 obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT)   += touchright.o
 obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN)     += touchwin.o
 obj-$(CONFIG_TOUCHSCREEN_UCB1400)      += ucb1400_ts.o
+obj-$(CONFIG_TOUCHSCREEN_TSC2102)      += tsc2102_ts.o
+obj-$(CONFIG_TOUCHSCREEN_OMAP) += omap/
index c6164b6f476a3ecb5fde27af07ddd05c38557d01..0c496d5d19597cd7702641c4867d39a994dd5320 100644 (file)
@@ -17,8 +17,9 @@
  *  it under the terms of the GNU General Public License version 2 as
  *  published by the Free Software Foundation.
  */
-#include <linux/device.h>
+#include <linux/hwmon.h>
 #include <linux/init.h>
+#include <linux/err.h>
 #include <linux/delay.h>
 #include <linux/input.h>
 #include <linux/interrupt.h>
@@ -54,7 +55,8 @@
  * files.
  */
 
-#define        TS_POLL_PERIOD  msecs_to_jiffies(10)
+#define TS_POLL_DELAY  (1 * 1000000)   /* ns delay before the first sample */
+#define        TS_POLL_PERIOD  (5 * 1000000)   /* ns delay between samples */
 
 /* this driver doesn't aim at the peak continuous sample rate */
 #define        SAMPLE_BITS     (8 /*cmd*/ + 16 /*sample*/ + 2 /* before, after */)
@@ -76,7 +78,7 @@ struct ads7846 {
        char                    phys[32];
 
        struct spi_device       *spi;
-       struct attribute_group  *attr_group;
+       struct class_device     *hwmon;
        u16                     model;
        u16                     vref_delay_usecs;
        u16                     x_plate_ohms;
@@ -99,13 +101,16 @@ struct ads7846 {
        u16                     debounce_rep;
 
        spinlock_t              lock;
-       struct timer_list       timer;          /* P: lock */
+       struct hrtimer          timer;
        unsigned                pendown:1;      /* P: lock */
        unsigned                pending:1;      /* P: lock */
 // FIXME remove "irq_disabled"
        unsigned                irq_disabled:1; /* P: lock */
        unsigned                disabled:1;
 
+       int                     (*filter)(void *data, int data_idx, int *val);
+       void                    *filter_data;
+       void                    (*filter_cleanup)(void *data);
        int                     (*get_pendown_state)(void);
 };
 
@@ -142,15 +147,16 @@ struct ads7846 {
 #define        MAX_12BIT       ((1<<12)-1)
 
 /* leave ADC powered up (disables penirq) between differential samples */
-#define        READ_12BIT_DFR(x) (ADS_START | ADS_A2A1A0_d_ ## x \
-       | ADS_12_BIT | ADS_DFR)
+#define        READ_12BIT_DFR(x, adc, vref) (ADS_START | ADS_A2A1A0_d_ ## x \
+       | ADS_12_BIT | ADS_DFR | \
+       (adc ? ADS_PD10_ADC_ON : 0) | (vref ? ADS_PD10_REF_ON : 0))
 
-#define        READ_Y  (READ_12BIT_DFR(y)  | ADS_PD10_ADC_ON)
-#define        READ_Z1 (READ_12BIT_DFR(z1) | ADS_PD10_ADC_ON)
-#define        READ_Z2 (READ_12BIT_DFR(z2) | ADS_PD10_ADC_ON)
+#define        READ_Y(vref)    (READ_12BIT_DFR(y,  1, vref))
+#define        READ_Z1(vref)   (READ_12BIT_DFR(z1, 1, vref))
+#define        READ_Z2(vref)   (READ_12BIT_DFR(z2, 1, vref))
 
-#define        READ_X  (READ_12BIT_DFR(x)  | ADS_PD10_ADC_ON)
-#define        PWRDOWN (READ_12BIT_DFR(y)  | ADS_PD10_PDOWN)   /* LAST */
+#define        READ_X(vref)    (READ_12BIT_DFR(x,  1, vref))
+#define        PWRDOWN         (READ_12BIT_DFR(y,  0, 0))      /* LAST */
 
 /* single-ended samples need to first power up reference voltage;
  * we leave both ADC and VREF powered
@@ -158,14 +164,19 @@ struct ads7846 {
 #define        READ_12BIT_SER(x) (ADS_START | ADS_A2A1A0_ ## x \
        | ADS_12_BIT | ADS_SER)
 
-#define        REF_ON  (READ_12BIT_DFR(x) | ADS_PD10_ALL_ON)
-#define        REF_OFF (READ_12BIT_DFR(y) | ADS_PD10_PDOWN)
+#define        REF_ON  (READ_12BIT_DFR(x, 1, 1))
+#define        REF_OFF (READ_12BIT_DFR(y, 0, 0))
 
 /*--------------------------------------------------------------------------*/
 
 /*
  * Non-touchscreen sensors only use single-ended conversions.
+ * The range is GND..vREF. The ads7843 and ads7835 must use external vREF;
+ * ads7846 lets that pin be unconnected, to use internal vREF.
+ *
+ * FIXME make external vREF_mV be a module option, and use that as needed...
  */
+static const unsigned vREF_mV = 2500;
 
 struct ser_req {
        u8                      ref_on;
@@ -193,50 +204,55 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
        struct ser_req          *req = kzalloc(sizeof *req, GFP_KERNEL);
        int                     status;
        int                     sample;
-       int                     i;
+       int                     use_internal;
 
        if (!req)
                return -ENOMEM;
 
        spi_message_init(&req->msg);
 
-       /* activate reference, so it has time to settle; */
-       req->ref_on = REF_ON;
-       req->xfer[0].tx_buf = &req->ref_on;
-       req->xfer[0].len = 1;
-       req->xfer[1].rx_buf = &req->scratch;
-       req->xfer[1].len = 2;
-
-       /*
-        * for external VREF, 0 usec (and assume it's always on);
-        * for 1uF, use 800 usec;
-        * no cap, 100 usec.
-        */
-       req->xfer[1].delay_usecs = ts->vref_delay_usecs;
+       /* FIXME boards with ads7846 might use external vref instead ... */
+       use_internal = (ts->model == 7846);
+
+       /* maybe turn on internal vREF, and let it settle */
+       if (use_internal) {
+               req->ref_on = REF_ON;
+               req->xfer[0].tx_buf = &req->ref_on;
+               req->xfer[0].len = 1;
+               spi_message_add_tail(&req->xfer[0], &req->msg);
+
+               req->xfer[1].rx_buf = &req->scratch;
+               req->xfer[1].len = 2;
+
+               /* for 1uF, settle for 800 usec; no cap, 100 usec.  */
+               req->xfer[1].delay_usecs = ts->vref_delay_usecs;
+               spi_message_add_tail(&req->xfer[1], &req->msg);
+       }
 
        /* take sample */
        req->command = (u8) command;
        req->xfer[2].tx_buf = &req->command;
        req->xfer[2].len = 1;
+       spi_message_add_tail(&req->xfer[2], &req->msg);
+
        req->xfer[3].rx_buf = &req->sample;
        req->xfer[3].len = 2;
+       spi_message_add_tail(&req->xfer[3], &req->msg);
 
        /* REVISIT:  take a few more samples, and compare ... */
 
-       /* turn off reference */
-       req->ref_off = REF_OFF;
-       req->xfer[4].tx_buf = &req->ref_off;
-       req->xfer[4].len = 1;
-       req->xfer[5].rx_buf = &req->scratch;
-       req->xfer[5].len = 2;
-
-       CS_CHANGE(req->xfer[5]);
-
-       /* group all the transfers together, so we can't interfere with
-        * reading touchscreen state; disable penirq while sampling
-        */
-       for (i = 0; i < 6; i++)
-               spi_message_add_tail(&req->xfer[i], &req->msg);
+       /* maybe off internal vREF */
+       if (use_internal) {
+               req->ref_off = REF_OFF;
+               req->xfer[4].tx_buf = &req->ref_off;
+               req->xfer[4].len = 1;
+               spi_message_add_tail(&req->xfer[4], &req->msg);
+
+               req->xfer[5].rx_buf = &req->scratch;
+               req->xfer[5].len = 2;
+               CS_CHANGE(req->xfer[5]);
+               spi_message_add_tail(&req->xfer[5], &req->msg);
+       }
 
        ts->irq_disabled = 1;
        disable_irq(spi->irq);
@@ -256,21 +272,60 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
        return status ? status : sample;
 }
 
-#define SHOW(name) static ssize_t \
+#define SHOW(name,var,adjust) static ssize_t \
 name ## _show(struct device *dev, struct device_attribute *attr, char *buf) \
 { \
+       struct ads7846 *ts = dev_get_drvdata(dev); \
        ssize_t v = ads7846_read12_ser(dev, \
-                       READ_12BIT_SER(name) | ADS_PD10_ALL_ON); \
+                       READ_12BIT_SER(var) | ADS_PD10_ALL_ON); \
        if (v < 0) \
                return v; \
-       return sprintf(buf, "%u\n", (unsigned) v); \
+       return sprintf(buf, "%u\n", adjust(ts, v)); \
 } \
 static DEVICE_ATTR(name, S_IRUGO, name ## _show, NULL);
 
-SHOW(temp0)
-SHOW(temp1)
-SHOW(vaux)
-SHOW(vbatt)
+
+/* Sysfs conventions report temperatures in millidegrees Celcius.
+ * We could use the low-accuracy two-sample scheme, but can't do the high
+ * accuracy scheme without calibration data.  For now we won't try either;
+ * userspace sees raw sensor values, and must scale appropriately.
+ */
+static inline unsigned null_adjust(struct ads7846 *ts, ssize_t v)
+{
+       return v;
+}
+
+SHOW(temp0, temp0, null_adjust)                // temp1_input
+SHOW(temp1, temp1, null_adjust)                // temp2_input
+
+
+/* sysfs conventions report voltages in millivolts.  We can convert voltages
+ * if we know vREF.  userspace may need to scale vAUX to match the board's
+ * external resistors; we assume that vBATT only uses the internal ones.
+ */
+static inline unsigned vaux_adjust(struct ads7846 *ts, ssize_t v)
+{
+       unsigned retval = v;
+
+       /* external resistors may scale vAUX into 0..vREF */
+       retval *= vREF_mV;
+       retval = retval >> 12;
+       return retval;
+}
+
+static inline unsigned vbatt_adjust(struct ads7846 *ts, ssize_t v)
+{
+       unsigned retval = vaux_adjust(ts, v);
+
+       /* ads7846 has a resistor ladder to scale this signal down */
+       if (ts->model == 7846)
+               retval *= 4;
+       return retval;
+}
+
+SHOW(in0_input, vaux, vaux_adjust)
+SHOW(in1_input, vbatt, vbatt_adjust)
+
 
 static int is_pen_down(struct device *dev)
 {
@@ -318,49 +373,40 @@ static ssize_t ads7846_disable_store(struct device *dev,
 
 static DEVICE_ATTR(disable, 0664, ads7846_disable_show, ads7846_disable_store);
 
-static struct attribute *ads7846_attributes[] = {
-       &dev_attr_temp0.attr,
-       &dev_attr_temp1.attr,
-       &dev_attr_vbatt.attr,
-       &dev_attr_vaux.attr,
-       &dev_attr_pen_down.attr,
-       &dev_attr_disable.attr,
-       NULL,
-};
+/*--------------------------------------------------------------------------*/
 
-static struct attribute_group ads7846_attr_group = {
-       .attrs = ads7846_attributes,
-};
+static void ads7846_report_pen_state(struct ads7846 *ts, int down)
+{
+       struct input_dev        *input_dev = ts->input;
 
-/*
- * ads7843/7845 don't have temperature sensors, and
- * use the other sensors a bit differently too
- */
+       input_report_key(input_dev, BTN_TOUCH, down);
+       if (!down)
+               input_report_abs(input_dev, ABS_PRESSURE, 0);
+#ifdef VERBOSE
+       pr_debug("%s: %s\n", ts->spi->dev.bus_id, down ? "DOWN" : "UP");
+#endif
+}
 
-static struct attribute *ads7843_attributes[] = {
-       &dev_attr_vbatt.attr,
-       &dev_attr_vaux.attr,
-       &dev_attr_pen_down.attr,
-       &dev_attr_disable.attr,
-       NULL,
-};
+static void ads7846_report_pen_position(struct ads7846 *ts, int x, int y,
+                                       int pressure)
+{
+       struct input_dev        *input_dev = ts->input;
 
-static struct attribute_group ads7843_attr_group = {
-       .attrs = ads7843_attributes,
-};
+       input_report_abs(input_dev, ABS_X, x);
+       input_report_abs(input_dev, ABS_Y, y);
+       input_report_abs(input_dev, ABS_PRESSURE, pressure);
 
-static struct attribute *ads7845_attributes[] = {
-       &dev_attr_vaux.attr,
-       &dev_attr_pen_down.attr,
-       &dev_attr_disable.attr,
-       NULL,
-};
+#ifdef VERBOSE
+       pr_debug("%s: %d/%d/%d\n", ts->spi->dev.bus_id, x, y, pressure);
+#endif
+}
 
-static struct attribute_group ads7845_attr_group = {
-       .attrs = ads7845_attributes,
-};
+static void ads7846_sync_events(struct ads7846 *ts)
+{
+       struct input_dev        *input_dev = ts->input;
 
-/*--------------------------------------------------------------------------*/
+       input_sync(input_dev);
+}
 
 /*
  * PENIRQ only kicks the timer.  The timer only reissues the SPI transfer,
@@ -373,25 +419,22 @@ static struct attribute_group ads7845_attr_group = {
 static void ads7846_rx(void *ads)
 {
        struct ads7846          *ts = ads;
-       struct input_dev        *input_dev = ts->input;
        unsigned                Rt;
-       unsigned                sync = 0;
        u16                     x, y, z1, z2;
-       unsigned long           flags;
 
        /* adjust:  on-wire is a must-ignore bit, a BE12 value, then padding;
         * built from two 8 bit values written msb-first.
         */
-       x = (be16_to_cpu(ts->tc.x) >> 3) & 0x0fff;
-       y = (be16_to_cpu(ts->tc.y) >> 3) & 0x0fff;
-       z1 = (be16_to_cpu(ts->tc.z1) >> 3) & 0x0fff;
-       z2 = (be16_to_cpu(ts->tc.z2) >> 3) & 0x0fff;
+       x = ts->tc.x;
+       y = ts->tc.y;
+       z1 = ts->tc.z1;
+       z2 = ts->tc.z2;
 
        /* range filtering */
        if (x == MAX_12BIT)
                x = 0;
 
-       if (likely(x && z1 && !device_suspended(&ts->spi->dev))) {
+       if (likely(x && z1)) {
                /* compute touch pressure resistance using equation #2 */
                Rt = z2;
                Rt -= z1;
@@ -406,97 +449,108 @@ static void ads7846_rx(void *ads)
        * the maximum. Don't report it to user space, repeat at least
        * once more the measurement */
        if (ts->tc.ignore || Rt > ts->pressure_max) {
-               mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD);
+#ifdef VERBOSE
+               pr_debug("%s: ignored %d pressure %d\n",
+                       ts->spi->dev.bus_id, ts->tc.ignore, Rt);
+#endif
+               hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),
+                             HRTIMER_REL);
                return;
        }
 
-       /* NOTE:  "pendown" is inferred from pressure; we don't rely on
-        * being able to check nPENIRQ status, or "friendly" trigger modes
-        * (both-edges is much better than just-falling or low-level).
-        *
-        * REVISIT:  some boards may require reading nPENIRQ; it's
-        * needed on 7843.  and 7845 reads pressure differently...
-        *
-        * REVISIT:  the touchscreen might not be connected; this code
-        * won't notice that, even if nPENIRQ never fires ...
+       /* NOTE: We can't rely on the pressure to determine the pen down
+        * state. The pressure value can fluctuate for quite a while
+        * after lifting the pen and in some cases may not even settle at
+        * the expected value. The only safe way to check for the pen up
+        * condition is in the timer by reading the pen IRQ state.
         */
-       if (!ts->pendown && Rt != 0) {
-               input_report_key(input_dev, BTN_TOUCH, 1);
-               sync = 1;
-       } else if (ts->pendown && Rt == 0) {
-               input_report_key(input_dev, BTN_TOUCH, 0);
-               sync = 1;
-       }
-
        if (Rt) {
-               input_report_abs(input_dev, ABS_X, x);
-               input_report_abs(input_dev, ABS_Y, y);
-               sync = 1;
-       }
-
-       if (sync) {
-               input_report_abs(input_dev, ABS_PRESSURE, Rt);
-               input_sync(input_dev);
+               if (!ts->pendown) {
+                       ads7846_report_pen_state(ts, 1);
+                       ts->pendown = 1;
+               }
+               ads7846_report_pen_position(ts, x, y, Rt);
+               ads7846_sync_events(ts);
        }
 
-#ifdef VERBOSE
-       if (Rt || ts->pendown)
-               pr_debug("%s: %d/%d/%d%s\n", ts->spi->dev.bus_id,
-                       x, y, Rt, Rt ? "" : " UP");
-#endif
-
-       spin_lock_irqsave(&ts->lock, flags);
-
-       ts->pendown = (Rt != 0);
-       mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD);
-
-       spin_unlock_irqrestore(&ts->lock, flags);
+       hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD), HRTIMER_REL);
 }
 
-static void ads7846_debounce(void *ads)
+static int ads7846_debounce(void *ads, int data_idx, int *val)
 {
        struct ads7846          *ts = ads;
-       struct spi_message      *m;
-       struct spi_transfer     *t;
-       int                     val;
-       int                     status;
 
-       m = &ts->msg[ts->msg_idx];
-       t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
-       val = (be16_to_cpu(*(__be16 *)t->rx_buf) >> 3) & 0x0fff;
-       if (!ts->read_cnt || (abs(ts->last_read - val) > ts->debounce_tol)) {
+       if (!ts->read_cnt || (abs(ts->last_read - *val) > ts->debounce_tol)) {
+               /* Start over collecting consistent readings. */
+               ts->read_rep = 0;
                /* Repeat it, if this was the first read or the read
                 * wasn't consistent enough. */
                if (ts->read_cnt < ts->debounce_max) {
-                       ts->last_read = val;
+                       ts->last_read = *val;
                        ts->read_cnt++;
+                       return ADS7846_FILTER_REPEAT;
                } else {
                        /* Maximum number of debouncing reached and still
                         * not enough number of consistent readings. Abort
                         * the whole sample, repeat it in the next sampling
                         * period.
                         */
-                       ts->tc.ignore = 1;
                        ts->read_cnt = 0;
-                       /* Last message will contain ads7846_rx() as the
-                        * completion function.
-                        */
-                       m = ts->last_msg;
+                       return ADS7846_FILTER_IGNORE;
                }
-               /* Start over collecting consistent readings. */
-               ts->read_rep = 0;
        } else {
                if (++ts->read_rep > ts->debounce_rep) {
                        /* Got a good reading for this coordinate,
                         * go for the next one. */
-                       ts->tc.ignore = 0;
-                       ts->msg_idx++;
                        ts->read_cnt = 0;
                        ts->read_rep = 0;
-                       m++;
-               } else
+                       return ADS7846_FILTER_OK;
+               } else {
                        /* Read more values that are consistent. */
                        ts->read_cnt++;
+                       return ADS7846_FILTER_REPEAT;
+               }
+       }
+}
+
+static int ads7846_no_filter(void *ads, int data_idx, int *val)
+{
+       return ADS7846_FILTER_OK;
+}
+
+static void ads7846_rx_val(void *ads)
+{
+       struct ads7846 *ts = ads;
+       struct spi_message *m;
+       struct spi_transfer *t;
+       u16 *rx_val;
+       int val;
+       int action;
+       int status;
+
+       m = &ts->msg[ts->msg_idx];
+       t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
+       rx_val = (u16 *)t->rx_buf;
+       val = be16_to_cpu(*rx_val) >> 3;
+
+       action = ts->filter(ts->filter_data, ts->msg_idx, &val);
+       switch (action) {
+       case ADS7846_FILTER_REPEAT:
+               break;
+       case ADS7846_FILTER_IGNORE:
+               ts->tc.ignore = 1;
+               /* Last message will contain ads7846_rx() as the
+                * completion function.
+                */
+               m = ts->last_msg;
+               break;
+       case ADS7846_FILTER_OK:
+               *rx_val = val;
+               ts->tc.ignore = 0;
+               m = &ts->msg[++ts->msg_idx];
+               break;
+       default:
+               BUG();
        }
        status = spi_async(ts->spi, m);
        if (status)
@@ -504,21 +558,27 @@ static void ads7846_debounce(void *ads)
                                status);
 }
 
-static void ads7846_timer(unsigned long handle)
+static int ads7846_timer(struct hrtimer *handle)
 {
-       struct ads7846  *ts = (void *)handle;
+       struct ads7846  *ts = container_of(handle, struct ads7846, timer);
        int             status = 0;
 
        spin_lock_irq(&ts->lock);
 
-       if (unlikely(ts->msg_idx && !ts->pendown)) {
-               /* measurement cycle ended */
+       if (unlikely(!ts->get_pendown_state() ||
+                    device_suspended(&ts->spi->dev))) {
+               if (ts->pendown) {
+                       ads7846_report_pen_state(ts, 0);
+                       ads7846_sync_events(ts);
+                       ts->pendown = 0;
+               }
+
+               /* measurment cycle ended */
                if (!device_suspended(&ts->spi->dev)) {
                        ts->irq_disabled = 0;
                        enable_irq(ts->spi->irq);
                }
                ts->pending = 0;
-               ts->msg_idx = 0;
        } else {
                /* pen is still down, continue with the measurement */
                ts->msg_idx = 0;
@@ -528,6 +588,7 @@ static void ads7846_timer(unsigned long handle)
        }
 
        spin_unlock_irq(&ts->lock);
+       return HRTIMER_NORESTART;
 }
 
 static irqreturn_t ads7846_irq(int irq, void *handle)
@@ -538,15 +599,17 @@ static irqreturn_t ads7846_irq(int irq, void *handle)
        spin_lock_irqsave(&ts->lock, flags);
        if (likely(ts->get_pendown_state())) {
                if (!ts->irq_disabled) {
-                       /* The ARM do_simple_IRQ() dispatcher doesn't act
-                        * like the other dispatchers:  it will report IRQs
-                        * even after they've been disabled.  We work around
-                        * that here.  (The "generic irq" framework may help...)
+                       /* REVISIT irq logic for many ARM chips has cloned a
+                        * bug wherein disabling an irq in its handler won't
+                        * work;(it's disabled lazily, and too late to work.
+                        * until all their irq logic is fixed, we must shadow
+                        * that state here.
                         */
                        ts->irq_disabled = 1;
                        disable_irq(ts->spi->irq);
                        ts->pending = 1;
-                       mod_timer(&ts->timer, jiffies);
+                       hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_DELAY),
+                                       HRTIMER_REL);
                }
        }
        spin_unlock_irqrestore(&ts->lock, flags);
@@ -629,9 +692,11 @@ static int __devinit ads7846_probe(struct spi_device *spi)
 {
        struct ads7846                  *ts;
        struct input_dev                *input_dev;
+       struct class_device             *hwmon = ERR_PTR(-ENOMEM);
        struct ads7846_platform_data    *pdata = spi->dev.platform_data;
        struct spi_message              *m;
        struct spi_transfer             *x;
+       int                             vref;
        int                             err;
 
        if (!spi->irq) {
@@ -651,36 +716,38 @@ static int __devinit ads7846_probe(struct spi_device *spi)
                return -EINVAL;
        }
 
-       /* REVISIT when the irq can be triggered active-low, or if for some
-        * reason the touchscreen isn't hooked up, we don't need to access
-        * the pendown state.
-        */
        if (pdata->get_pendown_state == NULL) {
                dev_dbg(&spi->dev, "no get_pendown_state function?\n");
                return -EINVAL;
        }
 
-       /* We'd set TX wordsize 8 bits and RX wordsize to 13 bits ... except
-        * that even if the hardware can do that, the SPI controller driver
-        * may not.  So we stick to very-portable 8 bit words, both RX and TX.
+       /* We'd set the wordsize to 12 bits ... except that some controllers
+        * will then treat the 8 bit command words as 12 bits (and drop the
+        * four MSBs of the 12 bit result).  Result: inputs must be shifted
+        * to discard the four garbage LSBs.  (Also, not all controllers can
+        * support 12 bit words.)
         */
-       spi->bits_per_word = 8;
 
        ts = kzalloc(sizeof(struct ads7846), GFP_KERNEL);
        input_dev = input_allocate_device();
-       if (!ts || !input_dev) {
+       hwmon = hwmon_device_register(&spi->dev);
+       if (!ts || !input_dev || IS_ERR(hwmon)) {
                err = -ENOMEM;
                goto err_free_mem;
        }
 
        dev_set_drvdata(&spi->dev, ts);
        spi->dev.power.power_state = PMSG_ON;
+       spi->mode = SPI_MODE_1;
+       err = spi_setup(spi);
+       if (err < 0)
+               goto err_free_mem;
 
        ts->spi = spi;
        ts->input = input_dev;
+       ts->hwmon = hwmon;
 
-       init_timer(&ts->timer);
-       ts->timer.data = (unsigned long) ts;
+       hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_REL);
        ts->timer.function = ads7846_timer;
 
        spin_lock_init(&ts->lock);
@@ -689,14 +756,25 @@ static int __devinit ads7846_probe(struct spi_device *spi)
        ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100;
        ts->x_plate_ohms = pdata->x_plate_ohms ? : 400;
        ts->pressure_max = pdata->pressure_max ? : ~0;
-       if (pdata->debounce_max) {
+
+       if (pdata->filter != NULL) {
+               if (pdata->filter_init != NULL) {
+                       err = pdata->filter_init(pdata, &ts->filter_data);
+                       if (err < 0)
+                               goto err_free_mem;
+               }
+               ts->filter = pdata->filter;
+               ts->filter_cleanup = pdata->filter_cleanup;
+       } else if (pdata->debounce_max) {
                ts->debounce_max = pdata->debounce_max;
+               if (ts->debounce_max < 2)
+                       ts->debounce_max = 2;
                ts->debounce_tol = pdata->debounce_tol;
                ts->debounce_rep = pdata->debounce_rep;
-               if (ts->debounce_rep > ts->debounce_max + 1)
-                       ts->debounce_rep = ts->debounce_max - 1;
+               ts->filter = ads7846_debounce;
+               ts->filter_data = ts;
        } else
-               ts->debounce_tol = ~0;
+               ts->filter = ads7846_no_filter;
        ts->get_pendown_state = pdata->get_pendown_state;
 
        snprintf(ts->phys, sizeof(ts->phys), "%s/input0", spi->dev.bus_id);
@@ -718,6 +796,8 @@ static int __devinit ads7846_probe(struct spi_device *spi)
        input_set_abs_params(input_dev, ABS_PRESSURE,
                        pdata->pressure_min, pdata->pressure_max, 0, 0);
 
+       vref = pdata->keep_vref_on;
+
        /* set up the transfers to read touchscreen state; this assumes we
         * use formula #2 for pressure, not #3.
         */
@@ -727,7 +807,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
        spi_message_init(m);
 
        /* y- still on; turn on only y+ (and ADC) */
-       ts->read_y = READ_Y;
+       ts->read_y = READ_Y(vref);
        x->tx_buf = &ts->read_y;
        x->len = 1;
        spi_message_add_tail(x, m);
@@ -737,7 +817,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
        x->len = 2;
        spi_message_add_tail(x, m);
 
-       m->complete = ads7846_debounce;
+       m->complete = ads7846_rx_val;
        m->context = ts;
 
        m++;
@@ -745,7 +825,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
 
        /* turn y- off, x+ on, then leave in lowpower */
        x++;
-       ts->read_x = READ_X;
+       ts->read_x = READ_X(vref);
        x->tx_buf = &ts->read_x;
        x->len = 1;
        spi_message_add_tail(x, m);
@@ -755,7 +835,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
        x->len = 2;
        spi_message_add_tail(x, m);
 
-       m->complete = ads7846_debounce;
+       m->complete = ads7846_rx_val;
        m->context = ts;
 
        /* turn y+ off, x- on; we'll use formula #2 */
@@ -764,7 +844,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
                spi_message_init(m);
 
                x++;
-               ts->read_z1 = READ_Z1;
+               ts->read_z1 = READ_Z1(vref);
                x->tx_buf = &ts->read_z1;
                x->len = 1;
                spi_message_add_tail(x, m);
@@ -774,14 +854,14 @@ static int __devinit ads7846_probe(struct spi_device *spi)
                x->len = 2;
                spi_message_add_tail(x, m);
 
-               m->complete = ads7846_debounce;
+               m->complete = ads7846_rx_val;
                m->context = ts;
 
                m++;
                spi_message_init(m);
 
                x++;
-               ts->read_z2 = READ_Z2;
+               ts->read_z2 = READ_Z2(vref);
                x->tx_buf = &ts->read_z2;
                x->len = 1;
                spi_message_add_tail(x, m);
@@ -791,7 +871,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
                x->len = 2;
                spi_message_add_tail(x, m);
 
-               m->complete = ads7846_debounce;
+               m->complete = ads7846_rx_val;
                m->context = ts;
        }
 
@@ -816,47 +896,81 @@ static int __devinit ads7846_probe(struct spi_device *spi)
 
        ts->last_msg = m;
 
-       if (request_irq(spi->irq, ads7846_irq, IRQF_TRIGGER_FALLING,
-                       spi->dev.driver->name, ts)) {
+       if (request_irq(spi->irq, ads7846_irq,
+                       IRQF_SAMPLE_RANDOM | IRQF_TRIGGER_FALLING,
+                       spi->dev.bus_id, ts)) {
                dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
                err = -EBUSY;
-               goto err_free_mem;
+               goto err_cleanup_filter;
        }
 
-       dev_info(&spi->dev, "touchscreen, irq %d\n", spi->irq);
+       dev_info(&spi->dev, "touchscreen + hwmon, irq %d\n", spi->irq);
 
-       /* take a first sample, leaving nPENIRQ active; avoid
+       /* take a first sample, leaving nPENIRQ active and vREF off; avoid
         * the touchscreen, in case it's not connected.
         */
        (void) ads7846_read12_ser(&spi->dev,
                          READ_12BIT_SER(vaux) | ADS_PD10_ALL_ON);
 
-       switch (ts->model) {
-       case 7846:
-               ts->attr_group = &ads7846_attr_group;
-               break;
-       case 7845:
-               ts->attr_group = &ads7845_attr_group;
-               break;
-       default:
-               ts->attr_group = &ads7843_attr_group;
-               break;
+       /* ads7843/7845 don't have temperature sensors, and
+        * use the other ADC lines a bit differently too
+        */
+       if (ts->model == 7846) {
+               err = device_create_file(&spi->dev, &dev_attr_temp0);
+               if (err)
+                       goto err_remove_attr7;
+               err = device_create_file(&spi->dev, &dev_attr_temp1);
+               if (err)
+                       goto err_remove_attr6;
+       }
+       /* in1 == vBAT (7846), or a non-scaled ADC input */
+       if (ts->model != 7845) {
+               err = device_create_file(&spi->dev, &dev_attr_in1_input);
+               if (err)
+                       goto err_remove_attr5;
        }
-       err = sysfs_create_group(&spi->dev.kobj, ts->attr_group);
+       /* in0 == a non-scaled ADC input */
+       err = device_create_file(&spi->dev, &dev_attr_in0_input);
+       if (err)
+               goto err_remove_attr4;
+
+       /* non-hwmon device attributes */
+       err = device_create_file(&spi->dev, &dev_attr_pen_down);
+       if (err)
+               goto err_remove_attr3;
+       err = device_create_file(&spi->dev, &dev_attr_disable);
        if (err)
-               goto err_free_irq;
+               goto err_remove_attr2;
 
        err = input_register_device(input_dev);
        if (err)
-               goto err_remove_attr_group;
+               goto err_remove_attr1;
 
        return 0;
 
- err_remove_attr_group:
-       sysfs_remove_group(&spi->dev.kobj, ts->attr_group);
- err_free_irq:
+ err_remove_attr1:
+       device_remove_file(&spi->dev, &dev_attr_disable);
+ err_remove_attr2:
+       device_remove_file(&spi->dev, &dev_attr_pen_down);
+ err_remove_attr3:
+       device_remove_file(&spi->dev, &dev_attr_in0_input);
+ err_remove_attr4:
+       if (ts->model != 7845)
+               device_remove_file(&spi->dev, &dev_attr_in1_input);
+ err_remove_attr5:
+       if (ts->model == 7846) {
+               device_remove_file(&spi->dev, &dev_attr_temp1);
+ err_remove_attr6:
+               device_remove_file(&spi->dev, &dev_attr_temp0);
+       }
+ err_remove_attr7:
        free_irq(spi->irq, ts);
+ err_cleanup_filter:
+       if (ts->filter_cleanup)
+               ts->filter_cleanup(ts->filter_data);
  err_free_mem:
+       if (!IS_ERR(hwmon))
+               hwmon_device_unregister(hwmon);
        input_free_device(input_dev);
        kfree(ts);
        return err;
@@ -866,16 +980,28 @@ static int __devexit ads7846_remove(struct spi_device *spi)
 {
        struct ads7846          *ts = dev_get_drvdata(&spi->dev);
 
+       hwmon_device_unregister(ts->hwmon);
        input_unregister_device(ts->input);
 
        ads7846_suspend(spi, PMSG_SUSPEND);
 
-       sysfs_remove_group(&spi->dev.kobj, ts->attr_group);
+       device_remove_file(&spi->dev, &dev_attr_disable);
+       device_remove_file(&spi->dev, &dev_attr_pen_down);
+       if (ts->model == 7846) {
+               device_remove_file(&spi->dev, &dev_attr_temp1);
+               device_remove_file(&spi->dev, &dev_attr_temp0);
+       }
+       if (ts->model != 7845)
+               device_remove_file(&spi->dev, &dev_attr_in1_input);
+       device_remove_file(&spi->dev, &dev_attr_in0_input);
 
        free_irq(ts->spi->irq, ts);
        /* suspend left the IRQ disabled */
        enable_irq(ts->spi->irq);
 
+       if (ts->filter_cleanup != NULL)
+               ts->filter_cleanup(ts->filter_data);
+
        kfree(ts);
 
        dev_dbg(&spi->dev, "unregistered touchscreen\n");
@@ -923,7 +1049,7 @@ static int __init ads7846_init(void)
 
        return spi_register_driver(&ads7846_driver);
 }
-module_init(ads7846_init);
+device_initcall(ads7846_init);
 
 static void __exit ads7846_exit(void)
 {
diff --git a/drivers/input/touchscreen/omap/Makefile b/drivers/input/touchscreen/omap/Makefile
new file mode 100644 (file)
index 0000000..af6344e
--- /dev/null
@@ -0,0 +1,10 @@
+#
+# Makefile for the OMAP touchscreen input driver
+#
+
+obj-$(CONFIG_TOUCHSCREEN_OMAP) += omapts.o
+
+objs-$(CONFIG_ARCH_OMAP16XX)$(CONFIG_MACH_OMAP_H2) += ts_hx.o
+objs-$(CONFIG_ARCH_OMAP16XX)$(CONFIG_MACH_OMAP_H3) += ts_hx.o
+
+omapts-objs := omap_ts.o $(objs-yy)
diff --git a/drivers/input/touchscreen/omap/omap_ts.c b/drivers/input/touchscreen/omap/omap_ts.c
new file mode 100644 (file)
index 0000000..14dfc6a
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+ * input/touchscreen/omap/omap_ts.c
+ *
+ * touchscreen input device driver for various TI OMAP boards
+ * Copyright (c) 2002 MontaVista Software Inc.
+ * Copyright (c) 2004 Texas Instruments, Inc.
+ * Cleanup and modularization 2004 by Dirk Behme <dirk.behme@de.bosch.com>
+ *
+ * Assembled using driver code copyright the companies above.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * History:
+ * 12/12/2004    Srinath Modified and intergrated code for H2 and H3
+ *
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/interrupt.h>
+#include <linux/suspend.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-types.h>
+
+//#define DEBUG
+
+#include "omap_ts.h"
+
+#define OMAP_TS_NAME   "omap_ts"
+
+static struct ts_device *__initdata ts_devs[] = {
+#if defined(CONFIG_MACH_OMAP_H2) || defined(CONFIG_MACH_OMAP_H3)
+       &hx_ts,
+#endif
+};
+
+static struct omap_ts_t ts_omap;
+
+static int omap_ts_read(void)
+{
+       u16 data[4] = { 0, 0, 0, 0 };
+
+       ts_omap.dev->read(data);
+
+       input_report_abs(ts_omap.inputdevice, ABS_X, data[0]);
+       input_report_abs(ts_omap.inputdevice, ABS_Y, data[1]);
+       input_report_abs(ts_omap.inputdevice, ABS_PRESSURE, data[2]);
+       input_sync(ts_omap.inputdevice);
+
+       DEBUG_TS("omap_ts_read: read x=%d,y=%d,p=%d\n", data[0], data[1],
+                data[2]);
+
+       return 0;
+}
+
+static void omap_ts_timer(unsigned long data)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&ts_omap.lock, flags);
+
+       if (!ts_omap.dev->penup()) {
+               if (!ts_omap.touched) {
+                       DEBUG_TS("omap_ts_timer: pen down\n");
+                       input_report_key(ts_omap.inputdevice, BTN_TOUCH, 1);
+               }
+               ts_omap.touched = 1;
+               omap_ts_read();
+               ts_omap.ts_timer.expires = jiffies + HZ / 100;
+               add_timer(&(ts_omap.ts_timer));
+       } else {
+               if (ts_omap.touched) {
+                       DEBUG_TS("omap_ts_timer: pen up\n");
+                       ts_omap.touched = 0;
+                       input_report_abs(ts_omap.inputdevice, ABS_X, 0);
+                       input_report_abs(ts_omap.inputdevice, ABS_Y, 0);
+                       input_report_abs(ts_omap.inputdevice, ABS_PRESSURE,
+                                        0);
+                       input_sync(ts_omap.inputdevice);
+                       input_report_key(ts_omap.inputdevice, BTN_TOUCH, 0);
+               }
+               if (!ts_omap.irq_enabled) {
+                       ts_omap.irq_enabled = 1;
+                       enable_irq(ts_omap.irq);
+               }
+       }
+
+       spin_unlock_irqrestore(&ts_omap.lock, flags);
+}
+
+static irqreturn_t omap_ts_handler(int irq, void *dev_id)
+{
+       spin_lock(&ts_omap.lock);
+
+       if (ts_omap.irq_enabled) {
+               ts_omap.irq_enabled = 0;
+               disable_irq(irq);
+       }
+       // restart acquire
+       mod_timer(&ts_omap.ts_timer, jiffies + HZ / 100);
+
+       spin_unlock(&ts_omap.lock);
+
+       return IRQ_HANDLED;
+}
+
+static int __init omap_ts_probe(struct platform_device *pdev)
+{
+       int i;
+       int status = -ENODEV;
+
+       memset(&ts_omap, 0, sizeof(ts_omap));
+
+       ts_omap.inputdevice = input_allocate_device();
+       if (!ts_omap.inputdevice) {
+               return -ENOMEM;
+       }
+
+       spin_lock_init(&ts_omap.lock);
+
+       for (i = 0; i < ARRAY_SIZE(ts_devs); i++) {
+               if (!ts_devs[i] || !ts_devs[i]->probe)
+                       continue;
+               status = ts_devs[i]->probe(&ts_omap);
+               if (status == 0) {
+                       ts_omap.dev = ts_devs[i];
+                       break;
+               }
+       }
+
+       if (status != 0) {
+               input_free_device(ts_omap.inputdevice);
+               return status;
+       }
+
+       // Init acquisition timer function
+       init_timer(&ts_omap.ts_timer);
+       ts_omap.ts_timer.function = omap_ts_timer;
+
+       /* request irq */
+       if (ts_omap.irq != -1) {
+               if (request_irq(ts_omap.irq, omap_ts_handler,
+                               IRQF_SAMPLE_RANDOM | ts_omap.irq_type,
+                               OMAP_TS_NAME, &ts_omap)) {
+                       printk(KERN_ERR
+         "omap_ts.c: Could not allocate touchscreen IRQ!\n");
+                       ts_omap.irq = -1;
+                       ts_omap.dev->remove();
+                       input_free_device(ts_omap.inputdevice);
+                       return -EINVAL;
+               }
+               ts_omap.irq_enabled = 1;
+       } else {
+               printk(KERN_ERR "omap_ts.c: No touchscreen IRQ assigned!\n");
+               ts_omap.dev->remove();
+               input_free_device(ts_omap.inputdevice);
+               return -EINVAL;
+       }
+
+       ts_omap.inputdevice->name = OMAP_TS_NAME;
+       ts_omap.inputdevice->dev = &pdev->dev;
+       ts_omap.inputdevice->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+       ts_omap.inputdevice->keybit[LONG(BTN_TOUCH)] |= BIT(BTN_TOUCH);
+       ts_omap.inputdevice->absbit[0] =
+           BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);
+       input_register_device(ts_omap.inputdevice);
+
+       ts_omap.dev->enable();
+
+       printk("OMAP touchscreen driver initialized\n");
+
+       return 0;
+}
+
+static int omap_ts_remove(struct platform_device *pdev)
+{
+       ts_omap.dev->disable();
+       input_unregister_device(ts_omap.inputdevice);
+       if (ts_omap.irq != -1)
+               free_irq(ts_omap.irq, &ts_omap);
+
+       ts_omap.dev->remove();
+
+       return 0;
+}
+
+static int omap_ts_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       ts_omap.dev->disable();
+       return 0;
+}
+
+static int omap_ts_resume(struct platform_device *pdev)
+{
+       ts_omap.dev->enable();
+       return 0;
+}
+
+static void omap_ts_device_release(struct device *dev)
+{
+       /* Nothing */
+}
+static struct platform_driver omap_ts_driver = {
+       .probe          = omap_ts_probe,
+       .remove         = omap_ts_remove,
+       .suspend        = omap_ts_suspend,
+       .resume         = omap_ts_resume,
+       .driver = {
+               .name   = OMAP_TS_NAME,
+       },
+};
+
+static struct platform_device omap_ts_device = {
+       .name           = OMAP_TS_NAME,
+       .id             = -1,
+       .dev = {
+               .release        = omap_ts_device_release,
+       },
+};
+
+static int __init omap_ts_init(void)
+{
+       int ret;
+
+       if (machine_is_omap_osk() || machine_is_omap_innovator())
+               return -ENODEV;
+
+       ret = platform_device_register(&omap_ts_device);
+       if (ret != 0)
+               return -ENODEV;
+
+       ret = platform_driver_register(&omap_ts_driver);
+       if (ret != 0) {
+               platform_device_unregister(&omap_ts_device);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static void __exit omap_ts_exit(void)
+{
+       platform_driver_unregister(&omap_ts_driver);
+       platform_device_unregister(&omap_ts_device);
+}
+
+module_init(omap_ts_init);
+module_exit(omap_ts_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/omap/omap_ts.h b/drivers/input/touchscreen/omap/omap_ts.h
new file mode 100644 (file)
index 0000000..bef8e17
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * omap_ts.h - header file for OMAP touchscreen support
+ * 
+ * Copyright (c) 2002 MontaVista Software Inc.
+ * Copyright (c) 2004 Texas Instruments, Inc.
+ *
+ * Assembled using driver code copyright the companies above.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __OMAP_TS_H
+#define __OMAP_TS_H
+
+#ifdef DEBUG
+#define DEBUG_TS(fmt...)   printk(fmt)
+#else
+#define DEBUG_TS(fmt...)   do { } while (0)
+#endif
+
+struct omap_ts_t;
+
+struct ts_device {
+        int  (*probe)   (struct omap_ts_t *);
+        void (*read)    (u16 *);
+        void (*enable)  (void);
+        void (*disable) (void);
+        void (*remove)  (void);
+        int  (*penup)  (void);
+};
+
+struct omap_ts_t{
+       struct input_dev * inputdevice;
+       struct timer_list ts_timer;      // Timer for triggering acquisitions
+       int touched;
+       int irq;
+       int irq_type;
+       int irq_enabled;
+       struct ts_device *dev;
+       spinlock_t lock;
+};
+
+extern struct ts_device hx_ts;
+
+#endif /* __OMAP_TS_H */
diff --git a/drivers/input/touchscreen/omap/ts_hx.c b/drivers/input/touchscreen/omap/ts_hx.c
new file mode 100644 (file)
index 0000000..9f82f5a
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * input/touchscreen/omap/ts_hx.c
+ * touchscreen support for OMAP H3 and H2  boards
+ *
+ * Copyright (c) 2002 MontaVista Software Inc.
+ * Copyright (c) 2004 Texas Instruments, Inc.
+ *
+ * Assembled using driver code copyright the companies above.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * History:
+ * 9/12/2004   Srinath Modified and integrated  H2 and H3 code
+ *
+ */
+
+#include <linux/input.h>
+#include <linux/device.h>
+#include <asm/mach-types.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/hardware.h>
+#include <asm/hardware/tsc2101.h>
+
+#include "../drivers/ssi/omap-tsc2101.h"
+#include "omap_ts.h"
+
+#define        H2_GPIO_NUM             4
+#define        H3_GPIO_NUM             48
+
+#define OMAP_TSC2101_XRES                     500
+#define TOUCHSCREEN_DATA_REGISTERS_PAGE         0x0
+#define TOUCHSCREEN_CONTROL_REGISTERS_PAGE      0x1
+#define OMAP_TSC2101_READ_MAX             0x4
+#define TSC2101_GETSTATUS(ret)           (((ret) >> 11) & 0x1)
+#define TSC2101_MASKVAL                         0xFFF
+#define TSC2101_PRESSUREVAL(x)           ((x) << 12)
+
+static int hx_ts_penup(void);
+static int hx_ts_probe(struct omap_ts_t *ts);
+static void hx_ts_read(u16 * data);
+static void hx_ts_enable(void);
+static void hx_ts_disable(void);
+#ifdef MODULE
+static void hx_ts_remove(void);
+#endif
+
+struct ts_device hx_ts = {
+       .probe          = hx_ts_probe,
+       .read           = hx_ts_read,
+       .enable         = hx_ts_enable,
+       .disable        = hx_ts_disable,
+       .remove         = __exit_p(hx_ts_remove),
+       .penup          = hx_ts_penup,
+};
+
+static int hx_ts_penup(void)
+{
+       int ret = 0;
+       /* Read the status register */
+       ret = omap_tsc2101_read(TOUCHSCREEN_CONTROL_REGISTERS_PAGE,
+                               TSC2101_TS_STATUS);
+       /* Check for availability of data in status register */
+       ret = TSC2101_GETSTATUS(ret);
+       return !ret;
+
+}
+
+static int __init hx_ts_probe(struct omap_ts_t *ts)
+{
+       unsigned        gpio;
+
+       if (machine_is_omap_h2()) {
+               gpio = H2_GPIO_NUM;
+               omap_cfg_reg(P20_1610_GPIO4);
+       } else if (machine_is_omap_h3()) {
+               gpio = H3_GPIO_NUM;
+               omap_cfg_reg(W19_1610_GPIO48);
+       } else
+               return -ENODEV;
+
+       ts->irq = OMAP_GPIO_IRQ(gpio);
+       if (omap_request_gpio(gpio) != 0) {
+               printk(KERN_ERR "hX_ts_init.c: Could not reserve GPIO!\n");
+               return -EINVAL;
+       };
+
+       omap_set_gpio_direction(gpio, 1);
+       ts->irq_type = IRQF_TRIGGER_FALLING;
+       return 0;
+}
+
+static void hx_ts_read(u16 * values)
+{
+       s32 t, p = 0;
+       int i;
+
+       /* Read X, Y, Z1 and Z2 */
+       omap_tsc2101_reads(TOUCHSCREEN_DATA_REGISTERS_PAGE, TSC2101_TS_X,
+                          values, OMAP_TSC2101_READ_MAX);
+
+       for (i = 0; i < OMAP_TSC2101_READ_MAX; i++)
+               values[i] &= TSC2101_MASKVAL;
+
+       /* Calculate Pressure */
+       if (values[TSC2101_TS_Z1] != 0) {
+               t = ((OMAP_TSC2101_XRES * values[TSC2101_TS_X]) *
+                    (values[TSC2101_TS_Z2] - values[TSC2101_TS_Z1]));
+               p = t / (u32) (TSC2101_PRESSUREVAL(values[TSC2101_TS_Z1]));
+               if (p < 0)
+                       p = 0;
+       }
+
+       values[TSC2101_TS_Z1] = p;
+}
+
+static void hx_ts_enable(void)
+{
+       int ret = omap_tsc2101_enable();
+       if (ret) {
+               printk(KERN_ERR "FAILED TO INITIALIZE TSC CODEC\n");
+               return;
+       }
+
+       /* PINTDAV is data available only */
+       omap_tsc2101_write(TOUCHSCREEN_CONTROL_REGISTERS_PAGE,
+                          TSC2101_TS_STATUS, TSC2101_DATA_AVAILABLE);
+       /* disable buffer mode */
+       omap_tsc2101_write(TOUCHSCREEN_CONTROL_REGISTERS_PAGE,
+                          TSC2101_TS_BUFFER_CTRL, TSC2101_BUFFERMODE_DISABLE);
+       /* use internal reference, 100 usec power-up delay,
+        *        * power down between conversions, 1.25V internal reference */
+       omap_tsc2101_write(TOUCHSCREEN_CONTROL_REGISTERS_PAGE,
+                          TSC2101_TS_REF_CTRL, TSC2101_REF_POWERUP);
+       /* enable touch detection, 84usec precharge time, 32 usec sense time */
+       omap_tsc2101_write(TOUCHSCREEN_CONTROL_REGISTERS_PAGE,
+                          TSC2101_TS_CONFIG_CTRL, TSC2101_ENABLE_TOUCHDETECT);
+       /* 3 msec conversion delays  */
+       omap_tsc2101_write(TOUCHSCREEN_CONTROL_REGISTERS_PAGE,
+                          TSC2101_TS_PROG_DELAY, TSC2101_PRG_DELAY);
+       /*
+        * TSC2101-controlled conversions
+        * 12-bit samples
+        * continuous X,Y,Z1,Z2 scan mode
+        * average (mean) 4 samples per coordinate
+        * 1 MHz internal conversion clock
+        * 500 usec panel voltage stabilization delay
+        */
+       omap_tsc2101_write(TOUCHSCREEN_CONTROL_REGISTERS_PAGE,
+                          TSC2101_TS_ADC_CTRL, TSC2101_ADC_CONTROL);
+
+       return;
+
+}
+
+static void hx_ts_disable(void)
+{
+       /* stop conversions and power down */
+       omap_tsc2101_write(TOUCHSCREEN_CONTROL_REGISTERS_PAGE,
+                          TSC2101_TS_ADC_CTRL, TSC2101_ADC_POWERDOWN);
+       omap_tsc2101_disable();
+}
+
+#ifdef MODULE
+static void __exit hx_ts_remove(void)
+{
+       if (machine_is_omap_h2())
+               omap_free_gpio(H2_GPIO_NUM);
+       else if (machine_is_omap_h3())
+               omap_free_gpio(H3_GPIO_NUM);
+}
+#endif
diff --git a/drivers/input/touchscreen/tsc2102_ts.c b/drivers/input/touchscreen/tsc2102_ts.c
new file mode 100644 (file)
index 0000000..8188263
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * input/touchscreen/tsc2102_ts.c
+ *
+ * Touchscreen input device driver for the TSC 2102 chip.
+ *
+ * Copyright (c) 2006 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this package; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <linux/spi/tsc2102.h>
+
+struct input_dev *dev;
+
+static void tsc2102_touch(int touching)
+{
+       if (!touching) {
+               input_report_abs(dev, ABS_X, 0);
+               input_report_abs(dev, ABS_Y, 0);
+               input_report_abs(dev, ABS_PRESSURE, 0);
+               input_sync(dev);
+       }
+
+       input_report_key(dev, BTN_TOUCH, touching);
+}
+
+static void tsc2102_coords(int x, int y, int z1, int z2)
+{
+       int p;
+
+       /* Calculate the touch resistance a la equation #1 */
+       if (z1 != 0)
+               p = x * (z2 - z1) / (z1 << 4);
+       else
+               p = 1;
+
+       input_report_abs(dev, ABS_X, x);
+       input_report_abs(dev, ABS_Y, y);
+       input_report_abs(dev, ABS_PRESSURE, p);
+       input_sync(dev);
+}
+
+static int tsc2102_ts_probe(struct platform_device *pdev)
+{
+       int status;
+
+       dev = input_allocate_device();
+       if (!dev)
+               return -ENOMEM;
+
+       status = tsc2102_touch_cb(tsc2102_touch);
+       if (status) {
+               input_free_device(dev);
+               return status;
+       }
+
+       status = tsc2102_coords_cb(tsc2102_coords);
+       if (status) {
+               tsc2102_touch_cb(0);
+               input_free_device(dev);
+               return status;
+       }
+
+       dev->name = "TSC2102 Touchscreen";
+       dev->dev = &pdev->dev;
+       dev->cdev.dev = &pdev->dev;
+       dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+       dev->keybit[LONG(BTN_TOUCH)] |= BIT(BTN_TOUCH);
+       dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);
+       dev->phys = "tsc2102/input0";
+       dev->id.bustype = BUS_HOST;
+       dev->id.vendor = 0x0001;
+       dev->id.product = 0x2102;
+       dev->id.version = 0x0001;
+
+       status = input_register_device(dev);
+       if (status) {
+               tsc2102_coords_cb(0);
+               tsc2102_touch_cb(0);
+               input_free_device(dev);
+               return status;
+       }
+
+       printk(KERN_INFO "TSC2102 touchscreen driver initialized\n");
+       return 0;
+}
+
+static int tsc2102_ts_remove(struct platform_device *pdev)
+{
+       tsc2102_touch_cb(0);
+       tsc2102_coords_cb(0);
+       input_unregister_device(dev);
+       input_free_device(dev);
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int
+tsc2102_ts_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       return 0;
+}
+
+static int tsc2102_ts_resume(struct platform_device *pdev)
+{
+       return 0;
+}
+#else
+#define tsc2102_ts_suspend     NULL
+#define tsc2102_ts_resume      NULL
+#endif
+
+static struct platform_driver tsc2102_ts_driver = {
+       .probe          = tsc2102_ts_probe,
+       .remove         = tsc2102_ts_remove,
+       .suspend        = tsc2102_ts_suspend,
+       .resume         = tsc2102_ts_resume,
+       .driver         = {
+               .name   = "tsc2102-ts",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init tsc2102_ts_init(void)
+{
+       int ret;
+
+       ret = platform_driver_register(&tsc2102_ts_driver);
+       if (ret)
+               return -ENODEV;
+
+       return 0;
+}
+
+static void __exit tsc2102_ts_exit(void)
+{
+       platform_driver_unregister(&tsc2102_ts_driver);
+}
+
+module_init(tsc2102_ts_init);
+module_exit(tsc2102_ts_exit);
+
+MODULE_AUTHOR("Andrzej Zaborowski");
+MODULE_DESCRIPTION("Touchscreen input driver for TI TSC2102.");
+MODULE_LICENSE("GPL");
index 7399ba791116d882ecceae66fa7e9535cfea1404..7c2c352430f5500dda284735dcf656bc937baef5 100644 (file)
@@ -82,6 +82,27 @@ config LEDS_WRAP
        help
          This option enables support for the PCEngines WRAP programmable LEDs.
 
+config LEDS_OMAP_DEBUG
+       boolean "LED Support for OMAP debug board LEDs"
+       depends on LEDS_CLASS=y && ARCH_OMAP
+       help
+         Enables support for the LEDs on the debug board used with OMAP
+         reference boards like H2/H3/H4 and Perseus2.  Up to six of these
+         may be claimed by the original ARM debug LED API.
+
+config LEDS_OMAP
+       tristate "LED Support for OMAP GPIO LEDs"
+       depends on LEDS_CLASS && ARCH_OMAP
+       help
+         This option enables support for the LEDs on OMAP processors.
+
+config LEDS_OMAP_PWM
+       tristate "LED Support for OMAP PWM-controlled LEDs"
+       depends on LEDS_CLASS && ARCH_OMAP && OMAP_DM_TIMER
+       help
+         This options enables support for LEDs connected to GPIO lines
+         controlled by a PWM timer on OMAP CPUs.
+
 comment "LED Triggers"
 
 config LEDS_TRIGGERS
index 500de3dc962adedcb2576e543754f6d54d439988..d39541a88d03eba4681880cce7d6e1f00d5b025f 100644 (file)
@@ -14,6 +14,8 @@ obj-$(CONFIG_LEDS_S3C24XX)            += leds-s3c24xx.o
 obj-$(CONFIG_LEDS_AMS_DELTA)           += leds-ams-delta.o
 obj-$(CONFIG_LEDS_NET48XX)             += leds-net48xx.o
 obj-$(CONFIG_LEDS_WRAP)                        += leds-wrap.o
+obj-$(CONFIG_LEDS_OMAP)                        += leds-omap.o
+obj-$(CONFIG_LEDS_OMAP_PWM)            += leds-omap-pwm.o
 
 # LED Triggers
 obj-$(CONFIG_LEDS_TRIGGER_TIMER)       += ledtrig-timer.o
diff --git a/drivers/leds/leds-omap-pwm.c b/drivers/leds/leds-omap-pwm.c
new file mode 100644 (file)
index 0000000..6b195d6
--- /dev/null
@@ -0,0 +1,354 @@
+/* drivers/leds/leds-omap_pwm.c
+ *
+ * Driver to blink LEDs using OMAP PWM timers
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Author: Timo Teras
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/ctype.h>
+#include <asm/delay.h>
+#include <asm/arch/board.h>
+#include <asm/arch/dmtimer.h>
+
+struct omap_pwm_led {
+       struct led_classdev cdev;
+       struct omap_pwm_led_platform_data *pdata;
+       struct omap_dm_timer *intensity_timer;
+       struct omap_dm_timer *blink_timer;
+       int powered;
+       unsigned int on_period, off_period;
+};
+
+static inline struct omap_pwm_led *pdev_to_omap_pwm_led(struct platform_device *pdev)
+{
+       return platform_get_drvdata(pdev);
+}
+
+static inline struct omap_pwm_led *cdev_to_omap_pwm_led(struct led_classdev *led_cdev)
+{
+       return container_of(led_cdev, struct omap_pwm_led, cdev);
+}
+
+static void omap_pwm_led_set_blink(struct omap_pwm_led *led)
+{
+       if (!led->powered)
+               return;
+
+       if (led->on_period != 0 && led->off_period != 0) {
+               unsigned long load_reg, cmp_reg;
+
+               load_reg = 32768 * (led->on_period + led->off_period) / 1000;
+               cmp_reg = 32768 * led->on_period / 1000;
+
+               omap_dm_timer_stop(led->blink_timer);
+               omap_dm_timer_set_load(led->blink_timer, 1, -load_reg);
+               omap_dm_timer_set_match(led->blink_timer, 1, -cmp_reg);
+               omap_dm_timer_set_pwm(led->blink_timer, 1, 1,
+                                     OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE);
+               omap_dm_timer_write_counter(led->blink_timer, -2);
+               omap_dm_timer_start(led->blink_timer);
+       } else {
+               omap_dm_timer_set_pwm(led->blink_timer, 1, 1,
+                                     OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE);
+               omap_dm_timer_stop(led->blink_timer);
+       }
+}
+
+static void omap_pwm_led_power_on(struct omap_pwm_led *led)
+{
+       if (led->powered)
+               return;
+       led->powered = 1;
+
+       /* Select clock */
+       omap_dm_timer_enable(led->intensity_timer);
+       omap_dm_timer_set_source(led->intensity_timer, OMAP_TIMER_SRC_32_KHZ);
+
+       /* Turn voltage on */
+       if (led->pdata->set_power != NULL)
+               led->pdata->set_power(led->pdata, 1);
+
+       /* Enable PWM timers */
+       if (led->blink_timer != NULL) {
+               omap_dm_timer_enable(led->blink_timer);
+               omap_dm_timer_set_source(led->blink_timer,
+                                        OMAP_TIMER_SRC_32_KHZ);
+               omap_pwm_led_set_blink(led);
+       }
+
+       omap_dm_timer_set_load(led->intensity_timer, 1, 0xffffff00);
+}
+
+static void omap_pwm_led_power_off(struct omap_pwm_led *led)
+{
+       if (!led->powered)
+               return;
+       led->powered = 0;
+
+       /* Everything off */
+       omap_dm_timer_stop(led->intensity_timer);
+       omap_dm_timer_disable(led->intensity_timer);
+
+       if (led->blink_timer != NULL) {
+               omap_dm_timer_stop(led->blink_timer);
+               omap_dm_timer_disable(led->blink_timer);
+       }
+
+       if (led->pdata->set_power != NULL)
+               led->pdata->set_power(led->pdata, 0);
+}
+
+static void omap_pwm_led_set_pwm_cycle(struct omap_pwm_led *led, int cycle)
+{
+       int n;
+
+       if (cycle == 0)
+               n = 0xff;
+       else    n = cycle - 1;
+
+       if (cycle == LED_FULL) {
+               omap_dm_timer_set_pwm(led->intensity_timer, 1, 1,
+                                     OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE);
+               omap_dm_timer_stop(led->intensity_timer);
+       } else {
+               omap_dm_timer_set_pwm(led->intensity_timer, 0, 1,
+                                     OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE);
+               omap_dm_timer_set_match(led->intensity_timer, 1,
+                                       (0xffffff00) | cycle);
+               omap_dm_timer_start(led->intensity_timer);
+       }
+}
+
+static void omap_pwm_led_set(struct led_classdev *led_cdev,
+                            enum led_brightness value)
+{
+       struct omap_pwm_led *led = cdev_to_omap_pwm_led(led_cdev);
+
+       if (value != LED_OFF) {
+               omap_pwm_led_power_on(led);
+               omap_pwm_led_set_pwm_cycle(led, value);
+       } else {
+               omap_pwm_led_power_off(led);
+       }
+}
+
+static ssize_t omap_pwm_led_on_period_show(struct class_device *cdev, char *buf)
+{
+       struct led_classdev *led_cdev = class_get_devdata(cdev);
+       struct omap_pwm_led *led = cdev_to_omap_pwm_led(led_cdev);
+
+       return sprintf(buf, "%u\n", led->on_period) + 1;
+}
+
+static ssize_t omap_pwm_led_on_period_store(struct class_device *cdev,
+                                           const char *buf, size_t size)
+{
+       struct led_classdev *led_cdev = class_get_devdata(cdev);
+       struct omap_pwm_led *led = cdev_to_omap_pwm_led(led_cdev);
+       int ret = -EINVAL;
+       unsigned long val;
+       char *after;
+       size_t count;
+
+       val = simple_strtoul(buf, &after, 10);
+       count = after - buf;
+       if (*after && isspace(*after))
+               count++;
+
+       if (count == size) {
+               led->on_period = val;
+               omap_pwm_led_set_blink(led);
+               ret = count;
+       }
+
+       return ret;
+}
+
+static ssize_t omap_pwm_led_off_period_show(struct class_device *cdev, char *buf)
+{
+       struct led_classdev *led_cdev = class_get_devdata(cdev);
+       struct omap_pwm_led *led = cdev_to_omap_pwm_led(led_cdev);
+
+       return sprintf(buf, "%u\n", led->off_period) + 1;
+}
+
+static ssize_t omap_pwm_led_off_period_store(struct class_device *cdev,
+                                            const char *buf, size_t size)
+{
+       struct led_classdev *led_cdev = class_get_devdata(cdev);
+       struct omap_pwm_led *led = cdev_to_omap_pwm_led(led_cdev);
+       int ret = -EINVAL;
+       unsigned long val;
+       char *after;
+       size_t count;
+
+       val = simple_strtoul(buf, &after, 10);
+       count = after - buf;
+       if (*after && isspace(*after))
+               count++;
+
+       if (count == size) {
+               led->off_period = val;
+               omap_pwm_led_set_blink(led);
+               ret = count;
+       }
+
+       return ret;
+}
+
+static CLASS_DEVICE_ATTR(on_period, 0644, omap_pwm_led_on_period_show,
+                        omap_pwm_led_on_period_store);
+static CLASS_DEVICE_ATTR(off_period, 0644, omap_pwm_led_off_period_show,
+                        omap_pwm_led_off_period_store);
+
+static int omap_pwm_led_probe(struct platform_device *pdev)
+{
+       struct omap_pwm_led_platform_data *pdata = pdev->dev.platform_data;
+       struct omap_pwm_led *led;
+       int ret;
+
+       led = kzalloc(sizeof(struct omap_pwm_led), GFP_KERNEL);
+       if (led == NULL) {
+               dev_err(&pdev->dev, "No memory for device\n");
+               return -ENOMEM;
+       }
+
+       platform_set_drvdata(pdev, led);
+       led->cdev.brightness_set = omap_pwm_led_set;
+       led->cdev.default_trigger = NULL;
+       led->cdev.name = pdata->name;
+       led->pdata = pdata;
+
+       dev_info(&pdev->dev, "OMAP PWM LED (%s) at GP timer %d/%d\n",
+                pdata->name, pdata->intensity_timer, pdata->blink_timer);
+
+       /* register our new led device */
+       ret = led_classdev_register(&pdev->dev, &led->cdev);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "led_classdev_register failed\n");
+               goto error_classdev;
+       }
+
+       /* get related dm timers */
+       led->intensity_timer = omap_dm_timer_request_specific(pdata->intensity_timer);
+       if (led->intensity_timer == NULL) {
+               dev_err(&pdev->dev, "failed to request intensity pwm timer\n");
+               ret = -ENODEV;
+               goto error_intensity;
+       }
+       omap_dm_timer_disable(led->intensity_timer);
+
+       if (pdata->blink_timer != 0) {
+               led->blink_timer = omap_dm_timer_request_specific(pdata->blink_timer);
+               if (led->blink_timer == NULL) {
+                       dev_err(&pdev->dev, "failed to request blinking pwm timer\n");
+                       ret = -ENODEV;
+                       goto error_blink1;
+               }
+               omap_dm_timer_disable(led->blink_timer);
+
+               ret = class_device_create_file(led->cdev.class_dev,
+                                              &class_device_attr_on_period);
+               if(ret)
+                       goto error_blink2;
+
+               ret = class_device_create_file(led->cdev.class_dev,
+                                               &class_device_attr_off_period);
+               if(ret)
+                       goto error_blink3;
+
+       }
+
+       return 0;
+
+error_blink3:
+       class_device_remove_file(led->cdev.class_dev,
+                                &class_device_attr_on_period);
+error_blink2:
+       dev_err(&pdev->dev, "failed to create device file(s)\n");
+error_blink1:
+       omap_dm_timer_free(led->intensity_timer);
+error_intensity:
+       led_classdev_unregister(&led->cdev);
+error_classdev:
+       kfree(led);
+       return ret;
+}
+
+static int omap_pwm_led_remove(struct platform_device *pdev)
+{
+       struct omap_pwm_led *led = pdev_to_omap_pwm_led(pdev);
+
+       class_device_remove_file(led->cdev.class_dev,
+                                &class_device_attr_on_period);
+       class_device_remove_file(led->cdev.class_dev,
+                                &class_device_attr_off_period);
+       led_classdev_unregister(&led->cdev);
+
+       omap_pwm_led_set(&led->cdev, LED_OFF);
+       if (led->blink_timer != NULL)
+               omap_dm_timer_free(led->blink_timer);
+       omap_dm_timer_free(led->intensity_timer);
+       kfree(led);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int omap_pwm_led_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct omap_pwm_led *led = pdev_to_omap_pwm_led(pdev);
+
+       led_classdev_suspend(&led->cdev);
+       return 0;
+}
+
+static int omap_pwm_led_resume(struct platform_device *pdev)
+{
+       struct omap_pwm_led *led = pdev_to_omap_pwm_led(pdev);
+
+       led_classdev_resume(&led->cdev);
+       return 0;
+}
+#else
+#define omap_pwm_led_suspend NULL
+#define omap_pwm_led_resume NULL
+#endif
+
+static struct platform_driver omap_pwm_led_driver = {
+       .probe          = omap_pwm_led_probe,
+       .remove         = omap_pwm_led_remove,
+       .suspend        = omap_pwm_led_suspend,
+       .resume         = omap_pwm_led_resume,
+       .driver         = {
+               .name           = "omap_pwm_led",
+               .owner          = THIS_MODULE,
+       },
+};
+
+static int __init omap_pwm_led_init(void)
+{
+       return platform_driver_register(&omap_pwm_led_driver);
+}
+
+static void __exit omap_pwm_led_exit(void)
+{
+       platform_driver_unregister(&omap_pwm_led_driver);
+}
+
+module_init(omap_pwm_led_init);
+module_exit(omap_pwm_led_exit);
+
+MODULE_AUTHOR("Timo Teras");
+MODULE_DESCRIPTION("OMAP PWM LED driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/leds/leds-omap.c b/drivers/leds/leds-omap.c
new file mode 100644 (file)
index 0000000..040b7e4
--- /dev/null
@@ -0,0 +1,135 @@
+/* drivers/leds/leds-omap.c
+ *
+ * (C) 2006 Samsung Electronics
+ * Kyungmin Park <kyungmin.park@samsung.com>
+ *
+ * OMAP - LEDs GPIO driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/led.h>
+
+/* our context */
+
+static void omap_set_led_gpio(struct led_classdev *led_cdev,
+                           enum led_brightness value)
+{
+       struct omap_led_config *led_dev;
+
+       led_dev = container_of(led_cdev, struct omap_led_config, cdev);
+
+       if (value)
+               omap_set_gpio_dataout(led_dev->gpio, 1);
+       else
+               omap_set_gpio_dataout(led_dev->gpio, 0);
+}
+
+static void omap_configure_led_gpio(int gpio)
+{
+       if (omap_request_gpio(gpio) < 0) {
+               printk(KERN_ERR "Failed to request GPIO%d for LEDs\n", gpio);
+               return;
+       }
+       omap_set_gpio_direction(gpio, 0);       /* OUT */
+}
+
+static int omap_led_probe(struct platform_device *dev)
+{
+       struct omap_led_platform_data *pdata = dev->dev.platform_data;
+       struct omap_led_config *leds = pdata->leds;
+       int i, ret = 0;
+
+       for (i = 0; ret >= 0 && i < pdata->nr_leds; i++) {
+               omap_configure_led_gpio(leds[i].gpio);
+               if (!leds[i].cdev.brightness_set)
+                       leds[i].cdev.brightness_set = omap_set_led_gpio;
+
+               ret = led_classdev_register(&dev->dev, &leds[i].cdev);
+       }
+
+       if (ret < 0 && i > 1) {
+               for (i = i - 2; i >= 0; i--)
+                       led_classdev_unregister(&leds[i].cdev);
+       }
+
+       return ret;
+}
+
+static int omap_led_remove(struct platform_device *dev)
+{
+       struct omap_led_platform_data *pdata = dev->dev.platform_data;
+       struct omap_led_config *leds = pdata->leds;
+       int i;
+
+       for (i = 0; i < pdata->nr_leds; i++)
+               led_classdev_unregister(&leds[i].cdev);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int omap_led_suspend(struct platform_device *dev, pm_message_t state)
+{
+       struct omap_led_platform_data *pdata = dev->dev.platform_data;
+       struct omap_led_config *leds = pdata->leds;
+       int i;
+
+       for (i = 0; i < pdata->nr_leds; i++)
+               led_classdev_suspend(&leds[i].cdev);
+
+       return 0;
+}
+
+static int omap_led_resume(struct platform_device *dev)
+{
+       struct omap_led_platform_data *pdata = dev->dev.platform_data;
+       struct omap_led_config *leds = pdata->leds;
+       int i;
+
+       for (i = 0; i < pdata->nr_leds; i++)
+               led_classdev_resume(&leds[i].cdev);
+
+       return 0;
+}
+#else
+#define omap_led_suspend       NULL
+#define omap_led_resume                NULL
+#endif
+
+static struct platform_driver omap_led_driver = {
+       .probe          = omap_led_probe,
+       .remove         = omap_led_remove,
+       .suspend        = omap_led_suspend,
+       .resume         = omap_led_resume,
+       .driver         = {
+               .name           = "omap-led",
+               .owner          = THIS_MODULE,
+       },
+};
+
+static int __init omap_led_init(void)
+{
+       return platform_driver_register(&omap_led_driver);
+}
+
+static void __exit omap_led_exit(void)
+{
+       platform_driver_unregister(&omap_led_driver);
+}
+
+module_init(omap_led_init);
+module_exit(omap_led_exit);
+
+MODULE_AUTHOR("Kyungmin Park<kyungmin.park@samsung.com>");
+MODULE_DESCRIPTION("OMAP LED driver");
+MODULE_LICENSE("GPL");
index 57357db31b8a7b58a841252fe7912b57e199a9b8..fea92e0bf266e21145a5acb3a9e451f7b6895a65 100644 (file)
@@ -763,4 +763,6 @@ source "drivers/media/video/pwc/Kconfig"
 
 endmenu # V4L USB devices
 
+source drivers/media/video/omap/Kconfig
+
 endmenu
index 9b1f3f06bb7ce267d5dc868be48b4e2dd6965cc4..9817c19dfe6595e568a261ba352bb4eecf4997b8 100644 (file)
@@ -85,6 +85,7 @@ obj-$(CONFIG_VIDEO_BTCX)  += btcx-risc.o
 obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
 
 obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o
+obj-$(CONFIG_VIDEO_OMAP_CAMERA) += omap/
 
 obj-$(CONFIG_VIDEO_CX25840) += cx25840/
 obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o
diff --git a/drivers/media/video/omap/Kconfig b/drivers/media/video/omap/Kconfig
new file mode 100644 (file)
index 0000000..809193b
--- /dev/null
@@ -0,0 +1,12 @@
+config VIDEO_OMAP_CAMERA
+       tristate "OMAP Camera support (EXPERIMENTAL)"
+       select VIDEO_BUF
+       depends on VIDEO_DEV && (ARCH_OMAP16XX || ARCH_OMAP24XX)
+       help
+         V4L2 camera driver support for OMAP1/2 based boards.
+       
+config VIDEO_CAMERA_SENSOR_OV9640
+       tristate "OV9640 sensor support"
+       depends on VIDEO_OMAP_CAMERA
+       help
+         OmniVision 9640 camera sensor support
diff --git a/drivers/media/video/omap/Makefile b/drivers/media/video/omap/Makefile
new file mode 100644 (file)
index 0000000..36ae615
--- /dev/null
@@ -0,0 +1,12 @@
+# Makefile for OMAP1/2 camera driver
+
+obj-$(CONFIG_VIDEO_OMAP_CAMERA) += omapcamera.o
+obj-$(CONFIG_VIDEO_CAMERA_SENSOR_OV9640) += sensor_ov9640.o
+
+objs-y$(CONFIG_ARCH_OMAP16XX) += omap16xxcam.o camera_core.o
+objs-y$(CONFIG_MACH_OMAP_H3) += h3_sensor_power.o
+objs-y$(CONFIG_MACH_OMAP_H4) += h4_sensor_power.o
+
+omapcamera-objs := $(objs-yy)
+
+EXTRA_CFLAGS = -I$(src)/..
diff --git a/drivers/media/video/omap/camera_core.c b/drivers/media/video/omap/camera_core.c
new file mode 100644 (file)
index 0000000..9440718
--- /dev/null
@@ -0,0 +1,1193 @@
+/*
+ * drivers/media/video/omap/camera_core.c
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc. 
+ *
+ * Video-for-Linux (Version 2) camera capture driver for
+ * the OMAP H2 and H3 camera controller.
+ *
+ * Adapted from omap24xx driver written by Andy Lowe (source@mvista.com)
+ * Copyright (C) 2003-2004 MontaVista Software, Inc.
+ * 
+ * This package is free software; you can redistribute it and/or modify 
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation. 
+ * 
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 
+ *
+ * History:
+ *   27/03/05   Vladimir Barinov - Added support for power management
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/version.h>
+#include <linux/dma-mapping.h>
+#include <linux/fb.h>
+
+#include <media/v4l2-common.h>
+
+#include <asm/io.h>
+
+#include "sensor_if.h"
+#include "camera_hw_if.h"
+#include "camera_core.h"
+
+
+static struct camera_device *camera_dev;
+static void camera_core_sgdma_process(struct camera_device *cam);
+
+/* module parameters */
+static int video_nr = -1;      /* video device minor (-1 ==> auto assign) */
+
+/* Maximum amount of memory to use for capture buffers.
+ * Default is 4800KB, enough to double-buffer SXGA.
+ */
+static int capture_mem = 1280*960*2*2;
+
+/*Size of video overlay framebuffer. This determines the maximum image size
+ *that can be previewed. Default is 600KB, enough for sxga.
+ */
+static int overlay_mem = 640*480*2;
+
+/* DMA completion routine for the scatter-gather DMA fragments. */
+/* This function is called when a scatter DMA fragment is completed */
+static void
+camera_core_callback_sgdma(void *arg1, void *arg2)
+{
+       struct camera_device *cam = (struct camera_device *)arg1;
+       int sgslot = (int)arg2;
+
+       struct sgdma_state *sgdma;
+
+       spin_lock(&cam->sg_lock);
+       sgdma = cam->sgdma + sgslot;
+       if (!sgdma->queued_sglist)
+       {
+               spin_unlock(&cam->sg_lock);
+               printk(KERN_ERR CAM_NAME ": SGDMA completed when none queued\n");
+               return;
+       }
+       if (!--sgdma->queued_sglist) {
+               /* queue for this sglist is empty so check whether transfer
+               ** of the frame has been completed */
+               if (sgdma->next_sglist == sgdma->sglen) {
+                       dma_callback_t callback = sgdma->callback;
+                       void *arg = sgdma->arg;
+                       /* all done with this sglist */
+                       cam->free_sgdma++;
+                       if (callback) {
+                               spin_unlock(&cam->sg_lock);
+                               (*callback)(cam, arg);
+                               camera_core_sgdma_process(cam);
+                               return;
+                       }
+               }
+       }
+       spin_unlock(&cam->sg_lock);
+       camera_core_sgdma_process(cam);
+
+       return;
+}
+
+static void
+camera_core_sgdma_init(struct camera_device *cam)
+{
+       int sg;
+
+       /* Initialize the underlying camera DMA */
+       cam->cam_hardware->init_dma(cam->hardware_data);
+       spin_lock_init(&cam->sg_lock);
+       
+       cam->free_sgdma = NUM_SG_DMA;
+       cam->next_sgdma = 0;
+       for (sg = 0; sg < NUM_SG_DMA; sg++) {
+               cam->sgdma[sg].sglen = 0;
+               cam->sgdma[sg].next_sglist = 0;
+               cam->sgdma[sg].queued_sglist = 0;
+               cam->sgdma[sg].csr = 0;
+               cam->sgdma[sg].callback = NULL;
+               cam->sgdma[sg].arg = NULL;
+       }
+}
+
+/*
+ * Process the scatter-gather DMA queue by starting queued transfers
+ * This function is called to program the dma to start the transfer of an image.
+ */
+static void
+camera_core_sgdma_process(struct camera_device *cam)
+{
+       unsigned long irqflags;
+       int queued_sgdma, sgslot;
+       struct sgdma_state *sgdma;
+       const struct scatterlist *sglist;
+       
+       spin_lock_irqsave(&cam->sg_lock, irqflags);
+       if (1 == cam->in_use) {
+               spin_unlock_irqrestore(&cam->sg_lock, irqflags);
+               return;
+       }
+       cam->in_use = 1;
+       spin_unlock_irqrestore(&cam->sg_lock, irqflags);
+
+       queued_sgdma = NUM_SG_DMA - cam->free_sgdma;
+       sgslot = (cam->next_sgdma + cam->free_sgdma) % (NUM_SG_DMA);
+       while (queued_sgdma > 0) {
+               sgdma = cam->sgdma + sgslot;
+               while (sgdma->next_sglist < sgdma->sglen) {
+                       sglist = sgdma->sglist + sgdma->next_sglist;
+                       if (cam->cam_hardware->start_dma(sgdma, camera_core_callback_sgdma,
+                               (void *)cam, (void *)sgslot, cam->hardware_data)) {
+                                       /* dma start failed */
+                                       cam->in_use = 0;
+                                       return;
+                       }
+                       else {
+                               /* dma start successful */
+                               sgdma->next_sglist ++;
+                               sgdma->queued_sglist ++;
+                       }
+               }
+               queued_sgdma-- ;
+               sgslot = (sgslot + 1) % (NUM_SG_DMA);
+       }
+
+       cam->in_use = 0;
+}
+
+/* Queue a scatter-gather DMA transfer from the camera to memory.
+ * Returns zero if the transfer was successfully queued, or
+ * non-zero if all of the scatter-gather slots are already in use.
+ */
+static int
+camera_core_sgdma_queue(struct camera_device *cam,
+        const struct scatterlist *sglist, int sglen, dma_callback_t callback,
+        void *arg)
+{
+       unsigned long irqflags;
+       struct sgdma_state *sgdma;
+
+       if ((sglen < 0) || ((sglen > 0) & !sglist))
+               return -EINVAL;
+
+       spin_lock_irqsave(&cam->sg_lock, irqflags);
+
+       if (!cam->free_sgdma) {
+               spin_unlock_irqrestore(&cam->sg_lock, irqflags);
+               return -EBUSY;
+       }
+
+       sgdma = cam->sgdma + cam->next_sgdma;
+
+       sgdma->sglist = sglist;
+       sgdma->sglen = sglen;
+       sgdma->next_sglist = 0;
+       sgdma->queued_sglist = 0;
+       sgdma->csr = 0;
+       sgdma->callback = callback;
+       sgdma->arg = arg;
+
+       cam->next_sgdma = (cam->next_sgdma + 1) % (NUM_SG_DMA); 
+       cam->free_sgdma--;
+
+       spin_unlock_irqrestore(&cam->sg_lock, irqflags);
+
+       camera_core_sgdma_process(cam);
+
+       return 0;
+}
+
+
+/* -------------------overlay routines ------------------------------*/
+/* callback routine for overlay DMA completion. We just start another DMA
+ * transfer unless overlay has been turned off
+ */
+
+static void
+camera_core_overlay_callback(void *arg1, void *arg)
+{
+       struct camera_device *cam = (struct camera_device *)arg1;
+       int err;
+       unsigned long irqflags;
+       int i, j;
+       int count, index;
+       unsigned char *fb_buf = phys_to_virt((unsigned long)camera_dev->fbuf.base);
+
+       spin_lock_irqsave(&cam->overlay_lock, irqflags);
+
+       if (!cam->previewing || cam->overlay_cnt == 0) {
+               spin_unlock_irqrestore(&cam->overlay_lock, irqflags);
+               return;
+       }
+
+       --cam->overlay_cnt;
+       sg_dma_address(&cam->overlay_sglist) = cam->overlay_base_phys;
+       sg_dma_len(&cam->overlay_sglist) = cam->pix.sizeimage;
+
+       count = 0;
+       j = ((cam->pix.width - 1) * cam->fbuf.fmt.bytesperline);
+       for (i = 0 ; i < cam->pix.sizeimage; i += cam->pix.bytesperline) {
+               for (index = 0; index < cam->pix.bytesperline; index++) {
+                       fb_buf[j] = *(((unsigned char *) cam->overlay_base) +
+                                                                i + index);
+                       index++;
+                       fb_buf[j + 1] = *(((unsigned char *) cam->overlay_base) + i + index);
+                       j = j - cam->fbuf.fmt.bytesperline;
+               }
+               count += 2;
+               j = ((cam->pix.width - 1) * cam->fbuf.fmt.bytesperline) + count;
+       }
+
+       while (cam->overlay_cnt < 2) {
+               err = camera_core_sgdma_queue(cam, &cam->overlay_sglist, 1,
+                       camera_core_overlay_callback, NULL);
+               if (err)
+                       break;
+               ++cam->overlay_cnt;
+       }
+
+       spin_unlock_irqrestore(&cam->overlay_lock, irqflags);
+
+}
+
+static void
+camera_core_start_overlay(struct camera_device *cam)
+{
+       int err;
+       unsigned long irqflags;
+
+       if (!cam->previewing) 
+               return;
+
+       spin_lock_irqsave(&cam->overlay_lock, irqflags);
+
+       sg_dma_address(&cam->overlay_sglist) = cam->overlay_base_phys;
+       sg_dma_len(&cam->overlay_sglist)= cam->pix.sizeimage;
+       while (cam->overlay_cnt < 2) {
+               err = camera_core_sgdma_queue(cam, &cam->overlay_sglist, 1,
+                               camera_core_overlay_callback, NULL);
+               if (err)
+                       break;
+               ++cam->overlay_cnt;
+       }
+
+       spin_unlock_irqrestore(&cam->overlay_lock, irqflags);
+}
+
+/* ------------------ videobuf_queue_ops ---------------------------------------- */
+
+/* This routine is called from interrupt context when a scatter-gather DMA
+ * transfer of a videobuf_buffer completes.
+ */
+static void
+camera_core_vbq_complete(void *arg1, void *arg)
+{
+       struct camera_device *cam = (struct camera_device *)arg1;
+       struct videobuf_buffer *vb = (struct videobuf_buffer *)arg;
+
+       spin_lock(&cam->vbq_lock);
+
+       do_gettimeofday(&vb->ts);
+       vb->field_count = cam->field_count;
+       cam->field_count += 2;
+       vb->state = STATE_DONE;
+
+       wake_up(&vb->done);
+       
+       spin_unlock(&cam->vbq_lock);
+}
+
+static void
+camera_core_vbq_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+       videobuf_waiton(vb, 0, 0);
+       videobuf_dma_unmap(q, &vb->dma);
+       videobuf_dma_free(&vb->dma);
+
+       vb->state = STATE_NEEDS_INIT;
+}
+
+/* Limit the number of available kernel image capture buffers based on the
+ * number requested, the currently selected image size, and the maximum
+ * amount of memory permitted for kernel capture buffers.
+ */
+static int
+camera_core_vbq_setup(struct videobuf_queue *q, unsigned int *cnt, unsigned int *size)
+{
+       struct camera_device *cam = q->priv_data;
+
+       if (*cnt <= 0)
+               *cnt = VIDEO_MAX_FRAME; /* supply a default number of buffers */
+
+       if (*cnt > VIDEO_MAX_FRAME)
+               *cnt = VIDEO_MAX_FRAME;
+
+       spin_lock(&cam->img_lock);
+       *size = cam->pix.sizeimage;
+       spin_unlock(&cam->img_lock);
+
+       while (*size * *cnt > capture_mem)
+               (*cnt)--;
+
+       return 0;
+}
+
+static int
+camera_core_vbq_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
+        enum v4l2_field field)
+{
+       struct camera_device *cam = q->priv_data;
+       int err = 0;
+
+       spin_lock(&cam->img_lock);
+       if (cam->pix.sizeimage > vb->bsize) {
+               spin_unlock(&cam->img_lock);
+               return -EINVAL;
+       }
+       vb->size = cam->pix.sizeimage; 
+       vb->width = cam->pix.width;
+       vb->height = cam->pix.height;
+       vb->field = field;
+       spin_unlock(&cam->img_lock);
+
+       if (vb->state == STATE_NEEDS_INIT)
+               err = videobuf_iolock(q, vb, NULL);
+
+       if (!err)
+               vb->state = STATE_PREPARED;
+       else
+               camera_core_vbq_release (q, vb);
+
+       return err;
+}
+
+static void
+camera_core_vbq_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+       struct camera_device *cam = q->priv_data;
+       enum videobuf_state state = vb->state;
+       int err;
+
+       vb->state = STATE_QUEUED;
+       err = camera_core_sgdma_queue(cam, vb->dma.sglist, vb->dma.sglen,
+                camera_core_vbq_complete, vb);
+       if (err) {
+               /* Oops.  We're not supposed to get any errors here.  The only
+               * way we could get an error is if we ran out of scatter-gather
+               * DMA slots, but we are supposed to have at least as many
+               * scatter-gather DMA slots as video buffers so that can't
+               * happen.
+               */
+               printk(KERN_DEBUG CAM_NAME
+                       ": Failed to queue a video buffer for SGDMA\n");
+               vb->state = state;
+       }
+}
+
+/* ------------------ videobuf_queue_ops ---------------------------------------- */
+
+static int
+camera_core_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, 
+                    void *arg)
+{
+       struct camera_fh *fh  = file->private_data;
+       struct camera_device *cam = fh->cam;
+       int err;
+
+       switch (cmd) {
+               case VIDIOC_ENUMINPUT:
+               {
+                       /* default handler assumes 1 video input (the camera) */
+                       struct v4l2_input *input = (struct v4l2_input *)arg;
+                       int index = input->index;
+
+                       memset(input, 0, sizeof(*input));
+                       input->index = index;
+
+                       if (index > 0)
+                               return -EINVAL;
+
+                       strlcpy(input->name, "camera", sizeof(input->name));
+                       input->type = V4L2_INPUT_TYPE_CAMERA;
+
+                       return 0;
+               }
+
+               case VIDIOC_G_INPUT:
+               {
+                       unsigned int *input = arg;
+                       *input = 0;
+
+                       return 0;
+               }
+
+               case VIDIOC_S_INPUT:
+               {
+                       unsigned int *input = arg;
+
+                       if (*input > 0)
+                               return -EINVAL;
+
+                       return 0;
+               }
+
+               case VIDIOC_ENUM_FMT:
+               {
+                       struct v4l2_fmtdesc *fmt = arg;
+                       return cam->cam_sensor->enum_pixformat(fmt, cam->sensor_data);
+               }       
+
+               case VIDIOC_TRY_FMT:
+               {
+                       struct v4l2_format *fmt = arg;
+                       return cam->cam_sensor->try_format(&fmt->fmt.pix, cam->sensor_data);
+
+               }
+
+               case VIDIOC_G_FMT:
+               {
+                       struct v4l2_format *fmt = arg;
+
+                       /* get the current format */
+                       memset(&fmt->fmt.pix, 0, sizeof (fmt->fmt.pix));
+                       fmt->fmt.pix = cam->pix;
+                       
+                       return 0;
+               }
+
+               case VIDIOC_S_FMT:
+               {
+                       struct v4l2_format *fmt = arg;
+                       unsigned int temp_sizeimage = 0;
+
+                       temp_sizeimage = cam->pix.sizeimage;
+                       cam->cam_sensor->try_format(&fmt->fmt.pix, cam->sensor_data);
+                       cam->pix = fmt->fmt.pix;
+
+                       cam->xclk = cam->cam_sensor->calc_xclk(&cam->pix,
+                               &cam->nominal_timeperframe, cam->sensor_data);
+                       cam->cparm.timeperframe = cam->nominal_timeperframe;
+                       cam->xclk = cam->cam_hardware->set_xclk(cam->xclk, cam->hardware_data);
+                       return cam->cam_sensor->configure(&cam->pix, cam->xclk, 
+                                               &cam->cparm.timeperframe, cam->sensor_data);
+               }
+
+               case VIDIOC_QUERYCTRL:
+               {
+                       struct v4l2_queryctrl *qc = arg;
+                       return cam->cam_sensor->query_control(qc, cam->sensor_data);
+               }
+
+               case VIDIOC_G_CTRL:
+               {
+                       struct v4l2_control *vc = arg;
+                       return cam->cam_sensor->get_control(vc, cam->sensor_data);
+               }
+
+               case VIDIOC_S_CTRL:
+               {
+                       struct v4l2_control *vc = arg;
+                       return cam->cam_sensor->set_control(vc, cam->sensor_data);
+               }
+               
+               case VIDIOC_QUERYCAP:
+               {
+                       struct v4l2_capability *cap = 
+                               (struct v4l2_capability *) arg;
+
+                       memset(cap, 0, sizeof(*cap));
+                       strlcpy(cap->driver, CAM_NAME, sizeof(cap->driver));
+                       strlcpy(cap->card, cam->vfd->name, sizeof(cap->card));
+                       cap->bus_info[0] = '\0';
+                       cap->version = KERNEL_VERSION(0, 0, 0);
+                       cap->capabilities =
+                               V4L2_CAP_VIDEO_CAPTURE |
+                               V4L2_CAP_VIDEO_OVERLAY |
+                               V4L2_CAP_READWRITE | 
+                               V4L2_CAP_STREAMING;
+                       return 0;
+               }
+
+               case VIDIOC_G_FBUF: /* Get the frame buffer parameters */
+               {
+                       struct v4l2_framebuffer *fbuf =
+                               (struct v4l2_framebuffer *) arg;
+
+                       spin_lock(&cam->img_lock);
+                       *fbuf = cam->fbuf;
+                       spin_unlock(&cam->img_lock);
+                       return 0;
+               }
+
+               case VIDIOC_S_FBUF: /* set the frame buffer parameters */
+               {
+                       struct v4l2_framebuffer *fbuf =
+                               (struct v4l2_framebuffer *) arg;
+
+                       spin_lock(&cam->img_lock);
+                       if (cam->previewing) {
+                               spin_unlock(&cam->img_lock);
+                               return -EBUSY;
+                       }
+                       cam->fbuf.base = fbuf->base;
+                       cam->fbuf.fmt = fbuf->fmt;      
+                       
+                       spin_unlock(&cam->img_lock);
+                       return 0;
+               }
+
+               case VIDIOC_OVERLAY:
+               {
+                       int enable = *((int *) arg);
+
+                       /* 
+                        * check whether the capture format and 
+                        ** the display format matches 
+                        * return failure if they are different
+                        */
+                       if (cam->pix.pixelformat != cam->fbuf.fmt.pixelformat)
+                       {
+                               return -EINVAL;
+                       }
+
+                       /* If the camera image size is greater 
+                       ** than LCD size return failure */
+                       if ((cam->pix.width > cam->fbuf.fmt.height) || 
+                               (cam->pix.height > cam->fbuf.fmt.width))
+                       {
+                               return -EINVAL;
+                       }
+                       
+                       if (!cam->previewing && enable)
+                       {
+                               cam->previewing = fh;
+                               cam->overlay_cnt = 0;
+                               camera_core_start_overlay(cam);
+                       }
+                       else if (!enable)
+                       {
+                               cam->previewing = NULL;
+                       }
+       
+                       return 0;
+               }
+
+               case VIDIOC_REQBUFS:
+                       return videobuf_reqbufs(&fh->vbq, arg);
+
+               case VIDIOC_QUERYBUF:
+                       return videobuf_querybuf(&fh->vbq, arg);
+
+               case VIDIOC_QBUF:
+                       return videobuf_qbuf(&fh->vbq, arg);
+
+               case VIDIOC_DQBUF:
+                       return videobuf_dqbuf(&fh->vbq, arg,
+          file->f_flags & O_NONBLOCK);
+
+               case VIDIOC_STREAMON:
+               {
+                       spin_lock(&cam->img_lock);
+
+                       if (cam->streaming || cam->reading) {
+                               spin_unlock(&cam->img_lock);
+                               return -EBUSY;
+                       }
+                       else {
+                               cam->streaming = fh;
+                               /* FIXME: start camera interface */
+                       }
+
+                       spin_unlock(&cam->img_lock);
+
+                       return videobuf_streamon(&fh->vbq);
+               }
+               case VIDIOC_STREAMOFF:
+               {
+                       err = videobuf_streamoff(&fh->vbq);
+                       if (err < 0)
+                               return err;
+
+                       spin_lock(&cam->img_lock);
+                       if (cam->streaming == fh) {
+                               cam->streaming = NULL;
+                               /* FIXME: stop camera interface */
+                       }
+                       spin_unlock(&cam->img_lock);
+                       return 0;
+               }
+               case VIDIOC_ENUMSTD:
+               case VIDIOC_G_STD:
+               case VIDIOC_S_STD:
+               case VIDIOC_QUERYSTD:
+               {
+                       /* Digital cameras don't have an analog video standard, 
+                        * so we don't need to implement these ioctls.
+                        */
+                        return -EINVAL;
+               }
+               case VIDIOC_G_AUDIO:
+               case VIDIOC_S_AUDIO:
+               case VIDIOC_G_AUDOUT:
+               case VIDIOC_S_AUDOUT:
+               {
+                       /* we don't have any audio inputs or outputs */
+                       return -EINVAL;
+               }
+
+               case VIDIOC_G_JPEGCOMP:
+               case VIDIOC_S_JPEGCOMP:
+               {
+                       /* JPEG compression is not supported */
+                       return -EINVAL;
+               }
+
+               case VIDIOC_G_TUNER:
+               case VIDIOC_S_TUNER:
+               case VIDIOC_G_MODULATOR:
+               case VIDIOC_S_MODULATOR:
+               case VIDIOC_G_FREQUENCY:
+               case VIDIOC_S_FREQUENCY:
+               {
+                       /* we don't have a tuner or modulator */
+                       return -EINVAL;
+               }
+
+               case VIDIOC_ENUMOUTPUT:
+               case VIDIOC_G_OUTPUT:
+               case VIDIOC_S_OUTPUT:
+               {
+                       /* we don't have any video outputs */
+                       return -EINVAL;
+               }
+
+               default:
+               {
+                       /* unrecognized ioctl */
+                       return -ENOIOCTLCMD;
+               }
+       }
+       return 0;
+}
+
+/*
+ *  file operations
+ */
+
+static unsigned
+int camera_core_poll(struct file *file, struct poll_table_struct *wait)
+{
+       return -EINVAL;
+}
+
+/* ------------------------------------------------------------ */
+/* callback routine for read DMA completion. We just start another DMA
+ * transfer unless overlay has been turned off
+ */
+static void
+camera_core_capture_callback(void *arg1, void *arg)
+{
+       struct camera_device *cam = (struct camera_device *)arg1;
+       int err;
+       unsigned long irqflags;
+       static int done = 0;
+
+       spin_lock_irqsave(&cam->capture_lock, irqflags);
+       if (!cam->reading)
+       {
+               done = 0;
+               cam->capture_started = 0;
+               spin_unlock_irqrestore(&cam->capture_lock, irqflags);
+               return;
+       }
+
+       if (done < 14) {
+               ++done;
+               sg_dma_address(&cam->capture_sglist) = cam->capture_base_phys;
+               sg_dma_len(&cam->capture_sglist) = cam->pix.sizeimage;
+               err = camera_core_sgdma_queue(cam, &cam->capture_sglist, 1,
+                       camera_core_capture_callback, NULL);            
+       } else {
+               cam->capture_completed = 1;
+               if (cam->reading)
+               {
+                       /* Wake up any process which are waiting for the 
+                       ** DMA to complete */
+                       wake_up_interruptible(&camera_dev->new_video_frame);
+                       sg_dma_address(&cam->capture_sglist) = cam->capture_base_phys;
+                       sg_dma_len(&cam->capture_sglist) = cam->pix.sizeimage;
+                       err = camera_core_sgdma_queue(cam, &cam->capture_sglist, 1,
+                               camera_core_capture_callback, NULL);
+               }
+       }
+
+       spin_unlock_irqrestore(&cam->capture_lock, irqflags);
+}
+
+static ssize_t
+camera_core_read(struct file *file, char *data, size_t count, loff_t *ppos)
+{
+       struct camera_fh *fh = file->private_data;
+       struct camera_device *cam = fh->cam;
+       int err;
+       unsigned long irqflags;
+       long timeout;
+#if 0  /* use video_buf to do capture */
+       int i;
+       for (i = 0; i < 14; i++)
+               videobuf_read_one(file, &fh->vbq, data, count, ppos);
+       i = videobuf_read_one(file, &fh->vbq, data, count, ppos);
+       return i;
+#endif
+       
+       if (!cam->capture_base) {
+               cam->capture_base = (unsigned long)dma_alloc_coherent(NULL,
+                               cam->pix.sizeimage,
+                               (dma_addr_t *) &cam->capture_base_phys,
+                               GFP_KERNEL | GFP_DMA);
+       }
+       if (!cam->capture_base) {
+               printk(KERN_ERR CAM_NAME
+                       ": cannot allocate capture buffer\n");
+               return 0;
+       }
+
+       spin_lock_irqsave(&cam->capture_lock, irqflags);
+       cam->reading = fh;
+       cam->capture_started = 1;
+       sg_dma_address(&cam->capture_sglist) = cam->capture_base_phys;
+       sg_dma_len(&cam->capture_sglist)= cam->pix.sizeimage;
+       spin_unlock_irqrestore(&cam->capture_lock, irqflags);
+
+       err = camera_core_sgdma_queue(cam, &cam->capture_sglist, 1,
+                       camera_core_capture_callback, NULL);
+
+       /* Wait till DMA is completed */
+       timeout = HZ * 10;
+       cam->capture_completed = 0;
+       while (cam->capture_completed == 0) {
+               timeout = interruptible_sleep_on_timeout 
+                               (&cam->new_video_frame, timeout);
+               if (timeout == 0) {
+                       printk(KERN_ERR CAM_NAME ": timeout waiting video frame\n");    
+                       return -EIO; /* time out */
+               }
+       }
+       /* copy the data to the user buffer */
+       err = copy_to_user(data, (void *)cam->capture_base, cam->pix.sizeimage);
+       return (cam->pix.sizeimage - err);
+       
+}
+
+static int
+camera_core_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct camera_fh *fh = file->private_data;
+
+       return videobuf_mmap_mapper(&fh->vbq, vma);
+}
+
+static int
+camera_core_ioctl(struct inode *inode, struct file *file, unsigned int cmd, 
+                 unsigned long arg)
+{
+
+       return video_usercopy(inode, file, cmd, arg, camera_core_do_ioctl);
+}
+
+static int
+camera_core_release(struct inode *inode, struct file *file)
+{
+       struct camera_fh *fh = file->private_data;
+       struct camera_device *cam = fh->cam;
+       
+       file->private_data = NULL;
+       kfree(fh);
+
+       spin_lock(&cam->img_lock);
+       if (cam->previewing == fh) {
+               cam->previewing = NULL;
+       }
+       if (cam->streaming == fh) {
+               cam->streaming = NULL;
+       }
+       if (cam->reading == fh) {
+               cam->reading = NULL;
+       }
+       spin_unlock(&cam->img_lock);
+
+       camera_dev->cam_hardware->finish_dma(cam->hardware_data);
+
+       if (cam->capture_base) {
+               dma_free_coherent(NULL, cam->pix.sizeimage, 
+                                       (void *)cam->capture_base, 
+                                       cam->capture_base_phys);
+               cam->capture_base = 0;
+               cam->capture_base_phys = 0;
+       }
+       if (fh->vbq.read_buf) {
+               camera_core_vbq_release(&fh->vbq, fh->vbq.read_buf);
+               kfree(fh->vbq.read_buf);
+       }
+
+       cam->cam_hardware->close(cam->hardware_data);
+       cam->active = 0;
+       return 0;
+}
+
+static int
+camera_core_open(struct inode *inode, struct file *file)
+{
+       int minor = iminor(inode);
+       struct camera_device *cam = camera_dev;
+       struct camera_fh *fh;
+
+       if (!cam || !cam->vfd || (cam->vfd->minor != minor))
+               return -ENODEV;
+
+       /* allocate per-filehandle data */
+       fh = kmalloc(sizeof(*fh), GFP_KERNEL);
+       if (NULL == fh)
+               return -ENOMEM;
+       file->private_data = fh;
+       fh->cam = cam;
+       fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+       spin_lock(&cam->img_lock);
+       if (cam->active == 1) {
+               printk (KERN_ERR CAM_NAME ": Camera device Active\n");
+               spin_unlock(&cam->img_lock);
+               return -EPERM;
+       }
+       cam->active = 1;
+       spin_unlock(&cam->img_lock);
+
+       videobuf_queue_init(&fh->vbq, &cam->vbq_ops, NULL, &cam->vbq_lock,
+               fh->type, V4L2_FIELD_NONE, sizeof(struct videobuf_buffer), fh);
+
+       cam->capture_completed = 0;
+       cam->capture_started = 0;
+
+       if (cam->cam_hardware->open(cam->hardware_data))
+       {
+               printk (KERN_ERR CAM_NAME ": Camera IF configuration failed\n");
+               cam->active = 0;
+               return -ENODEV;
+       }
+       
+       cam->xclk = cam->cam_hardware->set_xclk(cam->xclk, cam->hardware_data);
+       /* program the sensor for the capture format and rate */
+       if (cam->cam_sensor->configure(&cam->pix, cam->xclk, 
+                               &cam->cparm.timeperframe, cam->sensor_data))
+       {
+               printk (KERN_ERR CAM_NAME ": Camera sensor configuration failed\n");
+               cam->cam_hardware->close(cam->hardware_data);
+               cam->active = 0;
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int camera_core_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct camera_device *cam = platform_get_drvdata(pdev);
+       int ret = 0;
+
+       spin_lock(&cam->img_lock);
+       if (cam->active) {
+               cam->cam_hardware->close(cam->hardware_data);
+       }
+       cam->cam_sensor->power_off(cam->sensor_data);
+       spin_unlock(&cam->img_lock);
+
+       return ret;
+}
+
+static int camera_core_resume(struct platform_device *pdev)
+{
+       struct camera_device *cam = platform_get_drvdata(pdev);
+       int ret = 0;
+
+       spin_lock(&cam->img_lock);
+       cam->cam_sensor->power_on(cam->sensor_data);
+       if (cam->active) {
+               cam->capture_completed = 1;
+               cam->cam_hardware->open(cam->hardware_data);
+               cam->cam_hardware->set_xclk(cam->xclk, cam->hardware_data);
+
+               cam->cam_sensor->configure(&cam->pix, cam->xclk,
+                                          &cam->cparm.timeperframe,
+                                          cam->sensor_data);
+               camera_core_sgdma_process(cam);
+       }
+       spin_unlock(&cam->img_lock);
+       
+       return ret;
+}
+#endif /* CONFIG_PM */
+
+static struct file_operations camera_core_fops = 
+{
+       .owner                  = THIS_MODULE,
+       .llseek                 = no_llseek,
+       .read                   = camera_core_read,
+       .poll                   = camera_core_poll,
+       .ioctl                  = camera_core_ioctl,
+       .mmap                   = camera_core_mmap,
+       .open                   = camera_core_open,
+       .release                = camera_core_release,
+};
+
+static int __init camera_core_probe(struct platform_device *pdev)
+{
+       struct camera_device *cam;
+       struct video_device *vfd;
+       int     status;
+
+       cam = kzalloc(sizeof(struct camera_device), GFP_KERNEL);
+       if (!cam) {
+               printk(KERN_ERR CAM_NAME ": could not allocate memory\n");
+               status = -ENOMEM;
+               goto err0;
+       }
+
+       /* Save the pointer to camera device in a global variable */
+       camera_dev = cam;
+       
+       /* initialize the video_device struct */
+       vfd = cam->vfd = video_device_alloc();
+       if (!vfd) {
+               printk(KERN_ERR CAM_NAME 
+                       ": could not allocate video device struct\n");
+               status = -ENOMEM;
+               goto err1;
+       }
+       
+       vfd->release = video_device_release;
+
+       strlcpy(vfd->name, CAM_NAME, sizeof(vfd->name));
+       vfd->type = VID_TYPE_CAPTURE | VID_TYPE_OVERLAY | VID_TYPE_CHROMAKEY;
+       
+       /* need to register for a VID_HARDWARE_* ID in videodev.h */
+       vfd->hardware = 0;
+       vfd->fops = &camera_core_fops;
+       video_set_drvdata(vfd, cam);
+       vfd->minor = -1;
+
+       /* initialize the videobuf queue ops */
+       cam->vbq_ops.buf_setup = camera_core_vbq_setup;
+       cam->vbq_ops.buf_prepare = camera_core_vbq_prepare;
+       cam->vbq_ops.buf_queue = camera_core_vbq_queue;
+       cam->vbq_ops.buf_release = camera_core_vbq_release;
+
+       /* initilize the overlay interface */
+       cam->overlay_size = overlay_mem;
+       if (cam->overlay_size > 0)
+       {
+               cam->overlay_base = (unsigned long) dma_alloc_coherent(NULL,
+                                       cam->overlay_size,
+                                       (dma_addr_t *) &cam->overlay_base_phys,
+                                       GFP_KERNEL | GFP_DMA);
+               if (!cam->overlay_base) {
+                       printk(KERN_ERR CAM_NAME
+                               ": cannot allocate overlay framebuffer\n");
+                       status = -ENOMEM;
+                       goto err2;
+               }
+       }
+       memset((void*)cam->overlay_base, 0, cam->overlay_size);
+       spin_lock_init(&cam->overlay_lock);
+       spin_lock_init(&cam->capture_lock);
+
+       /*Initialise the pointer to the sensor interface and camera interface */
+       cam->cam_sensor = &camera_sensor_if;
+       cam->cam_hardware = &camera_hardware_if;
+
+       /* initialize the camera interface */
+       cam->hardware_data = cam->cam_hardware->init();
+       if (!cam->hardware_data) {
+               printk(KERN_ERR CAM_NAME ": cannot initialize interface hardware\n");
+               status = -ENODEV;
+               goto err3;
+       }
+        
+       /* initialize the spinlock used to serialize access to the image 
+        * parameters
+        */
+       spin_lock_init(&cam->img_lock);
+
+       /* initialize the streaming capture parameters */
+       cam->cparm.capability = V4L2_CAP_TIMEPERFRAME;
+       cam->cparm.readbuffers = 1;
+
+       /* Enable the xclk output.  The sensor may (and does, in the case of 
+        * the OV9640) require an xclk input in order for its initialization 
+        * routine to work.
+        */
+       cam->xclk = 21000000;   /* choose an arbitrary xclk frequency */
+       cam->xclk = cam->cam_hardware->set_xclk(cam->xclk, cam->hardware_data);
+
+       /* initialize the sensor and define a default capture format cam->pix */
+       cam->sensor_data = cam->cam_sensor->init(&cam->pix);
+       if (!cam->sensor_data) {
+               cam->cam_hardware->disable(cam->hardware_data);
+               printk(KERN_ERR CAM_NAME ": cannot initialize sensor\n");
+               status = -ENODEV;
+               goto err4;
+       }
+
+       printk(KERN_INFO CAM_NAME ": %s interface with %s sensor\n",
+               cam->cam_hardware->name, cam->cam_sensor->name);
+
+       /* select an arbitrary default capture frame rate of 15fps */
+       cam->nominal_timeperframe.numerator = 1;
+       cam->nominal_timeperframe.denominator = 15;
+
+       /* calculate xclk based on the default capture format and default 
+        * frame rate
+        */
+       cam->xclk = cam->cam_sensor->calc_xclk(&cam->pix,
+               &cam->nominal_timeperframe, cam->sensor_data);
+       cam->cparm.timeperframe = cam->nominal_timeperframe;
+
+       /* initialise the wait queue */
+       init_waitqueue_head(&cam->new_video_frame);
+
+       /* Initialise the DMA structures */
+       camera_core_sgdma_init(cam);
+
+       /* Disable the Camera after detection */
+       cam->cam_hardware->disable(cam->hardware_data);
+       
+       platform_set_drvdata(pdev, cam);
+       
+       if (video_register_device(vfd, VFL_TYPE_GRABBER, video_nr) < 0) {
+               printk(KERN_ERR CAM_NAME 
+                       ": could not register Video for Linux device\n");
+               status = -ENODEV;
+               goto err5;
+       }
+
+       printk(KERN_INFO CAM_NAME 
+              ": registered device video%d [v4l2]\n", vfd->minor);
+
+       return 0;
+
+ err5:
+       cam->cam_sensor->cleanup(cam->sensor_data);
+ err4:
+       cam->cam_hardware->cleanup(cam->hardware_data);
+ err3:
+       dma_free_coherent(NULL, cam->overlay_size,
+                               (void *)cam->overlay_base, 
+                               cam->overlay_base_phys);
+       cam->overlay_base = 0;
+ err2:
+       video_device_release(vfd);
+ err1:
+       kfree(cam);
+       camera_dev = NULL;
+ err0:
+       return status;
+}
+
+static int camera_core_remove(struct platform_device *pdev)
+{
+       struct camera_device *cam = platform_get_drvdata(pdev);
+       struct video_device *vfd;
+
+       vfd = cam->vfd;
+       if (vfd) {
+               if (vfd->minor == -1) {
+                       /* The device never got registered, so release the 
+                       ** video_device struct directly
+                       */
+                       video_device_release(vfd);
+               } else {
+                       /* The unregister function will release the video_device
+                       ** struct as well as unregistering it.
+                       */
+                       video_unregister_device(vfd);
+               }
+               cam->vfd = NULL;
+       }
+       if (cam->overlay_base) {
+               dma_free_coherent(NULL, cam->overlay_size,
+                                       (void *)cam->overlay_base, 
+                                       cam->overlay_base_phys);
+               cam->overlay_base = 0;
+       }       
+       cam->overlay_base_phys = 0;
+
+       cam->cam_sensor->cleanup(cam->sensor_data);
+       cam->cam_hardware->cleanup(cam->hardware_data);
+       kfree(cam);
+       camera_dev = NULL;
+
+       return 0;
+}
+
+static struct platform_driver camera_core_driver = {
+       .driver = {
+               .name           = CAM_NAME,
+               .owner          = THIS_MODULE,
+       },
+       .probe                  = camera_core_probe,
+       .remove                 = camera_core_remove,
+#ifdef CONFIG_PM
+       .suspend                = camera_core_suspend,
+       .resume                 = camera_core_resume,
+#endif
+};
+
+/* FIXME register omap16xx or omap24xx camera device in arch/arm/...
+ * system init code, with its resources and mux setup, NOT here.
+ * Then MODULE_ALIAS(CAM_NAME) so it hotplugs and coldplugs; this
+ * "legacy" driver style is trouble.
+ */
+static struct platform_device *cam;
+
+static void __exit
+camera_core_cleanup(void)
+{
+       platform_driver_unregister(&camera_core_driver);
+       platform_device_unregister(cam);
+}
+
+static char banner[] __initdata = KERN_INFO "OMAP Camera driver initializing\n";
+
+static int __init
+camera_core_init(void)
+{
+
+       printk(banner);
+       platform_driver_register(&camera_core_driver);
+
+       cam = platform_device_register_simple(CAM_NAME, -1, NULL, 0);
+
+       return 0;
+}
+
+MODULE_AUTHOR("Texas Instruments.");
+MODULE_DESCRIPTION("OMAP Video for Linux camera driver");
+MODULE_LICENSE("GPL");
+
+module_param(video_nr, int, 0);
+MODULE_PARM_DESC(video_nr, 
+               "Minor number for video device (-1 ==> auto assign)");
+module_param(capture_mem, int, 0);
+MODULE_PARM_DESC(capture_mem,
+        "Maximum amount of memory for capture buffers (default 4800KB)");
+
+module_init(camera_core_init);
+module_exit(camera_core_cleanup);
+
diff --git a/drivers/media/video/omap/camera_core.h b/drivers/media/video/omap/camera_core.h
new file mode 100644 (file)
index 0000000..0f94446
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ *  drivers/media/video/omap/camera_core.h
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc. 
+ * 
+ * This package is free software; you can redistribute it and/or modify 
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation. 
+ * 
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 
+ */
+
+#ifndef CAMERA_CORE__H
+#define CAMERA_CORE__H
+
+struct camera_fh;
+
+#include <media/video-buf.h>
+#include <asm/scatterlist.h>
+
+struct camera_device;
+typedef void (*dma_callback_t)(void *arg1, void *arg2);
+
+struct sgdma_state {
+       const struct scatterlist *sglist;
+       int sglen;              /* number of sglist entries */
+       int next_sglist;        /* index of next sglist entry to process */
+       int queued_sglist;      /* number of sglist entries queued for DMA */
+       unsigned long csr;      /* DMA return code */
+       dma_callback_t callback;
+       void *arg;
+};
+
+/* NUM_SG_DMA is the number of scatter-gather DMA transfers that can be queued.
+ */
+#define NUM_SG_DMA VIDEO_MAX_FRAME+2
+/* per-device data structure */
+struct camera_device {
+       struct device dev;
+       struct video_device *vfd;
+       
+       spinlock_t overlay_lock;        /* spinlock for overlay DMA counter */
+       int overlay_cnt;                /* count of queued overlay DMA xfers */
+       struct scatterlist overlay_sglist;
+       unsigned long overlay_base_phys;
+       unsigned long overlay_base;
+       unsigned long overlay_size;
+
+       spinlock_t vbq_lock;            /* spinlock for videobuf queues */
+       struct videobuf_queue_ops vbq_ops;      /* videobuf queue operations */
+       unsigned long field_count;      /* field counter for videobuf_buffer */
+
+       /* scatter-gather DMA management */
+       spinlock_t sg_lock;
+       int free_sgdma; /* number of free sg dma slots */
+       int next_sgdma; /* index of next sg dma slot to use */
+       struct sgdma_state sgdma[NUM_SG_DMA];
+       char in_use;
+
+       /* The img_lock is used to serialize access to the image parameters for 
+        * overlay and capture.  Need to use spin_lock_irq when writing to the 
+        * reading, streaming, and previewing parameters.  A regular spin_lock 
+        * will suffice for all other cases.
+        */
+       spinlock_t img_lock;
+       /* We allow reading from at most one filehandle at a time.
+        * non-NULL means reading is in progress.
+        */
+       struct camera_fh *reading;
+       /* We allow streaming from at most one filehandle at a time.  
+        * non-NULL means streaming is in progress.
+        */
+       struct camera_fh *streaming;
+       /* We allow previewing from at most one filehandle at a time.  
+        * non-NULL means previewing is in progress.
+        */
+       struct camera_fh *previewing;
+
+       /* capture parameters (frame rate, number of buffers) */
+       struct v4l2_captureparm cparm;
+
+       /* This is the frame period actually requested by the user. */
+       struct v4l2_fract nominal_timeperframe;
+       
+       /* frequency (in Hz) of camera interface xclk output */
+       unsigned long xclk;
+
+       /* Pointer to the sensor interface ops */
+       struct omap_camera_sensor *cam_sensor;
+       void *sensor_data;
+       
+       /* Pointer to the camera interface hardware ops */
+       struct camera_hardware *cam_hardware;
+       void *hardware_data;
+
+       /* pix defines the size and pixel format of the image captured by the 
+        * sensor.  This also defines the size of the framebuffers.  The 
+        * same pool of framebuffers is used for video capture and video 
+        * overlay.  These parameters are set/queried by the 
+        * VIDIOC_S_FMT/VIDIOC_G_FMT ioctls with a CAPTURE buffer type.
+        */
+       struct v4l2_pix_format pix;
+       struct v4l2_pix_format pix2;
+
+       /* crop defines the size and offset of the video overlay source window 
+        * within the framebuffer.  These parameters are set/queried by the 
+        * VIDIOC_S_CROP/VIDIOC_G_CROP ioctls with an OVERLAY buffer type.  
+        * The cropping rectangle allows a subset of the captured image to be 
+        * previewed.  It only affects the portion of the image previewed, not 
+        * captured; the entire camera image is always captured.
+        */
+       struct v4l2_rect crop;
+
+       /* win defines the size and offset of the video overlay target window 
+        * within the video display.  These parameters are set/queried by the 
+        * VIDIOC_S_FMT/VIDIOC_G_FMT ioctls with an OVERLAY buffer type.
+        */
+       struct v4l2_window win;
+
+       /* fbuf reflects the size of the video display.  It is queried with the 
+        * VIDIOC_G_FBUF ioctl.  The size of the video display cannot be 
+        * changed with the VIDIOC_S_FBUF ioctl.
+        */
+       struct v4l2_framebuffer fbuf;
+
+       /* end of generic stuff, the above should be common to all omaps */
+
+       /* note, 2420 uses videobuf to do caprure, it is more memory efficient
+          we need 1710 and 2420 do capture in the same way */
+       /* Variables to store the capture state */
+       /* Wait till DMA is completed */
+       wait_queue_head_t new_video_frame;
+       char capture_completed;
+       char capture_started;
+       spinlock_t capture_lock;
+       struct scatterlist capture_sglist;
+       unsigned long capture_base;
+       unsigned long capture_base_phys;
+
+       char active;
+};
+
+/* per-filehandle data structure */
+struct camera_fh {
+       struct camera_device *cam;
+       enum v4l2_buf_type type;
+       struct videobuf_queue vbq;
+};
+
+#define CAM_NAME "omap_camera"
+
+#endif /* CAMERA_CORE__H */
diff --git a/drivers/media/video/omap/camera_hw_if.h b/drivers/media/video/omap/camera_hw_if.h
new file mode 100644 (file)
index 0000000..0976e45
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ *  drivers/media/video/omap/camera_hw_if.h
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc. 
+ * 
+ * Camera interface to OMAP camera capture drivers
+ * Camera interface hardware driver should implement this interface
+ *
+ * This package is free software; you can redistribute it and/or modify 
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation. 
+ * 
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 
+ */
+#ifndef OMAP_CAMERA_HW_IF_H
+#define OMAP_CAMERA_HW_IF_H
+
+#define LEN_HW_IF_NAME         31
+
+struct sgdma_state;
+
+struct camera_hardware {
+       unsigned int version;  //version of camera driver module
+       char name[LEN_HW_IF_NAME + 1];
+
+       void *(*init)(void);
+       int (*cleanup)(void *);
+
+       int (*open)(void *);  /* acquire h/w resources (irq,DMA), etc. */
+       int (*close)(void *); /* free h/w resources, stop i/f */
+
+       int (*enable)(void *);
+       int (*disable)(void *);
+
+       int (*abort)(void *);
+
+       int (*set_xclk)(int, void *);
+
+       int (*init_dma)(void *);
+       int (*start_dma)(struct sgdma_state *, void (*)(void *arg1, void *arg2),
+                       void *, void *, void *);
+       int (*finish_dma)(void *);
+};
+
+extern struct camera_hardware camera_hardware_if;
+
+#endif /* OMAP_CAMERA_HW_IF_H */
diff --git a/drivers/media/video/omap/h3_sensor_power.c b/drivers/media/video/omap/h3_sensor_power.c
new file mode 100644 (file)
index 0000000..ae76688
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * drivers/media/video/omap/h3_sensor_power.c
+ *
+ * H3 sensor powerup/down functions.
+ *
+ * Author: Andy Lowe (source@mvista.com)
+ *
+ * Copyright (C) 2004 MontaVista Software, Inc.
+ * Copyright (C) 2004 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+
+#include <asm/arch/gpioexpander.h>
+
+int h3_sensor_powerup(void);
+int h3_sensor_powerdown(void);
+
+int
+h3_sensor_powerup(void)
+{
+       unsigned char expa;
+       int err;
+
+       /* read the current state of GPIO EXPA output */
+       if (( err = read_gpio_expa(&expa, 0x27))) {
+               printk(KERN_ERR "Error reading GPIO EXPA \n");
+               return err;
+       }
+       /* set GPIO EXPA P7 CAMERA_MOD_EN to power-up sensor */
+       if ((err = write_gpio_expa(expa | 0x80, 0x27))) {
+               printk(KERN_ERR "Error writing to GPIO EXPA \n");
+               return err;
+       }
+       return 0;
+}
+
+int
+h3_sensor_powerdown(void)
+{
+       unsigned char expa;
+       int err;
+
+       /* read the current state of GPIO EXPA output */
+       if (( err = read_gpio_expa(&expa, 0x27))) {
+               printk(KERN_ERR "Error reading GPIO EXPA \n");
+               return err;
+       }
+       /* clear GPIO EXPA P7 CAMERA_MOD_EN to power-up sensor */
+       if ((err = write_gpio_expa(expa & ~0x80, 0x27))) {
+               printk(KERN_ERR "Error writing to GPIO EXPA \n");
+               return err;
+       }
+       return 0;
+}
+
+EXPORT_SYMBOL(h3_sensor_powerup);
+EXPORT_SYMBOL(h3_sensor_powerdown);
diff --git a/drivers/media/video/omap/h3sensorpower.h b/drivers/media/video/omap/h3sensorpower.h
new file mode 100644 (file)
index 0000000..8587729
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * drivers/media/video/omap/h3sensorpower.h
+ *
+ * Copyright (C) 2005 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef H3SENSORPOWER_H
+#define H3SENSORPOWER_H
+
+int h3_sensor_powerup(void);
+int h3_sensor_powerdown(void);
+
+#endif /*H3SENSORPOWER_H*/
diff --git a/drivers/media/video/omap/h4_sensor_power.c b/drivers/media/video/omap/h4_sensor_power.c
new file mode 100644 (file)
index 0000000..f8db956
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * drivers/media/video/omap/h4_sensor_power.c
+ *
+ * H4 sensor powerup/down functions.
+ *
+ * Author: Andy Lowe (source@mvista.com)
+ *
+ * Copyright (C) 2004 MontaVista Software, Inc.
+ * Copyright (C) 2004 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+
+#include <asm/arch/gpioexpander.h>
+
+int h4_sensor_powerup(void);
+int h4_sensor_powerdown(void);
+
+int
+h4_sensor_powerup(void)
+{
+       unsigned char expa;
+       int err;
+
+       /* read current state of GPIO EXPA outputs */
+       if ((err = read_gpio_expa(&expa, 0x20))) {
+               printk(KERN_ERR "Error reading GPIO EXPA\n");
+               return err;
+       }
+       /* Set GPIO EXPA P3 (CAMERA_MODULE_EN) to power-up sensor */
+       if ((err = write_gpio_expa(expa | 0x08, 0x20))) {
+               printk(KERN_ERR "Error writing to GPIO EXPA\n");
+               return err;
+       }
+
+       /* read current state of GPIO EXPA outputs */
+       if ((err = read_gpio_expa(&expa, 0x22))) {
+               printk(KERN_ERR "Error reading GPIO EXPA\n");
+               return err;
+       }
+       /* Clear GPIO EXPA P7 (CAM_RST) */
+       if ((err = write_gpio_expa(expa & ~0x80, 0x22))) {
+               printk(KERN_ERR "Error writing to GPIO EXPA\n");
+               return err;
+       }
+
+       return 0;
+}
+
+int
+h4_sensor_powerdown(void)
+{
+       unsigned char expa;
+       int err;
+
+       /* read current state of GPIO EXPA outputs */
+       if ((err = read_gpio_expa(&expa, 0x20))) {
+               printk(KERN_ERR "Error reading GPIO EXPA\n");
+               return err;
+       }
+       /* Clear GPIO EXPA P3 (CAMERA_MODULE_EN) to power-down sensor */
+       if ((err = write_gpio_expa(expa & ~0x08, 0x20))) {
+               printk(KERN_ERR "Error writing to GPIO EXPA\n");
+               return err;
+       }
+
+       return 0;
+}
+
+EXPORT_SYMBOL(h4_sensor_powerup);
+EXPORT_SYMBOL(h4_sensor_powerdown);
diff --git a/drivers/media/video/omap/h4sensorpower.h b/drivers/media/video/omap/h4sensorpower.h
new file mode 100644 (file)
index 0000000..4eeae11
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * drivers/media/video/omap/h4sensorpower.h
+ *
+ * Copyright (C) 2005 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef H4SENSORPOWER_H
+#define H4SENSORPOWER_H
+
+int h4_sensor_powerup(void);
+int h4_sensor_powerdown(void);
+
+#endif /*H4SENSORPOWER_H*/
diff --git a/drivers/media/video/omap/omap16xxcam.c b/drivers/media/video/omap/omap16xxcam.c
new file mode 100644 (file)
index 0000000..34cf1a6
--- /dev/null
@@ -0,0 +1,590 @@
+/*
+ * drivers/media/video/omap/omap16xxcam.c
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc. 
+ * 
+ * Video-for-Linux (Version 2) camera capture driver for
+ * the OMAP H2 and H3 camera controller.
+ *
+ * leverage some code from CEE distribution 
+ * Copyright (C) 2003-2004 MontaVista Software, Inc.
+ * 
+ * This package is free software; you can redistribute it and/or modify 
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation. 
+ * 
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 
+ */
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+
+#include <asm/arch/irqs.h>
+#include <asm/arch/dma.h>
+#include <asm/arch/hardware.h>
+#include <asm/io.h>
+#include <asm/scatterlist.h>
+#include <asm/mach-types.h>
+
+#include "omap16xxcam.h"
+#include "camera_hw_if.h"
+#include "camera_core.h"
+
+#define CONF_CAMERAIF_RESET_R 5
+#define EN_PER   0
+
+/* NUM_CAMDMA_CHANNELS is the number of logical channels used for
+ * DMA data transfer.
+ */
+#define NUM_CAMDMA_CHANNELS 2
+
+typedef struct {
+        unsigned int ctrlclock;     /* 00 */
+        unsigned int it_status;     /* 04 */
+        unsigned int mode;          /* 08 */
+        unsigned int status;        /* 0C */
+        unsigned int camdata;       /* 10 */
+        unsigned int gpio;         /* 14 */
+        unsigned int peak_counter;  /* 18 */
+} camera_regs_t;
+
+struct camdma_state {
+       dma_callback_t callback;
+       void *arg1;
+       void *arg2;
+};
+
+struct omap16xxcam {
+       camera_regs_t *camera_regs;
+       unsigned long iobase_phys;
+
+       /* frequncy (in Hz) of camera interface functional clock (ocp_clk) */
+       unsigned long ocp_clk;
+
+       struct clk *func_clk;
+
+       /* dma related stuff */
+       spinlock_t dma_lock;
+       int free_dmach;
+       int next_dmach;
+       struct camdma_state camdma[NUM_CAMDMA_CHANNELS];
+       int dma_channel_number1;
+       int dma_channel_number2;
+
+       wait_queue_head_t vsync_wait;
+
+       int new;
+};
+static struct omap16xxcam hardware_data;
+   
+static int omap16xxcam_set_xclk(int, void *);
+static void omap16xx_cam_dma_link_callback(int, unsigned short, void *);
+
+/* Clears the camera data FIFO by setting RAZ_FIFO bit in MODE configuration
+   register. */
+static void
+omap16xx_cam_clear_fifo(struct omap16xxcam *data)
+{
+       data->camera_regs->mode |= RAZ_FIFO;
+       udelay(10);
+       data->camera_regs->mode &= ~RAZ_FIFO;
+}
+  
+static void
+omap16xx_cam_reset(struct omap16xxcam *data, int yes)
+{
+       if (machine_is_omap_h3())
+               data->camera_regs->gpio = yes ? 0 : 1;
+       else
+               data->camera_regs->gpio = yes ? 1 : 0;
+}
+
+static void 
+omap16xx_cam_init(void)
+{
+       /*
+        * FIXME - Use mux API's instead of directly writing in to MUX registers
+        */
+       omap_writel(omap_readl(FUNC_MUX_CTRL_4) & ~(0x1ff << 21), FUNC_MUX_CTRL_4);
+       omap_writel(0, FUNC_MUX_CTRL_5);
+       omap_writel(omap_readl(PULL_DWN_CTRL_0) & ~(0x1FFF << 17), PULL_DWN_CTRL_0);
+       omap_writel(omap_readl(PU_PD_SEL_0) & ~(0x1FFF << 17), PU_PD_SEL_0);
+
+       omap_writel(0xeaef, COMP_MODE_CTRL_0);
+       omap_writel(omap_readl(OMAP1610_RESET_CONTROL) & ~(1 << CONF_CAMERAIF_RESET_R),
+                       OMAP1610_RESET_CONTROL);
+       omap_writel(omap_readl(OMAP1610_RESET_CONTROL) | (1 << CONF_CAMERAIF_RESET_R),
+                       OMAP1610_RESET_CONTROL);
+    
+       /* Enable peripheral reset */
+       omap_writew(omap_readw(ARM_RSTCT2) | (1 << EN_PER), ARM_RSTCT2);
+
+       /* enable peripheral clock */
+       clk_enable(hardware_data.func_clk);
+}
+
+static void
+omap16xx_cam_waitfor_syncedge(struct omap16xxcam *data, u32 edge_mask)
+{
+       data->camera_regs->mode = (FIFO_TRIGGER_LVL << THRESHOLD_BIT) | edge_mask;
+       do {
+               interruptible_sleep_on(&data->vsync_wait);
+       } while (signal_pending(current));
+}
+
+static void
+omap16xx_cam_configure_dma(struct omap16xxcam *data)
+{
+
+       data->camera_regs->mode = (FIFO_TRIGGER_LVL << THRESHOLD_BIT)
+                        | EN_DMA | EN_FIFO_FULL;
+       data->camera_regs->ctrlclock |= LCLK_EN; 
+}
+
+/* acquire h/w resources DMA */
+static int
+omap16xx_cam_link_open(struct omap16xxcam *data)
+{
+       int ret;
+
+       /* Acquire first dma channel */
+       if ((ret = omap_request_dma(OMAP_DMA_CAMERA_IF_RX, 
+                               "camera dma 1", omap16xx_cam_dma_link_callback,
+                               (void *)data, &data->dma_channel_number1))) {
+                return ret;
+       }
+       /* Acquire second dma channel */
+       if ((ret = omap_request_dma(OMAP_DMA_CAMERA_IF_RX, 
+                               "camera dma 2", omap16xx_cam_dma_link_callback,
+                               (void *)data, &data->dma_channel_number2))) {
+                printk ("No DMA available for camera\n");
+                return ret;
+        }
+       data->next_dmach = data->dma_channel_number1;
+       OMAP_DMA_CLNK_CTRL_REG(data->dma_channel_number1) =
+               data->dma_channel_number2;
+       OMAP_DMA_CLNK_CTRL_REG(data->dma_channel_number2) =
+               data->dma_channel_number1;
+
+       return 0;
+}
+
+/* free h/w resources, stop i/f */
+static int
+omap16xx_cam_link_close(struct omap16xxcam *data)
+{
+       /* free dma channels */
+       omap_stop_dma(data->dma_channel_number1);
+       omap_stop_dma(data->dma_channel_number2);
+
+       omap_free_dma (data->dma_channel_number1);
+       omap_free_dma (data->dma_channel_number2);
+
+       return 0;
+}
+
+/* dma callback routine. */
+static void
+omap16xx_cam_dma_link_callback(int lch, unsigned short ch_status, void *data)
+{
+       int count;
+       void *arg1, *arg2;
+       struct sgdma_state *sgdma = sgdma;
+       struct omap16xxcam *cam = (struct omap16xxcam *)data;
+       dma_callback_t callback;
+
+       spin_lock(&cam->dma_lock);
+       if (cam->free_dmach == 2)
+       {
+               printk("callback all CHANNELS WERE IDLE \n");
+               spin_unlock(&cam->dma_lock);
+               return;
+       }
+       if (cam->free_dmach == 0) {
+               lch = cam->next_dmach;
+       } else {
+               lch = cam->next_dmach == cam->dma_channel_number1 ? 
+                       cam->dma_channel_number2 : cam->dma_channel_number1;
+       }
+
+       while (cam->free_dmach < 2)
+       {
+               if (OMAP_DMA_CCR_REG(lch) & (1 << 7))
+                       break;  
+
+               count = (lch == cam->dma_channel_number2) ? 1 : 0;
+
+               callback = cam->camdma[count].callback;
+               arg1 = cam->camdma[count].arg1;
+               arg2 = cam->camdma[count].arg2;
+               cam->free_dmach++;
+
+               spin_unlock(&cam->dma_lock);            
+               callback(arg1, arg2);
+               spin_lock(&cam->dma_lock);
+
+               lch = (lch == cam->dma_channel_number2) ? cam->dma_channel_number1 :
+                                                       cam->dma_channel_number2;
+       }
+       spin_unlock(&cam->dma_lock);
+       
+}
+
+static irqreturn_t
+omap16xx_cam_isr(int irq, void *client_data)
+{
+       struct omap16xxcam *data = (struct omap16xxcam *)client_data;
+       unsigned int itstat = data->camera_regs->it_status;
+
+       /* VSYNC UP interrupt, start filling FIFO and enabling DMA */
+       if (itstat & V_UP) {            
+               data->camera_regs->mode &= ~EN_V_UP;
+               omap16xx_cam_clear_fifo(data);  
+               omap16xx_cam_configure_dma(data);
+               omap_start_dma(data->next_dmach);
+               wake_up_interruptible(&data->vsync_wait);
+       }
+
+       if (itstat & V_DOWN) {
+               data->camera_regs->mode &= ~EN_V_DOWN;
+               wake_up_interruptible(&data->vsync_wait);
+       }
+
+       if (itstat & H_UP)
+               printk("H_UP\n");
+       
+       if (itstat & H_DOWN)
+               printk("H_DOWN\n");
+       
+       if (itstat & FIFO_FULL) {
+               omap16xx_cam_clear_fifo(data);  
+               printk("FIFO_FULL\n");
+       }
+       
+       if (itstat & DATA_XFER)
+               printk("DATA_TRANS\n");
+       
+       return IRQ_HANDLED;
+}
+/* ------------- below are interface functions ----------------- */
+/* ------------- these functions are named omap16xxcam_<name> -- */
+static int
+omap16xxcam_init_dma(void *priv)
+{
+       int ch;
+       struct omap16xxcam *data = (struct omap16xxcam *) priv;
+
+       data->free_dmach = 2;
+       for (ch = 0; ch < 2; ++ch) {
+               data->camdma[ch].callback = NULL;
+               data->camdma[ch].arg1 = NULL;
+               data->camdma[ch].arg2 = NULL;
+       }
+
+       return 0;
+}
+
+/* start the dma of chains */
+static int 
+omap16xxcam_start_dma(struct sgdma_state *sgdma,
+               dma_callback_t callback, void *arg1, void *arg2, void *priv)
+{
+       struct omap16xxcam *data = (struct omap16xxcam *) priv;
+       struct scatterlist *sglist;
+       unsigned long irqflags;
+       int dmach;
+       int prev_dmach;
+       int count;
+
+       spin_lock_irqsave(&data->dma_lock, irqflags);
+       sglist = (struct scatterlist *)(sgdma->sglist + sgdma->next_sglist);
+
+       if (!data->free_dmach) {
+               spin_unlock_irqrestore(&data->dma_lock, irqflags);
+               return -EBUSY;
+       } 
+       dmach = data->next_dmach;
+       count = (dmach == data->dma_channel_number2) ? 1:0;
+       data->camdma[count].callback = callback;
+       data->camdma[count].arg1 = arg1;
+       data->camdma[count].arg2 = arg2;
+
+       if (cpu_is_omap1710())
+               omap_set_dma_src_params(dmach, OMAP_DMA_PORT_OCP_T1,
+                           OMAP_DMA_AMODE_CONSTANT, CAM_CAMDATA_REG,
+                           0, 0);
+       else
+               omap_set_dma_src_params(dmach, OMAP_DMA_PORT_TIPB,
+                           OMAP_DMA_AMODE_CONSTANT, CAM_CAMDATA_REG,
+                           0, 0);
+
+       omap_set_dma_dest_params(dmach, OMAP_DMA_PORT_EMIFF,
+                            OMAP_DMA_AMODE_POST_INC, sg_dma_address(sglist),
+                            0, 0);
+
+       omap_set_dma_transfer_params(dmach, OMAP_DMA_DATA_TYPE_S32,
+                       FIFO_TRIGGER_LVL, 
+                       sg_dma_len(sglist)/(4 * FIFO_TRIGGER_LVL), 
+                       OMAP_DMA_SYNC_FRAME,
+                       0, 0);
+
+       OMAP_DMA_CLNK_CTRL_REG(dmach) &= ~( 1<< 15);
+
+       prev_dmach = (dmach == data->dma_channel_number2) ? 
+               data->dma_channel_number1 : data->dma_channel_number2;
+       
+       if (data->new) {
+               data->new = 0;
+               omap16xx_cam_waitfor_syncedge(data, EN_V_UP);
+       } else {
+               if (OMAP_DMA_CCR_REG(prev_dmach) & (1 << 7))
+                       OMAP_DMA_CLNK_CTRL_REG(prev_dmach) |= (1 << 15);
+               else {
+                       /* no transfer is in progress */
+                       omap_start_dma(dmach);
+               }       
+       }
+       
+       data->next_dmach = prev_dmach; 
+       data->free_dmach--;
+       spin_unlock_irqrestore(&data->dma_lock, irqflags);
+       return 0;
+}
+int static
+omap16xxcam_finish_dma(void *priv)
+{
+       struct omap16xxcam *data = (struct omap16xxcam *) priv;
+
+       while (data->free_dmach < 2)
+               mdelay(1);
+
+       return 0;
+}
+
+
+/* Enables the camera. Takes camera out of reset. Enables the clocks. */ 
+static int
+omap16xxcam_enable(void *priv)
+{
+       struct omap16xxcam *data = (struct omap16xxcam *) priv;
+
+       omap16xx_cam_reset(data, 1);
+       
+       /* give clock to camera_module */
+       data->camera_regs->mode = (FIFO_TRIGGER_LVL << THRESHOLD_BIT);
+       data->camera_regs->ctrlclock = MCLK_EN | CAMEXCLK_EN;
+
+       omap16xx_cam_clear_fifo(data);
+
+       /* wait for camera to settle down */
+       mdelay(5);
+
+       return 0;
+}
+/* Disables all the camera clocks. Put the camera interface in reset. */
+static int
+omap16xxcam_disable(void *priv)
+{      
+       struct omap16xxcam *data = (struct omap16xxcam *) priv;
+
+       omap16xx_cam_clear_fifo(data);
+
+       data->camera_regs->ctrlclock = 0x00000000;     
+       data->camera_regs->mode = 0x00000000;
+       
+       omap16xx_cam_reset(data, 0);
+
+       return 0;
+}
+
+/* Abort the data transfer */
+static int
+omap16xxcam_abort(void *priv)
+{
+       return omap16xxcam_disable(priv);
+}
+
+static int
+omap16xxcam_set_xclk(int xclk, void *priv)
+{      
+       struct omap16xxcam *data = (struct omap16xxcam *) priv;
+       int xclk_val;
+       int divisor = 1;
+       divisor = data->ocp_clk/xclk;
+       if ( divisor * xclk < data->ocp_clk)
+               ++divisor; 
+
+       switch (divisor) {
+               case 1:
+               case 2:
+                       xclk_val = FOSCMOD_TC2_CK2;
+                       break;
+               case 3:
+                       xclk_val = FOSCMOD_TC2_CK3;
+                       break;
+               case 4:
+               case 5:
+               case 6:
+               case 7:
+                       xclk_val = FOSCMOD_TC2_CK4;
+                       break;
+               case 8:
+               case 9:
+                       xclk_val = FOSCMOD_TC2_CK8;
+                       break;
+               case 10:
+               case 11:
+                       xclk_val = FOSCMOD_TC2_CK10;
+                       break;
+               case 12:
+               case 13:
+               case 14:
+               case 15:
+                       xclk_val = FOSCMOD_TC2_CK12;
+                       break;
+               case 16:
+                       xclk_val = FOSCMOD_TC2_CK16;
+                       break;
+               default:
+                       xclk_val = FOSCMOD_TC2_CK16;
+       }
+       
+       /* follow the protocol to change the XCLK clock */
+       data->camera_regs->ctrlclock &= ~CAMEXCLK_EN;
+       data->camera_regs->ctrlclock |= xclk_val;
+       data->camera_regs->ctrlclock |= CAMEXCLK_EN;
+
+       return (data->ocp_clk/divisor);
+}
+
+static int
+omap16xxcam_open(void *priv)
+{
+       struct omap16xxcam *data = (struct omap16xxcam *) priv;
+       int ret;
+
+       if ((ret = request_irq(INT_CAMERA, omap16xx_cam_isr, IRQF_DISABLED,
+                                       "camera", data))) {
+               printk("FAILED to aquire irq\n");
+               return ret;
+       }
+
+       data->new = 1;
+       omap16xxcam_enable(data);
+       omap16xxcam_init_dma(data);
+
+       return omap16xx_cam_link_open(data);
+}
+
+static int
+omap16xxcam_close(void *priv)
+{
+       struct omap16xxcam *data = (struct omap16xxcam *) priv;
+
+       omap16xxcam_disable(priv);
+        
+       free_irq(INT_CAMERA, data);
+       
+       return omap16xx_cam_link_close(data);
+}
+
+static int
+omap16xxcam_cleanup(void *priv)
+{
+       struct omap16xxcam *data = (struct omap16xxcam *) priv;
+
+       if (!data->camera_regs)
+               return -EINVAL;
+
+       omap16xxcam_disable(data);
+       if (cpu_is_omap1710())
+               iounmap((void *)data->camera_regs);
+       data->camera_regs= NULL;
+
+       if (data->iobase_phys) {
+               release_mem_region(data->iobase_phys, CAMERA_IOSIZE);
+               data->iobase_phys = 0;
+       }
+
+       if (hardware_data.func_clk) {
+               clk_disable(hardware_data.func_clk);
+               clk_put(hardware_data.func_clk);
+               hardware_data.func_clk = NULL;
+       }
+
+       return 0;
+}
+
+/* Initialise the OMAP camera interface */
+static void *
+omap16xxcam_init(void)
+{
+       unsigned long cam_iobase;
+
+       if (!request_mem_region(CAMERA_BASE, CAMERA_IOSIZE,
+                               camera_hardware_if.name)) {
+               pr_debug("%s is already in use\n", camera_hardware_if.name);
+               return NULL;
+       }
+
+       if (cpu_is_omap1710()) {
+               cam_iobase = (unsigned long) ioremap (CAMERA_BASE,
+                               CAMERA_IOSIZE);
+               if (!cam_iobase) {
+                       printk("CANNOT MAP CAMERA REGISTER\n");
+                       return NULL;
+               }
+       }
+       else
+               cam_iobase = io_p2v(CAMERA_BASE);
+
+       /* Set the base address of the camera registers */
+       hardware_data.camera_regs = (camera_regs_t *)cam_iobase;
+       hardware_data.iobase_phys = (unsigned long) CAMERA_BASE;
+
+       /* get the input clock value to camera interface and store it */
+       if (cpu_is_omap1710())
+               hardware_data.func_clk = clk_get(0, "tc2_ck");
+       else
+               hardware_data.func_clk = clk_get(0, "armper_ck");
+       hardware_data.ocp_clk = clk_get_rate(hardware_data.func_clk);
+
+       /* Init the camera IF */
+       omap16xx_cam_init();
+       /* enable it. This is needed for sensor detection */
+       omap16xxcam_enable((void*)&hardware_data);
+       /* Init dma data */
+       spin_lock_init(&hardware_data.dma_lock);
+
+       init_waitqueue_head(&hardware_data.vsync_wait);
+       return (void*)&hardware_data;
+}
+
+struct camera_hardware camera_hardware_if = {
+       .version        = 0x01,
+       .name           = "OMAP16xx Parallel Camera",
+       .init           = omap16xxcam_init,
+       .cleanup        = omap16xxcam_cleanup,
+       .open           = omap16xxcam_open,
+       .close          = omap16xxcam_close,
+       .enable         = omap16xxcam_enable,
+       .disable        = omap16xxcam_disable,
+       .abort          = omap16xxcam_abort,
+       .set_xclk       = omap16xxcam_set_xclk,
+       .init_dma       = omap16xxcam_init_dma,
+       .start_dma      = omap16xxcam_start_dma,
+       .finish_dma     = omap16xxcam_finish_dma,
+};
+
diff --git a/drivers/media/video/omap/omap16xxcam.h b/drivers/media/video/omap/omap16xxcam.h
new file mode 100644 (file)
index 0000000..14de5b7
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ *  drivers/media/video/omap/omap16xxcam.h
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc. 
+ * 
+ * This package is free software; you can redistribute it and/or modify 
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation. 
+ * 
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 
+ */
+#ifndef OMAP_16XX_CAM_H
+#define OMAP_16XX_CAM_H
+
+#define DMA_ELEM_SIZE   4
+#define FIFO_TRIGGER_LVL (32)
+
+/*
+ * ---------------------------------------------------------------------------
+ *  OMAP1610 Camera Interface
+ * ---------------------------------------------------------------------------
+ */
+
+#ifdef CONFIG_MACH_OMAP_H3
+#define CAMERA_BASE          (0x2007d800)
+#else
+#define CAMERA_BASE          (IO_PHYS + 0x6800)
+#endif
+
+#define CAM_CTRLCLOCK_REG    (CAMERA_BASE + 0x00)
+#define CAM_IT_STATUS_REG    (CAMERA_BASE + 0x04)
+#define CAM_MODE_REG         (CAMERA_BASE + 0x08)
+#define CAM_STATUS_REG       (CAMERA_BASE + 0x0C)
+#define CAM_CAMDATA_REG      (CAMERA_BASE + 0x10)
+#define CAM_GPIO_REG         (CAMERA_BASE + 0x14)
+#define CAM_PEAK_CTR_REG     (CAMERA_BASE + 0x18)
+#define CAMERA_IOSIZE        0x1C
+
+/* CTRLCLOCK bit shifts */
+#define FOSCMOD_BIT                    0
+#define FOSCMOD_MASK                   (0x7 << FOSCMOD_BIT)
+#define FOSCMOD_12MHz          0x0
+#define        FOSCMOD_6MHz            0x2
+#define        FOSCMOD_9_6MHz          0x4
+#define        FOSCMOD_24MHz           0x5
+#define        FOSCMOD_8MHz            0x6
+#define        FOSCMOD_TC2_CK2         0x3
+#define        FOSCMOD_TC2_CK3         0x1
+#define        FOSCMOD_TC2_CK4         0x5
+#define        FOSCMOD_TC2_CK8         0x0
+#define        FOSCMOD_TC2_CK10        0x4
+#define        FOSCMOD_TC2_CK12        0x6
+#define        FOSCMOD_TC2_CK16        0x2
+#define        POLCLK                  (1<<3)
+#define        CAMEXCLK_EN             (1<<4)
+#define        MCLK_EN                 (1<<5)
+#define        DPLL_EN                 (1<<6)
+#define        LCLK_EN                 (1<<7)
+
+/* IT_STATUS bit shifts */
+#define V_UP           (1<<0)
+#define V_DOWN         (1<<1)
+#define H_UP           (1<<2)
+#define H_DOWN         (1<<3)
+#define FIFO_FULL      (1<<4)
+#define DATA_XFER      (1<<5)
+
+/* MODE bit shifts */
+#define CAMOSC         (1<<0)
+#define IMGSIZE_BIT    1
+#define IMGSIZE_MASK   (0x3 << IMGSIZE_BIT)
+#define        IMGSIZE_CIF      (0x0 << IMGSIZE_BIT)    /* 352x288 */
+#define        IMGSIZE_QCIF     (0x1 << IMGSIZE_BIT)    /* 176x144 */
+#define        IMGSIZE_VGA      (0x2 << IMGSIZE_BIT)    /* 640x480 */
+#define        IMGSIZE_QVGA     (0x3 << IMGSIZE_BIT)    /* 320x240 */
+#define ORDERCAMD      (1<<3)
+#define EN_V_UP        (1<<4)
+#define EN_V_DOWN      (1<<5)
+#define EN_H_UP        (1<<6)
+#define EN_H_DOWN      (1<<7)
+#define EN_DMA         (1<<8)
+#define THRESHOLD      (1<<9)
+#define THRESHOLD_BIT  9
+#define THRESHOLD_MASK (0x7f<<9)
+#define EN_NIRQ        (1<<16)
+#define EN_FIFO_FULL   (1<<17)
+#define RAZ_FIFO       (1<<18)
+
+/* STATUS bit shifts */
+#define VSTATUS        (1<<0)
+#define HSTATUS        (1<<1)
+
+/* GPIO bit shifts */
+#define CAM_RST        (1<<0)
+
+
+#define XCLK_6MHZ     6000000
+#define XCLK_8MHZ     8000000
+#define XCLK_9_6MHZ   9000000
+#define XCLK_12MHZ   12000000
+#define XCLK_24MHZ   24000000
+
+#endif /* OMAP_16XX_CAM_H */
diff --git a/drivers/media/video/omap/ov9640.h b/drivers/media/video/omap/ov9640.h
new file mode 100644 (file)
index 0000000..4cdba05
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * drivers/media/video/omap/ov9640.h
+ *
+ * Register definitions for the OmniVision OV9640 CameraChip.
+ *
+ * Author: Andy Lowe (source@mvista.com)
+ *
+ * Copyright (C) 2004 MontaVista Software, Inc.
+ * Copyright (C) 2004 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License 
+ * version 2. This program is licensed "as is" without any warranty of any 
+ * kind, whether express or implied.
+ */
+
+#ifndef OV9640_H
+#define OV9640_H
+
+/* The OV9640 I2C sensor chip has a fixed slave address of 0x30. */
+#ifdef CONFIG_OMAP24XX_VIRTIO
+#define OV9640_I2C_ADDR                0x60
+#else
+#define OV9640_I2C_ADDR                0x30
+#endif
+
+/* define register offsets for the OV9640 sensor chip */
+#define OV9640_GAIN            0x00
+#define OV9640_BLUE            0x01
+#define OV9640_RED             0x02
+#define OV9640_VREF            0x03
+#define OV9640_COM1            0x04
+#define OV9640_BAVE            0x05
+#define OV9640_GEAVE           0x06
+#define OV9640_RAVE            0x08
+#define OV9640_COM2            0x09
+#define OV9640_PID             0x0A
+#define OV9640_VER             0x0B
+#define OV9640_COM3            0x0C
+#define OV9640_COM4            0x0D
+#define OV9640_COM5            0x0E
+#define OV9640_COM6            0x0F
+#define OV9640_AECH            0x10
+#define OV9640_CLKRC           0x11
+#define OV9640_COM7            0x12
+#define OV9640_COM8            0x13
+#define OV9640_COM9            0x14
+#define OV9640_COM10           0x15
+#define OV9640_HSTRT           0x17
+#define OV9640_HSTOP           0x18
+#define OV9640_VSTRT           0x19
+#define OV9640_VSTOP           0x1A
+#define OV9640_PSHFT           0x1B
+#define OV9640_MIDH            0x1C
+#define OV9640_MIDL            0x1D
+#define OV9640_MVFP            0x1E
+#define OV9640_LAEC            0x1F
+#define OV9640_BOS             0x20
+#define OV9640_GBOS            0x21
+#define OV9640_GROS            0x22
+#define OV9640_ROS             0x23
+#define OV9640_AEW             0x24
+#define OV9640_AEB             0x25
+#define OV9640_VPT             0x26
+#define OV9640_BBIAS           0x27
+#define OV9640_GBBIAS          0x28
+#define OV9640_EXHCH           0x2A
+#define OV9640_EXHCL           0x2B
+#define OV9640_RBIAS           0x2C
+#define OV9640_ADVFL           0x2D
+#define OV9640_ADVFH           0x2E
+#define OV9640_YAVE            0x2F
+#define OV9640_HSYST           0x30
+#define OV9640_HSYEN           0x31
+#define OV9640_HREF            0x32
+#define OV9640_CHLF            0x33
+#define OV9640_ARBLM           0x34
+#define OV9640_ADC             0x37
+#define OV9640_ACOM            0x38
+#define OV9640_OFON            0x39
+#define OV9640_TSLB            0x3A
+#define OV9640_COM11           0x3B
+#define OV9640_COM12           0x3C
+#define OV9640_COM13           0x3D
+#define OV9640_COM14           0x3E
+#define OV9640_EDGE            0x3F
+#define OV9640_COM15           0x40
+#define OV9640_COM16           0x41
+#define OV9640_COM17           0x42
+#define OV9640_MTX1            0x4F
+#define OV9640_MTX2            0x50
+#define OV9640_MTX3            0x51
+#define OV9640_MTX4            0x52
+#define OV9640_MTX5            0x53
+#define OV9640_MTX6            0x54
+#define OV9640_MTX7            0x55
+#define OV9640_MTX8            0x56
+#define OV9640_MTX9            0x57
+#define OV9640_MTXS            0x58
+#define OV9640_LCC1            0x62
+#define OV9640_LCC2            0x63
+#define OV9640_LCC3            0x64
+#define OV9640_LCC4            0x65
+#define OV9640_LCC5            0x66
+#define OV9640_MANU            0x67
+#define OV9640_MANV            0x68
+#define OV9640_HV              0x69
+#define OV9640_MBD             0x6A
+#define OV9640_DBLV            0x6B
+#define OV9640_GSP1            0x6C
+#define OV9640_GSP2            0x6D
+#define OV9640_GSP3            0x6E
+#define OV9640_GSP4            0x6F
+#define OV9640_GSP5            0x70
+#define OV9640_GSP6            0x71
+#define OV9640_GSP7            0x72
+#define OV9640_GSP8            0x73
+#define OV9640_GSP9            0x74
+#define OV9640_GSP10           0x75
+#define OV9640_GSP11           0x76
+#define OV9640_GSP12           0x77
+#define OV9640_GSP13           0x78
+#define OV9640_GSP14           0x79
+#define OV9640_GSP15           0x7A
+#define OV9640_GSP16           0x7B
+#define OV9640_GST1            0x7C
+#define OV9640_GST2            0x7D
+#define OV9640_GST3            0x7E
+#define OV9640_GST4            0x7F
+#define OV9640_GST5            0x80
+#define OV9640_GST6            0x81
+#define OV9640_GST7            0x82
+#define OV9640_GST8            0x83
+#define OV9640_GST9            0x84
+#define OV9640_GST10           0x85
+#define OV9640_GST11           0x86
+#define OV9640_GST12           0x87
+#define OV9640_GST13           0x88
+#define OV9640_GST14           0x89
+#define OV9640_GST15           0x8A
+
+#define OV9640_NUM_REGS                (OV9640_GST15 + 1)
+
+#define OV9640_PID_MAGIC       0x96    /* high byte of product ID number */
+#define OV9640_VER_REV2                0x48    /* low byte of product ID number */
+#define OV9640_VER_REV3                0x49    /* low byte of product ID number */
+#define OV9640_MIDH_MAGIC      0x7F    /* high byte of mfg ID */
+#define OV9640_MIDL_MAGIC      0xA2    /* low byte of mfg ID */
+
+/* define a structure for ov9640 register initialization values */
+struct ov9640_reg {
+       unsigned char reg;
+       unsigned char val;
+};
+
+enum image_size { QQCIF, QQVGA, QCIF, QVGA, CIF, VGA, SXGA };
+enum pixel_format { YUV, RGB565, RGB555 };
+#define NUM_IMAGE_SIZES 7
+#define NUM_PIXEL_FORMATS 3
+
+struct capture_size {
+       unsigned long width;
+       unsigned long height;
+};
+
+/* Array of image sizes supported by OV9640.  These must be ordered from 
+ * smallest image size to largest.
+ */
+const static struct capture_size ov9640_sizes[] = {
+       {   88,  72 },  /* QQCIF */
+       {  160, 120 },  /* QQVGA */
+       {  176, 144 },  /* QCIF */
+       {  320, 240 },  /* QVGA */
+       {  352, 288 },  /* CIF */
+       {  640, 480 },  /* VGA */
+       { 1280, 960 },  /* SXGA */
+};
+
+#endif /* ifndef OV9640_H */
+
diff --git a/drivers/media/video/omap/sensor_if.h b/drivers/media/video/omap/sensor_if.h
new file mode 100644 (file)
index 0000000..47bb716
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * drivers/media/video/omap/sensor_if.h
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc. 
+ * 
+ * Sensor interface to OMAP camera capture drivers
+ * Sensor driver should implement this interface
+ *
+ * This package is free software; you can redistribute it and/or modify 
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation. 
+ * 
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 
+ */
+#ifndef OMAP_SENSOR_IF_H
+#define OMAP_SENSOR_IF_H
+
+#define OMAP_SENSOR_NAME_LEN           31
+
+struct omap_camera_sensor {
+       unsigned int version;
+       char name[OMAP_SENSOR_NAME_LEN + 1];
+
+       void *(*init)(struct v4l2_pix_format *);
+       int (*cleanup)(void *);
+
+       int (*power_on)(void *);
+       int (*power_off)(void *);
+
+       int (*enum_pixformat)(struct v4l2_fmtdesc *, void *);
+       int (*try_format)(struct v4l2_pix_format *, void *);
+
+       unsigned long (*calc_xclk)(struct v4l2_pix_format *,
+                                  struct v4l2_fract *, void *);
+
+       int (*configure)(struct v4l2_pix_format *, unsigned long,
+                        struct v4l2_fract *, void *);
+
+       int (*query_control) (struct v4l2_queryctrl *, void *);
+       int (*get_control)(struct v4l2_control *, void *);
+       int (*set_control)(struct v4l2_control *, void *);
+
+};
+
+extern struct omap_camera_sensor camera_sensor_if;
+
+#endif
diff --git a/drivers/media/video/omap/sensor_ov9640.c b/drivers/media/video/omap/sensor_ov9640.c
new file mode 100644 (file)
index 0000000..78c8250
--- /dev/null
@@ -0,0 +1,1220 @@
+
+/*
+ * drivers/media/video/omap/sensor_ov9640.c
+ *
+ * Ov9640 Sensor driver for OMAP camera sensor interface
+ *
+ * Author: Andy Lowe (source@mvista.com)
+ *
+ * Copyright (C) 2004 MontaVista Software, Inc.
+ * Copyright (C) 2004 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License 
+ * version 2. This program is licensed "as is" without any warranty of any 
+ * kind, whether express or implied.
+ */
+
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/videodev.h>
+#include <media/video-buf.h>
+#include <linux/delay.h>
+#include <asm/mach-types.h>
+#include <asm/arch/gpio.h>
+
+#include "sensor_if.h"
+#include "ov9640.h"
+#include "h3sensorpower.h"
+#include "h4sensorpower.h"
+
+
+struct ov9640_sensor {
+       /* I2C parameters */
+       struct i2c_client client;
+       int ver; /* OV9640 version */
+};
+
+static struct ov9640_sensor ov9640;
+
+/* list of image formats supported by OV9640 sensor */
+const static struct v4l2_fmtdesc ov9640_formats[] = {
+       {
+               /* Note:  V4L2 defines RGB565 as:
+                *
+                *      Byte 0                    Byte 1
+                *      g2 g1 g0 r4 r3 r2 r1 r0   b4 b3 b2 b1 b0 g5 g4 g3
+                *
+                * We interpret RGB565 as:
+                *
+                *      Byte 0                    Byte 1
+                *      g2 g1 g0 b4 b3 b2 b1 b0   r4 r3 r2 r1 r0 g5 g4 g3
+                */
+               .description    = "RGB565, le",
+               .pixelformat    = V4L2_PIX_FMT_RGB565,
+       },{
+               /* Note:  V4L2 defines RGB565X as:
+                *
+                *      Byte 0                    Byte 1
+                *      b4 b3 b2 b1 b0 g5 g4 g3   g2 g1 g0 r4 r3 r2 r1 r0
+                *
+                * We interpret RGB565X as:
+                *
+                *      Byte 0                    Byte 1
+                *      r4 r3 r2 r1 r0 g5 g4 g3   g2 g1 g0 b4 b3 b2 b1 b0
+                */
+               .description    = "RGB565, be",
+               .pixelformat    = V4L2_PIX_FMT_RGB565X,
+       },
+       {
+               .description    = "YUYV (YUV 4:2:2), packed",
+               .pixelformat    = V4L2_PIX_FMT_YUYV,
+       },{
+               .description    = "UYVY, packed",
+               .pixelformat    = V4L2_PIX_FMT_UYVY,
+       },
+       {
+               /* Note:  V4L2 defines RGB555 as:
+                *
+                *      Byte 0                    Byte 1
+                *      g2 g1 g0 r4 r3 r2 r1 r0   x  b4 b3 b2 b1 b0 g4 g3
+                *
+                * We interpret RGB555 as:
+                *
+                *      Byte 0                    Byte 1
+                *      g2 g1 g0 b4 b3 b2 b1 b0   x  r4 r3 r2 r1 r0 g4 g3
+                */
+               .description    = "RGB555, le",
+               .pixelformat    = V4L2_PIX_FMT_RGB555,
+       },{
+               /* Note:  V4L2 defines RGB555X as:
+                *
+                *      Byte 0                    Byte 1
+                *      x  b4 b3 b2 b1 b0 g4 g3   g2 g1 g0 r4 r3 r2 r1 r0
+                *
+                * We interpret RGB555X as:
+                *
+                *      Byte 0                    Byte 1
+                *      x  r4 r3 r2 r1 r0 g4 g3   g2 g1 g0 b4 b3 b2 b1 b0
+                */
+               .description    = "RGB555, be",
+               .pixelformat    = V4L2_PIX_FMT_RGB555X,
+       }
+};
+
+#define NUM_CAPTURE_FORMATS ARRAY_SIZE(ov9640_formats)
+#ifdef CONFIG_ARCH_OMAP24XX
+#define NUM_OVERLAY_FORMATS 4
+#else
+#define NUM_OVERLAY_FORMATS 2
+#endif
+
+/* register initialization tables for OV9640 */
+
+#define OV9640_REG_TERM 0xFF   /* terminating list entry for reg */
+#define OV9640_VAL_TERM 0xFF   /* terminating list entry for val */
+
+/* common OV9640 register initialization for all image sizes, pixel formats, 
+ * and frame rates
+ */
+const static struct ov9640_reg ov9640_common[] = {
+#ifdef CONFIG_ARCH_OMAP24XX
+       { 0x12, 0x80 }, { 0x11, 0x80 }, { 0x13, 0x8F }, /* COM7, CLKRC, COM8 */
+       { 0x01, 0x80 }, { 0x02, 0x80 }, { 0x04, 0x00 }, /* BLUE, RED, COM1 */
+       { 0x0E, 0x81 }, { 0x0F, 0x4F }, { 0x14, 0x4A }, /* COM5, COM6, COM9 */
+#else
+       { 0x12, 0x80 }, { 0x11, 0x80 }, { 0x13, 0x88 }, /* COM7, CLKRC, COM8 */
+       { 0x01, 0x58 }, { 0x02, 0x24 }, { 0x04, 0x00 }, /* BLUE, RED, COM1 */
+       { 0x0E, 0x81 }, { 0x0F, 0x4F }, { 0x14, 0xcA }, /* COM5, COM6, COM9 */
+#endif
+       { 0x16, 0x02 }, { 0x1B, 0x01 }, { 0x24, 0x70 }, /* ?, PSHFT, AEW */
+       { 0x25, 0x68 }, { 0x26, 0xD3 }, { 0x27, 0x90 }, /* AEB, VPT, BBIAS */
+       { 0x2A, 0x00 }, { 0x2B, 0x00 }, { 0x32, 0x24 }, /* EXHCH, EXHCL, HREF */
+       { 0x33, 0x02 }, { 0x37, 0x02 }, { 0x38, 0x13 }, /* CHLF, ADC, ACOM */
+       { 0x39, 0xF0 }, { 0x3A, 0x00 }, { 0x3B, 0x01 }, /* OFON, TSLB, COM11 */
+       { 0x3D, 0x90 }, { 0x3E, 0x02 }, { 0x3F, 0xF2 }, /* COM13, COM14, EDGE */
+       { 0x41, 0x02 }, { 0x42, 0xC8 },         /* COM16, COM17 */
+       { 0x43, 0xF0 }, { 0x44, 0x10 }, { 0x45, 0x6C }, /* ?, ?, ? */
+       { 0x46, 0x6C }, { 0x47, 0x44 }, { 0x48, 0x44 }, /* ?, ?, ? */
+       { 0x49, 0x03 }, { 0x59, 0x49 }, { 0x5A, 0x94 }, /* ?, ?, ? */
+       { 0x5B, 0x46 }, { 0x5C, 0x84 }, { 0x5D, 0x5C }, /* ?, ?, ? */
+       { 0x5E, 0x08 }, { 0x5F, 0x00 }, { 0x60, 0x14 }, /* ?, ?, ? */
+       { 0x61, 0xCE },                                 /* ? */
+       { 0x62, 0x70 }, { 0x63, 0x00 }, { 0x64, 0x04 }, /* LCC1, LCC2, LCC3 */
+       { 0x65, 0x00 }, { 0x66, 0x00 },                 /* LCC4, LCC5 */
+       { 0x69, 0x00 }, { 0x6A, 0x3E }, { 0x6B, 0x3F }, /* HV, MBD, DBLV */
+       { 0x6C, 0x40 }, { 0x6D, 0x30 }, { 0x6E, 0x4B }, /* GSP1, GSP2, GSP3 */
+       { 0x6F, 0x60 }, { 0x70, 0x70 }, { 0x71, 0x70 }, /* GSP4, GSP5, GSP6 */
+       { 0x72, 0x70 }, { 0x73, 0x70 }, { 0x74, 0x60 }, /* GSP7, GSP8, GSP9 */
+       { 0x75, 0x60 }, { 0x76, 0x50 }, { 0x77, 0x48 }, /* GSP10,GSP11,GSP12 */
+       { 0x78, 0x3A }, { 0x79, 0x2E }, { 0x7A, 0x28 }, /* GSP13,GSP14,GSP15 */
+       { 0x7B, 0x22 }, { 0x7C, 0x04 }, { 0x7D, 0x07 }, /* GSP16,GST1, GST2 */
+       { 0x7E, 0x10 }, { 0x7F, 0x28 }, { 0x80, 0x36 }, /* GST3, GST4, GST5 */
+       { 0x81, 0x44 }, { 0x82, 0x52 }, { 0x83, 0x60 }, /* GST6, GST7, GST8 */
+       { 0x84, 0x6C }, { 0x85, 0x78 }, { 0x86, 0x8C }, /* GST9, GST10,GST11 */
+       { 0x87, 0x9E }, { 0x88, 0xBB }, { 0x89, 0xD2 }, /* GST12,GST13,GST14 */
+#ifdef CONFIG_ARCH_OMAP24XX
+       { 0x8A, 0xE6 }, { 0x13, 0x8F }, { 0x00, 0x7F }, /* GST15, COM8 */
+#else
+       { 0x8A, 0xE6 }, { 0x13, 0xaF }, { 0x15, 0x02 }, /* GST15, COM8 */
+       { 0x22, 0x8a }, /* GROS */
+#endif
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+
+/* OV9640 register configuration for all combinations of pixel format and 
+ * image size
+ */
+       /* YUV (YCbCr) QQCIF */
+const static struct ov9640_reg qqcif_yuv[] = {
+       { 0x12, 0x08 }, { 0x3C, 0x46 }, { 0x40, 0xC0 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x24 }, { 0x0C, 0x00 }, { 0x0D, 0x40 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x50 }, { 0x50, 0x43 }, { 0x51, 0x0D }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x19 }, { 0x53, 0x4C }, { 0x54, 0x65 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x40 }, { 0x56, 0x40 }, { 0x57, 0x40 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x0F },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* YUV (YCbCr) QQVGA */
+const static struct ov9640_reg qqvga_yuv[] = {
+       { 0x12, 0x10 }, { 0x3C, 0x46 }, { 0x40, 0xC0 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x24 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x50 }, { 0x50, 0x43 }, { 0x51, 0x0D }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x19 }, { 0x53, 0x4C }, { 0x54, 0x65 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x40 }, { 0x56, 0x40 }, { 0x57, 0x40 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x0F },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* YUV (YCbCr) QCIF */
+const static struct ov9640_reg qcif_yuv[] = {
+       { 0x12, 0x08 }, { 0x3C, 0x46 }, { 0x40, 0xC0 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x50 }, { 0x50, 0x43 }, { 0x51, 0x0D }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x19 }, { 0x53, 0x4C }, { 0x54, 0x65 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x40 }, { 0x56, 0x40 }, { 0x57, 0x40 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x0F },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* YUV (YCbCr) QVGA */
+const static struct ov9640_reg qvga_yuv[] = {
+       { 0x12, 0x10 }, { 0x3C, 0x46 }, { 0x40, 0xC0 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x50 }, { 0x50, 0x43 }, { 0x51, 0x0D }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x19 }, { 0x53, 0x4C }, { 0x54, 0x65 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x40 }, { 0x56, 0x40 }, { 0x57, 0x40 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x0F },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* YUV (YCbCr) CIF */
+const static struct ov9640_reg cif_yuv[] = {
+       { 0x12, 0x20 }, { 0x3C, 0x46 }, { 0x40, 0xC0 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x50 }, { 0x50, 0x43 }, { 0x51, 0x0D }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x19 }, { 0x53, 0x4C }, { 0x54, 0x65 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x40 }, { 0x56, 0x40 }, { 0x57, 0x40 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x0F },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* YUV (YCbCr) VGA */
+const static struct ov9640_reg vga_yuv[] = {
+       { 0x12, 0x40 }, { 0x3C, 0x46 }, { 0x40, 0xC0 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x50 }, { 0x50, 0x43 }, { 0x51, 0x0D }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x19 }, { 0x53, 0x4C }, { 0x54, 0x65 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x40 }, { 0x56, 0x40 }, { 0x57, 0x40 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x0F },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* YUV (YCbCr) SXGA */
+const static struct ov9640_reg sxga_yuv[] = {
+       { 0x12, 0x00 }, { 0x3C, 0x46 }, { 0x40, 0xC0 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x00 }, { 0x0C, 0x00 }, { 0x0D, 0x40 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x50 }, { 0x50, 0x43 }, { 0x51, 0x0D }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x19 }, { 0x53, 0x4C }, { 0x54, 0x65 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x40 }, { 0x56, 0x40 }, { 0x57, 0x40 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x0F },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* RGB565 QQCIF */
+const static struct ov9640_reg qqcif_565[] = {
+       { 0x12, 0x0C }, { 0x3C, 0x40 }, { 0x40, 0x10 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x24 }, { 0x0C, 0x00 }, { 0x0D, 0x40 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x65 },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* RGB565 QQVGA */
+const static struct ov9640_reg qqvga_565[] = {
+       { 0x12, 0x14 }, { 0x3C, 0x40 }, { 0x40, 0x10 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x24 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x65 },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* RGB565 QCIF */
+const static struct ov9640_reg qcif_565[] = {
+       { 0x12, 0x0C }, { 0x3C, 0x40 }, { 0x40, 0x10 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x65 },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* RGB565 QVGA */
+const static struct ov9640_reg qvga_565[] = {
+       { 0x12, 0x14 }, { 0x3C, 0x40 }, { 0x40, 0x10 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x65 },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* RGB565 CIF */
+const static struct ov9640_reg cif_565[] = {
+       { 0x12, 0x24 }, { 0x3C, 0x40 }, { 0x40, 0x10 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x65 },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* RGB565 VGA */
+const static struct ov9640_reg vga_565[] = {
+       { 0x12, 0x44 }, { 0x3C, 0x40 }, { 0x40, 0x10 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x65 },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* RGB565 SXGA */
+const static struct ov9640_reg sxga_565[] = {
+       { 0x12, 0x04 }, { 0x3C, 0x40 }, { 0x40, 0x10 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x00 }, { 0x0C, 0x00 }, { 0x0D, 0x40 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x65 },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* RGB555 QQCIF */
+const static struct ov9640_reg qqcif_555[] = {
+       { 0x12, 0x0C }, { 0x3C, 0x40 }, { 0x40, 0x30 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x24 }, { 0x0C, 0x00 }, { 0x0D, 0x40 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x65 },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* RGB555 QQVGA */
+const static struct ov9640_reg qqvga_555[] = {
+       { 0x12, 0x14 }, { 0x3C, 0x40 }, { 0x40, 0x30 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x24 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x65 },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* RGB555 QCIF */
+const static struct ov9640_reg qcif_555[] = {
+       { 0x12, 0x0C }, { 0x3C, 0x40 }, { 0x40, 0x30 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x65 },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* RGB555 QVGA */
+const static struct ov9640_reg qvga_555[] = {
+       { 0x12, 0x14 }, { 0x3C, 0x40 }, { 0x40, 0x30 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x65 },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* RGB555 CIF */
+const static struct ov9640_reg cif_555[] = {
+       { 0x12, 0x24 }, { 0x3C, 0x40 }, { 0x40, 0x30 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x65 },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* RGB555 VGA */
+const static struct ov9640_reg vga_555[] = {
+       { 0x12, 0x44 }, { 0x3C, 0x40 }, { 0x40, 0x30 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x65 },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* RGB555 SXGA */
+const static struct ov9640_reg sxga_555[] = {
+       { 0x12, 0x04 }, { 0x3C, 0x40 }, { 0x40, 0x30 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x00 }, { 0x0C, 0x00 }, { 0x0D, 0x40 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x65 },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+
+#define DEF_GAIN         31
+#define DEF_AUTOGAIN      1
+#define DEF_EXPOSURE    154
+#define DEF_AEC           1
+#define DEF_FREEZE_AGCAEC 0
+#define DEF_BLUE        153
+#define DEF_RED         (255 - DEF_BLUE)
+#define DEF_AWB           1
+#define DEF_HFLIP         0
+#define DEF_VFLIP         0
+
+/* Our own specific controls */
+#define V4L2_CID_FREEZE_AGCAEC V4L2_CID_PRIVATE_BASE+0
+#define V4L2_CID_AUTOEXPOSURE V4L2_CID_PRIVATE_BASE+1
+#define V4L2_CID_LAST_PRIV  V4L2_CID_AUTOEXPOSURE
+
+/*  Video controls  */
+static struct vcontrol {
+        struct v4l2_queryctrl qc;
+        int current_value;
+        u8 reg;
+        u8 mask;
+        u8 start_bit;
+} control[] = {
+        { { V4L2_CID_GAIN, V4L2_CTRL_TYPE_INTEGER, "Gain", 0, 63, 1,
+            DEF_GAIN },
+          0, OV9640_GAIN, 0x3f, 0 },
+        { { V4L2_CID_AUTOGAIN, V4L2_CTRL_TYPE_BOOLEAN, "Auto Gain", 0, 1, 0,
+            DEF_AUTOGAIN },
+          0, OV9640_COM8, 0x04, 2 },
+        { { V4L2_CID_EXPOSURE, V4L2_CTRL_TYPE_INTEGER, "Exposure", 0, 255, 1,
+            DEF_EXPOSURE },
+          0, OV9640_AECH, 0xff, 0 },
+        { { V4L2_CID_AUTOEXPOSURE, V4L2_CTRL_TYPE_BOOLEAN, "Auto Exposure", 0, 1, 0,
+            DEF_AEC },
+          0, OV9640_COM8, 0x01, 0 },
+        { { V4L2_CID_FREEZE_AGCAEC, V4L2_CTRL_TYPE_BOOLEAN, "Freeze AGC/AEC", 0,1,0,
+            DEF_FREEZE_AGCAEC },
+          0, OV9640_COM9, 0x01, 0 },
+        { { V4L2_CID_RED_BALANCE, V4L2_CTRL_TYPE_INTEGER, "Red Balance", 0, 255, 1,
+            DEF_RED },
+          0, OV9640_RED, 0xff, 0 },
+        { { V4L2_CID_BLUE_BALANCE, V4L2_CTRL_TYPE_INTEGER, "Blue Balance", 0, 255, 1,
+            DEF_BLUE },
+          0, OV9640_BLUE, 0xff, 0 },
+        { { V4L2_CID_AUTO_WHITE_BALANCE, V4L2_CTRL_TYPE_BOOLEAN, "Auto White Balance", 0,1,0,
+            DEF_AWB },
+          0, OV9640_COM8, 0x02, 1 },
+        { { V4L2_CID_HFLIP, V4L2_CTRL_TYPE_BOOLEAN, "Mirror Image", 0, 1, 0,
+            DEF_HFLIP },
+          0, OV9640_MVFP, 0x20, 5 },
+        { { V4L2_CID_VFLIP, V4L2_CTRL_TYPE_BOOLEAN, "Vertical Flip", 0, 1, 0,
+            DEF_VFLIP },
+          0, OV9640_MVFP, 0x10, 4 },
+};
+
+#define NUM_CONTROLS ARRAY_SIZE(control)
+
+const static struct ov9640_reg *
+       ov9640_reg_init[NUM_PIXEL_FORMATS][NUM_IMAGE_SIZES] =
+{
+ { qqcif_yuv, qqvga_yuv, qcif_yuv, qvga_yuv, cif_yuv, vga_yuv, sxga_yuv },
+ { qqcif_565, qqvga_565, qcif_565, qvga_565, cif_565, vga_565, sxga_565 },
+ { qqcif_555, qqvga_555, qcif_555, qvga_555, cif_555, vga_555, sxga_555 },
+};
+
+
+/* 
+ * Read a value from a register in an OV9640 sensor device.  The value is 
+ * returned in 'val'.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int 
+ov9640_read_reg(struct i2c_client *client, u8 reg, u8 *val)
+{
+       int err;
+       struct i2c_msg msg[1];
+       unsigned char data[1];
+
+       if (!client->adapter)
+               return -ENODEV;
+
+       msg->addr = client->addr;
+       msg->flags = 0;
+       msg->len = 1;
+       msg->buf = data;
+       *data = reg;
+       err = i2c_transfer(client->adapter, msg, 1);
+       if (err >= 0) {
+               msg->flags = I2C_M_RD;
+               err = i2c_transfer(client->adapter, msg, 1);
+       }
+       if (err >= 0) {
+               *val = *data;
+               return 0;
+       }
+       return err;
+}
+
+/* Write a value to a register in an OV9640 sensor device.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int 
+ov9640_write_reg(struct i2c_client *client, u8 reg, u8 val)
+{
+       int err;
+       struct i2c_msg msg[1];
+       unsigned char data[2];
+
+       if (!client->adapter)
+               return -ENODEV;
+       
+       msg->addr = client->addr;
+       msg->flags = 0;
+       msg->len = 2;
+       msg->buf = data;
+       data[0] = reg;
+       data[1] = val;
+       err = i2c_transfer(client->adapter, msg, 1);
+       if (err >= 0)
+               return 0;
+       return err;
+}
+
+static int 
+ov9640_write_reg_mask(struct i2c_client *client, u8 reg, u8 *val, u8 mask)
+{
+       u8 oldval, newval;
+       int rc;
+
+       if (mask == 0xff)
+               newval = *val;
+       else {
+               /* need to do read - modify - write */
+               if ((rc = ov9640_read_reg(client, reg, &oldval)))
+                       return rc;
+               oldval &= (~mask);              /* Clear the masked bits */
+               *val &= mask;                  /* Enforce mask on value */
+               newval = oldval | *val;        /* Set the desired bits */
+       }
+
+       /* write the new value to the register */
+       if ((rc = ov9640_write_reg(client, reg, newval)))
+               return rc;
+
+       if ((rc = ov9640_read_reg(client, reg, &newval)))
+               return rc;
+
+       *val = newval & mask;
+       return 0;
+}
+
+static int 
+ov9640_read_reg_mask(struct i2c_client *client, u8 reg, u8 *val, u8 mask)
+{
+       int rc;
+
+       if ((rc = ov9640_read_reg(client, reg, val)))
+               return rc;
+       (*val) &= mask;
+
+       return 0;
+}
+
+/* Initialize a list of OV9640 registers.
+ * The list of registers is terminated by the pair of values 
+ * { OV9640_REG_TERM, OV9640_VAL_TERM }.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int 
+ov9640_write_regs(struct i2c_client *client, const struct ov9640_reg reglist[])
+{
+       int err;
+       const struct ov9640_reg *next = reglist;
+       
+       while (!((next->reg == OV9640_REG_TERM) 
+               && (next->val == OV9640_VAL_TERM)))
+       {
+               err = ov9640_write_reg(client, next->reg, next->val);
+               udelay(100);
+               if (err)
+                       return err;
+               next++;
+       }
+       return 0;
+}
+
+/* Returns the index of the requested ID from the control structure array */
+static int
+find_vctrl(int id)
+{
+       int i;
+
+       if (id < V4L2_CID_BASE)
+               return -EDOM;
+
+       for (i = NUM_CONTROLS - 1; i >= 0; i--)
+               if (control[i].qc.id == id)
+                       break;
+       if (i < 0)
+               i = -EINVAL;
+       return i;
+}
+
+/* Calculate the internal clock divisor (value of the CLKRC register) of the 
+ * OV9640 given the image size, the frequency (in Hz) of its XCLK input and a 
+ * desired frame period (in seconds).  The frame period 'fper' is expressed as 
+ * a fraction.  The frame period is an input/output parameter.
+ * Returns the value of the OV9640 CLKRC register that will yield the frame 
+ * period returned in 'fper' at the specified xclk frequency.  The 
+ * returned period will be as close to the requested period as possible.
+ */
+static unsigned char
+ov9640_clkrc(enum image_size isize, unsigned long xclk, struct v4l2_fract *fper)
+{
+       unsigned long fpm, fpm_max;     /* frames per minute */
+       unsigned long divisor;
+       const unsigned long divisor_max = 64;
+#ifdef CONFIG_ARCH_OMAP24XX
+       const static unsigned long clks_per_frame[] =
+               { 200000, 400000, 200000, 400000, 400000, 800000, 3200000 };
+      /*         QQCIF   QQVGA    QCIF    QVGA  CIF     VGA    SXGA
+       *         199680,400000, 199680, 400000, 399360, 800000, 3200000
+       */
+#else
+       const static unsigned long clks_per_frame[] = 
+               { 200000, 200000, 200000, 200000, 400000, 800000, 3200000 };
+#endif
+
+       if (fper->numerator > 0)
+               fpm = (fper->denominator*60)/fper->numerator;
+       else
+               fpm = 0xffffffff;
+       fpm_max = (xclk*60)/clks_per_frame[isize];
+       if (fpm_max == 0)
+               fpm_max = 1;
+       if (fpm > fpm_max)
+               fpm = fpm_max;
+       if (fpm == 0)
+               fpm = 1;
+       divisor = fpm_max/fpm;
+       if (divisor > divisor_max)
+               divisor = divisor_max;
+       fper->numerator = divisor*60;
+       fper->denominator = fpm_max;
+
+       /* try to reduce the fraction */
+       while (!(fper->denominator % 5) && !(fper->numerator % 5)) {
+               fper->numerator /= 5;
+               fper->denominator /= 5;
+       }
+       while (!(fper->denominator % 3) && !(fper->numerator % 3)) {
+               fper->numerator /= 3;
+               fper->denominator /= 3;
+       }
+       while (!(fper->denominator % 2) && !(fper->numerator % 2)) {
+               fper->numerator /= 2;
+               fper->denominator /= 2;
+       }
+       if (fper->numerator < fper->denominator) {
+               if (!(fper->denominator % fper->numerator)) {
+                       fper->denominator /= fper->numerator;
+                       fper->numerator = 1;
+               }
+       }
+       else {
+               if (!(fper->numerator % fper->denominator)) {
+                       fper->numerator /= fper->denominator;
+                       fper->denominator = 1;
+               }
+       }
+
+       /* we set bit 7 in CLKRC to enable the digital PLL */
+       return (0x80 | (divisor - 1));
+}
+
+/* Configure the OV9640 for a specified image size, pixel format, and frame 
+ * period.  xclk is the frequency (in Hz) of the xclk input to the OV9640.  
+ * fper is the frame period (in seconds) expressed as a fraction.
+ * Returns zero if successful, or non-zero otherwise.
+ * The actual frame period is returned in fper.
+ */
+static int
+ov9640_configure(struct i2c_client *client, 
+       enum image_size isize, 
+       enum pixel_format pfmt,
+       unsigned long xclk,
+       struct v4l2_fract *fper)
+{
+       int err;
+       unsigned char clkrc;
+
+       /* common register initialization */
+       err = ov9640_write_regs(client, ov9640_common);
+       if (err)
+               return err;
+
+       /* configure image size and pixel format */
+       err = ov9640_write_regs(client, ov9640_reg_init[pfmt][isize]);
+       if (err)
+               return err;
+
+       /* configure frame rate */
+       clkrc = ov9640_clkrc(isize, xclk, fper);
+       err = ov9640_write_reg(client, OV9640_CLKRC, clkrc);
+       if (err)
+               return err;
+
+       return 0;
+}
+
+static int
+ov9640_powerup(void)
+{
+       int err;
+
+       if (machine_is_omap_h2())
+               return 0;
+
+#ifdef CONFIG_OMAP_OSK_MISTRAL
+       if (machine_is_omap_osk())
+               omap_set_gpio_dataout(11, 1);
+#endif
+
+       if (machine_is_omap_h3()) {
+               err = h3_sensor_powerup();
+               if (err)
+                       return err;
+       }
+
+       if (machine_is_omap_h4()) {
+               err = h4_sensor_powerup();
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+static int
+ov9640_powerdown(void)
+{
+       int err;
+
+       if (machine_is_omap_h2())
+               return 0;
+
+#ifdef CONFIG_OMAP_OSK_MISTRAL
+       if (machine_is_omap_osk())
+               omap_set_gpio_dataout(11, 0);
+#endif
+
+       if (machine_is_omap_h3()) {
+               err = h3_sensor_powerdown();
+               if (err)
+                       return err;
+       }
+
+       if (machine_is_omap_h4()) {
+               err = h4_sensor_powerdown();
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
+static int
+ov9640sensor_power_on(void *priv)
+{
+       return ov9640_powerup();
+}
+
+static int
+ov9640sensor_power_off(void *priv)
+{
+       return ov9640_powerdown();
+}
+
+/* Detect if an OV9640 is present, and if so which revision. 
+ * A device is considered to be detected if the manufacturer ID (MIDH and MIDL) 
+ * and the product ID (PID) registers match the expected values.  
+ * Any value of the version ID (VER) register is accepted.
+ * Here are the version numbers we know about:
+ *     0x48 --> OV9640 Revision 1 or OV9640 Revision 2
+ *     0x49 --> OV9640 Revision 3
+ * Returns a negative error number if no device is detected, or the 
+ * non-negative value of the version ID register if a device is detected.
+ */
+static int
+ov9640_detect(struct i2c_client *client)
+{
+       u8 midh, midl, pid, ver;
+
+       if (!client)
+               return -ENODEV;
+       if (ov9640_read_reg(client, OV9640_MIDH, &midh))
+               return -ENODEV;
+       if (ov9640_read_reg(client, OV9640_MIDL, &midl))
+               return -ENODEV;
+       if (ov9640_read_reg(client, OV9640_PID, &pid))
+               return -ENODEV;
+       if (ov9640_read_reg(client, OV9640_VER, &ver))
+               return -ENODEV;
+
+       if ((midh != OV9640_MIDH_MAGIC) 
+               || (midl != OV9640_MIDL_MAGIC)
+               || (pid != OV9640_PID_MAGIC))
+       {
+               /* We didn't read the values we expected, so 
+                * this must not be an OV9640.
+                */
+               return -ENODEV;
+       }
+       return ver;
+}
+
+static struct i2c_driver ov9640sensor_i2c_driver;
+
+/* This function registers an I2C client via i2c_attach_client() for an OV9640 
+ * sensor device.  If 'probe' is non-zero, then the I2C client is only 
+ * registered if the device can be detected.  If 'probe' is zero, then no 
+ * device detection is attempted and the I2C client is always registered.
+ * Returns zero if an I2C client is successfully registered, or non-zero 
+ * otherwise.
+ */
+static int 
+ov9640_i2c_attach_client(struct i2c_adapter *adap, int addr, int probe)
+{
+       struct ov9640_sensor *sensor = &ov9640;
+       struct i2c_client *client = &sensor->client;
+       int err;
+
+       if (client->adapter)
+               return -EBUSY;  /* our client is already attached */
+
+       client->addr = addr;
+       client->driver = &ov9640sensor_i2c_driver;
+       client->adapter = adap;
+       strcpy(client->name, ov9640sensor_i2c_driver.driver.name);
+
+       err = i2c_attach_client(client);
+       if (err) {
+               client->adapter = NULL;
+               return err;
+       }
+
+       if (probe) {
+               err = ov9640_detect(client);
+               if (err < 0) {
+                       i2c_detach_client(client);
+                       client->adapter = NULL;
+                       return err;
+               }
+               sensor->ver = err;
+       }
+       return 0;
+}
+
+/* This function is called by i2c_del_adapter() and i2c_del_driver() 
+ * if the adapter or driver with which this I2C client is associated is 
+ * removed.  This function unregisters the client via i2c_detach_client().
+ * Returns zero if the client is successfully detached, or non-zero 
+ * otherwise.
+ */
+static int 
+ov9640_i2c_detach_client(struct i2c_client *client)
+{
+       int err;
+
+       if (!client->adapter)
+               return -ENODEV; /* our client isn't attached */
+
+       err = i2c_detach_client(client);
+       client->adapter = NULL;
+
+       return err;
+}
+
+/* This function will be called for each registered I2C bus adapter when our 
+ * I2C driver is registered via i2c_add_driver().  It will also be called 
+ * whenever a new I2C adapter is registered after our I2C driver is registered.
+ * This function probes the specified I2C bus adapter to determine if an 
+ * OV9640 sensor device is present.  If a device is detected, an I2C client 
+ * is registered for it via ov9640_i2c_attach_client().  Note that we can't use 
+ * the standard i2c_probe() function to look for the sensor because the OMAP 
+ * I2C controller doesn't support probing.
+ * Returns zero if an OV9640 device is detected and an I2C client successfully 
+ * registered for it, or non-zero otherwise.
+ */
+static int 
+ov9640_i2c_probe_adapter(struct i2c_adapter *adap)
+{
+       return ov9640_i2c_attach_client(adap, OV9640_I2C_ADDR, 1);
+}
+
+/* Find the best match for a requested image capture size.  The best match 
+ * is chosen as the nearest match that has the same number or fewer pixels 
+ * as the requested size, or the smallest image size if the requested size 
+ * has fewer pixels than the smallest image.
+ */
+static enum image_size
+ov9640_find_size(unsigned int width, unsigned int height)
+{
+       enum image_size isize;
+       unsigned long pixels = width*height;
+
+       for (isize = QQCIF; isize < SXGA; isize++) {
+               if (ov9640_sizes[isize + 1].height*
+                       ov9640_sizes[isize + 1].width > pixels)
+               {
+                       return isize;
+               }
+       }
+       return SXGA;
+}
+
+/* following are sensor interface functions implemented by 
+ * OV9640 sensor driver.
+ */
+static int
+ov9640sensor_query_control(struct v4l2_queryctrl *qc, void *priv)
+{
+       int i;
+
+       i = find_vctrl (qc->id);
+       if (i == -EINVAL) {
+               qc->flags = V4L2_CTRL_FLAG_DISABLED;
+               return 0;
+       }
+       if (i < 0)
+               return -EINVAL;
+
+       *qc = control[i].qc;
+       return 0;
+}
+
+static int
+ov9640sensor_get_control(struct v4l2_control *vc, void *priv)
+{
+       struct ov9640_sensor *sensor = (struct ov9640_sensor *) priv;
+       struct i2c_client *client = &sensor->client;
+       int i, val;
+       struct vcontrol * lvc;
+       
+       i = find_vctrl(vc->id);
+       if (i < 0)
+               return -EINVAL;
+
+       lvc = &control[i];      
+       if (ov9640_read_reg_mask(client, lvc->reg, (u8 *)&val, lvc->mask))
+               return -EIO;
+               
+       val = val >> lvc->start_bit;    
+       if (val >= 0) {
+               vc->value = lvc->current_value = val;
+               return 0;
+       } else
+               return val;
+}
+
+static int
+ov9640sensor_set_control(struct v4l2_control *vc, void *priv)
+{
+       struct ov9640_sensor *sensor = (struct ov9640_sensor *) priv;
+       struct i2c_client *client = &sensor->client;
+       struct vcontrol *lvc;
+       int val = vc->value;
+       int i;
+
+       i = find_vctrl(vc->id);
+       if (i < 0)
+               return -EINVAL;
+
+       lvc = &control[i];
+       val = val << lvc->start_bit;
+       if (ov9640_write_reg_mask(client, lvc->reg, (u8 *)&val, (u8)lvc->mask))
+               return -EIO;
+
+       val = val>> lvc->start_bit;
+       if (val >= 0) {
+               lvc->current_value = val;
+               return 0;
+       } else
+               return val;
+}
+
+/* Implement the VIDIOC_ENUM_FMT ioctl for the CAPTURE buffer type.
+ */
+static int
+ov9640sensor_enum_pixformat(struct v4l2_fmtdesc *fmt, void *priv)
+{
+       int index = fmt->index;
+       enum v4l2_buf_type type = fmt->type;
+
+       memset(fmt, 0, sizeof(*fmt));
+       fmt->index = index;
+       fmt->type = type;
+
+       switch (fmt->type) {
+               case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+               if (index >= NUM_CAPTURE_FORMATS)
+                       return -EINVAL;
+               break;
+
+               case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+               if (index >= NUM_OVERLAY_FORMATS)
+                       return -EINVAL;
+               break;
+
+               default:
+                       return -EINVAL;
+       }
+
+       fmt->flags = ov9640_formats[index].flags;
+       strlcpy(fmt->description, ov9640_formats[index].description, sizeof(fmt->description));
+       fmt->pixelformat = ov9640_formats[index].pixelformat;
+
+       return 0;
+}
+
+/* Implement the VIDIOC_TRY_FMT ioctl for the CAPTURE buffer type.  This 
+ * ioctl is used to negotiate the image capture size and pixel format 
+ * without actually making it take effect.
+ */
+static int
+ov9640sensor_try_format(struct v4l2_pix_format *pix, void *priv)
+{
+       enum image_size isize;
+       int ifmt;
+
+       isize = ov9640_find_size(pix->width, pix->height);
+       pix->width = ov9640_sizes[isize].width;
+       pix->height = ov9640_sizes[isize].height;
+       for (ifmt = 0; ifmt < NUM_CAPTURE_FORMATS; ifmt++) {
+               if (pix->pixelformat == ov9640_formats[ifmt].pixelformat)
+                       break;
+       }
+       if (ifmt == NUM_CAPTURE_FORMATS)
+               ifmt = 0;
+       pix->pixelformat = ov9640_formats[ifmt].pixelformat;
+       pix->field = V4L2_FIELD_NONE;
+       pix->bytesperline = pix->width*2;
+       pix->sizeimage = pix->bytesperline*pix->height;
+       pix->priv = 0;
+       switch (pix->pixelformat) {
+               case V4L2_PIX_FMT_YUYV:
+               case V4L2_PIX_FMT_UYVY:
+               default:
+                       pix->colorspace = V4L2_COLORSPACE_JPEG;
+                       break;
+               case V4L2_PIX_FMT_RGB565:
+               case V4L2_PIX_FMT_RGB565X:
+               case V4L2_PIX_FMT_RGB555:
+               case V4L2_PIX_FMT_RGB555X:
+                       pix->colorspace = V4L2_COLORSPACE_SRGB;
+                       break;
+       }
+       return 0;
+}
+
+/* Given the image capture format in pix, the nominal frame period in 
+ * timeperframe, calculate the required xclk frequency 
+ * The nominal xclk input frequency of the OV9640 is 24MHz, maximum 
+ * frequency is 48MHz, and minimum frequency is 10MHz.
+ */
+static unsigned long
+ov9640sensor_calc_xclk(struct v4l2_pix_format *pix,
+                       struct v4l2_fract *timeperframe, void *priv)
+{
+       unsigned long tgt_xclk;                 /* target xclk */
+       unsigned long tgt_fpm;                  /* target frames per minute */
+       enum image_size isize;
+
+       /* We use arbitrary rules to select the xclk frequency.  If the 
+        * capture size is VGA and the frame rate is greater than 900 
+        * frames per minute, or if the capture size is SXGA and the 
+        * frame rate is greater than 450 frames per minutes, then the 
+        * xclk frequency will be set to 48MHz.  Otherwise, the xclk 
+        * frequency will be set to 24MHz.  If the mclk frequency is such that 
+        * the target xclk frequency is not achievable, then xclk will be set 
+        * as close as to the target as possible.
+        */
+       if ((timeperframe->numerator == 0) 
+               || (timeperframe->denominator == 0))
+       {
+               /* supply a default nominal_timeperframe of 15 fps */
+               timeperframe->numerator = 1;
+               timeperframe->denominator = 15;
+       }
+       tgt_fpm = (timeperframe->denominator*60)
+               / timeperframe->numerator;
+       tgt_xclk = 24000000;
+       isize = ov9640_find_size(pix->width, pix->height);
+       switch (isize) {
+               case SXGA:
+                       if (tgt_fpm > 450)
+                               tgt_xclk = 48000000;
+                       break;
+               case VGA:
+                       if (tgt_fpm > 900)
+                               tgt_xclk = 48000000;
+                       break;
+               default:
+                       break;
+       }
+       return tgt_xclk;
+}
+
+/* Given a capture format in pix, the frame period in timeperframe, and
+ * the xclk frequency, set the capture format of the OV9640 sensor.
+ * The actual frame period will be returned in timeperframe.
+ */
+static int
+ov9640sensor_configure(struct v4l2_pix_format *pix, unsigned long xclk,
+                       struct v4l2_fract *timeperframe, void *priv)
+{
+       struct ov9640_sensor *sensor = (struct ov9640_sensor *) priv;
+       enum pixel_format pfmt = YUV;
+
+       switch (pix->pixelformat) {
+               case V4L2_PIX_FMT_RGB565:
+               case V4L2_PIX_FMT_RGB565X:
+                       pfmt = RGB565;
+                       break;
+               case V4L2_PIX_FMT_RGB555:
+               case V4L2_PIX_FMT_RGB555X:
+                       pfmt = RGB555;
+                       break;
+               case V4L2_PIX_FMT_YUYV:
+               case V4L2_PIX_FMT_UYVY:
+               default:
+                       pfmt = YUV;
+       }
+
+       return ov9640_configure(&sensor->client,
+                               ov9640_find_size(pix->width, pix->height),
+                               pfmt, xclk, timeperframe);
+}
+
+/* Prepare for the driver to exit.
+ * Balances ov9640sensor_init().
+ * This function must de-initialize the sensor and its associated data 
+ * structures.
+ */
+static int
+ov9640sensor_cleanup(void *priv)
+{
+       struct ov9640_sensor *sensor = (struct ov9640_sensor *) priv;
+
+       if (sensor) {
+               i2c_del_driver(&ov9640sensor_i2c_driver);
+               ov9640_powerdown();
+       }
+       return 0;
+}
+
+
+static struct i2c_driver ov9640sensor_i2c_driver = {
+       .driver = {
+               .name           = "ov9640",
+       },
+       .id             = I2C_DRIVERID_MISC, /*FIXME:accroding to i2c-ids.h */
+       .attach_adapter = ov9640_i2c_probe_adapter,
+       .detach_client  = ov9640_i2c_detach_client,
+};
+
+
+/* Initialize the OV9640 sensor.
+ * This routine allocates and initializes the data structure for the sensor, 
+ * powers up the sensor, registers the I2C driver, and sets a default image 
+ * capture format in pix.  The capture format is not actually programmed 
+ * into the OV9640 sensor by this routine.
+ * This function must return a non-NULL value to indicate that 
+ * initialization is successful.
+ */
+static void *
+ov9640sensor_init(struct v4l2_pix_format *pix)
+{
+       struct ov9640_sensor *sensor = &ov9640;
+       int err;
+
+       memset(sensor, 0, sizeof(*sensor));
+       /* power-up the sensor */
+       if (ov9640_powerup())
+               return NULL;
+
+       err = i2c_add_driver(&ov9640sensor_i2c_driver);
+       if (err) {
+               printk(KERN_ERR "Failed to register OV9640 I2C client.\n");
+               return NULL;
+       }
+       if (!sensor->client.adapter) {
+               printk(KERN_WARNING 
+                       "Failed to detect OV9640 sensor chip.\n");
+               return NULL;
+       }
+       else
+               printk(KERN_INFO 
+                       "OV9640 sensor chip version 0x%02x detected\n", sensor->ver);
+
+       /* Make the default capture format QCIF RGB565 */
+       pix->width = ov9640_sizes[QCIF].width;
+       pix->height = ov9640_sizes[QCIF].height;
+       pix->pixelformat = V4L2_PIX_FMT_RGB565;
+       ov9640sensor_try_format(pix, NULL);
+
+       return (void *)sensor;
+}
+
+struct omap_camera_sensor camera_sensor_if = {
+       .version        = 0x01,
+       .name           = "OV9640",
+       .init           = ov9640sensor_init,
+       .cleanup        = ov9640sensor_cleanup,
+       .enum_pixformat = ov9640sensor_enum_pixformat,
+       .try_format     = ov9640sensor_try_format,
+       .calc_xclk      = ov9640sensor_calc_xclk,
+       .configure      = ov9640sensor_configure,
+       .query_control  = ov9640sensor_query_control,
+       .get_control    = ov9640sensor_get_control,
+       .set_control    = ov9640sensor_set_control,
+       .power_on       = ov9640sensor_power_on,
+       .power_off      = ov9640sensor_power_off,
+};
+EXPORT_SYMBOL_GPL(camera_sensor_if);
+
+MODULE_LICENSE("GPL");
+
+#if 0
+void print_ov9640_regs(void *priv)
+{
+       struct ov9640_sensor *sensor = (struct ov9640_sensor *) priv;
+       u8 reg, val;
+       for (reg=0x00; reg <=0x8A; reg++)
+               if (ov9640_read_reg(&sensor->client,reg,&val))
+                       printk("error reading %x\n", reg);
+               else
+                       printk("reg %x = %x\n", reg, val);       
+}
+#endif
index d30540b2761420cff6bf445f761b8d0b27b34b40..796172a26ca8b8cc94e32d6412db0a52c84f7cde 100644 (file)
@@ -37,6 +37,7 @@
 #include <asm/arch/mux.h>
 #include <asm/arch/fpga.h>
 #include <asm/arch/tps65010.h>
+#include <asm/arch/board-sx1.h>
 
 #define        OMAP_MMC_REG_CMD        0x00
 #define        OMAP_MMC_REG_ARGL       0x04
@@ -907,7 +908,9 @@ static void innovator_fpga_socket_power(int on)
  */
 static void mmc_omap_power(struct mmc_omap_host *host, int on)
 {
-       if (on) {
+       if (machine_is_sx1())
+               sx1_setmmcpower(on);
+       else if (on) {
                if (machine_is_omap_innovator())
                        innovator_fpga_socket_power(1);
                else if (machine_is_omap_h2())
index e8d9ae535673d68d04b547f029dbdadefd6b3e58..a0a12af08aa034db80cf10cafb742d456bacb925 100644 (file)
@@ -61,12 +61,14 @@ static void omap_set_vpp(struct map_info *map, int enable)
 {
        static int      count;
 
-       if (enable) {
-               if (count++ == 0)
-                       OMAP_EMIFS_CONFIG_REG |= OMAP_EMIFS_CONFIG_WP;
-       } else {
-               if (count && (--count == 0))
-                       OMAP_EMIFS_CONFIG_REG &= ~OMAP_EMIFS_CONFIG_WP;
+       if (!cpu_is_omap24xx()) {
+               if (enable) {
+                       if (count++ == 0)
+                               OMAP_EMIFS_CONFIG_REG |= OMAP_EMIFS_CONFIG_WP;
+               } else {
+                       if (count && (--count == 0))
+                               OMAP_EMIFS_CONFIG_REG &= ~OMAP_EMIFS_CONFIG_WP;
+               }
        }
 }
 
@@ -133,11 +135,12 @@ out_free_info:
 static int __devexit omapflash_remove(struct platform_device *pdev)
 {
        struct omapflash_info *info = platform_get_drvdata(pdev);
+       struct flash_platform_data *pdata = pdev->dev.platform_data;
 
        platform_set_drvdata(pdev, NULL);
 
        if (info) {
-               if (info->parts) {
+               if (info->parts || (pdata && pdata->parts)) {
                        del_mtd_partitions(info->mtd);
                        kfree(info->parts);
                } else
index 358f55a82dbe4ebb73b1b0ee460063a6145e3f0e..dac231acacbd08c098913ce16cf7100dd3078c78 100644 (file)
@@ -63,6 +63,19 @@ config MTD_NAND_AMS_DELTA
        help
          Support for NAND flash on Amstrad E3 (Delta).
 
+config MTD_NAND_OMAP
+       tristate "NAND Flash device on OMAP H3/H2/P2 boards"
+       depends on ARM && ARCH_OMAP1 && MTD_NAND && (MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_PERSEUS2)
+       help
+         Support for NAND flash on Texas Instruments H3/H2/P2 platforms.
+
+config MTD_NAND_OMAP_HW
+       bool "OMAP HW NAND Flash controller support"
+        depends on ARM && ARCH_OMAP16XX && MTD_NAND
+
+       help
+         Driver for TI OMAP16xx hardware NAND flash controller.
+
 config MTD_NAND_TOTO
        tristate "NAND Flash device on TOTO board"
        depends on ARCH_OMAP && MTD_NAND && BROKEN
index f7a53f0b70177451680402a2c2cce4c98991cd6e..69da27e2285e107aab70b90915c43f5a03de027e 100644 (file)
@@ -23,6 +23,8 @@ obj-$(CONFIG_MTD_NAND_TS7250)         += ts7250.o
 obj-$(CONFIG_MTD_NAND_NANDSIM)         += nandsim.o
 obj-$(CONFIG_MTD_NAND_CS553X)          += cs553x_nand.o
 obj-$(CONFIG_MTD_NAND_NDFC)            += ndfc.o
+obj-$(CONFIG_MTD_NAND_OMAP)            += omap-nand-flash.o
+obj-$(CONFIG_MTD_NAND_OMAP_HW)         += omap-hw.o
 obj-$(CONFIG_MTD_NAND_AT91)            += at91_nand.o
 
 nand-objs := nand_base.o nand_bbt.o
diff --git a/drivers/mtd/nand/omap-hw.c b/drivers/mtd/nand/omap-hw.c
new file mode 100644 (file)
index 0000000..aaadb63
--- /dev/null
@@ -0,0 +1,869 @@
+/*
+ *  drivers/mtd/nand/omap-hw.c
+ *
+ *  This is the MTD driver for OMAP1710 internal HW NAND controller.
+ *
+ *  Copyright (C) 2004-2006 Nokia Corporation
+ *
+ *  Author: Jarkko Lavinen <jarkko.lavinen@nokia.com> and
+ *          Juha Yrjölä <juha.yrjola@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; see the file COPYING. If not, write to the Free Software
+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/dma-mapping.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+
+#include <asm/arch/board.h>
+#include <asm/arch/dma.h>
+
+#define NAND_BASE              0xfffbcc00
+#define NND_REVISION           0x00
+#define NND_ACCESS             0x04
+#define NND_ADDR_SRC           0x08
+#define NND_CTRL               0x10
+#define NND_MASK               0x14
+#define NND_STATUS             0x18
+#define NND_READY              0x1c
+#define NND_COMMAND            0x20
+#define NND_COMMAND_SEC                0x24
+#define NND_ECC_SELECT         0x28
+#define NND_ECC_START          0x2c
+#define NND_ECC_9              0x4c
+#define NND_RESET              0x50
+#define NND_FIFO               0x54
+#define NND_FIFOCTRL           0x58
+#define NND_PSC_CLK            0x5c
+#define NND_SYSTEST            0x60
+#define NND_SYSCFG             0x64
+#define NND_SYSSTATUS          0x68
+#define NND_FIFOTEST1          0x6c
+#define NND_FIFOTEST2          0x70
+#define NND_FIFOTEST3          0x74
+#define NND_FIFOTEST4          0x78
+#define NND_PSC1_CLK           0x8c
+#define NND_PSC2_CLK           0x90
+
+
+#define NND_CMD_READ1_LOWER    0x00
+#define NND_CMD_WRITE1_LOWER   0x00
+#define NND_CMD_READ1_UPPER    0x01
+#define NND_CMD_WRITE1_UPPER   0x01
+#define NND_CMD_PROGRAM_END    0x10
+#define NND_CMD_READ2_SPARE    0x50
+#define NND_CMD_WRITE2_SPARE   0x50
+#define NND_CMD_ERASE          0x60
+#define NND_CMD_STATUS         0x70
+#define NND_CMD_PROGRAM                0x80
+#define NND_CMD_READ_ID                0x90
+#define NND_CMD_ERASE_END      0xD0
+#define NND_CMD_RESET          0xFF
+
+
+#define NAND_Ecc_P1e           (1 << 0)
+#define NAND_Ecc_P2e           (1 << 1)
+#define NAND_Ecc_P4e           (1 << 2)
+#define NAND_Ecc_P8e           (1 << 3)
+#define NAND_Ecc_P16e          (1 << 4)
+#define NAND_Ecc_P32e          (1 << 5)
+#define NAND_Ecc_P64e          (1 << 6)
+#define NAND_Ecc_P128e         (1 << 7)
+#define NAND_Ecc_P256e         (1 << 8)
+#define NAND_Ecc_P512e         (1 << 9)
+#define NAND_Ecc_P1024e                (1 << 10)
+#define NAND_Ecc_P2048e                (1 << 11)
+
+#define NAND_Ecc_P1o           (1 << 16)
+#define NAND_Ecc_P2o           (1 << 17)
+#define NAND_Ecc_P4o           (1 << 18)
+#define NAND_Ecc_P8o           (1 << 19)
+#define NAND_Ecc_P16o          (1 << 20)
+#define NAND_Ecc_P32o          (1 << 21)
+#define NAND_Ecc_P64o          (1 << 22)
+#define NAND_Ecc_P128o         (1 << 23)
+#define NAND_Ecc_P256o         (1 << 24)
+#define NAND_Ecc_P512o         (1 << 25)
+#define NAND_Ecc_P1024o                (1 << 26)
+#define NAND_Ecc_P2048o                (1 << 27)
+
+#define TF(value)      (value ? 1 : 0)
+
+#define P2048e(a)      (TF(a & NAND_Ecc_P2048e)        << 0 )
+#define P2048o(a)      (TF(a & NAND_Ecc_P2048o)        << 1 )
+#define P1e(a)         (TF(a & NAND_Ecc_P1e)           << 2 )
+#define P1o(a)         (TF(a & NAND_Ecc_P1o)           << 3 )
+#define P2e(a)         (TF(a & NAND_Ecc_P2e)           << 4 )
+#define P2o(a)         (TF(a & NAND_Ecc_P2o)           << 5 )
+#define P4e(a)         (TF(a & NAND_Ecc_P4e)           << 6 )
+#define P4o(a)         (TF(a & NAND_Ecc_P4o)           << 7 )
+
+#define P8e(a)         (TF(a & NAND_Ecc_P8e)           << 0 )
+#define P8o(a)         (TF(a & NAND_Ecc_P8o)           << 1 )
+#define P16e(a)                (TF(a & NAND_Ecc_P16e)          << 2 )
+#define P16o(a)                (TF(a & NAND_Ecc_P16o)          << 3 )
+#define P32e(a)                (TF(a & NAND_Ecc_P32e)          << 4 )
+#define P32o(a)                (TF(a & NAND_Ecc_P32o)          << 5 )
+#define P64e(a)                (TF(a & NAND_Ecc_P64e)          << 6 )
+#define P64o(a)                (TF(a & NAND_Ecc_P64o)          << 7 )
+
+#define P128e(a)       (TF(a & NAND_Ecc_P128e)         << 0 )
+#define P128o(a)       (TF(a & NAND_Ecc_P128o)         << 1 )
+#define P256e(a)       (TF(a & NAND_Ecc_P256e)         << 2 )
+#define P256o(a)       (TF(a & NAND_Ecc_P256o)         << 3 )
+#define P512e(a)       (TF(a & NAND_Ecc_P512e)         << 4 )
+#define P512o(a)       (TF(a & NAND_Ecc_P512o)         << 5 )
+#define P1024e(a)      (TF(a & NAND_Ecc_P1024e)        << 6 )
+#define P1024o(a)      (TF(a & NAND_Ecc_P1024o)        << 7 )
+
+#define P8e_s(a)       (TF(a & NAND_Ecc_P8e)           << 0 )
+#define P8o_s(a)       (TF(a & NAND_Ecc_P8o)           << 1 )
+#define P16e_s(a)      (TF(a & NAND_Ecc_P16e)          << 2 )
+#define P16o_s(a)      (TF(a & NAND_Ecc_P16o)          << 3 )
+#define P1e_s(a)       (TF(a & NAND_Ecc_P1e)           << 4 )
+#define P1o_s(a)       (TF(a & NAND_Ecc_P1o)           << 5 )
+#define P2e_s(a)       (TF(a & NAND_Ecc_P2e)           << 6 )
+#define P2o_s(a)       (TF(a & NAND_Ecc_P2o)           << 7 )
+
+#define P4e_s(a)       (TF(a & NAND_Ecc_P4e)           << 0 )
+#define P4o_s(a)       (TF(a & NAND_Ecc_P4o)           << 1 )
+
+extern struct nand_oobinfo jffs2_oobinfo;
+
+/*
+ * MTD structure for OMAP board
+ */
+static struct mtd_info *omap_mtd;
+static struct clk *omap_nand_clk;
+static int omap_nand_dma_ch;
+static struct completion omap_nand_dma_comp;
+static unsigned long omap_nand_base = io_p2v(NAND_BASE);
+
+static inline u32 nand_read_reg(int idx)
+{
+       return __raw_readl(omap_nand_base + idx);
+}
+
+static inline void nand_write_reg(int idx, u32 val)
+{
+       __raw_writel(val, omap_nand_base + idx);
+}
+
+static inline u8 nand_read_reg8(int idx)
+{
+       return __raw_readb(omap_nand_base + idx);
+}
+
+static inline void nand_write_reg8(int idx, u8 val)
+{
+       __raw_writeb(val, omap_nand_base + idx);
+}
+
+static void omap_nand_select_chip(struct mtd_info *mtd, int chip)
+{
+       u32 l;
+
+       switch(chip) {
+       case -1:
+               l = nand_read_reg(NND_CTRL);
+               l |= (1 << 8) | (1 << 10) | (1 << 12) | (1 << 14);
+               nand_write_reg(NND_CTRL, l);
+               break;
+       case 0:
+               /* Also CS1, CS2, CS4 would be available */
+               l = nand_read_reg(NND_CTRL);
+               l &= ~(1 << 8);
+               nand_write_reg(NND_CTRL, l);
+               break;
+       default:
+               BUG();
+       }
+}
+
+static void nand_dma_cb(int lch, u16 ch_status, void *data)
+{
+       complete((struct completion *) data);
+}
+
+static void omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
+                                         unsigned int u32_count, int is_write)
+{
+       const int block_size = 16;
+       unsigned int block_count, len;
+       int dma_ch;
+       unsigned long fifo_reg, timeout, jiffies_before, jiffies_spent;
+       static unsigned long max_jiffies = 0;
+
+       dma_ch = omap_nand_dma_ch;
+       block_count = u32_count * 4 / block_size;
+       nand_write_reg(NND_STATUS, 0x0f);
+       nand_write_reg(NND_FIFOCTRL, (block_size << 24) | block_count);
+       fifo_reg = NAND_BASE + NND_FIFO;
+       if (is_write) {
+               omap_set_dma_dest_params(dma_ch, OMAP_DMA_PORT_TIPB,
+                                        OMAP_DMA_AMODE_CONSTANT, fifo_reg,
+                                        0, 0);
+               omap_set_dma_src_params(dma_ch, OMAP_DMA_PORT_EMIFF,
+                                       OMAP_DMA_AMODE_POST_INC,
+                                       virt_to_phys(addr),
+                                       0, 0);
+//             omap_set_dma_src_burst_mode(dma_ch, OMAP_DMA_DATA_BURST_4);
+               /* Set POSTWRITE bit */
+               nand_write_reg(NND_CTRL, nand_read_reg(NND_CTRL) | (1 << 16));
+       } else {
+               omap_set_dma_src_params(dma_ch, OMAP_DMA_PORT_TIPB,
+                                       OMAP_DMA_AMODE_CONSTANT, fifo_reg,
+                                       0, 0);
+               omap_set_dma_dest_params(dma_ch, OMAP_DMA_PORT_EMIFF,
+                                        OMAP_DMA_AMODE_POST_INC,
+                                        virt_to_phys(addr),
+                                        0, 0);
+//             omap_set_dma_dest_burst_mode(dma_ch, OMAP_DMA_DATA_BURST_8);
+               /* Set PREFETCH bit */
+               nand_write_reg(NND_CTRL, nand_read_reg(NND_CTRL) | (1 << 17));
+       }
+       omap_set_dma_transfer_params(dma_ch, OMAP_DMA_DATA_TYPE_S32, block_size / 4,
+                                    block_count, OMAP_DMA_SYNC_FRAME,
+                                    0, 0);
+       init_completion(&omap_nand_dma_comp);
+
+       len = u32_count << 2;
+       consistent_sync(addr, len, DMA_TO_DEVICE);
+       omap_start_dma(dma_ch);
+       jiffies_before = jiffies;
+       timeout = wait_for_completion_timeout(&omap_nand_dma_comp,
+                                             msecs_to_jiffies(1000));
+       jiffies_spent = (unsigned long)((long)jiffies - (long)jiffies_before);
+       if (jiffies_spent > max_jiffies)
+               max_jiffies = jiffies_spent;
+
+       if (timeout == 0) {
+               printk(KERN_WARNING "omap-hw-nand: DMA timeout after %u ms, max. seen latency %u ms\n",
+                      jiffies_to_msecs(jiffies_spent),
+                      jiffies_to_msecs(max_jiffies));
+               if (OMAP_DMA_CCR_REG(dma_ch) & (1 << 7)) {
+                       /* If the DMA transfer is still running, something
+                        * is really wrong. */
+                       printk(KERN_ERR "omap-hw-nand: DMA transfer still running. Not good.\n");
+                       printk(KERN_INFO "DMA ch %d: CCR %04x, CSR %04x, CCDEN_L %04x\n",
+                              dma_ch, omap_readw(OMAP_DMA_CCR_REG(dma_ch)), omap_readw(OMAP_DMA_CSR_REG(dma_ch)),
+                              omap_readw(OMAP_DMA_BASE + 0x40 * (dma_ch) + 0x34));
+               }
+       }
+       if (!is_write)
+               consistent_sync(addr, len, DMA_FROM_DEVICE);
+
+       nand_write_reg(NND_CTRL, nand_read_reg(NND_CTRL) & ~((1 << 16) | (1 << 17)));
+}
+
+static void fifo_read(u32 *out, unsigned int len)
+{
+       const int block_size = 16;
+       unsigned long status_reg, fifo_reg;
+       int c;
+
+       status_reg = omap_nand_base + NND_STATUS;
+       fifo_reg = omap_nand_base + NND_FIFO;
+       len = len * 4 / block_size;
+       nand_write_reg(NND_FIFOCTRL, (block_size << 24) | len);
+       nand_write_reg(NND_STATUS, 0x0f);
+       nand_write_reg(NND_CTRL, nand_read_reg(NND_CTRL) | (1 << 17));
+       c = block_size / 4;
+       while (len--) {
+               int i;
+
+               while ((__raw_readl(status_reg) & (1 << 2)) == 0);
+               __raw_writel(0x0f, status_reg);
+               for (i = 0; i < c; i++) {
+                       u32 l = __raw_readl(fifo_reg);
+                       *out++ = l;
+               }
+       }
+       nand_write_reg(NND_CTRL, nand_read_reg(NND_CTRL) & ~(1 << 17));
+       nand_write_reg(NND_STATUS, 0x0f);
+}
+
+static void omap_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+       unsigned long access_reg;
+
+       if (likely(((unsigned long) buf & 3) == 0 && (len & 3) == 0)) {
+               int u32_count = len >> 2;
+               u32 *dest = (u32 *) buf;
+               /* If the transfer is big enough and the length divisible by
+                * 16, we try to use DMA transfer, or FIFO copy in case of
+                * DMA failure (e.g. all channels busy) */
+               if (u32_count > 64 && (u32_count & 3) == 0) {
+                       if (omap_nand_dma_ch >= 0) {
+                               omap_nand_dma_transfer(mtd, buf, u32_count, 0);
+                               return;
+                       }
+                       /* In case of an error, fallback to FIFO copy */
+                       fifo_read((u32 *) buf, u32_count);
+                       return;
+               }
+               access_reg = omap_nand_base + NND_ACCESS;
+               /* Small buffers we just read directly */
+               while (u32_count--)
+                       *dest++ = __raw_readl(access_reg);
+       } else {
+               /* If we're not word-aligned, we use byte copy */
+               access_reg = omap_nand_base + NND_ACCESS;
+               while (len--)
+                       *buf++ = __raw_readb(access_reg);
+       }
+}
+
+static void omap_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+{
+       if (likely(((unsigned long) buf & 3) == 0 && (len & 3) == 0)) {
+               const u32 *src = (const u32 *) buf;
+
+               len >>= 2;
+#if 0
+               /* If the transfer is big enough and length divisible by 16,
+                * we try to use DMA transfer. */
+               if (len > 256 / 4 && (len & 3) == 0) {
+                       if (omap_nand_dma_transfer(mtd, (void *) buf, len, 1) == 0)
+                               return;
+                       /* In case of an error, fallback to CPU copy */
+               }
+#endif
+               while (len--)
+                       nand_write_reg(NND_ACCESS, *src++);
+       } else {
+               while (len--)
+                       nand_write_reg8(NND_ACCESS, *buf++);
+       }
+}
+
+static int omap_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
+{
+       if (likely(((unsigned long) buf & 3) == 0 && (len & 3) == 0)) {
+               const u32 *dest = (const u32 *) buf;
+               len >>= 2;
+               while (len--)
+                       if (*dest++ != nand_read_reg(NND_ACCESS))
+                               return -EFAULT;
+       } else {
+               while (len--)
+                       if (*buf++ != nand_read_reg8(NND_ACCESS))
+                               return -EFAULT;
+       }
+       return 0;
+}
+
+static u_char omap_nand_read_byte(struct mtd_info *mtd)
+{
+       return nand_read_reg8(NND_ACCESS);
+}
+
+static int omap_nand_dev_ready(struct mtd_info *mtd)
+{
+       u32 l;
+
+       l = nand_read_reg(NND_READY);
+       return l & 0x01;
+}
+
+static int nand_write_command(u8 cmd, u32 addr, int addr_valid)
+{
+       if (addr_valid) {
+               nand_write_reg(NND_ADDR_SRC, addr);
+               nand_write_reg8(NND_COMMAND, cmd);
+       } else {
+               nand_write_reg(NND_ADDR_SRC, 0);
+               nand_write_reg8(NND_COMMAND_SEC, cmd);
+       }
+       while (!omap_nand_dev_ready(NULL));
+       return 0;
+}
+
+/*
+ * Send command to NAND device
+ */
+static void omap_nand_command(struct mtd_info *mtd, unsigned command, int column, int page_addr)
+{
+       struct nand_chip *this = mtd->priv;
+
+       /*
+        * Write out the command to the device.
+        */
+       if (command == NAND_CMD_SEQIN) {
+               int readcmd;
+
+               if (column >= mtd->writesize) {
+                       /* OOB area */
+                       column -= mtd->writesize;
+                       readcmd = NAND_CMD_READOOB;
+               } else if (column < 256) {
+                       /* First 256 bytes --> READ0 */
+                       readcmd = NAND_CMD_READ0;
+               } else {
+                       column -= 256;
+                       readcmd = NAND_CMD_READ1;
+               }
+               nand_write_command(readcmd, 0, 0);
+       }
+       switch (command) {
+       case NAND_CMD_RESET:
+       case NAND_CMD_PAGEPROG:
+       case NAND_CMD_STATUS:
+       case NAND_CMD_ERASE2:
+               nand_write_command(command, 0, 0);
+               break;
+       case NAND_CMD_ERASE1:
+               nand_write_command(command, ((page_addr & 0xFFFFFF00) << 1) | (page_addr & 0XFF), 1);
+               break;
+       default:
+               nand_write_command(command, (page_addr << this->page_shift) | column, 1);
+       }
+}
+
+static void omap_nand_command_lp(struct mtd_info *mtd, unsigned command, int column, int page_addr)
+{
+       struct nand_chip *this = mtd->priv;
+
+       if (command == NAND_CMD_READOOB) {
+               column += mtd->writesize;
+               command = NAND_CMD_READ0;
+       }
+       switch (command) {
+       case NAND_CMD_RESET:
+       case NAND_CMD_PAGEPROG:
+       case NAND_CMD_STATUS:
+       case NAND_CMD_ERASE2:           
+               nand_write_command(command, 0, 0);
+               break;
+       case NAND_CMD_ERASE1:
+               nand_write_command(command, page_addr << this->page_shift >> 11, 1);
+               break;
+       default:
+               nand_write_command(command, (page_addr << 16) | column, 1);
+       }
+       if (command == NAND_CMD_READ0)
+               nand_write_command(NAND_CMD_READSTART, 0, 0);
+}
+
+/*
+ * Generate non-inverted ECC bytes.
+ *
+ * Using noninverted ECC can be considered ugly since writing a blank
+ * page ie. padding will clear the ECC bytes. This is no problem as long
+ * nobody is trying to write data on the seemingly unused page.
+ *
+ * Reading an erased page will produce an ECC mismatch between
+ * generated and read ECC bytes that has to be dealt with separately.
+ */
+static int omap_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
+{
+       u32 l;
+       int reg;
+       int n;
+       struct nand_chip *this = mtd->priv;
+
+       /* Ex NAND_ECC_HW12_2048 */
+       if ((this->ecc.mode == NAND_ECC_HW) && (this->ecc.size  == 2048))
+               n = 4;
+       else
+               n = 1;
+       reg = NND_ECC_START;
+       while (n--) {
+               l = nand_read_reg(reg);
+               *ecc_code++ = l;          // P128e, ..., P1e
+               *ecc_code++ = l >> 16;    // P128o, ..., P1o
+               // P2048o, P1024o, P512o, P256o, P2048e, P1024e, P512e, P256e
+               *ecc_code++ = ((l >> 8) & 0x0f) | ((l >> 20) & 0xf0);
+               reg += 4;
+       }
+       return 0;
+}
+
+/*
+ * This function will generate true ECC value, which can be used
+ * when correcting data read from NAND flash memory core
+ */
+static void gen_true_ecc(u8 *ecc_buf)
+{
+       u32 tmp = ecc_buf[0] | (ecc_buf[1] << 16) | ((ecc_buf[2] & 0xF0) << 20) | ((ecc_buf[2] & 0x0F) << 8);
+
+       ecc_buf[0] = ~(P64o(tmp) | P64e(tmp) | P32o(tmp) | P32e(tmp) | P16o(tmp) | P16e(tmp) | P8o(tmp) | P8e(tmp) );
+       ecc_buf[1] = ~(P1024o(tmp) | P1024e(tmp) | P512o(tmp) | P512e(tmp) | P256o(tmp) | P256e(tmp) | P128o(tmp) | P128e(tmp));
+       ecc_buf[2] = ~( P4o(tmp) | P4e(tmp) | P2o(tmp) | P2e(tmp) | P1o(tmp) | P1e(tmp) | P2048o(tmp) | P2048e(tmp));
+}
+
+/*
+ * This function compares two ECC's and indicates if there is an error.
+ * If the error can be corrected it will be corrected to the buffer
+ */
+static int omap_nand_compare_ecc(u8 *ecc_data1,   /* read from NAND memory */
+                                u8 *ecc_data2,   /* read from register */
+                                u8 *page_data)
+{
+       uint   i;
+       u8     tmp0_bit[8], tmp1_bit[8], tmp2_bit[8];
+       u8     comp0_bit[8], comp1_bit[8], comp2_bit[8];
+       u8     ecc_bit[24];
+       u8     ecc_sum = 0;
+       u8     find_bit = 0;
+       uint   find_byte = 0;
+       int    isEccFF;
+
+       isEccFF = ((*(u32 *)ecc_data1 & 0xFFFFFF) == 0xFFFFFF);
+
+       gen_true_ecc(ecc_data1);
+       gen_true_ecc(ecc_data2);
+
+       for (i = 0; i <= 2; i++) {
+               *(ecc_data1 + i) = ~(*(ecc_data1 + i));
+               *(ecc_data2 + i) = ~(*(ecc_data2 + i));
+       }
+
+       for (i = 0; i < 8; i++) {
+               tmp0_bit[i]      = *ecc_data1 % 2;
+               *ecc_data1       = *ecc_data1 / 2;
+       }
+
+       for (i = 0; i < 8; i++) {
+               tmp1_bit[i]      = *(ecc_data1 + 1) % 2;
+               *(ecc_data1 + 1) = *(ecc_data1 + 1) / 2;
+       }
+
+       for (i = 0; i < 8; i++) {
+               tmp2_bit[i]      = *(ecc_data1 + 2) % 2;
+               *(ecc_data1 + 2) = *(ecc_data1 + 2) / 2;
+       }
+
+       for (i = 0; i < 8; i++) {
+               comp0_bit[i]     = *ecc_data2 % 2;
+               *ecc_data2       = *ecc_data2 / 2;
+       }
+
+       for (i = 0; i < 8; i++) {
+               comp1_bit[i]     = *(ecc_data2 + 1) % 2;
+               *(ecc_data2 + 1) = *(ecc_data2 + 1) / 2;
+       }
+
+       for (i = 0; i < 8; i++) {
+               comp2_bit[i]     = *(ecc_data2 + 2) % 2;
+               *(ecc_data2 + 2) = *(ecc_data2 + 2) / 2;
+       }
+
+       for (i = 0; i< 6; i++ )
+               ecc_bit[i] = tmp2_bit[i + 2] ^ comp2_bit[i + 2];
+
+       for (i = 0; i < 8; i++)
+               ecc_bit[i + 6] = tmp0_bit[i] ^ comp0_bit[i];
+
+       for (i = 0; i < 8; i++)
+               ecc_bit[i + 14] = tmp1_bit[i] ^ comp1_bit[i];
+
+       ecc_bit[22] = tmp2_bit[0] ^ comp2_bit[0];
+       ecc_bit[23] = tmp2_bit[1] ^ comp2_bit[1];
+
+       for (i = 0; i < 24; i++)
+               ecc_sum += ecc_bit[i];
+
+       switch (ecc_sum) {
+       case 0:
+               /* Not reached because this function is not called if
+                  ECC values are equal */
+               return 0;
+
+       case 1:
+               /* Uncorrectable error */
+               DEBUG (MTD_DEBUG_LEVEL0, "ECC UNCORRECTED_ERROR 1\n");
+               return -1;
+
+       case 12:
+               /* Correctable error */
+               find_byte = (ecc_bit[23] << 8) + 
+                           (ecc_bit[21] << 7) + 
+                           (ecc_bit[19] << 6) +
+                           (ecc_bit[17] << 5) +
+                           (ecc_bit[15] << 4) +
+                           (ecc_bit[13] << 3) +
+                           (ecc_bit[11] << 2) +
+                           (ecc_bit[9]  << 1) +
+                           ecc_bit[7];
+
+               find_bit = (ecc_bit[5] << 2) + (ecc_bit[3] << 1) + ecc_bit[1];
+
+               DEBUG (MTD_DEBUG_LEVEL0, "Correcting single bit ECC error at offset: %d, bit: %d\n", find_byte, find_bit);
+
+               page_data[find_byte] ^= (1 << find_bit);
+
+               return 0;
+       default:
+               if (isEccFF) {
+                       if (ecc_data2[0] == 0 && ecc_data2[1] == 0 && ecc_data2[2] == 0)
+                               return 0;
+               } 
+               DEBUG (MTD_DEBUG_LEVEL0, "UNCORRECTED_ERROR default\n");
+               return -1;
+       }
+}
+
+static int omap_nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc)
+{
+       struct nand_chip *this;
+       int block_count = 0, i, r;
+
+       this = mtd->priv;
+       /* Ex NAND_ECC_HW12_2048 */
+       if ((this->ecc.mode == NAND_ECC_HW) && (this->ecc.size  == 2048))
+               block_count = 4;
+       else
+               block_count = 1;
+       for (i = 0; i < block_count; i++) {
+               if (memcmp(read_ecc, calc_ecc, 3) != 0) {
+                       r = omap_nand_compare_ecc(read_ecc, calc_ecc, dat);
+                       if (r < 0)
+                               return r;
+               }
+               read_ecc += 3;
+               calc_ecc += 3;
+               dat += 512;
+       }
+       return 0;
+}
+
+static void omap_nand_enable_hwecc(struct mtd_info *mtd, int mode)
+{
+       nand_write_reg(NND_RESET, 0x01);
+}
+
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+
+extern int mtdpart_setup(char *);
+
+static int __init add_dynamic_parts(struct mtd_info *mtd)
+{
+       static const char *part_parsers[] = { "cmdlinepart", NULL };
+       struct mtd_partition *parts;
+       const struct omap_flash_part_config *cfg;
+       char *part_str = NULL;
+       size_t part_str_len;
+       int c;
+
+       cfg = omap_get_var_config(OMAP_TAG_FLASH_PART, &part_str_len);
+       if (cfg != NULL) {
+               part_str = kmalloc(part_str_len + 1, GFP_KERNEL);
+               if (part_str == NULL)
+                       return -ENOMEM;
+               memcpy(part_str, cfg->part_table, part_str_len);
+               part_str[part_str_len] = '\0';
+               mtdpart_setup(part_str);
+       }
+       c = parse_mtd_partitions(omap_mtd, part_parsers, &parts, 0);
+       if (part_str != NULL) {
+               mtdpart_setup(NULL);
+               kfree(part_str);
+       }
+       if (c <= 0)
+               return -1;
+
+       add_mtd_partitions(mtd, parts, c);
+
+       return 0;
+}
+
+#else
+
+static inline int add_dynamic_parts(struct mtd_info *mtd)
+{
+       return -1;
+}
+
+#endif
+
+static inline int calc_psc(int ns, int cycle_ps)
+{
+       return (ns * 1000 + (cycle_ps - 1)) / cycle_ps;
+}
+
+static void set_psc_regs(int psc_ns, int psc1_ns, int psc2_ns)
+{
+       int psc[3], i;
+       unsigned long rate, ps;
+
+       rate = clk_get_rate(omap_nand_clk);
+       ps = 1000000000 / (rate / 1000);
+       psc[0] = calc_psc(psc_ns, ps);
+       psc[1] = calc_psc(psc1_ns, ps);
+       psc[2] = calc_psc(psc2_ns, ps);
+       for (i = 0; i < 3; i++) {
+               if (psc[i] < 2)
+                       psc[i] = 2;
+               else if (psc[i] > 256)
+                       psc[i] = 256;
+       }
+       nand_write_reg(NND_PSC_CLK, psc[0] - 1);
+       nand_write_reg(NND_PSC1_CLK, psc[1] - 1);
+       nand_write_reg(NND_PSC2_CLK, psc[2] - 1);
+       printk(KERN_INFO "omap-hw-nand: using PSC values %d, %d, %d\n", psc[0], psc[1], psc[2]);
+}
+
+/*
+ * Main initialization routine
+ */
+static int __init omap_nand_init(void)
+{
+       struct nand_chip *this;
+       int err = 0;
+       u32 l;
+
+       omap_nand_clk = clk_get(NULL, "armper_ck");
+       BUG_ON(omap_nand_clk == NULL);
+       clk_enable(omap_nand_clk);
+
+       l = nand_read_reg(NND_REVISION);        
+       printk(KERN_INFO "omap-hw-nand: OMAP NAND Controller rev. %d.%d\n", l>>4, l & 0xf);
+
+       /* Reset the NAND Controller */
+       nand_write_reg(NND_SYSCFG, 0x02);
+       while ((nand_read_reg(NND_SYSSTATUS) & 0x01) == 0);
+
+       /* No Prefetch, no postwrite, write prot & enable pairs disabled,
+          addres counter set to send 4 byte addresses to flash,
+          A8 is set not to be sent to flash (erase addre needs formatting),
+          choose little endian, enable 512 byte ECC logic,        
+        */
+       nand_write_reg(NND_CTRL, 0xFF01);
+
+       /* Allocate memory for MTD device structure and private data */
+       omap_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
+       if (!omap_mtd) {
+               printk(KERN_WARNING "omap-hw-nand: Unable to allocate OMAP NAND MTD device structure.\n");
+               err = -ENOMEM;
+               goto free_clock;
+       }
+#if 1
+       err = omap_request_dma(OMAP_DMA_NAND, "NAND", nand_dma_cb,
+                              &omap_nand_dma_comp, &omap_nand_dma_ch);
+       if (err < 0) {
+               printk(KERN_WARNING "omap-hw-nand: Unable to reserve DMA channel\n");
+               omap_nand_dma_ch = -1;
+       }
+#else
+       omap_nand_dma_ch = -1;
+#endif
+       /* Get pointer to private data */
+       this = (struct nand_chip *) (&omap_mtd[1]);
+
+       /* Initialize structures */
+       memset((char *) omap_mtd, 0, sizeof(struct mtd_info));
+       memset((char *) this, 0, sizeof(struct nand_chip));
+
+       /* Link the private data with the MTD structure */
+       omap_mtd->priv = this;
+       omap_mtd->name = "omap-nand";
+
+       this->options = NAND_SKIP_BBTSCAN;
+
+       /* Used from chip select and nand_command() */
+       this->read_byte = omap_nand_read_byte;
+
+       this->select_chip   = omap_nand_select_chip;
+       this->dev_ready     = omap_nand_dev_ready;
+       this->chip_delay    = 0;
+       this->ecc.mode      = NAND_ECC_HW;
+       this->ecc.bytes     = 3;
+       this->ecc.size      = 512;
+       this->cmdfunc       = omap_nand_command;
+       this->write_buf     = omap_nand_write_buf;
+       this->read_buf      = omap_nand_read_buf;
+       this->verify_buf    = omap_nand_verify_buf;
+       this->ecc.calculate = omap_nand_calculate_ecc;
+       this->ecc.correct   = omap_nand_correct_data;
+       this->ecc.hwctl     = omap_nand_enable_hwecc;
+
+       nand_write_reg(NND_SYSCFG, 0x1); /* Enable auto idle */
+       nand_write_reg(NND_PSC_CLK, 10);
+       /* Scan to find existance of the device */
+       if (nand_scan(omap_mtd, 1)) {
+               err = -ENXIO;
+               goto out_mtd;
+       }
+
+       set_psc_regs(25, 15, 35);
+       if (this->page_shift == 11) {
+               this->cmdfunc = omap_nand_command_lp;
+               l = nand_read_reg(NND_CTRL);
+               l |= 1 << 4; /* Set the A8 bit in CTRL reg */
+               nand_write_reg(NND_CTRL, l);
+               this->ecc.mode = NAND_ECC_HW;
+               this->ecc.steps = 1;
+               this->ecc.size = 2048;
+               this->ecc.bytes = 12;
+               omap_mtd->eccsize = 2048;
+               nand_write_reg(NND_ECC_SELECT, 6);
+       }
+
+       /* We have to do bbt scanning ourselves */
+       if (this->scan_bbt (omap_mtd)) {
+               err = -ENXIO;
+               goto out_mtd;
+       }
+
+       err = add_dynamic_parts(omap_mtd);
+       if (err < 0) {
+               printk(KERN_ERR "omap-hw-nand: no partitions defined\n");
+               err = -ENODEV;
+               nand_release(omap_mtd);
+               goto out_mtd;
+       }
+       /* init completed */
+       return 0;
+out_mtd:
+       if (omap_nand_dma_ch >= 0)
+               omap_free_dma(omap_nand_dma_ch);
+       kfree(omap_mtd);
+free_clock:
+       clk_put(omap_nand_clk);
+       return err;
+}
+
+module_init(omap_nand_init);
+
+/*
+ * Clean up routine
+ */
+static void __exit omap_nand_cleanup (void)
+{
+       clk_disable(omap_nand_clk);
+       clk_put(omap_nand_clk);
+       nand_release(omap_mtd);
+       kfree(omap_mtd);
+}
+
+module_exit(omap_nand_cleanup);
+
diff --git a/drivers/mtd/nand/omap-nand-flash.c b/drivers/mtd/nand/omap-nand-flash.c
new file mode 100644 (file)
index 0000000..a231e18
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * drivers/mtd/nand/omap-nand-flash.c
+ *
+ * Copyright (c) 2004 Texas Instruments, Jian Zhang <jzhang@ti.com>
+ * Copyright (c) 2004 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/flash.h>
+#include <asm/arch/tc.h>
+
+#include <asm/io.h>
+#include <asm/arch/hardware.h>
+
+#define        DRIVER_NAME     "omapnand"
+
+#ifdef CONFIG_MTD_PARTITIONS
+static const char *part_probes[] = { "cmdlinepart", NULL };
+#endif
+
+struct omap_nand_info {
+       struct nand_platform_data *pdata;
+       struct mtd_partition    *parts;
+       struct mtd_info         mtd;
+       struct nand_chip        nand;
+};
+
+/*
+ *     hardware specific access to control-lines
+ *     NOTE:  boards may use different bits for these!!
+ *
+ *     ctrl:
+ *     NAND_NCE: bit 0 - don't care
+ *     NAND_CLE: bit 1 -> bit 1  (0x0002)
+ *     NAND_ALE: bit 2 -> bit 2  (0x0004)
+ */
+
+static void omap_nand_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+{
+       struct nand_chip *chip = mtd->priv;
+       unsigned long mask;
+
+       if (cmd == NAND_CMD_NONE)
+               return;
+
+       mask = (ctrl & NAND_CLE) ? 0x02 : 0;
+       if (ctrl & NAND_ALE)
+               mask |= 0x04;
+       writeb(cmd, (unsigned long)chip->IO_ADDR_W | mask);
+}
+
+static int omap_nand_dev_ready(struct mtd_info *mtd)
+{
+       struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, mtd);
+
+       return info->pdata->dev_ready(info->pdata);
+}
+
+static int __devinit omap_nand_probe(struct platform_device *pdev)
+{
+       struct omap_nand_info           *info;
+       struct nand_platform_data       *pdata = pdev->dev.platform_data;
+       struct resource                 *res = pdev->resource;
+       unsigned long                   size = res->end - res->start + 1;
+       int                             err;
+
+       info = kzalloc(sizeof(struct omap_nand_info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       if (!request_mem_region(res->start, size, pdev->dev.driver->name)) {
+               err = -EBUSY;
+               goto out_free_info;
+       }
+
+       info->nand.IO_ADDR_R = ioremap(res->start, size);
+       if (!info->nand.IO_ADDR_R) {
+               err = -ENOMEM;
+               goto out_release_mem_region;
+       }
+       info->nand.IO_ADDR_W = info->nand.IO_ADDR_R;
+       info->nand.cmd_ctrl = omap_nand_hwcontrol;
+       info->nand.ecc.mode = NAND_ECC_SOFT;
+       info->nand.options = pdata->options;
+       if (pdata->dev_ready)
+               info->nand.dev_ready = omap_nand_dev_ready;
+       else
+               info->nand.chip_delay = 20;
+
+       info->mtd.name = pdev->dev.bus_id;
+       info->mtd.priv = &info->nand;
+
+       info->pdata = pdata;
+
+       /* DIP switches on H2 and some other boards change between 8 and 16 bit
+        * bus widths for flash.  Try the other width if the first try fails.
+        */
+       if (nand_scan(&info->mtd, 1)) {
+               info->nand.options ^= NAND_BUSWIDTH_16;
+               if (nand_scan(&info->mtd, 1)) {
+                       err = -ENXIO;
+                       goto out_iounmap;
+               }
+       }
+       info->mtd.owner = THIS_MODULE;
+
+#ifdef CONFIG_MTD_PARTITIONS
+       err = parse_mtd_partitions(&info->mtd, part_probes, &info->parts, 0);
+       if (err > 0)
+               add_mtd_partitions(&info->mtd, info->parts, err);
+       else if (err < 0 && pdata->parts)
+               add_mtd_partitions(&info->mtd, pdata->parts, pdata->nr_parts);
+       else
+#endif
+               add_mtd_device(&info->mtd);
+
+       platform_set_drvdata(pdev, info);
+
+       return 0;
+
+out_iounmap:
+       iounmap(info->nand.IO_ADDR_R);
+out_release_mem_region:
+       release_mem_region(res->start, size);
+out_free_info:
+       kfree(info);
+
+       return err;
+}
+
+static int omap_nand_remove(struct platform_device *pdev)
+{
+       struct omap_nand_info *info = platform_get_drvdata(pdev);
+
+       platform_set_drvdata(pdev, NULL);
+       /* Release NAND device, its internal structures and partitions */
+       nand_release(&info->mtd);
+       iounmap(info->nand.IO_ADDR_R);
+       kfree(info);
+       return 0;
+}
+
+static struct platform_driver omap_nand_driver = {
+       .probe          = omap_nand_probe,
+       .remove         = omap_nand_remove,
+       .driver         = {
+               .name   = DRIVER_NAME,
+       },
+};
+MODULE_ALIAS(DRIVER_NAME);
+
+static int __init omap_nand_init(void)
+{
+       return platform_driver_register(&omap_nand_driver);
+}
+
+static void __exit omap_nand_exit(void)
+{
+       platform_driver_unregister(&omap_nand_driver);
+}
+
+module_init(omap_nand_init);
+module_exit(omap_nand_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jian Zhang <jzhang@ti.com> (and others)");
+MODULE_DESCRIPTION("Glue layer for NAND flash on TI OMAP boards");
+
index 7c8ccc09b60126a448a70c1ef4e3f77975a1f434..51a8b2c03ec2be278f280db4b4f5be2192eced05 100644 (file)
@@ -433,5 +433,15 @@ config MCS_FIR
          To compile it as a module, choose M here: the module will be called
          mcs7780.
 
+config OMAP_IR
+       tristate "OMAP IrDA(SIR/MIR/FIR)"
+       depends on IRDA && ARCH_OMAP
+       select GPIOEXPANDER_OMAP if (MACH_OMAP_H3 || MACH_OMAP_H4)
+        help
+         Say Y here if you want to build support for the Texas Instruments
+         OMAP IrDA device driver, which supports SIR/MIR/FIR. This driver
+         relies on platform specific helper routines so available capabilities
+         may vary from one OMAP target to another.
+
 endmenu
 
index 5be09f1b9ee2f4b8dc056540342955405b72b215..89c6389c697355c24f460f329353778ae00e5028 100644 (file)
@@ -20,6 +20,7 @@ obj-$(CONFIG_VLSI_FIR)                += vlsi_ir.o
 obj-$(CONFIG_VIA_FIR)          += via-ircc.o
 obj-$(CONFIG_PXA_FICP)         += pxaficp_ir.o
 obj-$(CONFIG_MCS_FIR)          += mcs7780.o
+obj-$(CONFIG_OMAP_IR)          += omap-ir.o
 # Old dongle drivers for old SIR drivers
 obj-$(CONFIG_ESI_DONGLE_OLD)           += esi.o
 obj-$(CONFIG_TEKRAM_DONGLE_OLD)        += tekram.o
diff --git a/drivers/net/irda/omap-ir.c b/drivers/net/irda/omap-ir.c
new file mode 100644 (file)
index 0000000..85658dc
--- /dev/null
@@ -0,0 +1,905 @@
+/*
+ * BRIEF MODULE DESCRIPTION
+ *
+ *     Infra-red driver for the OMAP1610-H2 and OMAP1710-H3 and H4 Platforms
+ *       (SIR/MIR/FIR modes)
+ *       (based on omap-sir.c)
+ *
+ * Copyright 2003 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *        source@mvista.com
+ *
+ * Copyright 2004 Texas Instruments.
+ *
+ *  This program is free software; you can redistribute         it and/or modify it
+ *  under  the terms of         the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the License, or (at your
+ *  option) any later version.
+ *
+ *  THIS  SOFTWARE  IS PROVIDED          ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,          INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED          TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA, OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN         CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ Modifications:
+ Feb 2004, Texas Instruments
+ - Ported to 2.6 kernel (Feb 2004).
+ *
+ Apr 2004, Texas Instruments
+ - Added support for H3 (Apr 2004).
+ Nov 2004, Texas Instruments
+ - Added support for Power Management.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/slab.h>
+#include <linux/rtnetlink.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/workqueue.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/irmod.h>
+#include <net/irda/wrapper.h>
+#include <net/irda/irda_device.h>
+
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/serial.h>
+#include <asm/mach-types.h>
+#include <asm/dma.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/irda.h>
+
+#define UART3_EFR_EN                   (1 << 4)
+#define UART3_MCR_EN_TCR_TLR           (1 << 6)
+
+#define UART3_LCR_WL_8                 (3 << 0)
+#define UART3_LCR_SP2                  (1 << 2)
+#define UART3_LCR_DIVEN                        (1 << 7)
+
+#define UART3_FCR_FIFO_EN              (1 << 0)
+#define UART3_FCR_FIFO_RX              (1 << 1)
+#define UART3_FCR_FIFO_TX              (1 << 2)
+#define UART3_FCR_FIFO_DMA1            (1 << 3)
+#define UART3_FCR_FIFO_TX_TRIG16       (1 << 4)
+#define UART3_FCR_FIFO_RX_TRIG16       (1 << 6)
+#define UART3_FCR_CONFIG       (\
+               UART3_FCR_FIFO_EN | UART3_FCR_FIFO_RX   |\
+               UART3_FCR_FIFO_TX | UART3_FCR_FIFO_DMA1 |\
+               UART3_FCR_FIFO_TX_TRIG16                |\
+               UART3_FCR_FIFO_RX_TRIG16)
+
+#define UART3_SCR_TX_TRIG1             (1 << 6)
+#define UART3_SCR_RX_TRIG1             (1 << 7)
+
+#define UART3_MDR1_RESET               (0x07)
+#define UART3_MDR1_SIR                 (1 << 0)
+#define UART3_MDR1_MIR                 (4 << 0)
+#define UART3_MDR1_FIR                 (5 << 0)
+#define UART3_MDR1_SIP_AUTO            (1 << 6)
+
+#define UART3_MDR2_TRIG1               (0 << 1)
+#define UART3_MDR2_IRTX_UNDERRUN       (1 << 0)
+
+#define UART3_ACERG_TX_UNDERRUN_DIS    (1 << 4)
+#define UART3_ACERG_SD_MODE_LOW                (1 << 6)
+#define UART3_ACERG_DIS_IR_RX          (1 << 5)
+
+#define UART3_IER_EOF                  (1 << 5)
+#define UART3_IER_CTS                  (1 << 7)
+
+#define UART3_IIR_TX_STATUS            (1 << 5)
+#define UART3_IIR_EOF                  (0x80)
+
+#define IS_FIR(omap_ir)                ((omap_ir)->speed >= 4000000)
+
+struct omap_irda {
+       unsigned char open;
+       int speed;              /* Current IrDA speed */
+       int newspeed;
+
+       struct net_device_stats stats;
+       struct irlap_cb *irlap;
+       struct qos_info qos;
+
+       int rx_dma_channel;
+       int tx_dma_channel;
+
+       dma_addr_t rx_buf_dma_phys;     /* Physical address of RX DMA buffer */
+       dma_addr_t tx_buf_dma_phys;     /* Physical address of TX DMA buffer */
+
+       void *rx_buf_dma_virt;          /* Virtual address of RX DMA buffer */
+       void *tx_buf_dma_virt;          /* Virtual address of TX DMA buffer */
+
+       struct device *dev;
+       struct omap_irda_config *pdata;
+};
+
+static void inline uart_reg_out(int idx, u8 val)
+{
+       omap_writeb(val, idx);
+}
+
+static u8 inline uart_reg_in(int idx)
+{
+       u8 b = omap_readb(idx);
+       return b;
+}
+
+/* forward declarations */
+extern void omap_stop_dma(int lch);
+static int omap_irda_set_speed(struct net_device *dev, int speed);
+
+static void omap_irda_start_rx_dma(struct omap_irda *omap_ir)
+{
+       /* Configure DMA */
+       omap_set_dma_src_params(omap_ir->rx_dma_channel, 0x3, 0x0,
+                               omap_ir->pdata->src_start,
+                               0, 0);
+
+       omap_enable_dma_irq(omap_ir->rx_dma_channel, 0x01);
+
+       omap_set_dma_dest_params(omap_ir->rx_dma_channel, 0x0, 0x1,
+                               omap_ir->rx_buf_dma_phys,
+                               0, 0);
+
+       omap_set_dma_transfer_params(omap_ir->rx_dma_channel, 0x0,
+                               IRDA_SKB_MAX_MTU, 0x1,
+                               0x0, omap_ir->pdata->rx_trigger, 0);
+
+       omap_start_dma(omap_ir->rx_dma_channel);
+}
+
+static void omap_start_tx_dma(struct omap_irda *omap_ir, int size)
+{
+       /* Configure DMA */
+       omap_set_dma_dest_params(omap_ir->tx_dma_channel, 0x03, 0x0,
+                               omap_ir->pdata->dest_start, 0, 0);
+
+       omap_enable_dma_irq(omap_ir->tx_dma_channel, 0x01);
+
+       omap_set_dma_src_params(omap_ir->tx_dma_channel, 0x0, 0x1,
+                               omap_ir->tx_buf_dma_phys,
+                               0, 0);
+
+       omap_set_dma_transfer_params(omap_ir->tx_dma_channel, 0x0, size, 0x1,
+                               0x0, omap_ir->pdata->tx_trigger, 0);
+
+       /* Start DMA */
+       omap_start_dma(omap_ir->tx_dma_channel);
+}
+
+/* DMA RX callback - normally, we should not go here,
+ * it calls only if something is going wrong
+ */
+static void omap_irda_rx_dma_callback(int lch, u16 ch_status, void *data)
+{
+       struct net_device *dev = data;
+       struct omap_irda *omap_ir = netdev_priv(dev);
+
+       printk(KERN_ERR "RX Transfer error or very big frame\n");
+
+       /* Clear interrupts */
+       uart_reg_in(UART3_IIR);
+
+       omap_ir->stats.rx_frame_errors++;
+
+       uart_reg_in(UART3_RESUME);
+
+       /* Re-init RX DMA */
+       omap_irda_start_rx_dma(omap_ir);
+}
+
+/* DMA TX callback - calling when frame transfer has been finished */
+static void omap_irda_tx_dma_callback(int lch, u16 ch_status, void *data)
+{
+       struct net_device *dev = data;
+       struct omap_irda *omap_ir = netdev_priv(dev);
+
+       /*Stop DMA controller */
+       omap_stop_dma(omap_ir->tx_dma_channel);
+}
+
+/*
+ * Set the IrDA communications speed.
+ * Interrupt have to be disabled here.
+ */
+static int omap_irda_startup(struct net_device *dev)
+{
+       struct omap_irda *omap_ir = netdev_priv(dev);
+
+       /* FIXME: use clk_* apis for UART3 clock*/
+       /* Enable UART3 clock and set UART3 to IrDA mode */
+       if (machine_is_omap_h2() || machine_is_omap_h3())
+               omap_writel(omap_readl(MOD_CONF_CTRL_0) | (1 << 31) | (1 << 15),
+                               MOD_CONF_CTRL_0);
+
+       /* Only for H2?
+        */
+       if (omap_ir->pdata->transceiver_mode && machine_is_omap_h2()) {
+               /* Is it select_irda on H2 ? */
+               omap_writel(omap_readl(FUNC_MUX_CTRL_A) | 7,
+                                       FUNC_MUX_CTRL_A);
+               omap_ir->pdata->transceiver_mode(omap_ir->dev, IR_SIRMODE);
+       }
+
+       uart_reg_out(UART3_MDR1, UART3_MDR1_RESET);     /* Reset mode */
+
+       /* Clear DLH and DLL */
+       uart_reg_out(UART3_LCR, UART3_LCR_DIVEN);
+
+       uart_reg_out(UART3_DLL, 0);
+       uart_reg_out(UART3_DLH, 0);
+       uart_reg_out(UART3_LCR, 0xbf);  /* FIXME: Add #define */
+
+       uart_reg_out(UART3_EFR, UART3_EFR_EN);
+       uart_reg_out(UART3_LCR, UART3_LCR_DIVEN);
+
+       /* Enable access to UART3_TLR and UART3_TCR registers */
+       uart_reg_out(UART3_MCR, UART3_MCR_EN_TCR_TLR);
+
+       uart_reg_out(UART3_SCR, 0);
+       /* Set Rx trigger to 1 and Tx trigger to 1 */
+       uart_reg_out(UART3_TLR, 0);
+
+       /* Set LCR to 8 bits and 1 stop bit */
+       uart_reg_out(UART3_LCR, 0x03);
+
+       /* Clear RX and TX FIFO and enable FIFO */
+       /* Use DMA Req for transfers */
+       uart_reg_out(UART3_FCR, UART3_FCR_CONFIG);
+
+       uart_reg_out(UART3_MCR, 0);
+
+       uart_reg_out(UART3_SCR, UART3_SCR_TX_TRIG1 |
+                       UART3_SCR_RX_TRIG1);
+
+       /* Enable UART3 SIR Mode,(Frame-length method to end frames) */
+       uart_reg_out(UART3_MDR1, UART3_MDR1_SIR);
+
+       /* Set Status FIFO trig to 1 */
+       uart_reg_out(UART3_MDR2, 0);
+
+       /* Enables RXIR input */
+       /* and disable TX underrun */
+       /* SEND_SIP pulse */
+       uart_reg_out(UART3_ACREG, UART3_ACERG_SD_MODE_LOW |
+                       UART3_ACERG_TX_UNDERRUN_DIS);
+
+       /* Enable EOF Interrupt only */
+       uart_reg_out(UART3_IER, UART3_IER_CTS | UART3_IER_EOF);
+
+       /* Set Maximum Received Frame size to 2048 bytes */
+       uart_reg_out(UART3_RXFLL, 0x00);
+       uart_reg_out(UART3_RXFLH, 0x08);
+
+       uart_reg_in(UART3_RESUME);
+
+       return 0;
+}
+
+static int omap_irda_shutdown(struct omap_irda *omap_ir)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+
+       /* Disable all UART3 Interrupts */
+       uart_reg_out(UART3_IER, 0);
+
+       /* Disable UART3 and disable baud rate generator */
+       uart_reg_out(UART3_MDR1, UART3_MDR1_RESET);
+
+       /* set SD_MODE pin to high and Disable RX IR */
+       uart_reg_out(UART3_ACREG, (UART3_ACERG_DIS_IR_RX |
+                       ~(UART3_ACERG_SD_MODE_LOW)));
+
+       /* Clear DLH and DLL */
+       uart_reg_out(UART3_LCR, UART3_LCR_DIVEN);
+       uart_reg_out(UART3_DLL, 0);
+       uart_reg_out(UART3_DLH, 0);
+
+       local_irq_restore(flags);
+
+       return 0;
+}
+
+static irqreturn_t
+omap_irda_irq(int irq, void *dev_id)
+{
+       struct net_device *dev = dev_id;
+       struct omap_irda *omap_ir = netdev_priv(dev);
+       struct sk_buff *skb;
+
+       u8 status;
+       int w = 0;
+
+       /* Clear EOF interrupt */
+       status = uart_reg_in(UART3_IIR);
+
+       if (status & UART3_IIR_TX_STATUS) {
+               u8 mdr2 = uart_reg_in(UART3_MDR2);
+               if (mdr2 & UART3_MDR2_IRTX_UNDERRUN)
+                       printk(KERN_ERR "IrDA Buffer underrun error\n");
+
+               omap_ir->stats.tx_packets++;
+
+               if (omap_ir->newspeed) {
+                       omap_irda_set_speed(dev, omap_ir->newspeed);
+                       omap_ir->newspeed = 0;
+               }
+
+               netif_wake_queue(dev);
+               if (!(status & UART3_IIR_EOF))
+                       return IRQ_HANDLED;
+       }
+
+       /* Stop DMA and if there are no errors, send frame to upper layer */
+       omap_stop_dma(omap_ir->rx_dma_channel);
+
+       status = uart_reg_in(UART3_SFLSR);      /* Take a frame status */
+
+       if (status != 0) {      /* Bad frame? */
+               omap_ir->stats.rx_frame_errors++;
+               uart_reg_in(UART3_RESUME);
+       } else {
+               /* We got a frame! */
+               skb = dev_alloc_skb(IRDA_SKB_MAX_MTU);
+
+               if (!skb) {
+                       printk(KERN_ERR "omap_sir: out of memory for RX SKB\n");
+                       return IRQ_HANDLED;
+               }
+               /*
+                * Align any IP headers that may be contained
+                * within the frame.
+                */
+
+               skb_reserve(skb, 1);
+
+               w = OMAP_DMA_CDAC_REG(omap_ir->rx_dma_channel);
+
+               if (cpu_is_omap16xx())
+                       w -= OMAP1_DMA_CDSA_L_REG(omap_ir->rx_dma_channel);
+               if (cpu_is_omap24xx())
+                       w -= OMAP2_DMA_CDSA_REG(omap_ir->rx_dma_channel);
+
+               if (!IS_FIR(omap_ir))
+                       /* Copy DMA buffer to skb */
+                       memcpy(skb_put(skb, w - 2), omap_ir->rx_buf_dma_virt,
+                                       w - 2);
+               else
+                       /* Copy DMA buffer to skb */
+                       memcpy(skb_put(skb, w - 4), omap_ir->rx_buf_dma_virt,
+                                       w - 4);
+
+               skb->dev = dev;
+               skb->mac.raw = skb->data;
+               skb->protocol = htons(ETH_P_IRDA);
+               omap_ir->stats.rx_packets++;
+               omap_ir->stats.rx_bytes += skb->len;
+               netif_receive_skb(skb); /* Send data to upper level */
+       }
+
+       /* Re-init RX DMA */
+       omap_irda_start_rx_dma(omap_ir);
+
+       dev->last_rx = jiffies;
+
+       return IRQ_HANDLED;
+}
+
+static int omap_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct omap_irda *omap_ir = netdev_priv(dev);
+       int speed = irda_get_next_speed(skb);
+       int mtt = irda_get_mtt(skb);
+       int xbofs = irda_get_next_xbofs(skb);
+
+
+       /*
+        * Does this packet contain a request to change the interface
+        * speed?  If so, remember it until we complete the transmission
+        * of this frame.
+        */
+       if (speed != omap_ir->speed && speed != -1)
+               omap_ir->newspeed = speed;
+
+       if (xbofs) /* Set number of addtional BOFS */
+               uart_reg_out(UART3_EBLR, xbofs + 1);
+
+       /*
+        * If this is an empty frame, we can bypass a lot.
+        */
+       if (skb->len == 0) {
+               if (omap_ir->newspeed) {
+                       omap_ir->newspeed = 0;
+                       omap_irda_set_speed(dev, speed);
+               }
+               dev_kfree_skb(skb);
+               return 0;
+       }
+
+       netif_stop_queue(dev);
+
+       /* Copy skb data to DMA buffer */
+       memcpy(omap_ir->tx_buf_dma_virt, skb->data, skb->len);
+
+       /* Copy skb data to DMA buffer */
+       omap_ir->stats.tx_bytes += skb->len;
+
+       /* Set frame length */
+       uart_reg_out(UART3_TXFLL, (skb->len & 0xff));
+       uart_reg_out(UART3_TXFLH, (skb->len >> 8));
+
+       if (mtt > 1000)
+               mdelay(mtt / 1000);
+       else
+               udelay(mtt);
+
+       /* Start TX DMA transfer */
+       omap_start_tx_dma(omap_ir, skb->len);
+
+       /* We can free skb now because it's already in DMA buffer */
+       dev_kfree_skb(skb);
+
+       dev->trans_start = jiffies;
+
+       return 0;
+}
+
+static int
+omap_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd)
+{
+       struct if_irda_req *rq = (struct if_irda_req *)ifreq;
+       struct omap_irda *omap_ir = netdev_priv(dev);
+       int ret = -EOPNOTSUPP;
+
+
+       switch (cmd) {
+       case SIOCSBANDWIDTH:
+               if (capable(CAP_NET_ADMIN)) {
+                       /*
+                        * We are unable to set the speed if the
+                        * device is not running.
+                        */
+                       if (omap_ir->open)
+                               ret = omap_irda_set_speed(dev,
+                                               rq->ifr_baudrate);
+                       else {
+                               printk(KERN_ERR "omap_ir: SIOCSBANDWIDTH:"
+                                               " !netif_running\n");
+                               ret = 0;
+                       }
+               }
+               break;
+
+       case SIOCSMEDIABUSY:
+               ret = -EPERM;
+               if (capable(CAP_NET_ADMIN)) {
+                       irda_device_set_media_busy(dev, TRUE);
+                       ret = 0;
+               }
+               break;
+
+       case SIOCGRECEIVING:
+               rq->ifr_receiving = 0;
+               break;
+
+       default:
+               break;
+       }
+
+       return ret;
+}
+
+static struct net_device_stats *omap_irda_stats(struct net_device *dev)
+{
+       struct omap_irda *omap_ir = netdev_priv(dev);
+       return &omap_ir->stats;
+}
+
+static int omap_irda_start(struct net_device *dev)
+{
+       struct omap_irda *omap_ir = netdev_priv(dev);
+       int err;
+
+       omap_ir->speed = 9600;
+
+       err = request_irq(dev->irq, omap_irda_irq, 0, dev->name, dev);
+       if (err)
+               goto err_irq;
+
+       /*
+        * The interrupt must remain disabled for now.
+        */
+       disable_irq(dev->irq);
+
+       /*  Request DMA channels for IrDA hardware */
+       if (omap_request_dma(omap_ir->pdata->rx_channel, "IrDA Rx DMA",
+                       (void *)omap_irda_rx_dma_callback,
+                       dev, &(omap_ir->rx_dma_channel))) {
+               printk(KERN_ERR "Failed to request IrDA Rx DMA\n");
+               goto err_irq;
+       }
+
+       if (omap_request_dma(omap_ir->pdata->tx_channel, "IrDA Tx DMA",
+                       (void *)omap_irda_tx_dma_callback,
+                       dev, &(omap_ir->tx_dma_channel))) {
+               printk(KERN_ERR "Failed to request IrDA Tx DMA\n");
+               goto err_irq;
+       }
+
+       /* Allocate TX and RX buffers for DMA channels */
+       omap_ir->rx_buf_dma_virt =
+               dma_alloc_coherent(NULL, IRDA_SKB_MAX_MTU,
+                               &(omap_ir->rx_buf_dma_phys),
+                               GFP_KERNEL);
+
+       if (!omap_ir->rx_buf_dma_virt) {
+               printk(KERN_ERR "Unable to allocate memory for rx_buf_dma\n");
+               goto err_irq;
+       }
+
+       omap_ir->tx_buf_dma_virt =
+               dma_alloc_coherent(NULL, IRDA_SIR_MAX_FRAME,
+                               &(omap_ir->tx_buf_dma_phys),
+                               GFP_KERNEL);
+
+       if (!omap_ir->tx_buf_dma_virt) {
+               printk(KERN_ERR "Unable to allocate memory for tx_buf_dma\n");
+               goto err_mem1;
+       }
+
+       /*
+        * Setup the serial port for the specified config.
+        */
+       if (omap_ir->pdata->select_irda)
+               omap_ir->pdata->select_irda(omap_ir->dev, IR_SEL);
+
+       err = omap_irda_startup(dev);
+
+       if (err)
+               goto err_startup;
+
+       omap_irda_set_speed(dev, omap_ir->speed = 9600);
+
+       /*
+        * Open a new IrLAP layer instance.
+        */
+       omap_ir->irlap = irlap_open(dev, &omap_ir->qos, "omap_sir");
+
+       err = -ENOMEM;
+       if (!omap_ir->irlap)
+               goto err_irlap;
+
+       /* Now enable the interrupt and start the queue */
+       omap_ir->open = 1;
+
+       /* Start RX DMA */
+       omap_irda_start_rx_dma(omap_ir);
+
+       enable_irq(dev->irq);
+       netif_start_queue(dev);
+
+       return 0;
+
+err_irlap:
+       omap_ir->open = 0;
+       omap_irda_shutdown(omap_ir);
+err_startup:
+       dma_free_coherent(NULL, IRDA_SIR_MAX_FRAME,
+                       omap_ir->tx_buf_dma_virt, omap_ir->tx_buf_dma_phys);
+err_mem1:
+       dma_free_coherent(NULL, IRDA_SKB_MAX_MTU,
+                       omap_ir->rx_buf_dma_virt, omap_ir->rx_buf_dma_phys);
+err_irq:
+       free_irq(dev->irq, dev);
+       return err;
+}
+
+static int omap_irda_stop(struct net_device *dev)
+{
+       struct omap_irda *omap_ir = netdev_priv(dev);
+
+       disable_irq(dev->irq);
+
+       netif_stop_queue(dev);
+
+       omap_free_dma(omap_ir->rx_dma_channel);
+       omap_free_dma(omap_ir->tx_dma_channel);
+
+       if (omap_ir->rx_buf_dma_virt)
+               dma_free_coherent(NULL, IRDA_SKB_MAX_MTU,
+                               omap_ir->rx_buf_dma_virt,
+                               omap_ir->rx_buf_dma_phys);
+       if (omap_ir->tx_buf_dma_virt)
+               dma_free_coherent(NULL, IRDA_SIR_MAX_FRAME,
+                               omap_ir->tx_buf_dma_virt,
+                               omap_ir->tx_buf_dma_phys);
+
+       omap_irda_shutdown(omap_ir);
+
+       /* Stop IrLAP */
+       if (omap_ir->irlap) {
+               irlap_close(omap_ir->irlap);
+               omap_ir->irlap = NULL;
+       }
+
+       omap_ir->open = 0;
+
+       /*
+        * Free resources
+        */
+       free_irq(dev->irq, dev);
+
+       return 0;
+}
+
+static int omap_irda_set_speed(struct net_device *dev, int speed)
+{
+       struct omap_irda *omap_ir = netdev_priv(dev);
+       int divisor;
+       unsigned long flags;
+
+       /* Set IrDA speed */
+       if (speed <= 115200) {
+
+               local_irq_save(flags);
+
+               /* SIR mode */
+               if (omap_ir->pdata->transceiver_mode)
+                       omap_ir->pdata->transceiver_mode(omap_ir->dev,
+                                                       IR_SIRMODE);
+
+               /* Set SIR mode */
+               uart_reg_out(UART3_MDR1, 1);
+               uart_reg_out(UART3_EBLR, 1);
+
+               divisor = 48000000 / (16 * speed);      /* Base clock 48 MHz */
+
+               uart_reg_out(UART3_LCR, UART3_LCR_DIVEN);
+               uart_reg_out(UART3_DLL, (divisor & 0xff));
+               uart_reg_out(UART3_DLH, (divisor >> 8));
+               uart_reg_out(UART3_LCR, 0x03);
+
+               uart_reg_out(UART3_MCR, 0);
+
+               local_irq_restore(flags);
+       } else if (speed <= 1152000) {
+
+               local_irq_save(flags);
+
+               /* Set MIR mode, auto SIP */
+               uart_reg_out(UART3_MDR1, UART3_MDR1_MIR |
+                               UART3_MDR1_SIP_AUTO);
+
+               uart_reg_out(UART3_EBLR, 2);
+
+               divisor = 48000000 / (41 * speed);      /* Base clock 48 MHz */
+
+               uart_reg_out(UART3_LCR, UART3_LCR_DIVEN);
+               uart_reg_out(UART3_DLL, (divisor & 0xff));
+               uart_reg_out(UART3_DLH, (divisor >> 8));
+               uart_reg_out(UART3_LCR, 0x03);
+
+               if (omap_ir->pdata->transceiver_mode)
+                       omap_ir->pdata->transceiver_mode(omap_ir->dev,
+                                                       IR_MIRMODE);
+
+               local_irq_restore(flags);
+       } else {
+               local_irq_save(flags);
+
+               /* FIR mode */
+               uart_reg_out(UART3_MDR1, UART3_MDR1_FIR |
+                               UART3_MDR1_SIP_AUTO);
+
+               if (omap_ir->pdata->transceiver_mode)
+                       omap_ir->pdata->transceiver_mode(omap_ir->dev,
+                                                       IR_FIRMODE);
+
+               local_irq_restore(flags);
+       }
+
+       omap_ir->speed = speed;
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+/*
+ * Suspend the IrDA interface.
+ */
+static int omap_irda_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct net_device *dev = platform_get_drvdata(pdev);
+       struct omap_irda *omap_ir = netdev_priv(dev);
+
+       if (!dev)
+               return 0;
+
+       if (omap_ir->open) {
+               /*
+                * Stop the transmit queue
+                */
+               netif_device_detach(dev);
+               disable_irq(dev->irq);
+               omap_irda_shutdown(omap_ir);
+       }
+       return 0;
+}
+
+/*
+ * Resume the IrDA interface.
+ */
+static int omap_irda_resume(struct platform_device *pdev)
+{
+       struct net_device *dev = platform_get_drvdata(pdev);
+       struct omap_irda *omap_ir= netdev_priv(dev);
+
+       if (!dev)
+               return 0;
+
+       if (omap_ir->open) {
+               /*
+                * If we missed a speed change, initialise at the new speed
+                * directly.  It is debatable whether this is actually
+                * required, but in the interests of continuing from where
+                * we left off it is desireable.  The converse argument is
+                * that we should re-negotiate at 9600 baud again.
+                */
+               if (omap_ir->newspeed) {
+                       omap_ir->speed = omap_ir->newspeed;
+                       omap_ir->newspeed = 0;
+               }
+
+               omap_irda_startup(dev);
+               omap_irda_set_speed(dev, omap_ir->speed);
+               enable_irq(dev->irq);
+
+               /*
+                * This automatically wakes up the queue
+                */
+               netif_device_attach(dev);
+       }
+
+       return 0;
+}
+#else
+#define omap_irda_suspend      NULL
+#define omap_irda_resume       NULL
+#endif
+
+static int omap_irda_probe(struct platform_device *pdev)
+{
+       struct net_device *dev;
+       struct omap_irda *omap_ir;
+       struct omap_irda_config *pdata = pdev->dev.platform_data;
+       unsigned int baudrate_mask;
+       int err = 0;
+       int irq = NO_IRQ;
+
+       if (!pdata) {
+               printk(KERN_ERR "IrDA Platform data not supplied\n");
+               return -ENOENT;
+       }
+
+       if (!pdata->rx_channel || !pdata->tx_channel) {
+               printk(KERN_ERR "IrDA invalid rx/tx channel value\n");
+               return -ENOENT;
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq <= 0) {
+               printk(KERN_WARNING "no irq for IrDA\n");
+               return -ENOENT;
+       }
+
+       dev = alloc_irdadev(sizeof(struct omap_irda));
+       if (!dev)
+               goto err_mem_1;
+
+
+       omap_ir = netdev_priv(dev);
+       omap_ir->dev = &pdev->dev;
+       omap_ir->pdata = pdata;
+
+       dev->hard_start_xmit    = omap_irda_hard_xmit;
+       dev->open               = omap_irda_start;
+       dev->stop               = omap_irda_stop;
+       dev->do_ioctl           = omap_irda_ioctl;
+       dev->get_stats          = omap_irda_stats;
+       dev->irq                = irq;
+
+       irda_init_max_qos_capabilies(&omap_ir->qos);
+
+       baudrate_mask = 0;
+       if (omap_ir->pdata->transceiver_cap & IR_SIRMODE)
+               baudrate_mask |= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
+       if (omap_ir->pdata->transceiver_cap & IR_MIRMODE)
+               baudrate_mask |= IR_57600 | IR_1152000;
+       if (omap_ir->pdata->transceiver_cap & IR_FIRMODE)
+               baudrate_mask |= IR_4000000 << 8;
+
+       omap_ir->qos.baud_rate.bits &= baudrate_mask;
+       omap_ir->qos.min_turn_time.bits = 7;
+
+       irda_qos_bits_to_value(&omap_ir->qos);
+
+       /* Any better way to avoid this? No. */
+       if (machine_is_omap_h3() || machine_is_omap_h4())
+               INIT_DELAYED_WORK(&omap_ir->pdata->gpio_expa, NULL);
+
+       err = register_netdev(dev);
+       if (!err)
+               platform_set_drvdata(pdev, dev);
+       else
+               free_netdev(dev);
+
+err_mem_1:
+       return err;
+}
+
+static int omap_irda_remove(struct platform_device *pdev)
+{
+       struct net_device *dev = platform_get_drvdata(pdev);
+
+       if (pdev) {
+               unregister_netdev(dev);
+               free_netdev(dev);
+       }
+       return 0;
+}
+
+static struct platform_driver omapir_driver = {
+       .probe          = omap_irda_probe,
+       .remove         = omap_irda_remove,
+       .suspend        = omap_irda_suspend,
+       .resume         = omap_irda_resume,
+       .driver         = {
+               .name   = "omapirda",
+       },
+};
+
+static char __initdata banner[] = KERN_INFO "OMAP IrDA driver initializing\n";
+
+static int __init omap_irda_init(void)
+{
+       printk(banner);
+       return platform_driver_register(&omapir_driver);
+}
+
+static void __exit omap_irda_exit(void)
+{
+       platform_driver_unregister(&omapir_driver);
+}
+
+module_init(omap_irda_init);
+module_exit(omap_irda_exit);
+
+MODULE_AUTHOR("MontaVista");
+MODULE_DESCRIPTION("OMAP IrDA Driver");
+MODULE_LICENSE("GPL");
+
index e62a9586fb95e3ca054d92b0972412c5daea8122..6d812795b29ef5993ea7d8be40944b5a4a53cd49 100644 (file)
@@ -497,6 +497,11 @@ static inline void  smc_rcv(struct net_device *dev)
                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)) {
index d2767e6584a98c320d1ac88ff1a830b5b4131149..ab2efd48aecb8b9acda33198a427cad3fe025823 100644 (file)
@@ -192,13 +192,14 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg)
 #include <asm/mach-types.h>
 #include <asm/arch/cpu.h>
 
-#define        SMC_IRQ_FLAGS (( \
-                  machine_is_omap_h2() \
-               || machine_is_omap_h3() \
-               || machine_is_omap_h4() \
-               || (machine_is_omap_innovator() && !cpu_is_omap1510()) \
-       ) ? IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING)
-
+#ifdef CONFIG_ARCH_OMAP1
+#define        SMC_IRQ_FLAGS           ((machine_is_omap_innovator() ||        \
+                                       machine_is_omap_osk())          \
+                               ? IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING)
+#else
+#define SMC_IRQ_FLAGS          (machine_is_omap_apollon()              \
+                               ? IRQF_TRIGGER_RISING : IRQF_TRIGGER_LOW)
+#endif
 
 #elif  defined(CONFIG_SH_SH4202_MICRODEV)
 
index d59880d44fba26e3555c46d000c13a65e12d3ec4..9de8d67f4f8d8ac71bcbc4c198d4b496d8c4dc27 100644 (file)
@@ -417,13 +417,13 @@ static int __devinit omap_rtc_probe(struct platform_device *pdev)
                rtc_write(OMAP_RTC_STATUS_ALARM, OMAP_RTC_STATUS_REG);
 
        /* handle periodic and alarm irqs */
-       if (request_irq(omap_rtc_timer, rtc_irq, SA_INTERRUPT,
+       if (request_irq(omap_rtc_timer, rtc_irq, IRQF_DISABLED,
                        rtc->class_dev.class_id, &rtc->class_dev)) {
                pr_debug("%s: RTC timer interrupt IRQ%d already claimed\n",
                        pdev->name, omap_rtc_timer);
                goto fail0;
        }
-       if (request_irq(omap_rtc_alarm, rtc_irq, SA_INTERRUPT,
+       if (request_irq(omap_rtc_alarm, rtc_irq, IRQF_DISABLED,
                        rtc->class_dev.class_id, &rtc->class_dev)) {
                pr_debug("%s: RTC alarm interrupt IRQ%d already claimed\n",
                        pdev->name, omap_rtc_alarm);
index 5261f0af8b101bcf4e1149caebdb484bbe92aa70..8d77c7b6f4b5de172cf8c088cefd889415e8254b 100644 (file)
@@ -1383,7 +1383,11 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id)
 
        DEBUG_INTR("end.\n");
 
+#ifdef CONFIG_ARCH_OMAP15XX
+       return IRQ_HANDLED;     /* FIXME: iir status not ready on 1510 */
+#else
        return IRQ_RETVAL(handled);
+#endif
 }
 
 /*
@@ -1930,6 +1934,19 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
                        /* 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);
@@ -1956,6 +1973,11 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
        unsigned int size = 8 << up->port.regshift;
        int ret = 0;
 
+#ifdef CONFIG_ARCH_OMAP
+       if (is_omap_port((unsigned int)up->port.membase))
+               size = 0x16 << up->port.regshift;
+#endif
+
        switch (up->port.iotype) {
        case UPIO_AU:
                size = 0x100000;
index d895a1adb428fbb10b32977e6a200a649766ec55..948a9dc79adbdbe0667a7919255134edb40c2982 100644 (file)
@@ -103,6 +103,20 @@ config SPI_S3C24XX_GPIO
          GPIO lines to provide the SPI bus. This can be used where
          the inbuilt hardware cannot provide the transfer mode, or
          where the board is using non hardware connected pins.
+
+config SPI_OMAP_UWIRE
+       tristate "OMAP MicroWire"
+       depends on SPI_MASTER && ARCH_OMAP
+       select SPI_BITBANG
+       help
+         This hooks up to the MicroWire controller on OMAP chips.
+
+config SPI_OMAP24XX
+       bool "McSPI driver for OMAP24xx"
+       depends on SPI_MASTER && ARCH_OMAP24XX
+       help
+         SPI master controller for OMAP24xx McSPI modules.
+
 #
 # Add new SPI master controllers in alphabetical order above this line
 #
@@ -121,7 +135,12 @@ config SPI_S3C24XX
 comment "SPI Protocol Masters"
        depends on SPI_MASTER
 
-
+config TSC2102
+       depends on SPI_MASTER
+       tristate "TSC2102 codec support"
+       ---help---
+         Say Y here if you want support for the TSC2102 chip.  It
+         will be needed for the touchscreen driver on some boards.
 #
 # Add new SPI protocol masters in alphabetical order above this line
 #
index 8f4cb67997b32afcc5207b49fb7ae2dfcb2654eb..83b3e70365f39ee0e9cfa306885089a48382f795 100644 (file)
@@ -17,9 +17,12 @@ obj-$(CONFIG_SPI_PXA2XX)             += pxa2xx_spi.o
 obj-$(CONFIG_SPI_MPC83xx)              += spi_mpc83xx.o
 obj-$(CONFIG_SPI_S3C24XX_GPIO)         += spi_s3c24xx_gpio.o
 obj-$(CONFIG_SPI_S3C24XX)              += spi_s3c24xx.o
+obj-$(CONFIG_SPI_OMAP24XX)             += omap2_mcspi.o
+obj-$(CONFIG_SPI_OMAP_UWIRE)           += omap_uwire.o
 #      ... add above this line ...
 
 # SPI protocol drivers (device/link on bus)
+obj-$(CONFIG_TSC2102)                  += tsc2102.o
 #      ... add above this line ...
 
 # SPI slave controller drivers (upstream link)
diff --git a/drivers/spi/omap2_mcspi.c b/drivers/spi/omap2_mcspi.c
new file mode 100644 (file)
index 0000000..b8d0ec0
--- /dev/null
@@ -0,0 +1,925 @@
+/*
+ * OMAP2 McSPI controller driver
+ *
+ * Copyright (C) 2005, 2006 Nokia Corporation
+ * Author: Samuel Ortiz <samuel.ortiz@nokia.com> and
+ *         Juha Yrjölä <juha.yrjola@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+
+#include <linux/spi/spi.h>
+
+#include <asm/io.h>
+#include <asm/arch/dma.h>
+#include <asm/arch/mcspi.h>
+
+#define OMAP2_MCSPI_MAX_FREQ           48000000
+
+#define OMAP2_MCSPI_REVISION           0x00
+#define OMAP2_MCSPI_SYSCONFIG          0x10
+#define OMAP2_MCSPI_SYSSTATUS          0x14
+#define OMAP2_MCSPI_IRQSTATUS          0x18
+#define OMAP2_MCSPI_IRQENABLE          0x1c
+#define OMAP2_MCSPI_WAKEUPENABLE       0x20
+#define OMAP2_MCSPI_SYST               0x24
+#define OMAP2_MCSPI_MODULCTRL          0x28
+#define OMAP2_MCSPI_CHCONF0            0x2c
+#define OMAP2_MCSPI_CHSTAT0            0x30
+#define OMAP2_MCSPI_CHCTRL0            0x34
+#define OMAP2_MCSPI_TX0                        0x38
+#define OMAP2_MCSPI_RX0                        0x3c
+
+#define OMAP2_MCSPI_SYSCONFIG_SOFTRESET        (1 << 1)
+
+#define OMAP2_MCSPI_SYSSTATUS_RESETDONE        (1 << 0)
+
+#define OMAP2_MCSPI_MODULCTRL_SINGLE   (1 << 0)
+#define OMAP2_MCSPI_MODULCTRL_MS       (1 << 2)
+#define OMAP2_MCSPI_MODULCTRL_STEST    (1 << 3)
+
+#define OMAP2_MCSPI_CHCONF_PHA         (1 << 0)
+#define OMAP2_MCSPI_CHCONF_POL         (1 << 1)
+#define OMAP2_MCSPI_CHCONF_CLKD_MASK   (0x0f << 2)
+#define OMAP2_MCSPI_CHCONF_EPOL                (1 << 6)
+#define OMAP2_MCSPI_CHCONF_WL_MASK     (0x1f << 7)
+#define OMAP2_MCSPI_CHCONF_TRM_RX_ONLY (0x01 << 12)
+#define OMAP2_MCSPI_CHCONF_TRM_TX_ONLY (0x02 << 12)
+#define OMAP2_MCSPI_CHCONF_TRM_MASK    (0x03 << 12)
+#define OMAP2_MCSPI_CHCONF_DMAW                (1 << 14)
+#define OMAP2_MCSPI_CHCONF_DMAR                (1 << 15)
+#define OMAP2_MCSPI_CHCONF_DPE0                (1 << 16)
+#define OMAP2_MCSPI_CHCONF_DPE1                (1 << 17)
+#define OMAP2_MCSPI_CHCONF_IS          (1 << 18)
+#define OMAP2_MCSPI_CHCONF_TURBO       (1 << 19)
+#define OMAP2_MCSPI_CHCONF_FORCE       (1 << 20)
+
+
+#define OMAP2_MCSPI_CHSTAT_RXS         (1 << 0)
+#define OMAP2_MCSPI_CHSTAT_TXS         (1 << 1)
+#define OMAP2_MCSPI_CHSTAT_EOT         (1 << 2)
+
+#define OMAP2_MCSPI_CHCTRL_EN          (1 << 0)
+
+/* We have 2 DMA channels per CS, one for RX and one for TX */
+struct omap2_mcspi_dma {
+       int dma_tx_channel;
+       int dma_rx_channel;
+
+       int dma_tx_sync_dev;
+       int dma_rx_sync_dev;
+
+       struct completion dma_tx_completion;
+       struct completion dma_rx_completion;
+};
+
+struct omap2_mcspi {
+       struct work_struct      work;
+       spinlock_t              lock;
+       struct list_head        msg_queue;
+       struct spi_master       *master;
+       struct clk              *ick;
+       struct clk              *fck;
+       /* Virtual base address of the controller */
+       unsigned long           base;
+       /* SPI1 has 4 channels, while SPI2 has 2 */
+       struct omap2_mcspi_dma  *dma_channels;
+};
+
+struct omap2_mcspi_cs {
+       u8 transmit_mode;
+       int word_len;
+};
+
+static struct workqueue_struct * omap2_mcspi_wq;
+
+#define MOD_REG_BIT(val, mask, set) do { \
+       if (set) \
+               val |= mask; \
+       else \
+               val &= ~mask; \
+} while(0)
+
+static inline void mcspi_write_reg(struct spi_master *master,
+                                  int idx, u32 val)
+{
+       struct omap2_mcspi * mcspi = class_get_devdata(&master->cdev);
+
+       __raw_writel(val, mcspi->base + idx);
+}
+
+static inline u32 mcspi_read_reg(struct spi_master *master,
+                                int idx)
+{
+       struct omap2_mcspi * mcspi = class_get_devdata(&master->cdev);
+
+       return __raw_readl(mcspi->base + idx);
+}
+
+static inline void mcspi_write_cs_reg(const struct spi_device *spi,
+                                     int idx, u32 val)
+{
+       struct omap2_mcspi * mcspi = class_get_devdata(&spi->master->cdev);
+
+       __raw_writel(val, mcspi->base + spi->chip_select * 0x14 + idx);
+}
+
+static inline u32 mcspi_read_cs_reg(const struct spi_device *spi,
+                                   int idx)
+{
+       struct omap2_mcspi * mcspi = class_get_devdata(&spi->master->cdev);
+
+       return __raw_readl(mcspi->base + spi->chip_select * 0x14 + idx);
+}
+
+static void omap2_mcspi_set_dma_req(const struct spi_device *spi,
+                                   int is_read, int enable)
+{
+       u32 l, rw;
+
+       l = mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCONF0);
+
+       if (is_read) /* 1 is read, 0 write */
+               rw = OMAP2_MCSPI_CHCONF_DMAR;
+       else
+               rw = OMAP2_MCSPI_CHCONF_DMAW;
+
+       MOD_REG_BIT(l, rw, enable);
+       mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCONF0, l);
+}
+
+static void omap2_mcspi_set_enable(const struct spi_device *spi, int enable)
+{
+       u32 l;
+
+       l = mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCTRL0);
+       MOD_REG_BIT(l, OMAP2_MCSPI_CHCTRL_EN, enable);
+       mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, l);
+}
+
+static void omap2_mcspi_force_cs(struct spi_device *spi, int cs_active)
+{
+       u32 l;
+
+       l = mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCONF0);
+       MOD_REG_BIT(l, OMAP2_MCSPI_CHCONF_FORCE, cs_active);
+       mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCONF0, l);
+}
+
+static void omap2_mcspi_set_master_mode(struct spi_device *spi, int single_channel)
+{
+       u32 l;
+
+       /* Need reset when switching from slave mode */
+       l = mcspi_read_reg(spi->master, OMAP2_MCSPI_MODULCTRL);
+       MOD_REG_BIT(l, OMAP2_MCSPI_MODULCTRL_STEST, 0);
+       MOD_REG_BIT(l, OMAP2_MCSPI_MODULCTRL_MS, 0);
+       MOD_REG_BIT(l, OMAP2_MCSPI_MODULCTRL_SINGLE, single_channel);
+       mcspi_write_reg(spi->master, OMAP2_MCSPI_MODULCTRL, l);
+}
+
+static void omap2_mcspi_txrx_dma(struct spi_device *spi,
+                                struct spi_transfer *xfer)
+{
+       struct omap2_mcspi      * mcspi;
+       struct omap2_mcspi_cs   * cs = spi->controller_state;
+       struct omap2_mcspi_dma  * mcspi_dma;
+       unsigned int            count, c;
+       unsigned long           base, tx_reg, rx_reg;
+       int                     word_len, data_type, element_count;
+       u8                      * rx;
+       const u8                * tx;
+       u32                     l;
+
+       mcspi = class_get_devdata(&spi->master->cdev);
+       mcspi_dma = &mcspi->dma_channels[spi->chip_select];
+
+       count = xfer->len;
+       c = count;
+       word_len = cs->word_len;
+
+       l = mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCONF0);
+       l &= ~OMAP2_MCSPI_CHCONF_TRM_MASK;
+       if (xfer->tx_buf == NULL)
+               l |= OMAP2_MCSPI_CHCONF_TRM_RX_ONLY;
+       else if (xfer->rx_buf == NULL)
+               l |= OMAP2_MCSPI_CHCONF_TRM_TX_ONLY;
+       mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCONF0, l);
+
+       omap2_mcspi_set_enable(spi, 1);
+
+       base = io_v2p(mcspi->base) + spi->chip_select * 0x14;
+       tx_reg = base + OMAP2_MCSPI_TX0;
+       rx_reg = base + OMAP2_MCSPI_RX0;
+       rx = xfer->rx_buf;
+       tx = xfer->tx_buf;
+
+       if (word_len <= 8) {
+               data_type = OMAP_DMA_DATA_TYPE_S8;
+               element_count = count;
+       } else if (word_len <= 16) {
+               data_type = OMAP_DMA_DATA_TYPE_S16;
+               element_count = count >> 1;
+       } else if (word_len <= 32) {
+               data_type = OMAP_DMA_DATA_TYPE_S32;
+               element_count = count >> 2;
+       } else
+               return;
+
+       /* RX_ONLY mode needs dummy data in TX reg */
+       if (tx == NULL)
+               __raw_writel(0, mcspi->base +
+                            spi->chip_select * 0x14 + OMAP2_MCSPI_TX0);
+
+       if (tx != NULL) {
+               xfer->tx_dma = dma_map_single(&spi->dev, (void *) tx, count,
+                                             DMA_TO_DEVICE);
+               if (dma_mapping_error(xfer->tx_dma)) {
+                       printk(KERN_ERR "%s(): Couldn't DMA map a %d bytes TX buffer\n",
+                              __FUNCTION__, count);
+                       return;
+               }
+
+               omap_set_dma_transfer_params(mcspi_dma->dma_tx_channel,
+                                            data_type, element_count, 1,
+                                            OMAP_DMA_SYNC_ELEMENT,
+                                            mcspi_dma->dma_tx_sync_dev, 0);
+
+               omap_set_dma_dest_params(mcspi_dma->dma_tx_channel, 0,
+                                        OMAP_DMA_AMODE_CONSTANT,
+                                        tx_reg, 0, 0);
+
+               omap_set_dma_src_params(mcspi_dma->dma_tx_channel, 0,
+                                       OMAP_DMA_AMODE_POST_INC,
+                                       xfer->tx_dma, 0, 0);
+       }
+
+       if (rx != NULL) {
+               xfer->rx_dma = dma_map_single(&spi->dev, rx, count,
+                                             DMA_FROM_DEVICE);
+               if (dma_mapping_error(xfer->rx_dma)) {
+                       printk(KERN_ERR "%s(): Couldn't DMA map a %d bytes RX buffer\n",
+                              __FUNCTION__, count);
+                       if (tx != NULL)
+                               dma_unmap_single(NULL, xfer->tx_dma,
+                                                count, DMA_TO_DEVICE);
+                       return;
+               }
+
+               omap_set_dma_transfer_params(mcspi_dma->dma_rx_channel,
+                                            data_type, element_count, 1,
+                                            OMAP_DMA_SYNC_ELEMENT,
+                                            mcspi_dma->dma_rx_sync_dev, 1);
+
+               omap_set_dma_src_params(mcspi_dma->dma_rx_channel, 0,
+                                       OMAP_DMA_AMODE_CONSTANT,
+                                       rx_reg, 0, 0);
+
+               omap_set_dma_dest_params(mcspi_dma->dma_rx_channel, 0,
+                                        OMAP_DMA_AMODE_POST_INC,
+                                        xfer->rx_dma, 0, 0);
+       }
+
+       if (tx != NULL) {
+               omap_start_dma(mcspi_dma->dma_tx_channel);
+               omap2_mcspi_set_dma_req(spi, 0, 1);
+       }
+
+       if (rx != NULL) {
+               omap_start_dma(mcspi_dma->dma_rx_channel);
+               omap2_mcspi_set_dma_req(spi, 1, 1);
+       }
+
+       if (tx != NULL) {
+               wait_for_completion(&mcspi_dma->dma_tx_completion);
+               dma_unmap_single(NULL, xfer->tx_dma, count, DMA_TO_DEVICE);
+       }
+
+       if (rx != NULL) {
+               wait_for_completion(&mcspi_dma->dma_rx_completion);
+               dma_unmap_single(NULL, xfer->rx_dma, count, DMA_FROM_DEVICE);
+       }
+
+       omap2_mcspi_set_enable(spi, 0);
+}
+
+static void omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
+{
+       struct omap2_mcspi * mcspi;
+       struct omap2_mcspi_cs *cs = spi->controller_state;
+       unsigned int            count, c;
+       u32                     l;
+       unsigned long           base, tx_reg, rx_reg, chstat_reg;
+       int                     word_len;
+
+       mcspi = class_get_devdata(&spi->master->cdev);
+       count = xfer->len;
+       c = count;
+       word_len = cs->word_len;
+
+       l = mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCONF0);
+       l &= ~OMAP2_MCSPI_CHCONF_TRM_MASK;
+       if (xfer->tx_buf == NULL)
+               l |= OMAP2_MCSPI_CHCONF_TRM_RX_ONLY;
+       else if (xfer->rx_buf == NULL)
+               l |= OMAP2_MCSPI_CHCONF_TRM_TX_ONLY;
+       mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCONF0, l);
+
+       omap2_mcspi_set_enable(spi, 1);
+
+       /* We store the pre-calculated register addresses on stack to speed
+        * up the transfer loop. */
+       base = mcspi->base + spi->chip_select * 0x14;
+       tx_reg          = base + OMAP2_MCSPI_TX0;
+       rx_reg          = base + OMAP2_MCSPI_RX0;
+       chstat_reg      = base + OMAP2_MCSPI_CHSTAT0;
+
+       /* RX_ONLY mode needs dummy data in TX reg */
+       if (xfer->tx_buf == NULL)
+               __raw_writel(0, tx_reg);
+
+       if (word_len <= 8) {
+               u8              *rx;
+               const u8        *tx;
+
+               rx = xfer->rx_buf;
+               tx = xfer->tx_buf;
+
+               while (c--) {
+                       if (tx != NULL) {
+                               while (!(__raw_readl(chstat_reg) & OMAP2_MCSPI_CHSTAT_TXS));
+#ifdef VERBOSE
+                               dev_dbg(&spi->dev, "write-%d %02x\n",
+                                               word_len, *tx);
+#endif
+                               __raw_writel(*tx, tx_reg);
+                       }
+                       if (rx != NULL) {
+                               while (!(__raw_readl(chstat_reg) & OMAP2_MCSPI_CHSTAT_RXS));
+                               if (c == 0 && tx == NULL)
+                                       omap2_mcspi_set_enable(spi, 0);
+                               *rx++ = __raw_readl(rx_reg);
+#ifdef VERBOSE
+                               dev_dbg(&spi->dev, "read-%d %02x\n",
+                                               word_len, *(rx - 1));
+#endif
+                       }
+               }
+       } else if (word_len <= 16) {
+               u16             *rx;
+               const u16       *tx;
+
+               rx = xfer->rx_buf;
+               tx = xfer->tx_buf;
+               c >>= 1;
+               while (c--) {
+                       if (tx != NULL) {
+                               while (!(__raw_readl(chstat_reg) & OMAP2_MCSPI_CHSTAT_TXS));
+#ifdef VERBOSE
+                               dev_dbg(&spi->dev, "write-%d %04x\n",
+                                               word_len, *tx);
+#endif
+                               __raw_writel(*tx++, tx_reg);
+                       }
+                       if (rx != NULL) {
+                               while (!(__raw_readl(chstat_reg) & OMAP2_MCSPI_CHSTAT_RXS));
+                               if (c == 0 && tx == NULL)
+                                       omap2_mcspi_set_enable(spi, 0);
+                               *rx++ = __raw_readl(rx_reg);
+#ifdef VERBOSE
+                               dev_dbg(&spi->dev, "read-%d %04x\n",
+                                               word_len, *(rx - 1));
+#endif
+                       }
+               }
+       } else if (word_len <= 32) {
+               u32             *rx;
+               const u32       *tx;
+
+               rx = xfer->rx_buf;
+               tx = xfer->tx_buf;
+               c >>= 2;
+               while (c--) {
+                       if (tx != NULL) {
+                               while (!(__raw_readl(chstat_reg) & OMAP2_MCSPI_CHSTAT_TXS));
+#ifdef VERBOSE
+                               dev_dbg(&spi->dev, "write-%d %04x\n",
+                                               word_len, *tx);
+#endif
+                               __raw_writel(*tx++, tx_reg);
+                       }
+                       if (rx != NULL) {
+                               while (!(__raw_readl(chstat_reg) & OMAP2_MCSPI_CHSTAT_RXS));
+                               if (c == 0 && tx == NULL)
+                                       omap2_mcspi_set_enable(spi, 0);
+                               *rx++ = __raw_readl(rx_reg);
+#ifdef VERBOSE
+                               dev_dbg(&spi->dev, "read-%d %04x\n",
+                                               word_len, *(rx - 1));
+#endif
+                       }
+               }
+       }
+
+       if (xfer->tx_buf != NULL) {
+               while (!(__raw_readl(chstat_reg) & OMAP2_MCSPI_CHSTAT_TXS));
+               while (!(__raw_readl(chstat_reg) & OMAP2_MCSPI_CHSTAT_EOT));
+               omap2_mcspi_set_enable(spi, 0);
+       }
+}
+
+static int omap2_mcspi_setup_transfer(struct spi_device *spi,
+                                     struct spi_transfer *t)
+{
+       struct omap2_mcspi_cs *cs = spi->controller_state;
+       struct omap2_mcspi_device_config *conf;
+       u32 l = 0, div = 0;
+       u8 word_len = spi->bits_per_word;
+
+       if (t != NULL && t->bits_per_word)
+               word_len = t->bits_per_word;
+       if (!word_len)
+               word_len = 8;
+
+       if (spi->bits_per_word > 32)
+               return -EINVAL;
+       cs->word_len = word_len;
+
+       conf = (struct omap2_mcspi_device_config *) spi->controller_data;
+
+       if (conf->single_channel == 1)
+               omap2_mcspi_set_master_mode(spi, 1);
+       else
+               omap2_mcspi_set_master_mode(spi, 0);
+
+       if (spi->max_speed_hz) {
+               while (div <= 15 && (OMAP2_MCSPI_MAX_FREQ / (1 << div)) > spi->max_speed_hz)
+                       div++;
+       } else
+               div = 15;
+
+       if (spi->chip_select > 3 ||
+           word_len < 4 || word_len > 32 ||
+           div > 15) {
+               dev_err(&spi->dev, "Invalid McSPI channel setting\n");
+               return -EINVAL;
+       }
+
+       l = mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCONF0);
+       l &= ~OMAP2_MCSPI_CHCONF_IS;
+       l &= ~OMAP2_MCSPI_CHCONF_DPE1;
+       l |= OMAP2_MCSPI_CHCONF_DPE0;
+       l &= ~OMAP2_MCSPI_CHCONF_WL_MASK;
+       l |= (word_len - 1) << 7;
+       if (!(spi->mode & SPI_CS_HIGH))
+               l |= OMAP2_MCSPI_CHCONF_EPOL;
+       else
+               l &= ~OMAP2_MCSPI_CHCONF_EPOL;
+       l &= ~OMAP2_MCSPI_CHCONF_CLKD_MASK;
+       l |= div << 2;
+       if (spi->mode & SPI_CPOL)
+               l |= OMAP2_MCSPI_CHCONF_POL;
+       else
+               l &= ~OMAP2_MCSPI_CHCONF_POL;
+       if (spi->mode & SPI_CPHA)
+               l &= ~OMAP2_MCSPI_CHCONF_PHA;
+       else
+               l |= OMAP2_MCSPI_CHCONF_PHA;
+       mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCONF0, l);
+
+       dev_dbg(&spi->dev, "setup: speed %d, sample %s edge, clk %s inverted\n",
+                       OMAP2_MCSPI_MAX_FREQ / (1 << div),
+                       (spi->mode & SPI_CPHA) ? "odd" : "even",
+                       (spi->mode & SPI_CPOL) ? "" : "not");
+
+       return 0;
+}
+
+static void omap2_mcspi_dma_rx_callback(int lch, u16 ch_status, void *data)
+{
+       struct spi_device * spi = (struct spi_device *)data;
+       struct omap2_mcspi * mcspi;
+       struct omap2_mcspi_dma * mcspi_dma;
+
+       mcspi = class_get_devdata(&spi->master->cdev);
+       mcspi_dma = &(mcspi->dma_channels[spi->chip_select]);
+
+       complete(&mcspi_dma->dma_rx_completion);
+
+       /* We must disable the DMA RX request */
+       omap2_mcspi_set_dma_req(spi, 1, 0);
+}
+
+static void omap2_mcspi_dma_tx_callback(int lch, u16 ch_status, void *data)
+{
+       struct spi_device * spi = (struct spi_device *)data;
+       struct omap2_mcspi * mcspi;
+       struct omap2_mcspi_dma * mcspi_dma;
+
+       mcspi = class_get_devdata(&spi->master->cdev);
+       mcspi_dma = &(mcspi->dma_channels[spi->chip_select]);
+
+       complete(&mcspi_dma->dma_tx_completion);
+
+       /* We must disable the DMA TX request */
+       omap2_mcspi_set_dma_req(spi, 0, 0);
+}
+
+static int omap2_mcspi_request_dma(struct spi_device *spi)
+{
+       int rx_dev_id, tx_dev_id;
+       struct spi_master *master = spi->master;
+       struct omap2_mcspi * mcspi;
+       struct omap2_mcspi_dma * mcspi_dma;
+
+       mcspi = class_get_devdata(&master->cdev);
+       mcspi_dma = &(mcspi->dma_channels[spi->chip_select]);
+
+       if (master->bus_num == 1) {
+               switch (spi->chip_select) {
+               case 0:
+                       rx_dev_id = OMAP24XX_DMA_SPI1_RX0;
+                       tx_dev_id = OMAP24XX_DMA_SPI1_TX0;
+                       break;
+               case 1:
+                       rx_dev_id = OMAP24XX_DMA_SPI1_RX1;
+                       tx_dev_id = OMAP24XX_DMA_SPI1_TX1;
+                       break;
+               case 2:
+                       rx_dev_id = OMAP24XX_DMA_SPI1_RX2;
+                       tx_dev_id = OMAP24XX_DMA_SPI1_TX2;
+                       break;
+               case 3:
+                       rx_dev_id = OMAP24XX_DMA_SPI1_RX3;
+                       tx_dev_id = OMAP24XX_DMA_SPI1_TX3;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       } else if (master->bus_num == 2) {
+               /* McSPI 2 has 1 chipselect */
+               switch (spi->chip_select) {
+               case 0:
+                       rx_dev_id = OMAP24XX_DMA_SPI2_RX0;
+                       tx_dev_id = OMAP24XX_DMA_SPI2_TX0;
+                       break;
+               case 1:
+                       rx_dev_id = OMAP24XX_DMA_SPI2_RX1;
+                       tx_dev_id = OMAP24XX_DMA_SPI2_TX1;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       } else
+               return -EINVAL;
+
+
+       if (omap_request_dma(rx_dev_id, "McSPI RX",
+                            omap2_mcspi_dma_rx_callback, spi,
+                            &mcspi_dma->dma_rx_channel)) {
+               printk(KERN_ERR "Unable to request DMA channel for McSPI RX\n");
+               return -EAGAIN;
+       }
+       
+       if (omap_request_dma(tx_dev_id, "McSPI TX",
+                            omap2_mcspi_dma_tx_callback, spi,
+                            &mcspi_dma->dma_tx_channel)) {
+               omap_free_dma(mcspi_dma->dma_rx_channel);
+               mcspi_dma->dma_rx_channel = -1;
+               printk(KERN_ERR "Unable to request DMA channel for McSPI TX\n");
+               return -EAGAIN;
+       }
+       
+       mcspi_dma->dma_rx_sync_dev = rx_dev_id;
+       mcspi_dma->dma_tx_sync_dev = tx_dev_id;
+
+       init_completion(&mcspi_dma->dma_rx_completion);
+       init_completion(&mcspi_dma->dma_tx_completion);
+       
+       return 0;
+}
+
+static int omap2_mcspi_setup(struct spi_device *spi)
+{
+       int ret;
+       struct omap2_mcspi * mcspi;
+       struct omap2_mcspi_dma * mcspi_dma;
+       struct omap2_mcspi_cs *cs = spi->controller_state;
+
+       mcspi = class_get_devdata(&spi->master->cdev);
+       mcspi_dma = &mcspi->dma_channels[spi->chip_select];
+
+       if (!cs) {
+               cs = kzalloc(sizeof *cs, GFP_KERNEL);
+               if (!cs)
+                       return -ENOMEM;
+               spi->controller_state = cs;
+       }
+       
+       if (mcspi_dma->dma_rx_channel == -1 ||
+           mcspi_dma->dma_tx_channel == -1) {
+               ret = omap2_mcspi_request_dma(spi);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return omap2_mcspi_setup_transfer(spi, NULL);
+}
+
+static void omap2_mcspi_cleanup(const struct spi_device *spi)
+{
+       struct omap2_mcspi * mcspi;
+       struct omap2_mcspi_dma * mcspi_dma;
+
+       mcspi = class_get_devdata(&spi->master->cdev);
+       mcspi_dma = &mcspi->dma_channels[spi->chip_select];
+
+       if (spi->controller_state != NULL)
+               kfree(spi->controller_state);
+
+       if (mcspi_dma->dma_rx_channel != -1 &&
+           mcspi_dma->dma_tx_channel != -1) {
+               omap_free_dma(mcspi_dma->dma_tx_channel);
+               omap_free_dma(mcspi_dma->dma_rx_channel);
+       }
+}
+
+
+static void omap2_mcspi_work(struct work_struct *work)
+{
+       struct omap2_mcspi      *mcspi = container_of(work, struct omap2_mcspi, work);
+       unsigned long           flags;
+
+       spin_lock_irqsave(&mcspi->lock, flags);
+       while (!list_empty(&mcspi->msg_queue)) {
+               struct spi_message              *m;
+               struct spi_device               *spi;
+               struct spi_transfer             *t = NULL;
+               int                             cs_active = 0;
+               struct omap2_mcspi_device_config *conf;
+               struct omap2_mcspi_cs           *cs;
+               int                             par_override = 0;
+               int status = 0;
+
+               m = container_of(mcspi->msg_queue.next, struct spi_message,
+                                queue);
+
+               list_del_init(&m->queue);
+               spin_unlock_irqrestore(&mcspi->lock, flags);
+
+               spi = m->spi;
+               conf = (struct omap2_mcspi_device_config *) spi->controller_data;
+               cs = (struct omap2_mcspi_cs *) spi->controller_state;
+
+               list_for_each_entry(t, &m->transfers, transfer_list) {
+                       if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) {
+                               status = -EINVAL;
+                               break;
+                       }
+                       if (par_override || t->speed_hz || t->bits_per_word) {
+                               par_override = 1;
+                               status = omap2_mcspi_setup_transfer(spi, t);
+                               if (status < 0)
+                                       break;
+                               if (!t->speed_hz && !t->bits_per_word)
+                                       par_override = 0;
+                       }
+
+                       if (!cs_active) {
+                               omap2_mcspi_force_cs(spi, 1);
+                               cs_active = 1;
+                       }
+
+                       if (m->is_dma_mapped &&
+                           (t->tx_dma != 0 || t->rx_dma != 0))
+                               omap2_mcspi_txrx_dma(spi, t);
+                       else
+                               omap2_mcspi_txrx_pio(spi, t);
+
+                       if (t->cs_change) {
+                               /* In the last transfer entry the flag means
+                                * _leave_ CS on */
+                               if (t->transfer_list.next != &m->transfers)
+                                       omap2_mcspi_force_cs(spi, 0);
+                               cs_active = 0;
+                       }
+               }
+
+               /* Restore defaults they are overriden */
+               if (par_override) {
+                       par_override = 0;
+                       status = omap2_mcspi_setup_transfer(spi, NULL);
+               }
+
+               if (cs_active)
+                       omap2_mcspi_force_cs(spi, 0);
+
+               m->status = status;
+               m->complete(m->context);
+
+               spin_lock_irqsave(&mcspi->lock, flags);
+       }
+       spin_unlock_irqrestore(&mcspi->lock, flags);
+}
+
+static int omap2_mcspi_transfer(struct spi_device *spi, struct spi_message *m)
+{
+       struct omap2_mcspi      *mcspi;
+       unsigned long           flags;
+
+       m->actual_length = 0;
+       m->status = 0;
+
+       mcspi = class_get_devdata(&spi->master->cdev);
+
+       spin_lock_irqsave(&mcspi->lock, flags);
+       list_add_tail(&m->queue, &mcspi->msg_queue);
+       spin_unlock_irqrestore(&mcspi->lock, flags);
+
+       queue_work(omap2_mcspi_wq, &mcspi->work);
+
+       return 0;
+}
+
+static int __devinit omap2_mcspi_reset(struct spi_master *master)
+{
+#if 0
+       mcspi_write_reg(master, OMAP2_MCSPI_SYSCONFIG,
+                       OMAP2_MCSPI_SYSCONFIG_SOFTRESET);
+       while (!(mcspi_read_reg(master, OMAP2_MCSPI_SYSSTATUS) & OMAP2_MCSPI_SYSSTATUS_RESETDONE));
+#else
+       return 0;
+#endif
+}
+
+static int __devinit omap2_mcspi_probe(struct platform_device *pdev)
+{
+       struct spi_master               *master;
+       struct omap2_mcspi_platform_config *pdata = pdev->dev.platform_data;
+       struct omap2_mcspi              *mcspi;
+       struct resource                 *r;
+       int                             status = 0, i;
+               
+       if (!pdata)
+               return -EINVAL;
+
+       master = spi_alloc_master(&pdev->dev, sizeof *mcspi);
+       if (master == NULL) {
+               dev_err(&pdev->dev, "master allocation failed\n");
+               return -ENOMEM;
+       }
+
+       if (pdev->id != -1)
+               master->bus_num = pdev->id;
+
+       master->setup = omap2_mcspi_setup;
+       master->transfer = omap2_mcspi_transfer;
+       master->cleanup = omap2_mcspi_cleanup;
+       master->num_chipselect = pdata->num_cs;
+
+       if (class_device_get(&master->cdev) == NULL) {
+               dev_err(&pdev->dev, "no master->cdev");
+               status = -ENOMEM;
+               goto err0;
+       }
+
+       dev_set_drvdata(&pdev->dev, master);
+
+       mcspi = class_get_devdata(&master->cdev);
+       mcspi->master = master;
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (r == NULL) {
+               status = -ENODEV;
+               goto err1;
+       }
+       
+       mcspi->base = io_p2v(r->start);
+
+       INIT_WORK(&mcspi->work, omap2_mcspi_work);
+
+       spin_lock_init(&mcspi->lock);
+       INIT_LIST_HEAD(&mcspi->msg_queue);
+
+       mcspi->ick = clk_get(&pdev->dev, "mcspi_ick");
+       if (IS_ERR(mcspi->ick)) {
+               dev_err(&pdev->dev, "can't get mcspi_ick\n");
+               status = PTR_ERR(mcspi->ick);
+               goto err1;
+       }
+       clk_enable(mcspi->ick);
+       mcspi->fck = clk_get(&pdev->dev, "mcspi_fck");
+       if (IS_ERR(mcspi->fck)) {
+               dev_err(&pdev->dev, "can't get mcspi_fck\n");
+               status = PTR_ERR(mcspi->fck);
+               goto err2;
+       }
+       clk_enable(mcspi->fck);
+
+       mcspi->dma_channels = 
+               (struct omap2_mcspi_dma *)kzalloc(master->num_chipselect *
+                                                 sizeof(struct omap2_mcspi_dma),
+                                                 GFP_KERNEL);
+       
+       if (mcspi->dma_channels == NULL)
+               goto err3;
+
+       for (i = 0; i < master->num_chipselect; i++) {
+               mcspi->dma_channels[i].dma_rx_channel = -1;
+               mcspi->dma_channels[i].dma_tx_channel = -1;
+       }
+
+       if (omap2_mcspi_reset(master) < 0)
+                goto err4;
+
+       status = spi_register_master(master);
+       if (status < 0)
+               goto err4;
+
+       return status;
+
+err4:
+       kfree(mcspi->dma_channels);
+err3:
+       clk_disable(mcspi->fck);
+       clk_put(mcspi->fck);
+err2:
+       clk_disable(mcspi->ick);
+       clk_put(mcspi->ick);
+err1:
+       class_device_put(&master->cdev);
+err0:
+       return status;
+}
+
+static int __devexit omap2_mcspi_remove(struct platform_device *pdev)
+{
+       struct spi_master               *master;
+       struct omap2_mcspi              *mcspi;
+
+       master = dev_get_drvdata(&pdev->dev);
+
+       spi_unregister_master(master);
+       mcspi = class_get_devdata(&master->cdev);
+       clk_disable(mcspi->fck);
+       clk_put(mcspi->fck);
+       clk_disable(mcspi->ick);
+       clk_put(mcspi->ick);
+       class_device_put(&master->cdev);
+       kfree(mcspi->dma_channels);
+
+       return 0;
+}
+
+struct platform_driver omap2_mcspi_driver = {
+       .driver = {
+               .name =         "omap2_mcspi",
+               .owner =        THIS_MODULE,
+       },
+       .probe =        omap2_mcspi_probe,
+       .remove =       __devexit_p(omap2_mcspi_remove),
+};
+EXPORT_SYMBOL_GPL(omap2_mcspi_driver);
+
+
+static int __init omap2_mcspi_init(void)
+{
+       printk(KERN_INFO "OMAP24xx McSPI driver initializing\n");
+       omap2_mcspi_wq = create_workqueue("OMAP McSPI");
+       if (omap2_mcspi_wq == NULL)
+               return -1;
+       return platform_driver_register(&omap2_mcspi_driver);
+}
+subsys_initcall(omap2_mcspi_init);
+
+static void __exit omap2_mcspi_exit(void)
+{
+       platform_driver_unregister(&omap2_mcspi_driver);
+}
+module_exit(omap2_mcspi_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/omap_uwire.c b/drivers/spi/omap_uwire.c
new file mode 100644 (file)
index 0000000..b5a4d62
--- /dev/null
@@ -0,0 +1,567 @@
+/*
+ * omap_uwire.c -- MicroWire interface driver for OMAP
+ *
+ * Copyright 2003 MontaVista Software Inc. <source@mvista.com>
+ *
+ * Ported to 2.6 OMAP uwire interface.
+ * Copyright (C) 2004 Texas Instruments.
+ *
+ * Generalization patches by Juha Yrjölä <juha.yrjola@nokia.com>
+ *
+ * Copyright (C) 2005 David Brownell (ported to 2.6 SPI interface)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/mux.h>
+#include <asm/arch/omap730.h>  /* OMAP730_IO_CONF registers */
+
+
+/* FIXME address is now a platform device resource,
+ * and irqs should show there too...
+ */
+#define UWIRE_BASE_PHYS                0xFFFB3000
+#define UWIRE_BASE             ((void *__iomem)IO_ADDRESS(UWIRE_BASE_PHYS))
+
+/* uWire Registers: */
+#define UWIRE_IO_SIZE 0x20
+#define UWIRE_TDR     0x00
+#define UWIRE_RDR     0x00
+#define UWIRE_CSR     0x01
+#define UWIRE_SR1     0x02
+#define UWIRE_SR2     0x03
+#define UWIRE_SR3     0x04
+#define UWIRE_SR4     0x05
+#define UWIRE_SR5     0x06
+
+/* CSR bits */
+#define        RDRB    (1 << 15)
+#define        CSRB    (1 << 14)
+#define        START   (1 << 13)
+#define        CS_CMD  (1 << 12)
+
+/* SR1 or SR2 bits */
+#define UWIRE_READ_FALLING_EDGE                0x0001
+#define UWIRE_READ_RISING_EDGE         0x0000
+#define UWIRE_WRITE_FALLING_EDGE       0x0000
+#define UWIRE_WRITE_RISING_EDGE                0x0002
+#define UWIRE_CS_ACTIVE_LOW            0x0000
+#define UWIRE_CS_ACTIVE_HIGH           0x0004
+#define UWIRE_FREQ_DIV_2               0x0000
+#define UWIRE_FREQ_DIV_4               0x0008
+#define UWIRE_FREQ_DIV_8               0x0010
+#define UWIRE_CHK_READY                        0x0020
+#define UWIRE_CLK_INVERTED             0x0040
+
+
+struct uwire_spi {
+       struct spi_bitbang      bitbang;
+       struct clk              *ck;
+};
+
+struct uwire_state {
+       unsigned        bits_per_word;
+       unsigned        div1_idx;
+};
+
+/* REVISIT compile time constant for idx_shift? */
+static unsigned int uwire_idx_shift;
+
+static inline void uwire_write_reg(int idx, u16 val)
+{
+       __raw_writew(val, UWIRE_BASE + (idx << uwire_idx_shift));
+}
+
+static inline u16 uwire_read_reg(int idx)
+{
+       return __raw_readw(UWIRE_BASE + (idx << uwire_idx_shift));
+}
+
+static inline void omap_uwire_configure_mode(u8 cs, unsigned long flags)
+{
+       u16     w, val = 0;
+       int     shift, reg;
+
+       if (flags & UWIRE_CLK_INVERTED)
+               val ^= 0x03;
+       val = flags & 0x3f;
+       if (cs & 1)
+               shift = 6;
+       else
+               shift = 0;
+       if (cs <= 1)
+               reg = UWIRE_SR1;
+       else
+               reg = UWIRE_SR2;
+
+       w = uwire_read_reg(reg);
+       w &= ~(0x3f << shift);
+       w |= val << shift;
+       uwire_write_reg(reg, w);
+}
+
+static int wait_uwire_csr_flag(u16 mask, u16 val, int might_not_catch)
+{
+       u16 w;
+       int c = 0;
+       unsigned long max_jiffies = jiffies + HZ;
+
+       for (;;) {
+               w = uwire_read_reg(UWIRE_CSR);
+               if ((w & mask) == val)
+                       break;
+               if (time_after(jiffies, max_jiffies)) {
+                       printk(KERN_ERR "%s: timeout. reg=%#06x "
+                                       "mask=%#06x val=%#06x\n",
+                              __FUNCTION__, w, mask, val);
+                       return -1;
+               }
+               c++;
+               if (might_not_catch && c > 64)
+                       break;
+       }
+       return 0;
+}
+
+static void uwire_set_clk1_div(int div1_idx)
+{
+       u16 w;
+
+       w = uwire_read_reg(UWIRE_SR3);
+       w &= ~(0x03 << 1);
+       w |= div1_idx << 1;
+       uwire_write_reg(UWIRE_SR3, w);
+}
+
+static void uwire_chipselect(struct spi_device *spi, int value)
+{
+       struct  uwire_state *ust = spi->controller_state;
+       u16     w;
+       int     old_cs;
+
+
+       BUG_ON(wait_uwire_csr_flag(CSRB, 0, 0));
+
+       w = uwire_read_reg(UWIRE_CSR);
+       old_cs = (w >> 10) & 0x03;
+       if (value == BITBANG_CS_INACTIVE || old_cs != spi->chip_select) {
+               /* Deselect this CS, or the previous CS */
+               w &= ~CS_CMD;
+               uwire_write_reg(UWIRE_CSR, w);
+       }
+       /* activate specfied chipselect */
+       if (value == BITBANG_CS_ACTIVE) {
+               uwire_set_clk1_div(ust->div1_idx);
+               /* invert clock? */
+               if (spi->mode & SPI_CPOL)
+                       uwire_write_reg(UWIRE_SR4, 1);
+               else
+                       uwire_write_reg(UWIRE_SR4, 0);
+
+               w = spi->chip_select << 10;
+               w |= CS_CMD;
+               uwire_write_reg(UWIRE_CSR, w);
+       }
+}
+
+static int uwire_txrx(struct spi_device *spi, struct spi_transfer *t)
+{
+       struct uwire_state *ust = spi->controller_state;
+       unsigned        len = t->len;
+       unsigned        bits = ust->bits_per_word;
+       unsigned        bytes;
+       u16             val, w;
+       int             status = 0;;
+
+       if (!t->tx_buf && !t->rx_buf)
+               return 0;
+
+       /* Microwire doesn't read and write concurrently */
+       if (t->tx_buf && t->rx_buf)
+               return -EPERM;
+
+       w = spi->chip_select << 10;
+       w |= CS_CMD;
+
+       if (t->tx_buf) {
+               const u8        *buf = t->tx_buf;
+
+               /* NOTE:  DMA could be used for TX transfers */
+
+               /* write one or two bytes at a time */
+               while (len >= 1) {
+                       /* tx bit 15 is first sent; we byteswap multibyte words
+                        * (msb-first) on the way out from memory.
+                        */
+                       val = *buf++;
+                       if (bits > 8) {
+                               bytes = 2;
+                               val |= *buf++ << 8;
+                       } else
+                               bytes = 1;
+                       val <<= 16 - bits;
+
+#ifdef VERBOSE
+                       pr_debug("%s: write-%d =%04x\n",
+                                       spi->dev.bus_id, bits, val);
+#endif
+                       if (wait_uwire_csr_flag(CSRB, 0, 0))
+                               goto eio;
+
+                       uwire_write_reg(UWIRE_TDR, val);
+
+                       /* start write */
+                       val = START | w | (bits << 5);
+
+                       uwire_write_reg(UWIRE_CSR, val);
+                       len -= bytes;
+
+                       /* Wait till write actually starts.
+                        * This is needed with MPU clock 60+ MHz.
+                        * REVISIT: we may not have time to catch it...
+                        */
+                       if (wait_uwire_csr_flag(CSRB, CSRB, 1))
+                               goto eio;
+
+                       status += bytes;
+               }
+
+               /* REVISIT:  save this for later to get more i/o overlap */
+               if (wait_uwire_csr_flag(CSRB, 0, 0))
+                       goto eio;
+
+       } else if (t->rx_buf) {
+               u8              *buf = t->rx_buf;
+
+               /* read one or two bytes at a time */
+               while (len) {
+                       if (bits > 8) {
+                               bytes = 2;
+                       } else
+                               bytes = 1;
+
+                       /* start read */
+                       val = START | w | (bits << 0);
+                       uwire_write_reg(UWIRE_CSR, val);
+                       len -= bytes;
+
+                       /* Wait till read actually starts */
+                       (void) wait_uwire_csr_flag(CSRB, CSRB, 1);
+
+                       if (wait_uwire_csr_flag(RDRB | CSRB,
+                                               RDRB, 0))
+                               goto eio;
+
+                       /* rx bit 0 is last received; multibyte words will
+                        * be properly byteswapped on the way to memory.
+                        */
+                       val = uwire_read_reg(UWIRE_RDR);
+                       val &= (1 << bits) - 1;
+                       *buf++ = (u8) val;
+                       if (bytes == 2)
+                               *buf++ = val >> 8;
+                       status += bytes;
+#ifdef VERBOSE
+                       pr_debug("%s: read-%d =%04x\n",
+                                       spi->dev.bus_id, bits, val);
+#endif
+
+               }
+       }
+       return status;
+eio:
+       return -EIO;
+}
+
+static int uwire_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
+{
+       struct uwire_state      *ust = spi->controller_state;
+       struct uwire_spi        *uwire;
+       unsigned                flags = 0;
+       unsigned                bits;
+       unsigned                hz;
+       unsigned long           rate;
+       int                     div1_idx;
+       int                     div1;
+       int                     div2;
+       int                     status;
+
+       uwire = spi_master_get_devdata(spi->master);
+
+       if (spi->chip_select > 3) {
+               pr_debug("%s: cs%d?\n", spi->dev.bus_id, spi->chip_select);
+               status = -ENODEV;
+               goto done;
+       }
+
+       bits = spi->bits_per_word;
+       if (t != NULL && t->bits_per_word)
+               bits = t->bits_per_word;
+       if (!bits)
+               bits = 8;
+
+       if (bits > 16) {
+               pr_debug("%s: wordsize %d?\n", spi->dev.bus_id, bits);
+               status = -ENODEV;
+               goto done;
+       }
+       ust->bits_per_word = bits;
+
+       /* mode 0..3, clock inverted separately;
+        * standard nCS signaling;
+        * don't treat DI=high as "not ready"
+        */
+       if (spi->mode & SPI_CS_HIGH)
+               flags |= UWIRE_CS_ACTIVE_HIGH;
+
+       if (spi->mode & SPI_CPOL)
+               flags |= UWIRE_CLK_INVERTED;
+
+       switch (spi->mode & (SPI_CPOL | SPI_CPHA)) {
+       case SPI_MODE_0:
+       case SPI_MODE_3:
+               flags |= UWIRE_WRITE_RISING_EDGE | UWIRE_READ_FALLING_EDGE;
+               break;
+       case SPI_MODE_1:
+       case SPI_MODE_2:
+               flags |= UWIRE_WRITE_FALLING_EDGE | UWIRE_READ_RISING_EDGE;
+               break;
+       }
+
+       /* assume it's already enabled */
+       rate = clk_get_rate(uwire->ck);
+
+       hz = spi->max_speed_hz;
+       if (t != NULL && t->speed_hz)
+               hz = t->speed_hz;
+
+       if (!hz) {
+               pr_debug("%s: zero speed?\n", spi->dev.bus_id);
+               status = -EINVAL;
+               goto done;
+       }
+
+       /* F_INT = mpu_xor_clk / DIV1 */
+       for (div1_idx = 0; div1_idx < 4; div1_idx++) {
+               switch (div1_idx) {
+               case 0:
+                       div1 = 2;
+                       break;
+               case 1:
+                       div1 = 4;
+                       break;
+               case 2:
+                       div1 = 7;
+                       break;
+               default:
+               case 3:
+                       div1 = 10;
+                       break;
+               }
+               div2 = (rate / div1 + hz - 1) / hz;
+               if (div2 <= 8)
+                       break;
+       }
+       if (div1_idx == 4) {
+               pr_debug("%s: lowest clock %ld, need %d\n",
+                       spi->dev.bus_id, rate / 10 / 8, hz);
+                       status = -EDOM;
+                       goto done;
+       }
+
+       /* we have to cache this and reset in uwire_chipselect as this is a
+        * global parameter and another uwire device can change it under
+        * us */
+       ust->div1_idx = div1_idx;
+       uwire_set_clk1_div(div1_idx);
+
+       rate /= div1;
+
+       switch (div2) {
+       case 0:
+       case 1:
+       case 2:
+               flags |= UWIRE_FREQ_DIV_2;
+               rate /= 2;
+               break;
+       case 3:
+       case 4:
+               flags |= UWIRE_FREQ_DIV_4;
+               rate /= 4;
+               break;
+       case 5:
+       case 6:
+       case 7:
+       case 8:
+               flags |= UWIRE_FREQ_DIV_8;
+               rate /= 8;
+               break;
+       }
+       omap_uwire_configure_mode(spi->chip_select, flags);
+       pr_debug("%s: uwire flags %02x, armxor %lu KHz, SCK %lu KHz\n",
+                       __FUNCTION__, flags,
+                       clk_get_rate(uwire->ck) / 1000,
+                       rate / 1000);
+       status = 0;
+done:
+       return status;
+}
+
+static int uwire_setup(struct spi_device *spi)
+{
+       struct uwire_state *ust = spi->controller_state;
+
+       if (ust == NULL) {
+               ust = kzalloc(sizeof(*ust), GFP_KERNEL);
+               if (ust == NULL)
+                       return -ENOMEM;
+               spi->controller_state = ust;
+       }
+
+       return uwire_setup_transfer(spi, NULL);
+}
+
+static void uwire_cleanup(const struct spi_device *spi)
+{
+       kfree(spi->controller_state);
+}
+
+static void uwire_off(struct uwire_spi *uwire)
+{
+       uwire_write_reg(UWIRE_SR3, 0);
+       clk_disable(uwire->ck);
+       clk_put(uwire->ck);
+       spi_master_put(uwire->bitbang.master);
+}
+
+static int uwire_probe(struct platform_device *pdev)
+{
+       struct spi_master       *master;
+       struct uwire_spi        *uwire;
+       int                     status;
+
+       master = spi_alloc_master(&pdev->dev, sizeof *uwire);
+       if (!master)
+               return -ENODEV;
+
+       uwire = spi_master_get_devdata(master);
+       dev_set_drvdata(&pdev->dev, uwire);
+
+       uwire->ck = clk_get(&pdev->dev, "armxor_ck");
+       if (!uwire->ck || IS_ERR(uwire->ck)) {
+               dev_dbg(&pdev->dev, "no mpu_xor_clk ?\n");
+               spi_master_put(master);
+               return -ENODEV;
+       }
+       clk_enable(uwire->ck);
+
+       if (cpu_is_omap730())
+               uwire_idx_shift = 1;
+       else
+               uwire_idx_shift = 2;
+
+       uwire_write_reg(UWIRE_SR3, 1);
+
+       master->bus_num = 2;    /* "official" */
+       master->num_chipselect = 4;
+       master->setup = uwire_setup;
+       master->cleanup = uwire_cleanup;
+
+       uwire->bitbang.master = master;
+       uwire->bitbang.chipselect = uwire_chipselect;
+       uwire->bitbang.setup_transfer = uwire_setup_transfer;
+       uwire->bitbang.txrx_bufs = uwire_txrx;
+
+       status = spi_bitbang_start(&uwire->bitbang);
+       if (status < 0)
+               uwire_off(uwire);
+       return status;
+}
+
+static int uwire_remove(struct platform_device *pdev)
+{
+       struct uwire_spi        *uwire = dev_get_drvdata(&pdev->dev);
+       int                     status;
+
+       // FIXME remove all child devices, somewhere ...
+
+       status = spi_bitbang_stop(&uwire->bitbang);
+       uwire_off(uwire);
+       return status;
+}
+
+static struct platform_driver uwire_driver = {
+       .driver = {
+               .name           = "omap_uwire",
+               .bus            = &platform_bus_type,
+               .owner          = THIS_MODULE,
+       },
+       .probe          = uwire_probe,
+       .remove         = uwire_remove,
+       // suspend ... unuse ck
+       // resume ... use ck
+};
+
+static int __init omap_uwire_init(void)
+{
+       /* FIXME move these into the relevant board init code. also, include
+        * H3 support; it uses tsc2101 like H2 (on a different chipselect).
+        */
+
+       if (machine_is_omap_h2()) {
+               /* defaults: W21 SDO, U18 SDI, V19 SCL */
+               omap_cfg_reg(N14_1610_UWIRE_CS0);
+               omap_cfg_reg(N15_1610_UWIRE_CS1);
+       }
+       if (machine_is_omap_perseus2()) {
+               /* configure pins: MPU_UW_nSCS1, MPU_UW_SDO, MPU_UW_SCLK */
+               int val = omap_readl(OMAP730_IO_CONF_9) & ~0x00EEE000;
+               omap_writel(val | 0x00AAA000, OMAP730_IO_CONF_9);
+       }
+
+       return platform_driver_register(&uwire_driver);
+}
+
+static void __exit omap_uwire_exit(void)
+{
+       platform_driver_unregister(&uwire_driver);
+}
+
+subsys_initcall(omap_uwire_init);
+module_exit(omap_uwire_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/tsc2102.c b/drivers/spi/tsc2102.c
new file mode 100644 (file)
index 0000000..130b1c2
--- /dev/null
@@ -0,0 +1,1198 @@
+/*
+ * drivers/spi/tsc2102.c
+ *
+ * TSC2102 interface driver.
+ *
+ * Copyright (c) 2005 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this package; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/suspend.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/tsc2102.h>
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+#include <asm/hardware.h>
+
+#ifdef CONFIG_APM
+#include <asm/apm.h>
+#endif
+
+/* Bit field definitions for chip registers */
+#define TSC2102_ADC_TS_CONTROL         0x8bf4
+#define TSC2102_ADC_SCAN_CONTROL       0x2ff4
+#define TSC2102_ADC_T1_CONTROL         0x2bf4
+#define TSC2102_ADC_T2_CONTROL         0x33f4
+#define TSC2102_ADC_DAV                        0x4000
+#define TSC2102_ADC_INT_REF            0x0016
+#define TSC2102_ADC_EXT_REF            0x0002
+#define TSC2102_CONFIG_TIMES           0x0008
+#define TSC2102_RESET                  0xbb00
+#define TSC2102_ADC_PSTCM              (1 << 15)
+#define TSC2102_ADC_ADST               (1 << 14)
+#define TSC2102_TS_DAV                 0x0780
+#define TSC2102_PS_DAV                 0x0078
+#define TSC2102_T1_DAV                 0x0004
+#define TSC2102_T2_DAV                 0x0002
+#define TSC2102_DAC_ON                 0x3ba0
+#define TSC2102_DAC_OFF                        0xafa0
+#define TSC2102_FS44K                  (1 << 13)
+#define TSC2102_PLL1_OFF               0x0000
+#define TSC2102_PLL1_44K               0x811c
+#define TSC2102_PLL1_48K               0x8120
+#define TSC2102_PLL2_44K               (5462 << 2)
+#define TSC2102_PLL2_48K               (1920 << 2)
+#define TSC2102_SLVMS                  (1 << 11)
+#define TSC2102_DEEMPF                 (1 << 0)
+#define TSC2102_BASSBC                 (1 << 1)
+#define TSC2102_KEYCLICK_OFF           0x0000
+
+#define CS_CHANGE(val)                 0
+
+struct tsc2102_spi_req {
+       struct spi_device *dev;
+       uint16_t command;
+       uint16_t data;
+       struct spi_transfer *transfer;
+       struct spi_message message;
+};
+
+struct tsc2102_dev {
+       struct tsc2102_config *pdata;
+       spinlock_t lock, lock_sync;
+       struct clk *bclk_ck;
+
+       int state;                      /* 0: TS, 1: Portscan, 2-3: Temps */
+       struct timer_list ts_timer;     /* Busy-wait for PEN UP */
+       struct timer_list mode_timer;   /* Change .state every some time */
+       int pendown;
+       int data_pending;
+       uint16_t status, adc_status, adc_data[4];
+       tsc2102_touch_t touch_cb;
+       tsc2102_coords_t coords_cb;
+       tsc2102_ports_t ports_cb;
+       tsc2102_temp_t temp1_cb;
+       tsc2102_temp_t temp2_cb;
+       unsigned int ts_msecs;          /* Interval for .ts_timer */
+       unsigned int mode_msecs;        /* Interval for .mode_timer */
+
+       struct spi_device *spi;
+       struct spi_transfer *transfers;
+       struct tsc2102_spi_req req_adc;
+       struct tsc2102_spi_req req_status;
+       struct tsc2102_spi_req req_pressure;
+       struct tsc2102_spi_req req_stopadc;
+       struct tsc2102_spi_req req_mode;
+
+       int bat[2], aux[1], temp[2];
+       struct class_device *hwmondev;
+};
+
+static struct tsc2102_dev tsc;
+
+module_param_named(touch_check_msecs, tsc.ts_msecs, uint, 0);
+MODULE_PARM_DESC(touch_check_msecs, "Pen-up polling interval in msecs");
+
+module_param_named(sensor_scan_msecs, tsc.mode_msecs, uint, 0);
+MODULE_PARM_DESC(sensor_scan_msecs, "Temperature & battery scan interval");
+
+void tsc2102_write_sync(int page, u8 address, u16 data)
+{
+       static struct tsc2102_spi_req req;
+       static struct spi_transfer transfer[2];
+       int ret;
+
+       spi_message_init(&req.message);
+       req.transfer = transfer;
+
+       /* Address */
+       req.command = (page << 11) | (address << 5);
+       req.transfer[0].tx_buf = &req.command;
+       req.transfer[0].rx_buf = 0;
+       req.transfer[0].len = 2;
+       spi_message_add_tail(&req.transfer[0], &req.message);
+
+       /* Data */
+       req.transfer[1].tx_buf = &data;
+       req.transfer[1].rx_buf = 0;
+       req.transfer[1].len = 2;
+       req.transfer[1].cs_change = CS_CHANGE(1);
+       spi_message_add_tail(&req.transfer[1], &req.message);
+
+       ret = spi_sync(tsc.spi, &req.message);
+       if (!ret && req.message.status)
+               ret = req.message.status;
+
+       if (ret)
+               printk(KERN_ERR "%s: error %i in SPI request\n",
+                               __FUNCTION__, ret);
+}
+
+void tsc2102_reads_sync(int page, u8 startaddress, u16 *data, int numregs)
+{
+       static struct tsc2102_spi_req req;
+       static struct spi_transfer transfer[6];
+       int ret, i, j;
+
+       BUG_ON(numregs + 1 > ARRAY_SIZE(transfer));
+
+       spi_message_init(&req.message);
+       req.transfer = transfer;
+       i = 0;
+       j = 0;
+
+       /* Address */
+       req.command = 0x8000 | (page << 11) | (startaddress << 5);
+       req.transfer[i].tx_buf = &req.command;
+       req.transfer[i].rx_buf = 0;
+       req.transfer[i].len = 2;
+       spi_message_add_tail(&req.transfer[i ++], &req.message);
+
+       /* Data */
+       while (j < numregs) {
+               req.transfer[i].tx_buf = 0;
+               req.transfer[i].rx_buf = &data[j ++];
+               req.transfer[i].len = 2;
+               req.transfer[i].cs_change = CS_CHANGE(j == numregs);
+               spi_message_add_tail(&req.transfer[i ++], &req.message);
+       }
+
+       ret = spi_sync(tsc.spi, &req.message);
+       if (!ret && req.message.status)
+               ret = req.message.status;
+
+       if (ret)
+               printk(KERN_ERR "%s: error %i in SPI request\n",
+                               __FUNCTION__, ret);
+}
+
+u16 tsc2102_read_sync(int page, u8 address)
+{
+       u16 ret;
+       tsc2102_reads_sync(page, address, &ret, 1);
+       return ret;
+}
+
+static void tsc2102_write_async(
+               struct tsc2102_spi_req *spi, int page, u8 address, u16 data,
+               void (*complete)(struct tsc2102_dev *context))
+{
+       int ret;
+
+       spi_message_init(&spi->message);
+       spi->message.complete = (void (*)(void *)) complete;
+       spi->message.context = &tsc;
+
+       /* Address */
+       spi->command = (page << 11) | (address << 5);
+       spi->transfer[0].tx_buf = &spi->command;
+       spi->transfer[0].rx_buf = 0;
+       spi->transfer[0].len = 2;
+       spi_message_add_tail(&spi->transfer[0], &spi->message);
+
+       /* Data */
+       spi->data = data;
+       spi->transfer[1].tx_buf = &spi->data;
+       spi->transfer[1].rx_buf = 0;
+       spi->transfer[1].len = 2;
+       spi->transfer[1].cs_change = CS_CHANGE(1);
+       spi_message_add_tail(&spi->transfer[1], &spi->message);
+
+       ret = spi_async(spi->dev, &spi->message);
+       if (ret)
+               printk(KERN_ERR "%s: error %i in SPI request\n",
+                               __FUNCTION__, ret);
+}
+
+static void tsc2102_reads_async(struct tsc2102_spi_req *spi,
+               int page, u8 startaddress, u16 *data, int numregs,
+               void (*complete)(struct tsc2102_dev *context))
+{
+       int ret, i, j;
+
+       spi_message_init(&spi->message);
+       spi->message.complete = (void (*)(void *)) complete;
+       spi->message.context = &tsc;
+       i = 0;
+       j = 0;
+
+       /* Address */
+       spi->command = 0x8000 | (page << 11) | (startaddress << 5);
+       spi->transfer[i].tx_buf = &spi->command;
+       spi->transfer[i].rx_buf = 0;
+       spi->transfer[i].len = 2;
+       spi_message_add_tail(&spi->transfer[i ++], &spi->message);
+
+       /* Data */
+       while (j < numregs) {
+               spi->transfer[i].tx_buf = 0;
+               spi->transfer[i].rx_buf = &data[j ++];
+               spi->transfer[i].len = 2;
+               spi->transfer[i].cs_change = CS_CHANGE(j == numregs);
+               spi_message_add_tail(&spi->transfer[i ++], &spi->message);
+       }
+
+       ret = spi_async(spi->dev, &spi->message);
+       if (ret)
+               printk(KERN_ERR "%s: error %i in SPI request\n",
+                               __FUNCTION__, ret);
+}
+
+static void tsc2102_read_async(struct tsc2102_spi_req *spi,
+               int page, u8 address, u16 *ret,
+               void (*complete)(struct tsc2102_dev *context))
+{
+       tsc2102_reads_async(spi, page, address, ret, 1, complete);
+}
+
+static void tsc2102_request_alloc(struct tsc2102_dev *dev,
+               struct tsc2102_spi_req *spi, int direction, int numregs,
+               struct spi_transfer **buffer)
+{
+       spi->dev = dev->spi;
+
+       if (direction == 1)     /* Write */
+               numregs = 2;
+       else                    /* Read */
+               numregs += 1;
+
+       spi->transfer = *buffer;
+       *buffer += numregs;
+}
+
+#define tsc2102_cb_register_func(cb, cb_t)     \
+int tsc2102_ ## cb(cb_t handler)       \
+{      \
+       spin_lock(&tsc.lock);   \
+       \
+       /* Lock the module */   \
+       if (handler && !tsc.cb) \
+               if (!try_module_get(THIS_MODULE)) {     \
+                       printk(KERN_INFO "Failed to get TSC module\n"); \
+               }       \
+       if (!handler && tsc.cb) \
+               module_put(THIS_MODULE);        \
+       \
+       tsc.cb = handler;       \
+       \
+       spin_unlock(&tsc.lock); \
+       return 0;       \
+}
+
+tsc2102_cb_register_func(touch_cb, tsc2102_touch_t)
+tsc2102_cb_register_func(coords_cb, tsc2102_coords_t)
+tsc2102_cb_register_func(ports_cb, tsc2102_ports_t)
+tsc2102_cb_register_func(temp1_cb, tsc2102_temp_t)
+tsc2102_cb_register_func(temp2_cb, tsc2102_temp_t)
+
+#ifdef DEBUG
+static void tsc2102_print_dav(void)
+{
+       u16 status = tsc2102_read_sync(TSC2102_TS_STATUS_CTRL);
+       if (status & 0x0fff)
+               printk("TSC2102: data in");
+       if (status & 0x0400)
+               printk(" X");
+       if (status & 0x0200)
+               printk(" Y");
+       if (status & 0x0100)
+               printk(" Z1");
+       if (status & 0x0080)
+               printk(" Z2");
+       if (status & 0x0040)
+               printk(" BAT1");
+       if (status & 0x0020)
+               printk(" BAT2");
+       if (status & 0x0010)
+               printk(" AUX1");
+       if (status & 0x0008)
+               printk(" AUX2");
+       if (status & 0x0004)
+               printk(" TEMP1");
+       if (status & 0x0002)
+               printk(" TEMP2");
+       if (status & 0x0001)
+               printk(" KP");
+       if (status & 0x0fff)
+               printk(".\n");
+}
+#endif
+
+static void tsc2102_complete_dummy(struct tsc2102_dev *dev)
+{
+}
+
+static inline void tsc2102_touchscreen_mode(struct tsc2102_dev *dev)
+{
+       /* Scan X, Y, Z1, Z2, chip controlled, 12-bit, 16 samples, 500 usec */
+       tsc2102_write_async(&dev->req_mode,
+                       TSC2102_TS_ADC_CTRL, TSC2102_ADC_TS_CONTROL,
+                       tsc2102_complete_dummy);
+}
+
+static inline void tsc2102_portscan_mode(struct tsc2102_dev *dev)
+{
+       /* Scan BAT1, BAT2, AUX, 12-bit, 16 samples, 500 usec */
+       tsc2102_write_async(&dev->req_mode,
+                       TSC2102_TS_ADC_CTRL, TSC2102_ADC_SCAN_CONTROL,
+                       tsc2102_complete_dummy);
+}
+
+static inline void tsc2102_temp1_mode(struct tsc2102_dev *dev)
+{
+       /* Scan TEMP1, 12-bit, 16 samples, 500 usec */
+       tsc2102_write_async(&dev->req_mode,
+                       TSC2102_TS_ADC_CTRL, TSC2102_ADC_T1_CONTROL,
+                       tsc2102_complete_dummy);
+}
+
+static inline void tsc2102_temp2_mode(struct tsc2102_dev *dev)
+{
+       /* Scan TEMP2, 12-bit, 16 samples, 500 usec */
+       tsc2102_write_async(&dev->req_mode,
+                       TSC2102_TS_ADC_CTRL, TSC2102_ADC_T2_CONTROL,
+                       tsc2102_complete_dummy);
+}
+
+static void tsc2102_mode(struct tsc2102_dev *dev)
+{
+       switch (dev->state) {
+       case 0:
+               tsc2102_touchscreen_mode(dev);
+               break;
+       case 1:
+               tsc2102_portscan_mode(dev);
+               break;
+       case 2:
+               tsc2102_temp1_mode(dev);
+               break;
+       case 3:
+               tsc2102_temp2_mode(dev);
+               break;
+       default:
+               dev->state = 0;
+               tsc2102_touchscreen_mode(dev);
+               break;
+       }
+}
+
+/* Lock is held when this is called.  */
+static void tsc2102_new_mode(struct tsc2102_dev *dev)
+{
+       /* Abort current conversion if any */
+       tsc2102_write_async(&dev->req_stopadc,
+                       TSC2102_TS_ADC_CTRL, TSC2102_ADC_ADST,
+                       tsc2102_complete_dummy);
+
+       dev->state ++;
+       tsc2102_mode(dev);
+}
+
+static void tsc2102_check_status(struct tsc2102_dev *dev);
+
+/* TSC has new data for us availiable.  */
+static irqreturn_t tsc2102_handler(int irq, void *dev_id)
+{
+       struct tsc2102_dev *dev = (struct tsc2102_dev *) dev_id;
+       spin_lock_irq(&dev->lock);
+
+       if (!dev->data_pending)
+               tsc2102_check_status(dev);
+
+       dev->data_pending ++;
+
+       spin_unlock_irq(&dev->lock);
+       return IRQ_HANDLED;
+}
+
+static void tsc2102_data_report(struct tsc2102_dev *dev)
+{
+       if (dev->status & TSC2102_TS_DAV) {
+               if (dev->coords_cb)
+                       dev->coords_cb(
+                                       dev->adc_data[0], dev->adc_data[1],
+                                       dev->adc_data[2], dev->adc_data[3]);
+       }
+
+       if (dev->status & TSC2102_PS_DAV) {
+               if (dev->ports_cb)
+                       dev->ports_cb(dev->adc_data[0],
+                                       dev->adc_data[1], dev->adc_data[2]);
+               dev->bat[0] = dev->adc_data[0];
+               dev->bat[1] = dev->adc_data[1];
+               dev->aux[0] = dev->adc_data[2];
+       }
+
+       if (dev->status & TSC2102_T1_DAV) {
+               if (dev->temp1_cb)
+                       dev->temp1_cb(*dev->adc_data);
+               dev->temp[0] = *dev->adc_data;
+       }
+
+       if (dev->status & TSC2102_T2_DAV) {
+               if (dev->temp2_cb)
+                       dev->temp2_cb(*dev->adc_data);
+               dev->temp[1] = *dev->adc_data;
+       }
+
+       spin_lock_irq(&dev->lock);
+
+       dev->data_pending --;
+
+       /*
+        * This may happen if the registers were successfully read and a
+        * new conversion was started and completed by the TSC before the
+        * completion for SPI read was called.
+        */
+       if (dev->data_pending)
+               tsc2102_check_status(dev);
+
+       if (dev->status & (TSC2102_PS_DAV | TSC2102_T1_DAV | TSC2102_T2_DAV))
+               tsc2102_new_mode(dev);
+
+       spin_unlock_irq(&dev->lock);
+}
+
+static void tsc2102_status_report(struct tsc2102_dev *dev)
+{
+       /*
+        * Read all converted data from corresponding registers
+        * so that the ADC can move on to a new conversion.
+        */
+       if (dev->status & TSC2102_TS_DAV) {
+               tsc2102_reads_async(&dev->req_adc, TSC2102_TS_X,
+                               dev->adc_data, 4, tsc2102_data_report);
+               if (!dev->pendown) {
+                       dev->pendown = 1;
+                       if (dev->touch_cb)
+                               dev->touch_cb(1);
+
+                       mod_timer(&dev->ts_timer, jiffies +
+                               msecs_to_jiffies(dev->ts_msecs));
+               }
+       }
+
+       if (dev->status & TSC2102_PS_DAV) {
+               tsc2102_reads_async(&dev->req_adc, TSC2102_TS_BAT1,
+                               dev->adc_data, 3, tsc2102_data_report);
+       }
+
+       if (dev->status & TSC2102_T1_DAV) {
+               tsc2102_read_async(&dev->req_adc, TSC2102_TS_TEMP1,
+                               dev->adc_data, tsc2102_data_report);
+       }
+
+       if (dev->status & TSC2102_T2_DAV) {
+               tsc2102_read_async(&dev->req_adc, TSC2102_TS_TEMP2,
+                               dev->adc_data, tsc2102_data_report);
+       }
+
+       if (!(dev->status & (TSC2102_TS_DAV | TSC2102_PS_DAV |
+                                       TSC2102_T1_DAV | TSC2102_T2_DAV))) {
+               spin_lock_irq(&dev->lock);
+               dev->data_pending --;
+               spin_unlock_irq(&dev->lock);
+
+               WARN_ON(!dev->state);
+       }
+}
+
+static void tsc2102_check_status(struct tsc2102_dev *dev)
+{
+       tsc2102_read_async(&dev->req_status, TSC2102_TS_STATUS_CTRL,
+                       &dev->status, tsc2102_status_report);
+}
+
+static void tsc2102_mode_timer(unsigned long data)
+{
+       struct tsc2102_dev *dev = (struct tsc2102_dev *) data;
+       spin_lock_irq(&dev->lock);
+
+       BUG_ON(dev->state);
+
+       tsc2102_new_mode(dev);
+
+       mod_timer(&dev->mode_timer, jiffies +
+                       msecs_to_jiffies(dev->mode_msecs));
+       spin_unlock_irq(&dev->lock);
+}
+
+/*
+ * There are at least three ways to check for pen-up:
+ *     - the PINT/DAV pin state,
+ *     - reading PSTCM bit in ADC Control register (D15, offset 0x00),
+ *     - reading ADST bit in ADC Control register (D14, offset 0x00),
+ *             ADC idle would indicate no screen touch.
+ * Unfortunately none of them seems to be 100% accurate and you will
+ * find they are totally inconsistent, i.e. you get to see any arbitrary
+ * combination of values in these three bits.  So we will busy-wait
+ * for a moment when all three indicate a pen-up, using a timer, before
+ * we report a pen-up.
+ */
+static void tsc2102_pressure_report(struct tsc2102_dev *dev)
+{
+       if (!dev->pendown)
+               return;
+
+       if (dev->state ||
+                       (dev->adc_status & TSC2102_ADC_PSTCM) ||
+                       !(dev->adc_status & TSC2102_ADC_ADST)) {
+               mod_timer(&dev->ts_timer, jiffies +
+                               msecs_to_jiffies(dev->ts_msecs));
+       } else {
+               dev->pendown = 0;
+               if (dev->touch_cb)
+                       dev->touch_cb(0);
+       }
+}
+
+static void tsc2102_pressure(unsigned long data)
+{
+       struct tsc2102_dev *dev = (struct tsc2102_dev *) data;
+
+       BUG_ON(!dev->pendown);
+
+       tsc2102_read_async(&dev->req_pressure, TSC2102_TS_ADC_CTRL,
+                       &dev->adc_status, tsc2102_pressure_report);
+}
+
+#ifdef CONFIG_SOUND
+/*
+ * Volume level values should be in the range [0, 127].
+ * Higher values mean lower volume.
+ */
+void tsc2102_set_volume(uint8_t left_ch, uint8_t right_ch)
+{
+       u16 val;
+       if (left_ch == 0x00 || left_ch == 0x7f) /* All 0's or all 1's */
+               left_ch ^= 0x7f;
+       if (right_ch == 0x00 || right_ch == 0x7f)
+               right_ch ^= 0x7f;
+
+       spin_lock(&tsc.lock_sync);
+
+       val = tsc2102_read_sync(TSC2102_DAC_GAIN_CTRL);
+
+       val &= 0x8080;  /* Preserve mute-bits */
+       val |= (left_ch << 8) | right_ch;
+
+       tsc2102_write_sync(TSC2102_DAC_GAIN_CTRL, val);
+
+       spin_unlock(&tsc.lock_sync);
+}
+
+void tsc2102_set_mute(int left_ch, int right_ch)
+{
+       u16 val;
+       spin_lock(&tsc.lock_sync);
+
+       val = tsc2102_read_sync(TSC2102_DAC_GAIN_CTRL);
+
+       val &= 0x7f7f;  /* Preserve volume settings */
+       val |= (left_ch << 15) | (right_ch << 7);
+
+       tsc2102_write_sync(TSC2102_DAC_GAIN_CTRL, val);
+
+       spin_unlock(&tsc.lock_sync);
+}
+
+void tsc2102_get_mute(int *left_ch, int *right_ch)
+{
+       u16 val;
+       spin_lock(&tsc.lock_sync);
+
+       val = tsc2102_read_sync(TSC2102_DAC_GAIN_CTRL);
+
+       spin_unlock(&tsc.lock_sync);
+
+       *left_ch = !!(val & (1 << 15));
+       *right_ch = !!(val & (1 << 7));
+}
+
+void tsc2102_set_deemphasis(int enable)
+{
+       u16 val;
+       spin_lock(&tsc.lock_sync);
+       val = tsc2102_read_sync(TSC2102_DAC_POWER_CTRL);
+
+       if (enable)
+               val &= ~TSC2102_DEEMPF;
+       else
+               val |= TSC2102_DEEMPF;
+
+       tsc2102_write_sync(TSC2102_DAC_POWER_CTRL, val);
+       spin_unlock(&tsc.lock_sync);
+}
+
+void tsc2102_set_bassboost(int enable)
+{
+       u16 val;
+       spin_lock(&tsc.lock_sync);
+       val = tsc2102_read_sync(TSC2102_DAC_POWER_CTRL);
+
+       if (enable)
+               val &= ~TSC2102_BASSBC;
+       else
+               val |= TSC2102_BASSBC;
+
+       tsc2102_write_sync(TSC2102_DAC_POWER_CTRL, val);
+       spin_unlock(&tsc.lock_sync);
+}
+
+/*     {rate, dsor, fsref}     */
+static const struct tsc2102_rate_info_s tsc2102_rates[] = {
+       /* Fsref / 6.0 */
+       {7350,  63,     1},
+       {8000,  63,     0},
+       /* Fsref / 6.0 */
+       {7350,  54,     1},
+       {8000,  54,     0},
+       /* Fsref / 5.0 */
+       {8820,  45,     1},
+       {9600,  45,     0},
+       /* Fsref / 4.0 */
+       {11025, 36,     1},
+       {12000, 36,     0},
+       /* Fsref / 3.0 */
+       {14700, 27,     1},
+       {16000, 27,     0},
+       /* Fsref / 2.0 */
+       {22050, 18,     1},
+       {24000, 18,     0},
+       /* Fsref / 1.5 */
+       {29400, 9,      1},
+       {32000, 9,      0},
+       /* Fsref */
+       {44100, 0,      1},
+       {48000, 0,      0},
+
+       {0,     0,      0},
+};
+
+int tsc2102_set_rate(int rate)
+{
+       int i;
+       uint16_t val;
+
+       for (i = 0; tsc2102_rates[i].sample_rate; i ++)
+               if (tsc2102_rates[i].sample_rate == rate)
+                       break;
+       if (tsc2102_rates[i].sample_rate == 0) {
+               printk(KERN_ERR "Unknown sampling rate %i.0 Hz\n", rate);
+               return -EINVAL;
+       }
+
+       spin_lock(&tsc.lock_sync);
+
+       tsc2102_write_sync(TSC2102_AUDIO1_CTRL, tsc2102_rates[i].divisor);
+
+       val = tsc2102_read_sync(TSC2102_AUDIO3_CTRL);
+
+       if (tsc2102_rates[i].fs_44k) {
+               tsc2102_write_sync(TSC2102_AUDIO3_CTRL, val | TSC2102_FS44K);
+               /* Enable Phase-locked-loop, set up clock dividers */
+               tsc2102_write_sync(TSC2102_PLL1_CTRL, TSC2102_PLL1_44K);
+               tsc2102_write_sync(TSC2102_PLL2_CTRL, TSC2102_PLL2_44K);
+       } else {
+               tsc2102_write_sync(TSC2102_AUDIO3_CTRL, val & ~TSC2102_FS44K);
+               /* Enable Phase-locked-loop, set up clock dividers */
+               tsc2102_write_sync(TSC2102_PLL1_CTRL, TSC2102_PLL1_48K);
+               tsc2102_write_sync(TSC2102_PLL2_CTRL, TSC2102_PLL2_48K);
+       }
+
+       spin_unlock(&tsc.lock_sync);
+       return 0;
+}
+
+/*
+ * Perform basic set-up with default values and power the DAC on.
+ */
+void tsc2102_dac_power(int state)
+{
+       spin_lock(&tsc.lock_sync);
+
+       if (state) {
+               /* 16-bit words, DSP mode, sample at Fsref */
+               tsc2102_write_sync(TSC2102_AUDIO1_CTRL, 0x0100);
+               /* Keyclicks off, soft-stepping at normal rate */
+               tsc2102_write_sync(TSC2102_AUDIO2_CTRL, TSC2102_KEYCLICK_OFF);
+               /* 44.1 kHz Fsref, continuous transfer mode, master DAC */
+               tsc2102_write_sync(TSC2102_AUDIO3_CTRL, 0x2800);
+               /* Soft-stepping enabled */
+               tsc2102_write_sync(TSC2102_AUDIO4_CTRL, 0x0000);
+
+               /* PLL generates 44.1 kHz */
+               tsc2102_write_sync(TSC2102_PLL1_CTRL, TSC2102_PLL1_44K);
+               tsc2102_write_sync(TSC2102_PLL2_CTRL, TSC2102_PLL2_44K);
+
+               /* Codec & DAC power up, virtual ground disabled */
+               tsc2102_write_sync(TSC2102_DAC_POWER_CTRL, TSC2102_DAC_ON);
+       } else {
+               /* All off */
+               tsc2102_write_sync(TSC2102_AUDIO4_CTRL, TSC2102_KEYCLICK_OFF);
+               tsc2102_write_sync(TSC2102_PLL1_CTRL, TSC2102_PLL1_OFF);
+       }
+
+       spin_unlock(&tsc.lock_sync);
+}
+
+void tsc2102_set_i2s_master(int state)
+{
+       uint16_t val;
+       spin_lock(&tsc.lock_sync);
+
+       val = tsc2102_read_sync(TSC2102_AUDIO3_CTRL);
+
+       if (state)
+               tsc2102_write_sync(TSC2102_AUDIO3_CTRL, val | TSC2102_SLVMS);
+       else
+               tsc2102_write_sync(TSC2102_AUDIO3_CTRL, val & ~TSC2102_SLVMS);
+
+       spin_unlock(&tsc.lock_sync);
+}
+#endif /* CONFIG_SOUND */
+
+static int tsc2102_configure(struct tsc2102_dev *dev)
+{
+       /* Reset the chip */
+       tsc2102_write_sync(TSC2102_TS_RESET_CTRL, TSC2102_RESET);
+
+       /* Reference mode, 100 usec delay, 1.25 V reference */
+       if (dev->pdata->use_internal)
+               tsc2102_write_sync(TSC2102_TS_REF_CTRL, TSC2102_ADC_INT_REF);
+       else
+               tsc2102_write_sync(TSC2102_TS_REF_CTRL, TSC2102_ADC_EXT_REF);
+
+       /* 84 usec precharge time, 32 usec sense time */
+       tsc2102_write_sync(TSC2102_TS_CONFIG_CTRL, TSC2102_CONFIG_TIMES);
+
+       /* PINT/DAV acts as DAV */
+       tsc2102_write_sync(TSC2102_TS_STATUS_CTRL, TSC2102_ADC_DAV);
+
+       tsc2102_mode(dev);
+       mod_timer(&dev->mode_timer, jiffies +
+                       msecs_to_jiffies(dev->mode_msecs));
+       return 0;
+}
+
+/*
+ * Retrieves chip revision.  Should be always 1.
+ */
+int tsc2102_get_revision(void)
+{
+       return tsc2102_read_sync(TSC2102_AUDIO3_CTRL) & 7;
+}
+
+/*
+ * Emit a short keyclick typically in order to give feedback to
+ * user on specific events.
+ *
+ * amplitude must be between 0 (lowest) and 2 (highest).
+ * freq must be between 0 (corresponds to 62.5 Hz) and 7 (8 kHz).
+ * length should be between 2 and 32 periods.
+ *
+ * This function sleeps but doesn't sleep until the sound has
+ * finished.
+ */
+void tsc2102_keyclick(int amplitude, int freq, int length)
+{
+       u16 val;
+       spin_lock(&tsc.lock_sync);
+       val = tsc2102_read_sync(TSC2102_AUDIO2_CTRL);
+       val &= 0x800f;
+
+       /* Set amplitude */
+       switch (amplitude) {
+       case 1:
+               val |= 4 << 12;
+               break;
+       case 2:
+               val |= 7 << 12;
+               break;
+       default:
+               break;
+       }
+
+       /* Frequency */
+       val |= (freq & 0x7) << 8;
+
+       /* Round to nearest supported length */
+       if (length > 20)
+               val |= 4 << 4;
+       else if (length > 6)
+               val |= 3 << 4;
+       else if (length > 4)
+               val |= 2 << 4;
+       else if (length > 2)
+               val |= 1 << 4;
+
+       /* Enable keyclick */
+       val |= 0x8000;
+
+       tsc2102_write_sync(TSC2102_AUDIO2_CTRL, val);
+       spin_unlock(&tsc.lock_sync);
+}
+
+#ifdef CONFIG_HWMON
+#define TSC2102_INPUT(devname, field)  \
+static ssize_t show_ ## devname(struct device *dev,    \
+               struct device_attribute *devattr, char *buf)    \
+{      \
+       struct tsc2102_dev *devhwmon = dev_get_drvdata(dev);    \
+       int value = devhwmon->field;    \
+       return sprintf(buf, "%i\n", value);     \
+}      \
+static DEVICE_ATTR(devname ## _input, S_IRUGO, show_ ## devname, NULL);
+
+TSC2102_INPUT(in0, bat[0])
+TSC2102_INPUT(in1, bat[1])
+TSC2102_INPUT(in2, aux[0])
+TSC2102_INPUT(in3, temp[0])
+TSC2102_INPUT(in4, temp[1])
+
+static ssize_t show_temp1(struct device *dev,
+               struct device_attribute *devattr, char *buf)
+{
+       struct tsc2102_dev *devhwmon = dev_get_drvdata(dev);
+       int t1, t2;
+       int value, diff;
+
+       t1 = devhwmon->temp[0];
+       t2 = devhwmon->temp[1];
+
+       /*
+        * Use method #2 (differential) to calculate current temperature.
+        * The difference between TEMP2 and TEMP1 input values is
+        * multiplied by a constant to obtain current temperature.
+        * To find this constant we use the values measured at 25 C as
+        * thermometer calibration data.
+        *
+        * 298150 is 25 degrees Celcius represented in Kelvins and
+        * multiplied by 1000 for fixed point precision (273.15 + 25).
+        * 273150 is zero degrees Celcius.
+        */
+       diff = devhwmon->pdata->temp_at25c[1] - devhwmon->pdata->temp_at25c[0];
+       BUG_ON(diff == 0);
+       value = (t2 - t1) * 298150 / diff;      /* This is in Kelvins now */
+
+       t1 = value - 273150;                    /* Celcius millidegree */
+       return sprintf(buf, "%i\n", t1);
+}
+static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp1, NULL);
+#endif /* CONFIG_HWMON */
+
+#ifdef CONFIG_APM
+static void tsc2102_get_power_status(struct apm_power_info *info)
+{
+       tsc.pdata->apm_report(info, tsc.bat);
+}
+#endif
+
+#ifdef CONFIG_PM
+/*
+ * Suspend the chip.
+ */
+static int
+tsc2102_suspend(struct spi_device *spi, pm_message_t state)
+{
+       struct tsc2102_dev *dev = dev_get_drvdata(&spi->dev);
+
+       if (!dev)
+               return 0;
+
+       spin_lock(&dev->lock_sync);
+
+       del_timer(&dev->mode_timer);
+       del_timer(&dev->ts_timer);
+
+       if (dev->pendown && dev->touch_cb)
+               dev->touch_cb(0);
+
+       /* Abort current conversion and power down the ADC */
+       tsc2102_write_sync(TSC2102_TS_ADC_CTRL, TSC2102_ADC_ADST);
+
+       dev->spi->dev.power.power_state = state;
+
+       spin_unlock(&dev->lock_sync);
+       return 0;
+}
+
+/*
+ * Resume chip operation.
+ */
+static int tsc2102_resume(struct spi_device *spi)
+{
+       struct tsc2102_dev *dev = dev_get_drvdata(&spi->dev);
+       int err;
+
+       if (!dev)
+               return 0;
+
+       spin_lock(&dev->lock_sync);
+
+       dev->spi->dev.power.power_state = PMSG_ON;
+
+       dev->state = 0;
+       dev->pendown = 0;
+
+       err = tsc2102_configure(dev);
+
+       spin_unlock(&dev->lock_sync);
+       return err;
+}
+#else
+#define tsc2102_suspend        NULL
+#define tsc2102_resume NULL
+#endif
+
+static struct platform_device tsc2102_ts_device = {
+       .name           = "tsc2102-ts",
+       .id             = -1,
+};
+
+static struct platform_device tsc2102_alsa_device = {
+       .name           = "tsc2102-alsa",
+       .id             = -1,
+};
+
+static int tsc2102_probe(struct spi_device *spi)
+{
+       struct tsc2102_config *pdata = spi->dev.platform_data;
+       struct spi_transfer *spi_buffer;
+       int err = 0;
+
+       if (!pdata) {
+               printk(KERN_ERR "TSC2102: Platform data not supplied\n");
+               return -ENOENT;
+       }
+
+       if (!spi->irq) {
+               printk(KERN_ERR "TSC2102: Invalid irq value\n");
+               return -ENOENT;
+       }
+
+       tsc.pdata = pdata;
+       tsc.state = 0;
+       tsc.pendown = 0;
+       tsc.data_pending = 0;
+       tsc.ts_msecs = 20;
+       tsc.mode_msecs = 1000;
+       tsc.spi = spi;
+
+       /* Allocate enough struct spi_transfer's for all requests */
+       spi_buffer = kzalloc(sizeof(struct spi_transfer) * 16, GFP_KERNEL);
+       if (!spi_buffer) {
+               printk(KERN_ERR "TSC2102: No memory for SPI buffers\n");
+               return -ENOMEM;
+       }
+
+       tsc.transfers = spi_buffer;
+       tsc2102_request_alloc(&tsc, &tsc.req_adc, 0, 4, &spi_buffer);
+       tsc2102_request_alloc(&tsc, &tsc.req_status, 0, 1, &spi_buffer);
+       tsc2102_request_alloc(&tsc, &tsc.req_pressure, 0, 1, &spi_buffer);
+       tsc2102_request_alloc(&tsc, &tsc.req_stopadc, 1, 1, &spi_buffer);
+       tsc2102_request_alloc(&tsc, &tsc.req_mode, 1, 1, &spi_buffer);
+
+       spin_lock_init(&tsc.lock);
+       spin_lock(&tsc.lock_sync);
+
+       /* Get the BCLK - assuming the rate is at 12000000 */
+       tsc.bclk_ck = clk_get(0, "bclk");
+       if (!tsc.bclk_ck) {
+               printk(KERN_ERR "Unable to get the clock BCLK\n");
+               err = -EPERM;
+               goto done;
+       }
+
+       clk_enable(tsc.bclk_ck);
+
+       if (request_irq(spi->irq, tsc2102_handler, IRQF_SAMPLE_RANDOM |
+                               IRQF_TRIGGER_FALLING, "tsc2102", &tsc)) {
+               printk(KERN_ERR "Could not allocate touchscreen IRQ!\n");
+               err = -EINVAL;
+               goto err_clk;
+       }
+
+       setup_timer(&tsc.ts_timer,
+                       tsc2102_pressure, (unsigned long) &tsc);
+       setup_timer(&tsc.mode_timer,
+                       tsc2102_mode_timer, (unsigned long) &tsc);
+
+       /* Set up the communication bus */
+       dev_set_drvdata(&spi->dev, &tsc);
+       spi->dev.power.power_state = PMSG_ON;
+       spi->mode = SPI_MODE_1;
+       spi->bits_per_word = 16;
+       err = spi_setup(spi);
+       if (err)
+               goto err_timer;
+
+       /* Now try to detect the chip, make first contact */
+       if (tsc2102_get_revision() != 0x1) {
+               printk(KERN_ERR "No TI TSC2102 chip found!\n");
+               goto err_timer;
+       }
+
+       err = tsc2102_configure(&tsc);
+       if (err)
+               goto err_timer;
+
+       /* Register devices controlled by TSC 2102 */
+       tsc2102_ts_device.dev.platform_data = pdata;
+       tsc2102_ts_device.dev.parent = &spi->dev;
+       err = platform_device_register(&tsc2102_ts_device);
+       if (err)
+               goto err_timer;
+
+       tsc2102_alsa_device.dev.platform_data = pdata->alsa_config;
+       tsc2102_alsa_device.dev.parent = &spi->dev;
+       err = platform_device_register(&tsc2102_alsa_device);
+       if (err)
+               goto err_ts;
+
+#ifdef CONFIG_HWMON
+       tsc.hwmondev = hwmon_device_register(&spi->dev);
+       if (IS_ERR(tsc.hwmondev)) {
+               printk(KERN_ERR "tsc2102_hwmon: Device registration failed\n");
+               err = PTR_ERR(tsc.hwmondev);
+               goto err_alsa;
+       }
+
+       if (pdata->monitor & TSC_BAT1)
+               err |= device_create_file(&spi->dev, &dev_attr_in0_input);
+       if (pdata->monitor & TSC_BAT2)
+               err |= device_create_file(&spi->dev, &dev_attr_in1_input);
+       if (pdata->monitor & TSC_AUX)
+               err |= device_create_file(&spi->dev, &dev_attr_in2_input);
+       if (pdata->monitor & TSC_TEMP) {
+               err |= device_create_file(&spi->dev, &dev_attr_temp1_input);
+               err |= device_create_file(&spi->dev, &dev_attr_in3_input);
+               err |= device_create_file(&spi->dev, &dev_attr_in4_input);
+       }
+
+       if (err)
+               printk(KERN_ERR "tsc2102_hwmon: Creating one or more "
+                               "attribute files failed\n");
+       err = 0;        /* Not fatal */
+#endif
+
+#ifdef CONFIG_APM
+       if (pdata->apm_report)
+               apm_get_power_status = tsc2102_get_power_status;
+#endif
+
+       if (!err)
+               goto done;
+
+err_alsa:
+       platform_device_unregister(&tsc2102_alsa_device);
+err_ts:
+       platform_device_unregister(&tsc2102_ts_device);
+err_timer:
+       del_timer(&tsc.ts_timer);
+       del_timer(&tsc.mode_timer);
+       dev_set_drvdata(&spi->dev, NULL);
+err_clk:
+       clk_disable(tsc.bclk_ck);
+       clk_put(tsc.bclk_ck);
+done:
+       spin_unlock(&tsc.lock_sync);
+       return err;
+}
+
+static int tsc2102_remove(struct spi_device *spi)
+{
+       struct tsc2102_dev *dev = dev_get_drvdata(&spi->dev);
+
+       spin_lock(&dev->lock_sync);
+
+       platform_device_unregister(&tsc2102_ts_device);
+       platform_device_unregister(&tsc2102_alsa_device);
+
+       dev_set_drvdata(&spi->dev, NULL);
+
+       /* Release the BCLK */
+       clk_disable(dev->bclk_ck);
+       clk_put(dev->bclk_ck);
+
+       del_timer(&tsc.mode_timer);
+       del_timer(&tsc.ts_timer);
+
+       kfree(tsc.transfers);
+
+#ifdef CONFIG_HWMON
+       hwmon_device_unregister(dev->hwmondev);
+#endif
+
+#ifdef CONFIG_APM
+       apm_get_power_status = 0;
+#endif
+
+       spin_unlock(&dev->lock_sync);
+
+       return 0;
+}
+
+static struct spi_driver tsc2102_driver = {
+       .probe          = tsc2102_probe,
+       .remove         = tsc2102_remove,
+       .suspend        = tsc2102_suspend,
+       .resume         = tsc2102_resume,
+       .driver         = {
+               .name   = "tsc2102",
+               .owner  = THIS_MODULE,
+               .bus    = &spi_bus_type,
+       },
+};
+
+static char __initdata banner[] = KERN_INFO "TI TSC2102 driver initializing\n";
+
+static int __init tsc2102_init(void)
+{
+       printk(banner);
+       return spi_register_driver(&tsc2102_driver);
+}
+
+static void __exit tsc2102_exit(void)
+{
+       spi_unregister_driver(&tsc2102_driver);
+}
+
+module_init(tsc2102_init);
+module_exit(tsc2102_exit);
+
+EXPORT_SYMBOL(tsc2102_read_sync);
+EXPORT_SYMBOL(tsc2102_reads_sync);
+EXPORT_SYMBOL(tsc2102_write_sync);
+EXPORT_SYMBOL(tsc2102_keyclick);
+
+MODULE_AUTHOR("Andrzej Zaborowski");
+MODULE_DESCRIPTION("Interface driver for TI TSC2102 chips.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ssi/Kconfig b/drivers/ssi/Kconfig
new file mode 100644 (file)
index 0000000..e84f9d2
--- /dev/null
@@ -0,0 +1,18 @@
+menu "Synchronous Serial Interfaces (SSI)"
+
+config OMAP_UWIRE
+       depends on ARCH_OMAP1
+       tristate "MicroWire support on OMAP"
+       ---help---
+         Say Y here if you want support for the MicroWire interface
+         on an OMAP processor.
+
+config OMAP_TSC2101
+       depends on ARCH_OMAP1 || ARCH_OMAP24XX
+       tristate "TSC2101 codec support for Touchscreen and audio"
+       select OMAP_UWIRE if MACH_OMAP_H3 || MACH_OMAP_H2
+       select GPIOEXPANDER_OMAP if MACH_OMAP_H3
+       ---help---
+         Say Y here if you want support for the TSC2101 codec.  It is
+         needed for touchscreen and audio on OMAP1610 and 1710.
+endmenu
diff --git a/drivers/ssi/Makefile b/drivers/ssi/Makefile
new file mode 100644 (file)
index 0000000..c63cf2b
--- /dev/null
@@ -0,0 +1,6 @@
+#
+# Makefile for the SSI drivers
+#
+
+obj-$(CONFIG_OMAP_UWIRE)        += omap-uwire.o
+obj-$(CONFIG_OMAP_TSC2101)      += omap-tsc2101.o
diff --git a/drivers/ssi/omap-tsc2101.c b/drivers/ssi/omap-tsc2101.c
new file mode 100644 (file)
index 0000000..5dfe994
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * linux/drivers/ssi/omap-tsc2101.c
+ *
+ * TSC2101 codec interface driver for the OMAP platform
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * History:
+ *
+ * 2004/11/07   Nishanth Menon - Modified for common hooks for Audio and Touchscreen
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+#include <asm/hardware.h>
+
+#include <asm/arch/mux.h>
+#include <asm/arch/io.h>
+#include <asm/arch/hardware.h>
+#include <asm/hardware/tsc2101.h>
+#include <asm/arch/gpioexpander.h>
+
+#include "omap-tsc2101.h"
+
+#if CONFIG_ARCH_OMAP16XX
+#include <../drivers/ssi/omap-uwire.h>
+#else
+#error "Unsupported configuration"
+#endif
+
+#define SPIO 1
+
+static int count;
+static spinlock_t tsc2101_lock = SPIN_LOCK_UNLOCKED;
+static struct clk  * tsc2101_mclk_ck;
+
+static int omap_tsc2101_configure(void);
+
+/* FIXME: add driver model usage to powerdown the tsc2101 on suspend */
+/* Clock  -Hard coding for the time being */
+#define CLK_SOFT_REQ_REG_BASE  (0xFFFE0800+0x34)
+#define SOFT_COM_MCK0_REQ_MASK (0x1<<6)
+
+int omap_tsc2101_enable(void)
+{
+       int ret = 0;
+
+       spin_lock(&tsc2101_lock);
+       if (count++ == 0) {
+               int ret = 0;
+               /* set the Mux to provide MCLK to TSC2101 */
+               if (machine_is_omap_h3()) {
+                       ret = omap_cfg_reg(V5_1710_MCLK_ON);
+               } else {
+                       if (machine_is_omap_h2()) {
+                               ret = omap_cfg_reg(R10_1610_MCLK_ON);
+                       }
+               }
+
+               /* Get the MCLK */
+               tsc2101_mclk_ck = clk_get(NULL, "mclk");
+               if (NULL == tsc2101_mclk_ck) {
+                       printk(KERN_ERR "Unable to get the clock MCLK!!!\n");;
+                       ret = -EPERM;
+                       goto done;
+               }
+               if (clk_set_rate(tsc2101_mclk_ck, 12000000)) {
+                       printk(KERN_ERR "Unable to set rate to the MCLK!!!\n");;
+                       ret = -EPERM;
+                       goto done;
+               }
+               clk_enable(tsc2101_mclk_ck);
+
+               ret = omap_tsc2101_configure();
+
+               /* Lock the module */
+               if (!ret && !try_module_get(THIS_MODULE)) {
+                       printk(KERN_CRIT "Failed to get TSC module\n");
+                       ret = -ESTALE;
+               }
+       }
+
+done:
+       spin_unlock(&tsc2101_lock);
+       return ret;
+}
+
+void omap_tsc2101_disable(void)
+{
+       spin_lock(&tsc2101_lock);
+       if (--count == 0) {
+               int ret = 0;
+               /* Remove the Mux to Stop MCLK to TSC2101 */
+               if (machine_is_omap_h3()) {
+                       ret = omap_cfg_reg(V5_1710_MCLK_OFF);
+               } else {
+                       if (machine_is_omap_h2()) {
+                               ret = omap_cfg_reg(R10_1610_MCLK_OFF);
+                       }
+               }
+
+               /* Release the MCLK */
+               clk_disable(tsc2101_mclk_ck);
+               clk_put(tsc2101_mclk_ck);
+               tsc2101_mclk_ck = NULL;
+
+               module_put(THIS_MODULE);
+       }
+       spin_unlock(&tsc2101_lock);
+}
+
+void omap_tsc2101_write(int page, u8 address, u16 data)
+{
+
+       int ret = 0;
+
+       if (machine_is_omap_h2()) {
+               ret =
+                   omap_uwire_data_transfer(1, 
+                                            (((page) << 11) | (address << 5)),
+                                            16, 0, NULL, 1);
+               if (ret) {
+                       printk(KERN_ERR
+                              "uwire-write returned error for address %x\n",
+                              address);
+                       return;
+               }
+               ret = omap_uwire_data_transfer(1, data, 16, 0, NULL, 0);
+               if (ret) {
+                       printk(KERN_ERR
+                              "uwire-write returned error for address %x\n",
+                              address);
+                       return;
+               }
+       }
+       if (machine_is_omap_h3()) {
+
+               ret =
+                   omap_uwire_data_transfer(0, ((page << 11) | (address << 5)),
+                                            16, 0, NULL, 1);
+               if (ret) {
+                       printk(KERN_ERR
+                              "uwire-write returned error for address %x\n",
+                              address);
+                       return;
+               }
+               ret = omap_uwire_data_transfer(0, data, 16, 0, NULL, 0);
+               if (ret) {
+                       printk(KERN_ERR
+                              "uwire-write returned error for address %x\n",
+                              address);
+                       return;
+               }
+       }
+
+}
+
+void omap_tsc2101_reads(int page, u8 startaddress, u16 * data, int numregs)
+{
+       int cs = 0, i;
+       if (machine_is_omap_h2()) {
+               cs = 1;
+       }
+       if (machine_is_omap_h3()) {
+               cs = 0;
+       }
+       (void)omap_uwire_data_transfer(cs, (0x8000 | (page << 11)
+                                           | (startaddress << 5)),
+                                      16, 0, NULL, 1);
+       for (i = 0; i < (numregs - 1); i++, data++) {
+               omap_uwire_data_transfer(cs, 0, 0, 16, data, 1);
+       }
+       omap_uwire_data_transfer(cs, 0, 0, 16, data, 0);
+}
+
+u16 omap_tsc2101_read(int page, u8 address)
+{
+       u16 ret;
+       omap_tsc2101_reads(page, address, &ret, 1);
+       return ret;
+}
+
+/* FIXME: adapt clock divisors for uwire to current ARM xor clock rate */
+static int omap_tsc2101_configure(void)
+{
+       unsigned long uwire_flags = 0;
+
+#ifdef CONFIG_MACH_OMAP_H3
+       int err = 0;
+       u8 ioExpanderVal = 0;
+
+       if ((err = read_gpio_expa(&ioExpanderVal, 0x24))) {
+               printk(" Error reading from I/O EXPANDER \n");
+               return err;
+       }
+       ioExpanderVal |= 0x8;
+
+       if ((err = write_gpio_expa(ioExpanderVal, 0x24))) {
+               printk(KERN_ERR ": Error writing to I/O EXPANDER \n");
+               return err;
+       }
+#endif
+
+       if (machine_is_omap_h2()) {
+               uwire_flags = UWIRE_READ_RISING_EDGE | UWIRE_WRITE_RISING_EDGE;
+               omap_cfg_reg(N15_1610_UWIRE_CS1);
+               omap_uwire_configure_mode(1, uwire_flags);
+       }
+       if (machine_is_omap_h3()) {
+               uwire_flags = UWIRE_READ_RISING_EDGE | UWIRE_WRITE_RISING_EDGE;
+               omap_cfg_reg(N14_1610_UWIRE_CS0);
+               omap_uwire_configure_mode(0, uwire_flags);
+       }
+
+       /* Configure MCLK enable */
+       omap_writel(omap_readl(PU_PD_SEL_2) | (1 << 22), PU_PD_SEL_2);  
+
+       return 0;
+}
+
+EXPORT_SYMBOL(omap_tsc2101_enable);
+EXPORT_SYMBOL(omap_tsc2101_read);
+EXPORT_SYMBOL(omap_tsc2101_reads);
+EXPORT_SYMBOL(omap_tsc2101_write);
+EXPORT_SYMBOL(omap_tsc2101_disable);
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION
+    ("Glue audio driver for the TI OMAP1610/OMAP1710 TSC2101 codec.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ssi/omap-tsc2101.h b/drivers/ssi/omap-tsc2101.h
new file mode 100644 (file)
index 0000000..f6b40b8
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * linux/drivers/ssi/omap-tsc2101.h
+ *
+ * TSC2101 codec interface driver for the OMAP platform
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * History:
+ *
+ * 2004/11/07   Nishanth Menon - Provided common hooks for Audio and Touchscreen
+ */
+
+#ifndef __OMAP_TSC2101_H
+#define __OMAP_TSC2101_H
+
+extern u16 omap_tsc2101_read(int page, u8 address);
+extern void omap_tsc2101_reads(int page, u8 startaddress, u16 * data,
+                              int numregs);
+extern void omap_tsc2101_write(int page, u8 address, u16 data);
+
+extern void omap_tsc2101_disable(void);
+extern int omap_tsc2101_enable(void);
+
+#endif
diff --git a/drivers/ssi/omap-uwire.c b/drivers/ssi/omap-uwire.c
new file mode 100644 (file)
index 0000000..61b3ca1
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * BRIEF MODULE DESCRIPTION
+ *
+ *     uWire interface driver for the OMAP Platform
+ *
+ * Copyright 2003 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *        source@mvista.com
+ *
+ * Ported to 2.6 uwire interface.
+ * Copyright (C) 2004 Texas Instruments.
+ *
+ * Generalization patches by Juha Yrjölä <juha.yrjola@nokia.com>
+ *
+ *  This program is free software; you can redistribute         it and/or modify it
+ *  under  the terms of         the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the License, or (at your
+ *  option) any later version.
+ *
+ *  THIS  SOFTWARE  IS PROVIDED          ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,          INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED          TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA, OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN         CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/omap730.h>  /* OMAP730_IO_CONF registers */
+
+#include "omap-uwire.h"
+
+/* uWire Registers: */
+#define UWIRE_BASE    0xFFFB3000
+#define UWIRE_IO_SIZE 0x20
+#define UWIRE_TDR     0x00
+#define UWIRE_RDR     0x00
+#define UWIRE_CSR     0x01
+#define UWIRE_SR1     0x02
+#define UWIRE_SR2     0x03
+#define UWIRE_SR3     0x04
+#define UWIRE_SR4     0x05
+#define UWIRE_SR5     0x06
+
+static unsigned short uwire_flags[4];
+static unsigned long uwire_base = io_p2v(UWIRE_BASE);
+static spinlock_t uwire_lock;
+static unsigned int uwire_idx_shift;
+
+static inline void uwire_write_reg(int idx, u16 val)
+{
+       __raw_writew(val, uwire_base + (idx << uwire_idx_shift));
+}
+
+static inline u16 uwire_read_reg(int idx)
+{
+       return __raw_readw(uwire_base + (idx << uwire_idx_shift));
+}
+
+void omap_uwire_configure_mode(int cs, unsigned long flags)
+{
+       u16 w, val = 0;
+       int shift, reg;
+
+       BUG_ON(cs > 3);
+
+       val = flags & 0x3f;
+       if (flags & UWIRE_CLK_INVERTED)
+               val ^= 0x03;
+       if (cs & 1)
+               shift = 6;
+       else
+               shift = 0;
+       if (cs <= 1)
+               reg = UWIRE_SR1;
+       else
+               reg = UWIRE_SR2;
+       spin_lock(&uwire_lock);
+       w = uwire_read_reg(reg);
+       w &= ~(0x3f << shift);
+       w |= val << shift;
+       uwire_write_reg(reg, w);
+       spin_unlock(&uwire_lock);
+
+       uwire_flags[cs] = flags;
+}
+
+static int wait_uwire_csr_flag(u16 mask, u16 val, int might_not_catch)
+{
+       u16 w;
+       int c = 0;
+       unsigned long max_jiffies = jiffies + HZ;
+
+       for (;;) {
+               w = uwire_read_reg(UWIRE_CSR);
+               if ((w & mask) == val)
+                       break;
+               if (time_after(jiffies, max_jiffies)) {
+                       printk(KERN_ERR "%s: timeout. reg=%#06x mask=%#06x val=%#06x\n",
+                              __FUNCTION__, w, mask, val);
+                       return -1;
+               }
+               c++;
+               if (might_not_catch && c > 64)
+                       break;
+       }
+       return 0;
+}
+
+int omap_uwire_data_transfer(int cs, u16 tx_data, int tx_size, int rx_size,
+                            u16 *rx_buf, int leave_cs_active)
+{
+       u16 ret = -1, w;
+       u16 mask;
+
+       BUG_ON(cs > 3);
+       BUG_ON(rx_size && !rx_buf);
+
+       spin_lock(&uwire_lock);
+
+       if (wait_uwire_csr_flag(1 << 14, 0, 0))
+               goto exit;
+
+       if (uwire_flags[cs] & UWIRE_CLK_INVERTED)
+               uwire_write_reg(UWIRE_SR4, 1);
+       else
+               uwire_write_reg(UWIRE_SR4, 0);
+
+       w = cs << 10;
+       w |= 1 << 12;                           /* CS_CMD : activate CS */
+       uwire_write_reg(UWIRE_CSR, w);
+
+       /* Shift data to 16bit MSb and place it in TX register. */
+       uwire_write_reg(UWIRE_TDR, tx_data << (16 - tx_size));
+
+       if (wait_uwire_csr_flag(1 << 14, 0, 0))
+               goto exit;
+
+       w = rx_size | (tx_size << 5) | (cs << 10);
+       w |= (1 << 12) | (1 << 13);
+       /* Start uWire read/write */
+       uwire_write_reg(UWIRE_CSR, w);
+
+       /* Wait till read/write actually starts.
+        * This is needed at high (>=60MHz) MPU frequencies
+        * REVISIT: But occasionally we won't have time to catch it
+        */
+       if (wait_uwire_csr_flag(1 << 14, 1 << 14, 1))
+               goto exit;
+
+       /* Wait for both transfers to be completed */
+       mask = 1 << 14;                 /* CSRB : reg busy */
+       w = 0;
+       if (rx_size) {
+               mask |= 1 << 15;        /* RDRB : reg busy */
+               w |= 1 << 15;
+       }
+
+       if (wait_uwire_csr_flag(mask, w, 0))
+               goto exit;
+
+       if (rx_size)
+               *rx_buf = uwire_read_reg(UWIRE_RDR);
+
+       if (!leave_cs_active)
+               uwire_write_reg(UWIRE_CSR, cs << 10);
+
+       ret = 0;
+
+exit:
+       spin_unlock(&uwire_lock);
+       return ret;
+}
+
+static int __init omap_uwire_init(void)
+{
+       spin_lock_init(&uwire_lock);
+       if (cpu_is_omap730())
+               uwire_idx_shift = 1;
+       else
+               uwire_idx_shift = 2;
+
+       uwire_write_reg(UWIRE_SR3, 1);
+       if (machine_is_omap_h2()) {
+               /* defaults: W21 SDO, U18 SDI, V19 SCL */
+               omap_cfg_reg(N14_1610_UWIRE_CS0);
+               omap_cfg_reg(N15_1610_UWIRE_CS1);
+       }
+       if (machine_is_omap_osk()) {
+               /* this is the standard expansion connector usage, with
+                * the other chipselect pins for MPUIO2 and MPUIO4.
+                */
+               omap_cfg_reg(N14_1610_UWIRE_CS0);
+               omap_cfg_reg(P15_1610_UWIRE_CS3);
+       }
+       if (machine_is_omap_perseus2()) {
+               /* configure pins: MPU_UW_nSCS1, MPU_UW_SDO, MPU_UW_SCLK */
+               int val = omap_readl(OMAP730_IO_CONF_9) & ~0x00EEE000;
+               omap_writel(val | 0x00AAA000, OMAP730_IO_CONF_9);
+       }
+       return 0;
+}
+
+static void __exit omap_uwire_exit(void)
+{
+}
+
+subsys_initcall(omap_uwire_init);
+module_exit(omap_uwire_exit);
+
+EXPORT_SYMBOL(omap_uwire_configure_mode);
+EXPORT_SYMBOL(omap_uwire_data_transfer);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/ssi/omap-uwire.h b/drivers/ssi/omap-uwire.h
new file mode 100644 (file)
index 0000000..a0d24bc
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef __ARCH_OMAP_UWIRE_H
+#define __ARCH_OMAP_UWIRE_H
+
+#define UWIRE_READ_FALLING_EDGE                0x0000
+#define UWIRE_READ_RISING_EDGE         0x0001
+#define UWIRE_WRITE_FALLING_EDGE       0x0000
+#define UWIRE_WRITE_RISING_EDGE                0x0002
+#define UWIRE_CS_ACTIVE_LOW            0x0000
+#define UWIRE_CS_ACTIVE_HIGH           0x0004
+#define UWIRE_FREQ_DIV_2               0x0000
+#define UWIRE_FREQ_DIV_4               0x0008
+#define UWIRE_FREQ_DIV_8               0x0010
+#define UWIRE_CHK_READY                        0x0020
+#define UWIRE_CLK_INVERTED             0x0040
+
+/*
+ * uWire for OMAP declarations
+ */
+extern void omap_uwire_configure_mode(int cs, unsigned long flags);
+
+/* NOTE: Make sure you don't call this from an interrupt handler! */
+extern int omap_uwire_data_transfer(int cs, u16 tx_data, int tx_size,
+                                   int rx_size, u16 *rx_buf,
+                                   int leave_cs_active);
+
+#endif
index 9980a4ddfed934617a7726c6c612a24edebb4d27..b3d850399b49f63aa718552206459fbc7fda1ad4 100644 (file)
@@ -81,6 +81,8 @@ source "drivers/usb/core/Kconfig"
 
 source "drivers/usb/host/Kconfig"
 
+source "drivers/usb/musb/Kconfig"
+
 source "drivers/usb/class/Kconfig"
 
 source "drivers/usb/storage/Kconfig"
index 4097a86c4b5e125c5de26dc6905259d52ab13657..2f9f1612559bcf96f7a4cea02616ecc5c85282c0 100644 (file)
@@ -155,10 +155,20 @@ config USB_LH7A40X
        select USB_GADGET_SELECTED
 
 
+# built in ../musb along with host support
+config USB_GADGET_MUSB_HDRC
+       boolean "Inventra HDRC USB Peripheral (TI, ...)"
+       depends on USB_MUSB_HDRC && (USB_MUSB_PERIPHERAL || USB_MUSB_OTG)
+       select USB_GADGET_DUALSPEED
+       select USB_GADGET_SELECTED
+       help
+         This OTG-capable silicon IP is used in dual designs including
+         the TI DaVinci, OMAP 243x, OMAP 343x, and TUSB 6010.
+
 config USB_GADGET_OMAP
        boolean "OMAP USB Device Controller"
        depends on ARCH_OMAP
-       select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3
+       select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_H4_OTG
        help
           Many Texas Instruments OMAP processors have flexible full
           speed USB device controllers, with support for up to 30
index cdcfd42843d46053deda8fe3863a67004079877a..91b3bb098d9f4f618b0eb6a60f47adb3b480463c 100644 (file)
@@ -2580,7 +2580,9 @@ omap_ep_setup(char *name, u8 addr, u8 type,
                 * and ignored for PIO-IN on newer chips
                 * (for more reliable behavior)
                 */
-               if (!use_dma || cpu_is_omap15xx() || cpu_is_omap24xx())
+               if ((!use_dma && (addr & USB_DIR_IN))
+                               || machine_is_omap_apollon()
+                               || cpu_is_omap15xx())
                        dbuf = 0;
 
                switch (maxp) {
index 27be1f9368853925da47e2b64cd18fb3ec59088e..b3da18b7b8a594a9751390cb7789dbeba73669c3 100644 (file)
@@ -227,7 +227,7 @@ static int ohci_omap_init(struct usb_hcd *hcd)
 
        omap_ohci_clock_power(1);
 
-       if (cpu_is_omap1510()) {
+       if (cpu_is_omap15xx()) {
                omap_1510_local_bus_power(1);
                omap_1510_local_bus_init();
        }
@@ -315,7 +315,7 @@ static int usb_hcd_omap_probe (const struct hc_driver *driver,
        if (IS_ERR(usb_host_ck))
                return PTR_ERR(usb_host_ck);
 
-       if (!cpu_is_omap1510())
+       if (!cpu_is_omap15xx())
                usb_dc_ck = clk_get(0, "usb_dc_ck");
        else
                usb_dc_ck = clk_get(0, "lb_ck");
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
new file mode 100644 (file)
index 0000000..a9bcd7e
--- /dev/null
@@ -0,0 +1,176 @@
+#
+# USB Dual Role (OTG-ready) Controller Drivers
+# for silicon based on Mentor Graphics INVENTRA designs
+#
+
+comment "Enable Host or Gadget support to see Inventra options"
+       depends on !USB && USB_GADGET=n
+
+# (M)HDRC = (Multipoint) Highspeed Dual-Role Controller
+config USB_MUSB_HDRC
+       depends on USB || USB_GADGET
+       tristate 'Inventra Highspeed Dual Role Controller (TI, ...)'
+       help
+         Say Y here if your system has a dual role high speed USB
+         controller based on the Mentor Graphics silicon IP.  Then
+         configure options to match your silicon and the board
+         it's being used with, including the USB peripheral role,
+         or the USB host role, or both.
+
+         Texas Instruments parts using this IP include DaVinci 644x,
+         OMAP 243x, OMAP 343x, and TUSB 6010.
+
+         If you do not know what this is, please say N.
+
+         To compile this driver as a module, choose M here; the
+         module will be called "musb_hdrc".
+
+config USB_MUSB_SOC
+       boolean
+       depends on USB_MUSB_HDRC
+       default y if ARCH_DAVINCI
+       default y if ARCH_OMAP2430
+       default y if ARCH_OMAP343X
+       help
+         Use a static <asm/arch/hdrc_cnf.h> file to describe how the
+         controller is configured (endpoints, mechanisms, etc) on the
+         current iteration of a given system-on-chip.
+
+comment "DaVinci 644x USB support"
+       depends on USB_MUSB_HDRC && ARCH_DAVINCI
+
+comment "OMAP 243x high speed USB support"
+       depends on USB_MUSB_HDRC && ARCH_OMAP2430
+
+comment "OMAP 343x high speed USB support"
+       depends on USB_MUSB_HDRC && ARCH_OMAP343X
+
+config USB_TUSB6010
+       boolean "TUSB 6010 support"
+       depends on USB_MUSB_HDRC && !USB_MUSB_SOC
+       default y
+       help
+         The TUSB 6010 chip, from Texas Instruments, connects a discrete
+         HDRC core using a 16-bit parallel bus (NOR flash style) or VLYNQ
+         (a high speed serial link).  It can use system-specific external
+         DMA controllers.
+
+choice
+       prompt "Driver Mode"
+       depends on USB_MUSB_HDRC
+       help
+         Dual-Role devices can support both host and peripheral roles,
+         as well as a the special "OTG Device" role which can switch
+         between both roles as needed.
+
+# use USB_MUSB_HDRC_HCD not USB_MUSB_HOST to #ifdef host side support;
+# OTG needs both roles, not just USB_MUSB_HOST.
+config USB_MUSB_HOST
+       depends on USB
+       bool "USB Host"
+       help
+         Say Y here if your system supports the USB host role.
+         If it has a USB "A" (rectangular), "Mini-A" (uncommon),
+         or "Mini-AB" connector, it supports the host role.
+         (With a "Mini-AB" connector, you should enable USB OTG.)
+
+# use USB_GADGET_MUSB_HDRC not USB_MUSB_PERIPHERAL to #ifdef peripheral
+# side support ... OTG needs both roles
+config USB_MUSB_PERIPHERAL
+       depends on USB_GADGET
+       bool "USB Peripheral (gadget stack)"
+       select USB_GADGET_MUSB_HDRC
+       help
+         Say Y here if your system supports the USB peripheral role.
+         If it has a USB "B" (squarish), "Mini-B", or "Mini-AB"
+         connector, it supports the peripheral role.
+         (With a "Mini-AB" connector, you should enable USB OTG.)
+
+config USB_MUSB_OTG
+       depends on USB && USB_GADGET && EXPERIMENTAL
+       bool "Both host and peripheral:  USB OTG (On The Go) Device"
+       select USB_GADGET_MUSB_HDRC
+       select USB_OTG
+       select PM
+       help
+          The most notable feature of USB OTG is support for a
+          "Dual-Role" device, which can act as either a device
+          or a host.  The initial role choice can be changed
+          later, when two dual-role devices talk to each other.
+
+          At this writing, the OTG support in this driver is incomplete,
+          omitting the mandatory HNP or SRP protocols.  However, some
+          of the cable based role switching works.  (That is, grounding
+          the ID pin switches the controller to host mode, while leaving
+          it floating leaves it in peripheral mode.)
+
+          Select this if your system has a Mini-AB connector, or
+          to simplify certain kinds of configuration.
+
+          To implement your OTG Targeted Peripherals List (TPL), enable
+          USB_OTG_WHITELIST and update "drivers/usb/core/otg_whitelist.h"
+          to match your requirements.
+
+endchoice
+
+# enable peripheral support (including with OTG)
+config USB_GADGET_MUSB_HDRC
+       bool
+       depends on USB_MUSB_HDRC && (USB_MUSB_PERIPHERAL || USB_MUSB_OTG)
+#      default y
+#      select USB_GADGET_DUALSPEED
+#      select USB_GADGET_SELECTED
+
+# enables host support (including with OTG)
+config USB_MUSB_HDRC_HCD
+       bool
+       depends on USB_MUSB_HDRC && (USB_MUSB_HOST || USB_MUSB_OTG)
+       select USB_OTG if USB_GADGET_MUSB_HDRC
+       default y
+
+
+config USB_INVENTRA_FIFO
+       bool 'Disable DMA (always use PIO)'
+       depends on USB_MUSB_HDRC
+       default y if USB_TUSB6010
+       help
+         All data is copied between memory and FIFO by the CPU.
+         DMA controllers are ignored.
+
+         Do not select 'n' here unless DMA support for your SOC or board
+         is unavailable (or unstable).  When DMA is enabled at compile time,
+         you can still disable it at run time using the "use_dma=n" module
+         parameter.
+
+config USB_INVENTRA_DMA
+       bool
+       depends on USB_MUSB_HDRC && !USB_INVENTRA_FIFO
+       default ARCH_OMAP2430 || ARCH_OMAP343X
+       help
+         Enable DMA transfers using Mentor's engine.
+
+config USB_TI_CPPI_DMA
+       bool
+       depends on USB_MUSB_HDRC && !USB_INVENTRA_FIFO
+       default ARCH_DAVINCI
+       help
+         Enable DMA transfers when TI CPPI DMA is available.
+
+config USB_TUSB_OMAP_DMA
+       bool
+       depends on USB_MUSB_HDRC && !USB_INVENTRA_FIFO
+       depends on USB_TUSB6010
+       depends on ARCH_OMAP
+       default y
+       help
+         Enable DMA transfers on TUSB 6010 when OMAP DMA is available.
+
+config USB_INVENTRA_HCD_LOGGING
+       depends on USB_MUSB_HDRC
+       int  'Logging Level (0 - none / 3 - annoying / ... )'
+       default 0
+       help
+         Set the logging level. 0 disables the debugging altogether,
+         although when USB_DEBUG is set the value is at least 1.
+         Starting at level 3, per-transfer (urb, usb_request, packet,
+         or dma transfer) tracing may kick in.
diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile
new file mode 100644 (file)
index 0000000..535ba40
--- /dev/null
@@ -0,0 +1,82 @@
+#
+# for USB OTG silicon based on Mentor Graphics INVENTRA designs
+#
+
+musb_hdrc-objs := plat_uds.o
+
+obj-$(CONFIG_USB_MUSB_HDRC)    += musb_hdrc.o
+
+ifeq ($(CONFIG_ARCH_DAVINCI),y)
+       musb_hdrc-objs  += davinci.o
+endif
+
+ifeq ($(CONFIG_USB_TUSB6010),y)
+       musb_hdrc-objs  += tusb6010.o
+endif
+
+ifeq ($(CONFIG_ARCH_OMAP2430),y)
+       musb_hdrc-objs  += omap2430.o
+endif
+
+ifeq ($(CONFIG_USB_GADGET_MUSB_HDRC),y)
+       musb_hdrc-objs          += g_ep0.o musb_gadget.o
+endif
+
+ifeq ($(CONFIG_USB_MUSB_HDRC_HCD),y)
+       musb_hdrc-objs          += virthub.o musb_host.o
+endif
+
+# the kconfig must guarantee that only one of the
+# possible I/O schemes will be enabled at a time ...
+# PIO (INVENTRA_FIFO), or DMA (several potential schemes).
+# though PIO is always there to back up DMA, and for ep0
+
+ifneq ($(CONFIG_USB_INVENTRA_FIFO),y)
+
+  ifeq ($(CONFIG_USB_INVENTRA_DMA),y)
+    musb_hdrc-objs             += musbhsdma.o
+
+  else
+    ifeq ($(CONFIG_USB_TI_CPPI_DMA),y)
+      musb_hdrc-objs           += cppi_dma.o
+
+    else
+      ifeq ($(CONFIG_USB_TUSB_OMAP_DMA),y)
+        musb_hdrc-objs         += tusb6010_omap.o
+
+      endif
+    endif
+  endif
+endif
+
+
+################################################################################
+
+# FIXME remove all these extra "-DMUSB_* things, stick to CONFIG_*
+
+ifeq ($(CONFIG_USB_INVENTRA_MUSB_HAS_AHB_ID),y)
+       EXTRA_CFLAGS += -DMUSB_AHB_ID
+endif
+
+# Debugging
+
+MUSB_DEBUG:=$(CONFIG_USB_INVENTRA_HCD_LOGGING)
+
+ifeq ("$(strip $(MUSB_DEBUG))","")
+    ifdef CONFIG_USB_DEBUG
+       MUSB_DEBUG:=1
+    else
+       MUSB_DEBUG:=0
+    endif
+endif
+
+ifneq ($(MUSB_DEBUG),0)
+    EXTRA_CFLAGS += -DDEBUG
+
+    ifeq ($(CONFIG_PROC_FS),y)
+       musb_hdrc-objs          += musb_procfs.o
+    endif
+
+endif
+
+EXTRA_CFLAGS += -DMUSB_DEBUG=$(MUSB_DEBUG)
diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c
new file mode 100644 (file)
index 0000000..673b4cf
--- /dev/null
@@ -0,0 +1,1567 @@
+/*
+ * Copyright (C) 2005-2006 by Texas Instruments
+ *
+ * This file implements a DMA  interface using TI's CPPI DMA.
+ * For now it's DaVinci-only, but CPPI isn't specific to DaVinci or USB.
+ * TUSB 6010 over VLYNQ has CPPI that looks much like DaVinci.
+ */
+
+#include <linux/usb.h>
+
+#include "musbdefs.h"
+#include "cppi_dma.h"
+
+
+/* CPPI DMA status 7-mar:
+ *
+ * - See musb_{host,gadget}.c for more info
+ *
+ * - Correct RX DMA generally forces the engine into irq-per-packet mode,
+ *   which can easily saturate the CPU under non-mass-storage loads.
+ *
+ * NOTES 24-aug (2.6.18-rc4):
+ *
+ * - peripheral RXDMA wedged in a test with packets of length 512/512/1.
+ *   evidently after the 1 byte packet was received and acked, the queue
+ *   of BDs got garbaged so it wouldn't empty the fifo.  (rxcsr 0x2003,
+ *   and RX DMA0: 4 left, 80000000 8feff880, 8feff860 8feff860; 8f321401
+ *   004001ff 00000001 .. 8feff860)  Host was just getting NAKed on tx
+ *   of its next (512 byte) packet.  IRQ issues?
+ *
+ * REVISIT:  the "transfer DMA" glue between CPPI and USB fifos will
+ * evidently also directly update the RX and TX CSRs ... so audit all
+ * host and peripheral side DMA code to avoid CSR access after DMA has
+ * been started.
+ */
+
+/* REVISIT now we can avoid preallocating these descriptors; or
+ * more simply, switch to a global freelist not per-channel ones.
+ * Note: at full speed, 64 descriptors == 4K bulk data.
+ */
+#define NUM_TXCHAN_BD       64
+#define NUM_RXCHAN_BD       64
+
+static inline void cpu_drain_writebuffer(void)
+{
+       wmb();
+#ifdef CONFIG_CPU_ARM926T
+       /* REVISIT this "should not be needed",
+        * but lack of it sure seemed to hurt ...
+        */
+       asm("mcr p15, 0, r0, c7, c10, 4 @ drain write buffer\n");
+#endif
+}
+
+static inline struct cppi_descriptor *
+cppi_bd_alloc(struct cppi_channel *c)
+{
+       struct cppi_descriptor  *bd = c->bdPoolHead;
+
+       if (bd)
+               c->bdPoolHead = bd->next;
+       return bd;
+}
+
+static inline void
+cppi_bd_free(struct cppi_channel *c, struct cppi_descriptor *bd)
+{
+       if (!bd)
+               return;
+       bd->next = c->bdPoolHead;
+       c->bdPoolHead = bd;
+}
+
+/*
+ *  Start Dma controller
+ *
+ *  Initialize the Dma Controller as necessary.
+ */
+
+#define        CAST (void *__force __iomem)
+
+/* zero out entire rx state RAM entry for the channel */
+static void cppi_reset_rx(struct cppi_rx_stateram *__iomem rx)
+{
+       musb_writel(CAST &rx->buffOffset, 0, 0);
+       musb_writel(CAST &rx->headPtr, 0, 0);
+       musb_writel(CAST &rx->sopDescPtr, 0, 0);
+       musb_writel(CAST &rx->currDescPtr, 0, 0);
+       musb_writel(CAST &rx->currBuffPtr, 0, 0);
+       musb_writel(CAST &rx->pktLength, 0, 0);
+       musb_writel(CAST &rx->byteCount, 0, 0);
+}
+
+static void __init cppi_pool_init(struct cppi *cppi, struct cppi_channel *c)
+{
+       int     j;
+
+       /* initialize channel fields */
+       c->activeQueueHead = NULL;
+       c->activeQueueTail = NULL;
+       c->lastHwBDProcessed = NULL;
+       c->Channel.bStatus = MGC_DMA_STATUS_UNKNOWN;
+       c->pController = cppi;
+       c->bLastModeRndis = 0;
+       c->Channel.pPrivateData = c;
+       c->bdPoolHead = NULL;
+
+       /* build the BD Free list for the channel */
+       for (j = 0; j < NUM_TXCHAN_BD + 1; j++) {
+               struct cppi_descriptor  *bd;
+               dma_addr_t              dma;
+
+               bd = dma_pool_alloc(cppi->pool, GFP_KERNEL, &dma);
+               bd->dma = dma;
+               cppi_bd_free(c, bd);
+       }
+}
+
+static int cppi_channel_abort(struct dma_channel *);
+
+static void cppi_pool_free(struct cppi_channel *c)
+{
+       struct cppi             *cppi = c->pController;
+       struct cppi_descriptor  *bd;
+
+       (void) cppi_channel_abort(&c->Channel);
+       c->Channel.bStatus = MGC_DMA_STATUS_UNKNOWN;
+       c->pController = NULL;
+
+       /* free all its bds */
+       bd = c->lastHwBDProcessed;
+       do {
+               if (bd)
+                       dma_pool_free(cppi->pool, bd, bd->dma);
+               bd = cppi_bd_alloc(c);
+       } while (bd);
+       c->lastHwBDProcessed = NULL;
+}
+
+static int __init cppi_controller_start(struct dma_controller *c)
+{
+       struct cppi     *pController;
+       void            *__iomem regBase;
+       int             i;
+
+       pController = container_of(c, struct cppi, Controller);
+
+       /* do whatever is necessary to start controller */
+       for (i = 0; i < ARRAY_SIZE(pController->txCppi); i++) {
+               pController->txCppi[i].bTransmit = TRUE;
+               pController->txCppi[i].chNo = i;
+       }
+       for (i = 0; i < ARRAY_SIZE(pController->rxCppi); i++) {
+               pController->rxCppi[i].bTransmit = FALSE;
+               pController->rxCppi[i].chNo = i;
+       }
+
+       /* setup BD list on a per channel basis */
+       for (i = 0; i < ARRAY_SIZE(pController->txCppi); i++)
+               cppi_pool_init(pController, pController->txCppi + i);
+       for (i = 0; i < ARRAY_SIZE(pController->rxCppi); i++)
+               cppi_pool_init(pController, pController->rxCppi + i);
+
+       /* Do Necessary configuartion in H/w to get started */
+       regBase =  pController->pCoreBase - DAVINCI_BASE_OFFSET;
+
+       INIT_LIST_HEAD(&pController->tx_complete);
+
+       /* initialise tx/rx channel head pointers to zero */
+       for (i = 0; i < ARRAY_SIZE(pController->txCppi); i++) {
+               struct cppi_channel     *txChannel = pController->txCppi + i;
+               struct cppi_tx_stateram *__iomem txState;
+
+               INIT_LIST_HEAD(&txChannel->tx_complete);
+
+               txState = regBase + DAVINCI_TXCPPI_STATERAM_OFFSET(i);
+               txChannel->stateRam = txState;
+               /* zero out entire state RAM entry for the channel */
+               txState->headPtr = 0;
+               txState->sopDescPtr = 0;
+               txState->currDescPtr = 0;
+               txState->currBuffPtr = 0;
+               txState->flags = 0;
+               txState->remLength = 0;
+               /*txState->dummy = 0; */
+               txState->completionPtr = 0;
+
+       }
+       for (i = 0; i < ARRAY_SIZE(pController->rxCppi); i++) {
+               struct cppi_channel     *rxChannel = pController->rxCppi + i;
+               struct cppi_rx_stateram *__iomem rxState;
+
+               INIT_LIST_HEAD(&rxChannel->tx_complete);
+
+               rxState = regBase + DAVINCI_RXCPPI_STATERAM_OFFSET(i);
+               rxChannel->stateRam = rxState;
+               cppi_reset_rx(rxChannel->stateRam);
+       }
+
+       /* enable individual cppi channels */
+       musb_writel(regBase, DAVINCI_TXCPPI_INTENAB_REG,
+                       DAVINCI_DMA_ALL_CHANNELS_ENABLE);
+       musb_writel(regBase, DAVINCI_RXCPPI_INTENAB_REG,
+                       DAVINCI_DMA_ALL_CHANNELS_ENABLE);
+
+       /* enable tx/rx CPPI control */
+       musb_writel(regBase, DAVINCI_TXCPPI_CTRL_REG, DAVINCI_DMA_CTRL_ENABLE);
+       musb_writel(regBase, DAVINCI_RXCPPI_CTRL_REG, DAVINCI_DMA_CTRL_ENABLE);
+
+       /* disable RNDIS mode, also host rx RNDIS autorequest */
+       musb_writel(regBase, DAVINCI_RNDIS_REG, 0);
+       musb_writel(regBase, DAVINCI_AUTOREQ_REG, 0);
+
+       return 0;
+}
+
+/*
+ *  Stop Dma controller
+ *
+ *  De-Init the Dma Controller as necessary.
+ */
+
+static int cppi_controller_stop(struct dma_controller *c)
+{
+       struct cppi             *pController;
+       void __iomem            *regBase;
+       int                     i;
+
+       pController = container_of(c, struct cppi, Controller);
+
+       regBase = pController->pCoreBase - DAVINCI_BASE_OFFSET;
+       /* DISABLE INDIVIDUAL CHANNEL Interrupts */
+       musb_writel(regBase, DAVINCI_TXCPPI_INTCLR_REG,
+                       DAVINCI_DMA_ALL_CHANNELS_ENABLE);
+       musb_writel(regBase, DAVINCI_RXCPPI_INTCLR_REG,
+                       DAVINCI_DMA_ALL_CHANNELS_ENABLE);
+
+       DBG(1, "Tearing down RX and TX Channels\n");
+       for (i = 0; i < ARRAY_SIZE(pController->txCppi); i++) {
+               /* FIXME restructure of txdma to use bds like rxdma */
+               pController->txCppi[i].lastHwBDProcessed = NULL;
+               cppi_pool_free(pController->txCppi + i);
+       }
+       for (i = 0; i < ARRAY_SIZE(pController->rxCppi); i++)
+               cppi_pool_free(pController->rxCppi + i);
+
+       /* in Tx Case proper teardown is supported. We resort to disabling
+        * Tx/Rx CPPI after cleanup of Tx channels. Before TX teardown is
+        * complete TX CPPI cannot be disabled.
+        */
+       /*disable tx/rx cppi */
+       musb_writel(regBase, DAVINCI_TXCPPI_CTRL_REG, DAVINCI_DMA_CTRL_DISABLE);
+       musb_writel(regBase, DAVINCI_RXCPPI_CTRL_REG, DAVINCI_DMA_CTRL_DISABLE);
+
+       return 0;
+}
+
+/* While dma channel is allocated, we only want the core irqs active
+ * for fault reports, otherwise we'd get irqs that we don't care about.
+ * Except for TX irqs, where dma done != fifo empty and reusable ...
+ *
+ * NOTE: docs don't say either way, but irq masking **enables** irqs.
+ *
+ * REVISIT same issue applies to pure PIO usage too, and non-cppi dma...
+ */
+static inline void core_rxirq_disable(void __iomem *tibase, unsigned epnum)
+{
+       musb_writel(tibase, DAVINCI_USB_INT_MASK_CLR_REG, 1 << (epnum + 8));
+}
+
+static inline void core_rxirq_enable(void __iomem *tibase, unsigned epnum)
+{
+       musb_writel(tibase, DAVINCI_USB_INT_MASK_SET_REG, 1 << (epnum + 8));
+}
+
+
+/*
+ * Allocate a CPPI Channel for DMA.  With CPPI, channels are bound to
+ * each transfer direction of a non-control endpoint, so allocating
+ * (and deallocating) is mostly a way to notice bad housekeeping on
+ * the software side.  We assume the irqs are always active.
+ */
+static struct dma_channel *
+cppi_channel_allocate(struct dma_controller *c,
+               struct musb_hw_ep *ep,
+               u8 bTransmit)
+{
+       struct cppi             *pController;
+       u8                      chNum;
+       struct cppi_channel     *otgCh;
+       void __iomem            *tibase;
+       int                     local_end = ep->bLocalEnd;
+
+       pController = container_of(c, struct cppi, Controller);
+       tibase = pController->pCoreBase - DAVINCI_BASE_OFFSET;
+
+       /* remember local_end: 1..Max_EndPt, and cppi ChNum:0..Max_EndPt-1 */
+       chNum = local_end - 1;
+
+       /* return the corresponding CPPI Channel Handle, and
+        * probably disable the non-CPPI irq until we need it.
+        */
+       if (bTransmit) {
+               if (local_end > ARRAY_SIZE(pController->txCppi)) {
+                       DBG(1, "no %cX DMA channel for ep%d\n", 'T', local_end);
+                       return NULL;
+               }
+               otgCh = pController->txCppi + chNum;
+       } else {
+               if (local_end > ARRAY_SIZE(pController->rxCppi)) {
+                       DBG(1, "no %cX DMA channel for ep%d\n", 'R', local_end);
+                       return NULL;
+               }
+               otgCh = pController->rxCppi + chNum;
+               core_rxirq_disable(tibase, local_end);
+       }
+
+       /* REVISIT make this an error later once the same driver code works
+        * with the Mentor DMA engine too
+        */
+       if (otgCh->pEndPt)
+               DBG(1, "re-allocating DMA%d %cX channel %p\n",
+                               chNum, bTransmit ? 'T' : 'R', otgCh);
+       otgCh->pEndPt = ep;
+       otgCh->Channel.bStatus = MGC_DMA_STATUS_FREE;
+
+       DBG(4, "Allocate CPPI%d %cX\n", chNum, bTransmit ? 'T' : 'R');
+       otgCh->Channel.pPrivateData = otgCh;
+       return &otgCh->Channel;
+}
+
+/* Release a CPPI Channel.  */
+static void cppi_channel_release(struct dma_channel *channel)
+{
+       struct cppi_channel     *c;
+       void __iomem            *tibase;
+       unsigned                epnum;
+
+       /* REVISIT:  for paranoia, check state and abort if needed... */
+
+       c = container_of(channel, struct cppi_channel, Channel);
+       epnum = c->chNo + 1;
+       tibase = c->pController->pCoreBase - DAVINCI_BASE_OFFSET;
+       if (!c->pEndPt)
+               DBG(1, "releasing idle DMA channel %p\n", c);
+       else if (!c->bTransmit)
+               core_rxirq_enable(tibase, epnum);
+
+       /* for now, leave its cppi IRQ enabled (we won't trigger it) */
+       c->pEndPt = NULL;
+       channel->bStatus = MGC_DMA_STATUS_UNKNOWN;
+}
+
+/* Context: controller irqlocked */
+static void
+cppi_dump_rx(int level, struct cppi_channel *c, const char *tag)
+{
+       void    *__iomem base = c->pController->pCoreBase;
+
+       MGC_SelectEnd(base, c->chNo + 1);
+
+       DBG(level, "RX DMA%d%s: %d left, csr %04x, "
+                       "%08x H%08x S%08x C%08x, "
+                       "B%08x L%08x %08x .. %08x"
+                       "\n",
+               c->chNo, tag,
+               musb_readl(base - DAVINCI_BASE_OFFSET,
+                       DAVINCI_RXCPPI_BUFCNT0_REG + 4 *c->chNo),
+               musb_readw(c->pEndPt->regs, MGC_O_HDRC_RXCSR),
+
+               musb_readl(c->stateRam, 0 * 4), /* buf offset */
+               musb_readl(c->stateRam, 1 * 4), /* head ptr */
+               musb_readl(c->stateRam, 2 * 4), /* sop bd */
+               musb_readl(c->stateRam, 3 * 4), /* current bd */
+
+               musb_readl(c->stateRam, 4 * 4), /* current buf */
+               musb_readl(c->stateRam, 5 * 4), /* pkt len */
+               musb_readl(c->stateRam, 6 * 4), /* byte cnt */
+               musb_readl(c->stateRam, 7 * 4)  /* completion */
+               );
+}
+
+/* Context: controller irqlocked */
+static void
+cppi_dump_tx(int level, struct cppi_channel *c, const char *tag)
+{
+       void    *__iomem base = c->pController->pCoreBase;
+
+       MGC_SelectEnd(base, c->chNo + 1);
+
+       DBG(level, "TX DMA%d%s: csr %04x, "
+                       "H%08x S%08x C%08x %08x, "
+                       "F%08x L%08x .. %08x"
+                       "\n",
+               c->chNo, tag,
+               musb_readw(c->pEndPt->regs, MGC_O_HDRC_TXCSR),
+
+               musb_readl(c->stateRam, 0 * 4), /* head ptr */
+               musb_readl(c->stateRam, 1 * 4), /* sop bd */
+               musb_readl(c->stateRam, 2 * 4), /* current bd */
+               musb_readl(c->stateRam, 3 * 4), /* buf offset */
+
+               musb_readl(c->stateRam, 4 * 4), /* flags */
+               musb_readl(c->stateRam, 5 * 4), /* len */
+               // dummy/unused word 6
+               musb_readl(c->stateRam, 7 * 4)  /* completion */
+               );
+}
+
+/* Context: controller irqlocked */
+static inline void
+cppi_rndis_update(struct cppi_channel *c, int is_rx,
+               void *__iomem tibase, int is_rndis)
+{
+       /* we may need to change the rndis flag for this cppi channel */
+       if (c->bLastModeRndis != is_rndis) {
+               u32     regVal = musb_readl(tibase, DAVINCI_RNDIS_REG);
+               u32     temp = 1 << (c->chNo);
+
+               if (is_rx)
+                       temp <<= 16;
+               if (is_rndis)
+                       regVal |= temp;
+               else
+                       regVal &= ~temp;
+               musb_writel(tibase, DAVINCI_RNDIS_REG, regVal);
+               c->bLastModeRndis = is_rndis;
+       }
+}
+
+static void cppi_dump_rxbd(const char *tag, struct cppi_descriptor *bd)
+{
+       pr_debug("RXBD/%s %08x: "
+                       "nxt %08x buf %08x off.blen %08x opt.plen %08x\n",
+                       tag, bd->dma,
+                       bd->hNext, bd->buffPtr, bd->bOffBLen, bd->hOptions);
+}
+
+static void cppi_dump_rxq(int level, const char *tag, struct cppi_channel *rx)
+{
+#if MUSB_DEBUG > 0
+       struct cppi_descriptor  *bd;
+
+       if (!_dbg_level(level))
+               return;
+       cppi_dump_rx(level, rx, tag);
+       if (rx->lastHwBDProcessed)
+               cppi_dump_rxbd("last", rx->lastHwBDProcessed);
+       for (bd = rx->activeQueueHead; bd; bd = bd->next)
+               cppi_dump_rxbd("active", bd);
+#endif
+}
+
+
+/* NOTE:  DaVinci autoreq is ignored except for host side "RNDIS" mode RX;
+ * so we won't ever use it (see "CPPI RX Woes" below).
+ */
+static inline int cppi_autoreq_update(struct cppi_channel *rx,
+               void *__iomem tibase, int onepacket, unsigned n_bds)
+{
+       u32     val;
+
+#ifdef RNDIS_RX_IS_USABLE
+       u32     tmp;
+       /* assert(is_host_active(musb)) */
+
+       /* start from "AutoReq never" */
+       tmp = musb_readl(tibase, DAVINCI_AUTOREQ_REG);
+       val = tmp & ~((0x3) << (rx->chNo * 2));
+
+       /* HCD arranged reqpkt for packet #1.  we arrange int
+        * for all but the last one, maybe in two segments.
+        */
+       if (!onepacket) {
+#if 0
+               /* use two segments, autoreq "all" then the last "never" */
+               val |= ((0x3) << (rx->chNo * 2));
+               n_bds--;
+#else
+               /* one segment, autoreq "all-but-last" */
+               val |= ((0x1) << (rx->chNo * 2));
+#endif
+       }
+
+       if (val != tmp) {
+               int n = 100;
+
+               /* make sure that autoreq is updated before continuing */
+               musb_writel(tibase, DAVINCI_AUTOREQ_REG, val);
+               do {
+                       tmp = musb_readl(tibase, DAVINCI_AUTOREQ_REG);
+                       if (tmp == val)
+                               break;
+                       cpu_relax();
+               } while (n-- > 0);
+       }
+#endif
+
+       /* REQPKT is turned off after each segment */
+       if (n_bds && rx->actualLen) {
+               void            *__iomem regs = rx->pEndPt->regs;
+
+               val = musb_readw(regs, MGC_O_HDRC_RXCSR);
+               if (!(val & MGC_M_RXCSR_H_REQPKT)) {
+                       val |= MGC_M_RXCSR_H_REQPKT | MGC_M_RXCSR_H_WZC_BITS;
+                       musb_writew(regs, MGC_O_HDRC_RXCSR, val);
+                       /* flush writebufer */
+                       val = musb_readw(regs, MGC_O_HDRC_RXCSR);
+               }
+       }
+       return n_bds;
+}
+
+
+/* Buffer enqueuing Logic:
+ *
+ *  - RX builds new queues each time, to help handle routine "early
+ *    termination" cases (faults, including errors and short reads)
+ *    more correctly.
+ *
+ *  - for now, TX reuses the same queue of BDs every time
+ *
+ * REVISIT long term, we want a normal dynamic model.
+ * ... the goal will be to append to the
+ * existing queue, processing completed "dma buffers" (segments) on the fly.
+ *
+ * Otherwise we force an IRQ latency between requests, which slows us a lot
+ * (especially in "transparent" dma).  Unfortunately that model seems to be
+ * inherent in the DMA model from the Mentor code, except in the rare case
+ * of transfers big enough (~128+ KB) that we could append "middle" segments
+ * in the TX paths.  (RX can't do this, see below.)
+ *
+ * That's true even in the CPPI- friendly iso case, where most urbs have
+ * several small segments provided in a group and where the "packet at a time"
+ * "transparent" DMA model is always correct, even on the RX side.
+ */
+
+/*
+ * CPPI TX:
+ * ========
+ * TX is a lot more reasonable than RX; it doesn't need to run in
+ * irq-per-packet mode very often.  RNDIS mode seems to behave too
+ * (other how it handles the exactly-N-packets case).  Building a
+ * txdma queue with multiple requests (urb or usb_request) looks
+ * like it would work ... but fault handling would need much testing.
+ *
+ * The main issue with TX mode RNDIS relates to transfer lengths that
+ * are an exact multiple of the packet length.  It appears that there's
+ * a hiccup in that case (maybe the DMA completes before the ZLP gets
+ * written?) boiling down to not being able to rely on CPPI writing any
+ * terminating zero length packet before the next transfer is written.
+ * So that's punted to PIO; better yet, gadget drivers can avoid it.
+ *
+ * Plus, there's allegedly an undocumented constraint that rndis transfer
+ * length be a multiple of 64 bytes ... but the chip doesn't act that
+ * way, and we really don't _want_ that behavior anyway.
+ *
+ * On TX, "transparent" mode works ... although experiments have shown
+ * problems trying to use the SOP/EOP bits in different USB packets.
+ *
+ * REVISIT try to handle terminating zero length packets using CPPI
+ * instead of doing it by PIO after an IRQ.  (Meanwhile, make Ethernet
+ * links avoid that issue by forcing them to avoid zlps.)
+ */
+static void
+cppi_next_tx_segment(struct musb *musb, struct cppi_channel *tx)
+{
+       unsigned                maxpacket = tx->pktSize;
+       dma_addr_t              addr = tx->startAddr + tx->currOffset;
+       size_t                  length = tx->transferSize - tx->currOffset;
+       struct cppi_descriptor  *bd;
+       unsigned                n_bds;
+       unsigned                i;
+       struct cppi_tx_stateram *txState = tx->stateRam;
+       int                     rndis;
+
+       /* TX can use the CPPI "rndis" mode, where we can probably fit this
+        * transfer in one BD and one IRQ.  The only time we would NOT want
+        * to use it is when hardware constraints prevent it, or if we'd
+        * trigger the "send a ZLP?" confusion.
+        */
+       rndis = (maxpacket & 0x3f) == 0
+               && length < 0xffff
+               && (length % maxpacket) != 0;
+
+       if (rndis) {
+               maxpacket = length;
+               n_bds = 1;
+       } else {
+               n_bds = length / maxpacket;
+               if (!length || (length % maxpacket))
+                       n_bds++;
+               n_bds = min(n_bds, (unsigned) NUM_TXCHAN_BD);
+               length = min(n_bds * maxpacket, length);
+       }
+
+       DBG(4, "TX DMA%d, pktSz %d %s bds %d dma 0x%x len %u\n",
+                       tx->chNo,
+                       maxpacket,
+                       rndis ? "rndis" : "transparent",
+                       n_bds,
+                       addr, length);
+
+       cppi_rndis_update(tx, 0, musb->ctrl_base, rndis);
+
+       /* assuming here that channel_program is called during
+        * transfer initiation ... current code maintains state
+        * for one outstanding request only (no queues, not even
+        * the implicit ones of an iso urb).
+        */
+
+       bd = tx->bdPoolHead;
+       tx->activeQueueHead = tx->bdPoolHead;
+       tx->lastHwBDProcessed = NULL;
+
+
+       /* Prepare queue of BDs first, then hand it to hardware.
+        * All BDs except maybe the last should be of full packet
+        * size; for RNDIS there _is_ only that last packet.
+        */
+       for (i = 0; i < n_bds; ) {
+               if (++i < n_bds && bd->next)
+                       bd->hNext = bd->next->dma;
+               else
+                       bd->hNext = 0;
+
+               bd->buffPtr = tx->startAddr
+                       + tx->currOffset;
+
+               /* FIXME set EOP only on the last packet,
+                * SOP only on the first ... avoid IRQs
+                */
+               if ((tx->currOffset + maxpacket)
+                               <= tx->transferSize) {
+                       tx->currOffset += maxpacket;
+                       bd->bOffBLen = maxpacket;
+                       bd->hOptions = CPPI_SOP_SET | CPPI_EOP_SET
+                               | CPPI_OWN_SET | maxpacket;
+               } else {
+                       /* only this one may be a partial USB Packet */
+                       u32 buffSz;
+
+                       buffSz = tx->transferSize - tx->currOffset;
+                       tx->currOffset = tx->transferSize;
+                       bd->bOffBLen = buffSz;
+
+                       bd->hOptions = CPPI_SOP_SET | CPPI_EOP_SET
+                               | CPPI_OWN_SET | buffSz;
+                       if (buffSz == 0)
+                               bd->hOptions |= CPPI_ZERO_SET;
+               }
+
+               DBG(5, "TXBD %p: nxt %08x buf %08x len %04x opt %08x\n",
+                               bd, bd->hNext, bd->buffPtr,
+                               bd->bOffBLen, bd->hOptions);
+
+               /* update the last BD enqueued to the list */
+               tx->activeQueueTail = bd;
+               bd = bd->next;
+       }
+
+       /* BDs live in DMA-coherent memory, but writes might be pending */
+       cpu_drain_writebuffer();
+
+       /* Write to the HeadPtr in StateRam to trigger */
+       txState->headPtr = (u32)tx->bdPoolHead->dma;
+
+       cppi_dump_tx(5, tx, "/S");
+}
+
+/*
+ * CPPI RX Woes:
+ * =============
+ * Consider a 1KB bulk RX buffer in two scenarios:  (a) it's fed two 300 byte
+ * packets back-to-back, and (b) it's fed two 512 byte packets back-to-back.
+ * (Full speed transfers have similar scenarios.)
+ *
+ * The correct behavior for Linux is that (a) fills the buffer with 300 bytes,
+ * and the next packet goes into a buffer that's queued later; while (b) fills
+ * the buffer with 1024 bytes.  How to do that with CPPI?
+ *
+ * - RX queues in "rndis" mode -- one single BD -- handle (a) correctly, but
+ *   (b) loses **BADLY** because nothing (!) happens when that second packet
+ *   fills the buffer, much less when a third one arrives.  (Which makes this
+ *   not a "true" RNDIS mode.  In the RNDIS protocol short-packet termination
+ *   is optional, and it's fine if peripherals -- not hosts! -- pad messages
+ *   out to end-of-buffer.  Standard PCI host controller DMA descriptors
+ *   implement that mode by default ... which is no accident.)
+ *
+ * - RX queues in "transparent" mode -- two BDs with 512 bytes each -- have
+ *   converse problems:  (b) is handled right, but (a) loses badly.  CPPI RX
+ *   ignores SOP/EOP markings and processes both of those BDs; so both packets
+ *   are loaded into the buffer (with a 212 byte gap between them), and the next
+ *   buffer queued will NOT get its 300 bytes of data. (It seems like SOP/EOP
+ *   are intended as outputs for RX queues, not inputs...)
+ *
+ * - A variant of "transparent" mode -- one BD at a time -- is the only way to
+ *   reliably make both cases work, with software handling both cases correctly
+ *   and at the significant penalty of needing an IRQ per packet.  (The lack of
+ *   I/O overlap can be slightly ameliorated by enabling double buffering.)
+ *
+ * So how to get rid of IRQ-per-packet?  The transparent multi-BD case could
+ * be used in special cases like mass storage, which sets URB_SHORT_NOT_OK
+ * (or maybe its peripheral side counterpart) to flag (a) scenarios as errors
+ * with guaranteed driver level fault recovery and scrubbing out what's left
+ * of that garbaged datastream.
+ *
+ * But there seems to be no way to identify the cases where CPPI RNDIS mode
+ * is appropriate -- which do NOT include RNDIS host drivers, but do include
+ * the CDC Ethernet driver! -- and the documentation is incomplete/wrong.
+ * So we can't _ever_ use RX RNDIS mode ... except by using a heuristic
+ * that applies best on the peripheral side (and which could fail rudely).
+ *
+ * Leaving only "transparent" mode; we avoid multi-bd modes in almost all
+ * cases other than mass storage class.  Otherwise we're correct but slow,
+ * since CPPI penalizes our need for a "true RNDIS" default mode.
+ */
+
+
+/* Heuristic, intended to kick in for ethernet/rndis peripheral ONLY
+ *
+ * IFF
+ *  (a)        peripheral mode ... since rndis peripherals could pad their
+ *     writes to hosts, causing i/o failure; or we'd have to cope with
+ *     a largely unknowable variety of host side protocol variants
+ *  (b)        and short reads are NOT errors ... since full reads would
+ *     cause those same i/o failures
+ *  (c)        and read length is
+ *     - less than 64KB (max per cppi descriptor)
+ *     - not a multiple of 4096 (g_zero default, full reads typical)
+ *     - N (>1) packets long, ditto (full reads not EXPECTED)
+ * THEN
+ *   try rx rndis mode
+ *
+ * Cost of heuristic failing:  RXDMA wedges at the end of transfers that
+ * fill out the whole buffer.  Buggy host side usb network drivers could
+ * trigger that, but "in the field" such bugs seem to be all but unknown.
+ *
+ * So this module parameter lets the heuristic be disabled.  When using
+ * gadgetfs, the heuristic will probably need to be disabled.
+ */
+static int cppi_rx_rndis = 1;
+
+module_param(cppi_rx_rndis, bool, 0);
+MODULE_PARM_DESC(cppi_rx_rndis, "enable/disable RX RNDIS heuristic");
+
+
+/**
+ * cppi_next_rx_segment - dma read for the next chunk of a buffer
+ * @musb: the controller
+ * @rx: dma channel
+ * @onepacket: true unless caller treats short reads as errors, and
+ *     performs fault recovery above usbcore.
+ * Context: controller irqlocked
+ *
+ * See above notes about why we can't use multi-BD RX queues except in
+ * rare cases (mass storage class), and can never use the hardware "rndis"
+ * mode (since it's not a "true" RNDIS mode) with complete safety..
+ *
+ * It's ESSENTIAL that callers specify "onepacket" mode unless they kick in
+ * code to recover from corrupted datastreams after each short transfer.
+ */
+static void
+cppi_next_rx_segment(struct musb *musb, struct cppi_channel *rx, int onepacket)
+{
+       unsigned                maxpacket = rx->pktSize;
+       dma_addr_t              addr = rx->startAddr + rx->currOffset;
+       size_t                  length = rx->transferSize - rx->currOffset;
+       struct cppi_descriptor  *bd, *tail;
+       unsigned                n_bds;
+       unsigned                i;
+       void                    *__iomem tibase = musb->ctrl_base;
+       int                     is_rndis = 0;
+
+       if (onepacket) {
+               /* almost every USB driver, host or peripheral side */
+               n_bds = 1;
+
+               /* maybe apply the heuristic above */
+               if (cppi_rx_rndis
+                               && is_peripheral_active(musb)
+                               && length > maxpacket
+                               && (length & ~0xffff) == 0
+                               && (length & 0x0fff) != 0
+                               && (length & (maxpacket - 1)) == 0) {
+                       maxpacket = length;
+                       is_rndis = 1;
+               }
+       } else {
+               /* virtually nothing except mass storage class */
+               if (length > 0xffff) {
+                       n_bds = 0xffff / maxpacket;
+                       length = n_bds * maxpacket;
+               } else {
+                       n_bds = length / maxpacket;
+                       if (length % maxpacket)
+                               n_bds++;
+               }
+               if (n_bds == 1)
+                       onepacket = 1;
+               else
+                       n_bds = min(n_bds, (unsigned) NUM_RXCHAN_BD);
+       }
+
+       /* In host mode, autorequest logic can generate some IN tokens; it's
+        * tricky since we can't leave REQPKT set in RXCSR after the transfer
+        * finishes. So:  multipacket transfers involve two or more segments.
+        * And always at least two IRQs ... RNDIS mode is not an option.
+        */
+       if (is_host_active(musb))
+               n_bds = cppi_autoreq_update(rx, tibase, onepacket, n_bds);
+
+       cppi_rndis_update(rx, 1, musb->ctrl_base, is_rndis);
+
+       length = min(n_bds * maxpacket, length);
+
+       DBG(4, "RX DMA%d seg, maxp %d %s bds %d (cnt %d) "
+                       "dma 0x%x len %u %u/%u\n",
+                       rx->chNo, maxpacket,
+                       onepacket
+                               ? (is_rndis ? "rndis" : "onepacket")
+                               : "multipacket",
+                       n_bds,
+                       musb_readl(tibase,
+                               DAVINCI_RXCPPI_BUFCNT0_REG + (rx->chNo * 4))
+                                       & 0xffff,
+                       addr, length, rx->actualLen, rx->transferSize);
+
+       /* only queue one segment at a time, since the hardware prevents
+        * correct queue shutdown after unexpected short packets
+        */
+       bd = cppi_bd_alloc(rx);
+       rx->activeQueueHead = bd;
+
+       /* Build BDs for all packets in this segment */
+       for (i = 0, tail = NULL; bd && i < n_bds; i++, tail = bd) {
+               u32     buffSz;
+
+               if (i) {
+                       bd = cppi_bd_alloc(rx);
+                       if (!bd)
+                               break;
+                       tail->next = bd;
+                       tail->hNext = bd->dma;
+               }
+               bd->hNext = 0;
+
+               /* all but the last packet will be maxpacket size */
+               if (maxpacket < length)
+                       buffSz = maxpacket;
+               else
+                       buffSz = length;
+
+               bd->buffPtr = addr;
+               addr += buffSz;
+               rx->currOffset += buffSz;
+
+               bd->bOffBLen = (0 /*offset*/ << 16) + buffSz;
+               bd->enqBuffLen = buffSz;
+
+               bd->hOptions = CPPI_OWN_SET | (i == 0 ? length : 0);
+               length -= buffSz;
+       }
+
+       /* we always expect at least one reusable BD! */
+       if (!tail) {
+               WARN("rx dma%d -- no BDs? need %d\n", rx->chNo, n_bds);
+               return;
+       } else if (i < n_bds)
+               WARN("rx dma%d -- only %d of %d BDs\n", rx->chNo, i, n_bds);
+
+       tail->next = NULL;
+       tail->hNext = 0;
+
+       bd = rx->activeQueueHead;
+       rx->activeQueueTail = tail;
+
+       /* short reads and other faults should terminate this entire
+        * dma segment.  we want one "dma packet" per dma segment, not
+        * one per USB packet, terminating the whole queue at once...
+        * NOTE that current hardware seems to ignore SOP and EOP.
+        */
+       bd->hOptions |= CPPI_SOP_SET;
+       tail->hOptions |= CPPI_EOP_SET;
+
+       if (debug >= 5) {
+               struct cppi_descriptor  *d;
+
+               for (d = rx->activeQueueHead; d; d = d->next)
+                       cppi_dump_rxbd("S", d);
+       }
+
+       /* in case the preceding transfer left some state... */
+       tail = rx->lastHwBDProcessed;
+       if (tail) {
+               tail->next = bd;
+               tail->hNext = bd->dma;
+       }
+
+       core_rxirq_enable(tibase, rx->chNo + 1);
+
+       /* BDs live in DMA-coherent memory, but writes might be pending */
+       cpu_drain_writebuffer();
+
+       /* REVISIT specs say to write this AFTER the BUFCNT register
+        * below ... but that loses badly.
+        */
+       musb_writel(rx->stateRam, 4, bd->dma);
+
+       /* bufferCount must be at least 3, and zeroes on completion
+        * unless it underflows below zero, or stops at two, or keeps
+        * growing ... grr.
+        */
+       i = musb_readl(tibase,
+                       DAVINCI_RXCPPI_BUFCNT0_REG + (rx->chNo * 4))
+                       & 0xffff;
+
+       if (!i)
+               musb_writel(tibase,
+                       DAVINCI_RXCPPI_BUFCNT0_REG + (rx->chNo * 4),
+                       n_bds + 2);
+       else if (n_bds > (i - 3))
+               musb_writel(tibase,
+                       DAVINCI_RXCPPI_BUFCNT0_REG + (rx->chNo * 4),
+                       n_bds - (i - 3));
+
+       i = musb_readl(tibase,
+                       DAVINCI_RXCPPI_BUFCNT0_REG + (rx->chNo * 4))
+                       & 0xffff;
+       if (i < (2 + n_bds)) {
+               DBG(2, "bufcnt%d underrun - %d (for %d)\n",
+                                       rx->chNo, i, n_bds);
+               musb_writel(tibase,
+                       DAVINCI_RXCPPI_BUFCNT0_REG + (rx->chNo * 4),
+                       n_bds + 2);
+       }
+
+       cppi_dump_rx(4, rx, "/S");
+}
+
+/**
+ * cppi_channel_program - program channel for data transfer
+ * @pChannel: the channel
+ * @wPacketSz: max packet size
+ * @mode: For RX, 1 unless the usb protocol driver promised to treat
+ *     all short reads as errors and kick in high level fault recovery.
+ *     For TX, ignored because of RNDIS mode races/glitches.
+ * @dma_addr: dma address of buffer
+ * @dwLength: length of buffer
+ * Context: controller irqlocked
+ */
+static int cppi_channel_program(struct dma_channel *pChannel,
+               u16 wPacketSz, u8 mode,
+               dma_addr_t dma_addr, u32 dwLength)
+{
+       struct cppi_channel     *otgChannel = pChannel->pPrivateData;
+       struct cppi             *pController = otgChannel->pController;
+       struct musb             *musb = pController->musb;
+
+       switch (pChannel->bStatus) {
+       case MGC_DMA_STATUS_BUS_ABORT:
+       case MGC_DMA_STATUS_CORE_ABORT:
+               /* fault irq handler should have handled cleanup */
+               WARN("%cX DMA%d not cleaned up after abort!\n",
+                               otgChannel->bTransmit ? 'T' : 'R',
+                               otgChannel->chNo);
+               //WARN_ON(1);
+               break;
+       case MGC_DMA_STATUS_BUSY:
+               WARN("program active channel?  %cX DMA%d\n",
+                               otgChannel->bTransmit ? 'T' : 'R',
+                               otgChannel->chNo);
+               //WARN_ON(1);
+               break;
+       case MGC_DMA_STATUS_UNKNOWN:
+               DBG(1, "%cX DMA%d not allocated!\n",
+                               otgChannel->bTransmit ? 'T' : 'R',
+                               otgChannel->chNo);
+               /* FALLTHROUGH */
+       case MGC_DMA_STATUS_FREE:
+               break;
+       }
+
+       pChannel->bStatus = MGC_DMA_STATUS_BUSY;
+
+       /* set transfer parameters, then queue up its first segment */
+       otgChannel->startAddr = dma_addr;
+       otgChannel->currOffset = 0;
+       otgChannel->pktSize = wPacketSz;
+       otgChannel->actualLen = 0;
+       otgChannel->transferSize = dwLength;
+
+       /* TX channel? or RX? */
+       if (otgChannel->bTransmit)
+               cppi_next_tx_segment(musb, otgChannel);
+       else
+               cppi_next_rx_segment(musb, otgChannel, mode);
+
+       return TRUE;
+}
+
+static int cppi_rx_scan(struct cppi *cppi, unsigned ch)
+{
+       struct cppi_channel             *rx = &cppi->rxCppi[ch];
+       struct cppi_rx_stateram         *state = rx->stateRam;
+       struct cppi_descriptor          *bd;
+       struct cppi_descriptor          *last = rx->lastHwBDProcessed;
+       int                             completed = 0, acked = 0;
+       int                             i;
+       dma_addr_t                      safe2ack;
+       void                            *__iomem regs = rx->pEndPt->regs;
+
+       cppi_dump_rx(6, rx, "/K");
+
+       bd = last ? last->next : rx->activeQueueHead;
+       if (!bd)
+               return 0;
+
+       /* run through all completed BDs */
+       for (i = 0, safe2ack = musb_readl(CAST &state->completionPtr, 0);
+                       (safe2ack || completed) && bd && i < NUM_RXCHAN_BD;
+                       i++, bd = bd->next) {
+               u16     len;
+
+               rmb();
+               if (!completed && (bd->hOptions & CPPI_OWN_SET))
+                       break;
+
+               DBG(5, "C/RXBD %08x: nxt %08x buf %08x "
+                       "off.len %08x opt.len %08x (%d)\n",
+                       bd->dma, bd->hNext, bd->buffPtr,
+                       bd->bOffBLen, bd->hOptions,
+                       rx->actualLen);
+
+               /* actual packet received length */
+               if ((bd->hOptions & CPPI_SOP_SET) && !completed)
+                       len = bd->bOffBLen & CPPI_RECV_PKTLEN_MASK;
+               else
+                       len = 0;
+
+               if (bd->hOptions & CPPI_EOQ_MASK)
+                       completed = 1;
+
+               if (!completed && len < bd->enqBuffLen) {
+                       /* NOTE:  when we get a short packet, RXCSR_H_REQPKT
+                        * must have been cleared, and no more DMA packets may
+                        * active be in the queue... TI docs didn't say, but
+                        * CPPI ignores those BDs even though OWN is still set.
+                        */
+                       completed = 1;
+                       DBG(3, "rx short %d/%d (%d)\n",
+                                       len, bd->enqBuffLen, rx->actualLen);
+               }
+
+               /* If we got here, we expect to ack at least one BD; meanwhile
+                * CPPI may completing other BDs while we scan this list...
+                *
+                * RACE: we can notice OWN cleared before CPPI raises the
+                * matching irq by writing that BD as the completion pointer.
+                * In such cases, stop scanning and wait for the irq, avoiding
+                * lost acks and states where BD ownership is unclear.
+                */
+               if (bd->dma == safe2ack) {
+                       musb_writel(CAST &state->completionPtr, 0, safe2ack);
+                       safe2ack = musb_readl(CAST &state->completionPtr, 0);
+                       acked = 1;
+                       if (bd->dma == safe2ack)
+                               safe2ack = 0;
+               }
+
+               rx->actualLen += len;
+
+               cppi_bd_free(rx, last);
+               last = bd;
+
+               /* stop scanning on end-of-segment */
+               if (bd->hNext == 0)
+                       completed = 1;
+       }
+       rx->lastHwBDProcessed = last;
+
+       /* dma abort, lost ack, or ... */
+       if (!acked && last) {
+               int     csr;
+
+               if (safe2ack == 0 || safe2ack == rx->lastHwBDProcessed->dma)
+                       musb_writel(CAST &state->completionPtr, 0, safe2ack);
+               if (safe2ack == 0) {
+                       cppi_bd_free(rx, last);
+                       rx->lastHwBDProcessed = NULL;
+
+                       /* if we land here on the host side, H_REQPKT will
+                        * be clear and we need to restart the queue...
+                        */
+                       WARN_ON(rx->activeQueueHead);
+               }
+               MGC_SelectEnd(cppi->pCoreBase, rx->chNo + 1);
+               csr = musb_readw(regs, MGC_O_HDRC_RXCSR);
+               if (csr & MGC_M_RXCSR_DMAENAB) {
+                       DBG(4, "list%d %p/%p, last %08x%s, csr %04x\n",
+                               rx->chNo,
+                               rx->activeQueueHead, rx->activeQueueTail,
+                               rx->lastHwBDProcessed
+                                       ? rx->lastHwBDProcessed->dma
+                                       : 0,
+                               completed ? ", completed" : "",
+                               csr);
+                       cppi_dump_rxq(4, "/what?", rx);
+               }
+       }
+       if (!completed) {
+               int     csr;
+
+               rx->activeQueueHead = bd;
+
+               /* REVISIT seems like "autoreq all but EOP" doesn't...
+                * setting it here "should" be racey, but seems to work
+                */
+               csr = musb_readw(rx->pEndPt->regs, MGC_O_HDRC_RXCSR);
+               if (is_host_active(cppi->musb)
+                               && bd
+                               && !(csr & MGC_M_RXCSR_H_REQPKT)) {
+                       csr |= MGC_M_RXCSR_H_REQPKT;
+                       musb_writew(regs, MGC_O_HDRC_RXCSR,
+                                       MGC_M_RXCSR_H_WZC_BITS | csr);
+                       csr = musb_readw(rx->pEndPt->regs, MGC_O_HDRC_RXCSR);
+               }
+       } else {
+               rx->activeQueueHead = NULL;
+               rx->activeQueueTail = NULL;
+       }
+
+       cppi_dump_rx(6, rx, completed ? "/completed" : "/cleaned");
+       return completed;
+}
+
+void cppi_completion(struct musb *pThis, u32 rx, u32 tx)
+{
+       void                    *__iomem regBase;
+       int                     i, chanNum, numCompleted;
+       u8                      bReqComplete;
+       struct cppi             *cppi;
+       struct cppi_descriptor  *bdPtr;
+       struct musb_hw_ep       *pEnd = NULL;
+
+       cppi = container_of(pThis->pDmaController, struct cppi, Controller);
+
+       regBase = pThis->ctrl_base;
+
+       chanNum = 0;
+       /* process TX channels */
+       for (chanNum = 0; tx; tx = tx >> 1, chanNum++) {
+               if (tx & 1) {
+                       struct cppi_channel             *txChannel;
+                       struct cppi_tx_stateram         *txState;
+
+                       txChannel = cppi->txCppi + chanNum;
+                       txState = txChannel->stateRam;
+
+                       /* FIXME  need a cppi_tx_scan() routine, which
+                        * can also be called from abort code
+                        */
+
+                       cppi_dump_tx(5, txChannel, "/E");
+
+                       bdPtr = txChannel->activeQueueHead;
+
+                       if (NULL == bdPtr) {
+                               DBG(1, "null BD\n");
+                               continue;
+                       }
+
+                       i = 0;
+                       bReqComplete = 0;
+
+                       numCompleted = 0;
+
+                       /* run through all completed BDs */
+                       for (i = 0;
+                                       !bReqComplete
+                                               && bdPtr
+                                               && i < NUM_TXCHAN_BD;
+                                       i++, bdPtr = bdPtr->next) {
+                               u16     len;
+
+                               rmb();
+                               if (bdPtr->hOptions & CPPI_OWN_SET)
+                                       break;
+
+                               DBG(5, "C/TXBD %p n %x b %x off %x opt %x\n",
+                                               bdPtr, bdPtr->hNext,
+                                               bdPtr->buffPtr,
+                                               bdPtr->bOffBLen,
+                                               bdPtr->hOptions);
+
+                               len = bdPtr->bOffBLen & CPPI_BUFFER_LEN_MASK;
+                               txChannel->actualLen += len;
+
+                               numCompleted++;
+                               txChannel->lastHwBDProcessed = bdPtr;
+
+                               /* write completion register to acknowledge
+                                * processing of completed BDs, and possibly
+                                * release the IRQ; EOQ might not be set ...
+                                *
+                                * REVISIT use the same ack strategy as rx
+                                *
+                                * REVISIT have observed bit 18 set; huh??
+                                */
+//                             if ((bdPtr->hOptions & CPPI_EOQ_MASK))
+                                       txState->completionPtr = bdPtr->dma;
+
+                               /* stop scanning on end-of-segment */
+                               if (bdPtr->hNext == 0)
+                                       bReqComplete = 1;
+                       }
+
+                       /* on end of segment, maybe go to next one */
+                       if (bReqComplete) {
+                               //cppi_dump_tx(4, txChannel, "/complete");
+
+                               /* transfer more, or report completion */
+                               if (txChannel->currOffset
+                                               >= txChannel->transferSize) {
+                                       txChannel->activeQueueHead = NULL;
+                                       txChannel->activeQueueTail = NULL;
+                                       txChannel->Channel.bStatus =
+                                                       MGC_DMA_STATUS_FREE;
+
+                                       pEnd = txChannel->pEndPt;
+
+                                       txChannel->Channel.dwActualLength =
+                                               txChannel->actualLen;
+
+                                       /* Peripheral role never repurposes the
+                                        * endpoint, so immediate completion is
+                                        * safe.  Host role waits for the fifo
+                                        * to empty (TXPKTRDY irq) before going
+                                        * to the next queued bulk transfer.
+                                        */
+                                       if (is_host_active(cppi->musb)) {
+#if 0
+                                               /* WORKAROUND because we may
+                                                * not always get TXKPTRDY ...
+                                                */
+                                               int     csr;
+
+                                               csr = musb_readw(pEnd->regs,
+                                                       MGC_O_HDRC_TXCSR);
+                                               if (csr & MGC_M_TXCSR_TXPKTRDY)
+#endif
+                                                       bReqComplete = 0;
+                                       }
+                                       if (bReqComplete)
+                                               musb_dma_completion(
+                                                       pThis, chanNum + 1, 1);
+
+                               } else {
+                                       /* Bigger transfer than we could fit in
+                                        * that first batch of descriptors...
+                                        */
+                                       cppi_next_tx_segment(pThis, txChannel);
+                               }
+                       } else
+                               txChannel->activeQueueHead = bdPtr;
+               }
+       }
+
+       /* Start processing the RX block */
+       for (chanNum = 0; rx; rx = rx >> 1, chanNum++) {
+
+               if (rx & 1) {
+                       struct cppi_channel             *rxChannel;
+
+                       rxChannel = cppi->rxCppi + chanNum;
+                       bReqComplete = cppi_rx_scan(cppi, chanNum);
+
+                       /* let incomplete dma segments finish */
+                       if (!bReqComplete)
+                               continue;
+
+                       /* start another dma segment if needed */
+                       if (rxChannel->actualLen != rxChannel->transferSize
+                                       && rxChannel->actualLen
+                                               == rxChannel->currOffset) {
+                               cppi_next_rx_segment(pThis, rxChannel, 1);
+                               continue;
+                       }
+
+                       /* all segments completed! */
+                       rxChannel->Channel.bStatus = MGC_DMA_STATUS_FREE;
+
+                       pEnd = rxChannel->pEndPt;
+
+                       rxChannel->Channel.dwActualLength =
+                                       rxChannel->actualLen;
+                       core_rxirq_disable(regBase, chanNum + 1);
+                       musb_dma_completion(pThis, chanNum + 1, 0);
+               }
+       }
+
+       /* write to CPPI EOI register to re-enable interrupts */
+       musb_writel(regBase, DAVINCI_CPPI_EOI_REG, 0);
+}
+
+/* Instantiate a software object representing a DMA controller. */
+struct dma_controller *__init
+dma_controller_create(struct musb *musb, void __iomem *pCoreBase)
+{
+       struct cppi             *pController;
+
+       pController = kzalloc(sizeof *pController, GFP_KERNEL);
+       if (!pController)
+               return NULL;
+
+       /* Initialize the Cppi DmaController  structure */
+       pController->pCoreBase = pCoreBase;
+       pController->musb = musb;
+       pController->Controller.pPrivateData = pController;
+       pController->Controller.start = cppi_controller_start;
+       pController->Controller.stop = cppi_controller_stop;
+       pController->Controller.channel_alloc = cppi_channel_allocate;
+       pController->Controller.channel_release = cppi_channel_release;
+       pController->Controller.channel_program = cppi_channel_program;
+       pController->Controller.channel_abort = cppi_channel_abort;
+
+       /* NOTE: allocating from on-chip SRAM would give the least
+        * contention for memory access, if that ever matters here.
+        */
+
+       /* setup BufferPool */
+       pController->pool = dma_pool_create("cppi",
+                       pController->musb->controller,
+                       sizeof(struct cppi_descriptor),
+                       CPPI_DESCRIPTOR_ALIGN, 0);
+       if (!pController->pool) {
+               kfree(pController);
+               return NULL;
+       }
+
+       return &pController->Controller;
+}
+
+/*
+ *  Destroy a previously-instantiated DMA controller.
+ */
+void dma_controller_destroy(struct dma_controller *c)
+{
+       struct cppi     *cppi;
+
+       cppi = container_of(c, struct cppi, Controller);
+
+       /* assert:  caller stopped the controller first */
+       dma_pool_destroy(cppi->pool);
+
+       kfree(cppi);
+}
+
+/*
+ * Context: controller irqlocked, endpoint selected
+ */
+static int cppi_channel_abort(struct dma_channel *channel)
+{
+       struct cppi_channel     *otgCh;
+       struct cppi             *pController;
+       int                     chNum;
+       void                    *__iomem mbase;
+       void                    *__iomem regBase;
+       void                    *__iomem regs;
+       u32                     regVal;
+       struct cppi_descriptor  *queue;
+
+       otgCh = container_of(channel, struct cppi_channel, Channel);
+
+       pController = otgCh->pController;
+       chNum = otgCh->chNo;
+
+       switch (channel->bStatus) {
+       case MGC_DMA_STATUS_BUS_ABORT:
+       case MGC_DMA_STATUS_CORE_ABORT:
+               /* from RX or TX fault irq handler */
+       case MGC_DMA_STATUS_BUSY:
+               /* the hardware needs shutting down */
+               regs = otgCh->pEndPt->regs;
+               break;
+       case MGC_DMA_STATUS_UNKNOWN:
+       case MGC_DMA_STATUS_FREE:
+               return 0;
+       default:
+               return -EINVAL;
+       }
+
+       if (!otgCh->bTransmit && otgCh->activeQueueHead)
+               cppi_dump_rxq(3, "/abort", otgCh);
+
+       mbase = pController->pCoreBase;
+       regBase = mbase - DAVINCI_BASE_OFFSET;
+
+       queue = otgCh->activeQueueHead;
+       otgCh->activeQueueHead = NULL;
+       otgCh->activeQueueTail = NULL;
+
+       /* REVISIT should rely on caller having done this,
+        * and caller should rely on us not changing it.
+        * peripheral code is safe ... check host too.
+        */
+       MGC_SelectEnd(mbase, chNum + 1);
+
+       if (otgCh->bTransmit) {
+               struct cppi_tx_stateram *__iomem txState;
+               int                     enabled;
+
+               /* mask interrupts raised to signal teardown complete.  */
+               enabled = musb_readl(regBase, DAVINCI_TXCPPI_INTENAB_REG)
+                               & (1 << otgCh->chNo);
+               if (enabled)
+                       musb_writel(regBase, DAVINCI_TXCPPI_INTCLR_REG,
+                                       (1 << otgCh->chNo));
+
+               // REVISIT put timeouts on these controller handshakes
+
+               cppi_dump_tx(6, otgCh, " (teardown)");
+
+               /* teardown DMA engine then usb core */
+               do {
+                       regVal = musb_readl(regBase, DAVINCI_TXCPPI_TEAR_REG);
+               } while (!(regVal & CPPI_TEAR_READY));
+               musb_writel(regBase, DAVINCI_TXCPPI_TEAR_REG, chNum);
+
+               txState = otgCh->stateRam;
+               do {
+                       regVal = txState->completionPtr;
+               } while (0xFFFFFFFC != regVal);
+               txState->completionPtr = 0xFFFFFFFC;
+
+               /* FIXME clean up the transfer state ... here?
+                * the completion routine should get called with
+                * an appropriate status code.
+                */
+
+               regVal = musb_readw(regs, MGC_O_HDRC_TXCSR);
+               regVal &= ~MGC_M_TXCSR_DMAENAB;
+               regVal |= MGC_M_TXCSR_FLUSHFIFO;
+               musb_writew(regs, MGC_O_HDRC_TXCSR, regVal);
+               musb_writew(regs, MGC_O_HDRC_TXCSR, regVal);
+
+               /* re-enable interrupt */
+               if (enabled)
+                       musb_writel(regBase, DAVINCI_TXCPPI_INTENAB_REG,
+                                       (1 << otgCh->chNo));
+
+               txState->headPtr = 0;
+               txState->sopDescPtr = 0;
+               txState->currBuffPtr = 0;
+               txState->currDescPtr = 0;
+               txState->flags = 0;
+               txState->remLength = 0;
+
+               /* Ensure that we clean up any Interrupt asserted
+                * 1. Write to completion Ptr value 0x1(bit 0 set)
+                *    (write back mode)
+                * 2. Write to completion Ptr value 0x0(bit 0 cleared)
+                *    (compare mode)
+                * Value written is compared(for bits 31:2) and being
+                * equal interrupt deasserted?
+                */
+
+               /* write back mode, bit 0 set, hence completion Ptr
+                * must be updated
+                */
+               txState->completionPtr = 0x1;
+               /* compare mode, write back zero now */
+               txState->completionPtr = 0;
+
+               cppi_dump_tx(5, otgCh, " (done teardown)");
+
+               /* REVISIT tx side _should_ clean up the same way
+                * as the RX side ... this does no cleanup at all!
+                */
+
+       } else /* RX */ {
+               u16                     csr;
+
+               /* NOTE: docs don't guarantee any of this works ...  we
+                * expect that if the usb core stops telling the cppi core
+                * to pull more data from it, then it'll be safe to flush
+                * current RX DMA state iff any pending fifo transfer is done.
+                */
+
+               core_rxirq_disable(regBase, otgCh->chNo + 1);
+
+               /* for host, ensure ReqPkt is never set again */
+               if (is_host_active(otgCh->pController->musb)) {
+                       regVal = musb_readl(regBase, DAVINCI_AUTOREQ_REG);
+                       regVal &= ~((0x3) << (otgCh->chNo * 2));
+                       musb_writel(regBase, DAVINCI_AUTOREQ_REG, regVal);
+               }
+
+               csr = musb_readw(regs, MGC_O_HDRC_RXCSR);
+
+               /* for host, clear (just) ReqPkt at end of current packet(s) */
+               if (is_host_active(otgCh->pController->musb)) {
+                       csr |= MGC_M_RXCSR_H_WZC_BITS;
+                       csr &= ~MGC_M_RXCSR_H_REQPKT;
+               } else
+                       csr |= MGC_M_RXCSR_P_WZC_BITS;
+
+               /* clear dma enable */
+               csr &= ~(MGC_M_RXCSR_DMAENAB);
+               musb_writew(regs, MGC_O_HDRC_RXCSR, csr);
+               csr = musb_readw(regs, MGC_O_HDRC_RXCSR);
+
+               /* quiesce: wait for current dma to finish (if not cleanup)
+                * we can't use bit zero of stateram->sopDescPtr since that
+                * refers to an entire "DMA packet" not just emptying the
+                * current fifo; most segments need multiple usb packets.
+                */
+               if (channel->bStatus == MGC_DMA_STATUS_BUSY)
+                       udelay(50);
+
+               /* scan the current list, reporting any data that was
+                * transferred and acking any IRQ
+                */
+               cppi_rx_scan(pController, chNum);
+
+               /* clobber the existing state once it's idle
+                *
+                * NOTE:  arguably, we should also wait for all the other
+                * RX channels to quiesce (how??) and then temporarily
+                * disable RXCPPI_CTRL_REG ... but it seems that we can
+                * rely on the controller restarting from state ram, with
+                * only RXCPPI_BUFCNT state being bogus.  BUFCNT will
+                * correct itself after the next DMA transfer though.
+                *
+                * REVISIT does using rndis mode change that?
+                */
+               cppi_reset_rx(otgCh->stateRam);
+
+               /* next DMA request _should_ load cppi head ptr */
+
+               /* ... we don't "free" that list, only mutate it in place.  */
+               cppi_dump_rx(5, otgCh, " (done abort)");
+
+               /* clean up previously pending bds */
+               cppi_bd_free(otgCh, otgCh->lastHwBDProcessed);
+               otgCh->lastHwBDProcessed = NULL;
+
+               while (queue) {
+                       struct cppi_descriptor  *tmp = queue->next;
+                       cppi_bd_free(otgCh, queue);
+                       queue = tmp;
+               }
+       }
+
+       channel->bStatus = MGC_DMA_STATUS_FREE;
+       otgCh->startAddr = 0;
+       otgCh->currOffset = 0;
+       otgCh->transferSize = 0;
+       otgCh->pktSize = 0;
+       return 0;
+}
+
+/* TBD Queries:
+ *
+ * Power Management ... probably turn off cppi during suspend, restart;
+ * check state ram?  Clocking is presumably shared with usb core.
+ */
diff --git a/drivers/usb/musb/cppi_dma.h b/drivers/usb/musb/cppi_dma.h
new file mode 100644 (file)
index 0000000..21e1cbe
--- /dev/null
@@ -0,0 +1,118 @@
+/* Copyright (C) 2005-2006 by Texas Instruments */
+
+#ifndef _CPPI_DMA_H_
+#define _CPPI_DMA_H_
+
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/dmapool.h>
+
+#include "dma.h"
+#include "musbdefs.h"
+#include "davinci.h"
+
+
+/* hOptions bit masks for CPPI BDs */
+#define CPPI_SOP_SET   ((u32)(1 << 31))
+#define CPPI_EOP_SET   ((u32)(1 << 30))
+#define CPPI_OWN_SET   ((u32)(1 << 29))        /* owned by cppi */
+#define CPPI_EOQ_MASK  ((u32)(1 << 28))
+#define CPPI_ZERO_SET  ((u32)(1 << 23))        /* rx saw zlp; tx issues one */
+#define CPPI_RXABT_MASK        ((u32)(1 << 19))        /* need more rx buffers */
+
+#define CPPI_RECV_PKTLEN_MASK 0xFFFF
+#define CPPI_BUFFER_LEN_MASK 0xFFFF
+
+#define CPPI_TEAR_READY ((u32)(1 << 31))
+
+/* CPPI data structure definitions */
+
+#define        CPPI_DESCRIPTOR_ALIGN   16      // bytes; 5-dec docs say 4-byte align
+
+struct cppi_descriptor {
+       /* Hardware Overlay */
+       u32 hNext;     /**< Next(hardware) Buffer Descriptor Pointer */
+       u32 buffPtr;       /**<Buffer Pointer (dma_addr_t) */
+       u32 bOffBLen;       /**<Buffer_offset16,buffer_length16 */
+       u32 hOptions;       /**<Option fields for SOP,EOP etc*/
+
+       struct cppi_descriptor *next;
+       dma_addr_t dma;         /* address of this descriptor */
+
+       /* for Rx Desc, track original Buffer len to detect short packets */
+       u32 enqBuffLen;
+} __attribute__ ((aligned(CPPI_DESCRIPTOR_ALIGN)));
+
+
+/* forward declaration for CppiDmaController structure */
+struct cppi;
+
+/**
+ *  Channel Control Structure
+ *
+ * CPPI  Channel Control structure. Using he same for Tx/Rx. If need be
+ * derive out of this later.
+ */
+struct cppi_channel {
+       /* First field must be dma_channel for easy type casting
+        * FIXME just use container_of() and be typesafe instead!
+        */
+       struct dma_channel Channel;
+
+       /* back pointer to the Dma Controller structure */
+       struct cppi             *pController;
+
+       /* which direction of which endpoint? */
+       struct musb_hw_ep       *pEndPt;
+       u8                      bTransmit;
+       u8                      chNo;
+
+       /* DMA modes:  RNDIS or "transparent" */
+       u8                      bLastModeRndis;
+
+       /* book keeping for current transfer request */
+       dma_addr_t              startAddr;
+       u32                     transferSize;
+       u32                     pktSize;
+       u32                     currOffset;     /* requested segments */
+       u32                     actualLen;      /* completed (Channel.actual) */
+
+       void __iomem            *stateRam;      /* CPPI state */
+
+       /* BD management fields */
+       struct cppi_descriptor  *bdPoolHead;
+       struct cppi_descriptor  *activeQueueHead;
+       struct cppi_descriptor  *activeQueueTail;
+       struct cppi_descriptor  *lastHwBDProcessed;
+
+       /* use tx_complete in host role to track endpoints waiting for
+        * FIFONOTEMPTY to clear.
+        */
+       struct list_head        tx_complete;
+};
+
+/**
+ *  CPPI Dma Controller Object
+ *
+ *  CPPI Dma controller object.Encapsulates all bookeeping and Data
+ *  structures pertaining to the CPPI Dma Controller.
+ */
+struct cppi {
+       struct dma_controller           Controller;
+       struct musb                     *musb;
+       void __iomem                    *pCoreBase;
+
+       struct cppi_channel             txCppi[MUSB_C_NUM_EPT - 1];
+       struct cppi_channel             rxCppi[MUSB_C_NUM_EPR - 1];
+
+       struct dma_pool                 *pool;
+
+       struct list_head                tx_complete;
+};
+
+/* irq handling hook */
+extern void cppi_completion(struct musb *, u32 rx, u32 tx);
+
+#endif                         /* end of ifndef _CPPI_DMA_H_ */
diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c
new file mode 100644 (file)
index 0000000..385640b
--- /dev/null
@@ -0,0 +1,461 @@
+/*
+ * Copyright (C) 2005-2006 by Texas Instruments
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * The Inventra Controller Driver for Linux is free software; you
+ * can redistribute it and/or modify it under the terms of the GNU
+ * General Public License version 2 as published by the Free Software
+ * Foundation.
+ *
+ * The Inventra Controller Driver for Linux is distributed in
+ * the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Inventra Controller Driver for Linux ; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/memory.h>
+#include <asm/arch/gpio.h>
+#include <asm/mach-types.h>
+
+#include "musbdefs.h"
+
+
+#ifdef CONFIG_MACH_DAVINCI_EVM
+#include <asm/arch/i2c-client.h>
+#endif
+
+#include "davinci.h"
+#include "cppi_dma.h"
+
+
+/* REVISIT (PM) we should be able to keep the PHY in low power mode most
+ * of the time (24 MHZ oscillator and PLL off, etc) by setting POWER.D0
+ * and, when in host mode, autosuspending idle root ports... PHYPLLON
+ * (overriding SUSPENDM?) then likely needs to stay off.
+ */
+
+static inline void phy_on(void)
+{
+       /* start the on-chip PHY and its PLL */
+       __raw_writel(USBPHY_SESNDEN | USBPHY_VBDTCTEN | USBPHY_PHYPLLON,
+                       IO_ADDRESS(USBPHY_CTL_PADDR));
+       while ((__raw_readl(IO_ADDRESS(USBPHY_CTL_PADDR))
+                       & USBPHY_PHYCLKGD) == 0)
+               cpu_relax();
+}
+
+static inline void phy_off(void)
+{
+       /* powerdown the on-chip PHY and its oscillator */
+       __raw_writel(USBPHY_OSCPDWN | USBPHY_PHYPDWN,
+                       IO_ADDRESS(USBPHY_CTL_PADDR));
+}
+
+static int dma_off = 1;
+
+void musb_platform_enable(struct musb *musb)
+{
+       u32     tmp, old, val;
+
+       /* workaround:  setup irqs through both register sets */
+       tmp = (musb->wEndMask & DAVINCI_USB_TX_ENDPTS_MASK)
+                       << DAVINCI_USB_TXINT_SHIFT;
+       musb_writel(musb->ctrl_base, DAVINCI_USB_INT_MASK_SET_REG, tmp);
+       old = tmp;
+       tmp = (musb->wEndMask & (0xfffe & DAVINCI_USB_RX_ENDPTS_MASK))
+                       << DAVINCI_USB_RXINT_SHIFT;
+       musb_writel(musb->ctrl_base, DAVINCI_USB_INT_MASK_SET_REG, tmp);
+       tmp |= old;
+
+       val = ~MGC_M_INTR_SOF;
+       tmp |= ((val & 0x01ff) << DAVINCI_USB_USBINT_SHIFT);
+       musb_writel(musb->ctrl_base, DAVINCI_USB_INT_MASK_SET_REG, tmp);
+
+       if (is_dma_capable() && !dma_off)
+               printk(KERN_WARNING "%s %s: dma not reactivated\n",
+                               __FILE__, __FUNCTION__);
+       else
+               dma_off = 0;
+
+       /* force a DRVVBUS irq so we can start polling for ID change */
+       if (is_otg_enabled(musb))
+               musb_writel(musb->ctrl_base, DAVINCI_USB_INT_SET_REG,
+                       DAVINCI_INTR_DRVVBUS << DAVINCI_USB_USBINT_SHIFT);
+}
+
+/*
+ * Disable the HDRC and flush interrupts
+ */
+void musb_platform_disable(struct musb *musb)
+{
+       /* because we don't set CTRLR.UINT, "important" to:
+        *  - not read/write INTRUSB/INTRUSBE
+        *  - (except during initial setup, as workaround)
+        *  - use INTSETR/INTCLRR instead
+        */
+       musb_writel(musb->ctrl_base, DAVINCI_USB_INT_MASK_CLR_REG,
+                         DAVINCI_USB_USBINT_MASK
+                       | DAVINCI_USB_TXINT_MASK
+                       | DAVINCI_USB_RXINT_MASK);
+       musb_writeb(musb->pRegs, MGC_O_HDRC_DEVCTL, 0);
+       musb_writel(musb->ctrl_base, DAVINCI_USB_EOI_REG, 0);
+
+       if (is_dma_capable() && !dma_off)
+               WARN("dma still active\n");
+}
+
+
+/* REVISIT it's not clear whether DaVinci can support full OTG.  */
+
+static int vbus_state = -1;
+
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+#define        portstate(stmt)         stmt
+#else
+#define        portstate(stmt)
+#endif
+
+
+/* VBUS SWITCHING IS BOARD-SPECIFIC */
+
+#ifdef CONFIG_MACH_DAVINCI_EVM
+#ifndef CONFIG_MACH_DAVINCI_EVM_OTG
+
+/* I2C operations are always synchronous, and require a task context.
+ * With unloaded systems, using the shared workqueue seems to suffice
+ * to satisfy the 100msec A_WAIT_VRISE timeout...
+ */
+static void evm_deferred_drvvbus(struct work_struct *ignored)
+{
+       davinci_i2c_expander_op(0x3a, USB_DRVVBUS, vbus_state);
+       vbus_state = !vbus_state;
+}
+DECLARE_WORK(evm_vbus_work, evm_deferred_drvvbus);
+
+#endif /* modified board */
+#endif /* EVM */
+
+static void davinci_source_power(struct musb *musb, int is_on, int immediate)
+{
+       if (is_on)
+               is_on = 1;
+
+       if (vbus_state == is_on)
+               return;
+       vbus_state = !is_on;            /* 0/1 vs "-1 == unknown/init" */
+
+#ifdef CONFIG_MACH_DAVINCI_EVM
+       if (machine_is_davinci_evm()) {
+#ifdef CONFIG_MACH_DAVINCI_EVM_OTG
+               /* modified EVM board switching VBUS with GPIO(6) not I2C
+                * NOTE:  PINMUX0.RGB888 (bit23) must be clear
+                */
+               if (is_on)
+                       gpio_set(GPIO(6));
+               else
+                       gpio_clear(GPIO(6));
+               immediate = 1;
+#else
+               if (immediate)
+                       davinci_i2c_expander_op(0x3a, USB_DRVVBUS, !is_on);
+               else
+                       schedule_work(&evm_vbus_work);
+#endif
+       }
+#endif
+       if (immediate)
+               vbus_state = is_on;
+}
+
+static void davinci_set_vbus(struct musb *musb, int is_on)
+{
+       WARN_ON(is_on && is_peripheral_active(musb));
+       return davinci_source_power(musb, is_on, 0);
+}
+
+
+#define        POLL_SECONDS    2
+
+static struct timer_list otg_workaround;
+
+static void otg_timer(unsigned long _musb)
+{
+       struct musb             *musb = (void *)_musb;
+       void    *__iomem        mregs = musb->pRegs;
+       u8                      devctl;
+       unsigned long           flags;
+
+       /* We poll because DaVinci's won't expose several OTG-critical
+       * status change events (from the transceiver) otherwise.
+        */
+       devctl = musb_readb(mregs, MGC_O_HDRC_DEVCTL);
+       DBG(7, "poll devctl %02x (%s)\n", devctl, otg_state_string(musb));
+
+       spin_lock_irqsave(&musb->Lock, flags);
+       switch (musb->xceiv.state) {
+       case OTG_STATE_A_WAIT_VFALL:
+               /* Wait till VBUS falls below SessionEnd (~0.2V); the 1.3 RTL
+                * seems to mis-handle session "start" otherwise (or in our
+                * case "recover"), in routine "VBUS was valid by the time
+                * VBUSERR got reported during enumeration" cases.
+                */
+               if (devctl & MGC_M_DEVCTL_VBUS) {
+                       mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
+                       break;
+               }
+               musb->xceiv.state = OTG_STATE_A_WAIT_VRISE;
+               musb_writel(musb->ctrl_base, DAVINCI_USB_INT_SET_REG,
+                       MGC_M_INTR_VBUSERROR << DAVINCI_USB_USBINT_SHIFT);
+               break;
+       case OTG_STATE_B_IDLE:
+               if (!is_peripheral_enabled(musb))
+                       break;
+
+               /* There's no ID-changed IRQ, so we have no good way to tell
+                * when to switch to the A-Default state machine (by setting
+                * the DEVCTL.SESSION flag).
+                *
+                * Workaround:  whenever we're in B_IDLE, try setting the
+                * session flag every few seconds.  If it works, ID was
+                * grounded and we're now in the A-Default state machine.
+                *
+                * NOTE setting the session flag is _supposed_ to trigger
+                * SRP, but clearly it doesn't.
+                */
+               musb_writeb(mregs, MGC_O_HDRC_DEVCTL,
+                               devctl | MGC_M_DEVCTL_SESSION);
+               devctl = musb_readb(mregs, MGC_O_HDRC_DEVCTL);
+               if (devctl & MGC_M_DEVCTL_BDEVICE)
+                       mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
+               else
+                       musb->xceiv.state = OTG_STATE_A_IDLE;
+               break;
+       default:
+               break;
+       }
+       spin_unlock_irqrestore(&musb->Lock, flags);
+}
+
+static irqreturn_t davinci_interrupt(int irq, void *__hci)
+{
+       unsigned long   flags;
+       irqreturn_t     retval = IRQ_NONE;
+       struct musb     *musb = __hci;
+       void            *__iomem tibase = musb->ctrl_base;
+       u32             tmp;
+
+       spin_lock_irqsave(&musb->Lock, flags);
+
+       /* NOTE: DaVinci shadows the Mentor IRQs.  Don't manage them through
+        * the Mentor registers (except for setup), use the TI ones and EOI.
+        *
+        * Docs describe irq "vector" registers asociated with the CPPI and
+        * USB EOI registers.  These hold a bitmask corresponding to the
+        * current IRQ, not an irq handler address.  Would using those bits
+        * resolve some of the races observed in this dispatch code??
+        */
+
+       /* CPPI interrupts share the same IRQ line, but have their own
+        * mask, state, "vector", and EOI registers.
+        */
+       if (is_cppi_enabled()) {
+               u32 cppi_tx = musb_readl(tibase, DAVINCI_TXCPPI_MASKED_REG);
+               u32 cppi_rx = musb_readl(tibase, DAVINCI_RXCPPI_MASKED_REG);
+
+               if (cppi_tx || cppi_rx) {
+                       DBG(4, "CPPI IRQ t%x r%x\n", cppi_tx, cppi_rx);
+                       cppi_completion(musb, cppi_rx, cppi_tx);
+                       retval = IRQ_HANDLED;
+               }
+       }
+
+       /* ack and handle non-CPPI interrupts */
+       tmp = musb_readl(tibase, DAVINCI_USB_INT_SRC_MASKED_REG);
+       musb_writel(tibase, DAVINCI_USB_INT_SRC_CLR_REG, tmp);
+       DBG(4, "IRQ %08x\n", tmp);
+
+       musb->int_rx = (tmp & DAVINCI_USB_RXINT_MASK)
+                       >> DAVINCI_USB_RXINT_SHIFT;
+       musb->int_tx = (tmp & DAVINCI_USB_TXINT_MASK)
+                       >> DAVINCI_USB_TXINT_SHIFT;
+       musb->int_usb = (tmp & DAVINCI_USB_USBINT_MASK)
+                       >> DAVINCI_USB_USBINT_SHIFT;
+
+       /* DRVVBUS irqs are the only proxy we have (a very poor one!) for
+        * DaVinci's missing ID change IRQ.  We need an ID change IRQ to
+        * switch appropriately between halves of the OTG state machine.
+        * Managing DEVCTL.SESSION per Mentor docs requires we know its
+        * value, but DEVCTL.BDEVICE is invalid without DEVCTL.SESSION set.
+        * Also, DRVVBUS pulses for SRP (but not at 5V) ...
+        */
+       if (tmp & (DAVINCI_INTR_DRVVBUS << DAVINCI_USB_USBINT_SHIFT)) {
+               int     drvvbus = musb_readl(tibase, DAVINCI_USB_STAT_REG);
+               void    *__iomem mregs = musb->pRegs;
+               u8      devctl = musb_readb(mregs, MGC_O_HDRC_DEVCTL);
+               int     err = musb->int_usb & MGC_M_INTR_VBUSERROR;
+
+               err = is_host_enabled(musb)
+                               && (musb->int_usb & MGC_M_INTR_VBUSERROR);
+               if (err) {
+                       /* The Mentor core doesn't debounce VBUS as needed
+                        * to cope with device connect current spikes. This
+                        * means it's not uncommon for bus-powered devices
+                        * to get VBUS errors during enumeration.
+                        *
+                        * This is a workaround, but newer RTL from Mentor
+                        * seems to lalow a better one: "re"starting sessions
+                        * without waiting (on EVM, a **long** time) for VBUS
+                        * to stop registering in devctl.
+                        */
+                       musb->int_usb &= ~MGC_M_INTR_VBUSERROR;
+                       musb->xceiv.state = OTG_STATE_A_WAIT_VFALL;
+                       mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
+                       WARN("VBUS error workaround (delay coming)\n");
+               } else if (is_host_enabled(musb) && drvvbus) {
+                       musb->is_active = 1;
+                       MUSB_HST_MODE(musb);
+                       musb->xceiv.default_a = 1;
+                       musb->xceiv.state = OTG_STATE_A_WAIT_VRISE;
+                       portstate(musb->port1_status |= USB_PORT_STAT_POWER);
+                       del_timer(&otg_workaround);
+               } else {
+                       musb->is_active = 0;
+                       MUSB_DEV_MODE(musb);
+                       musb->xceiv.default_a = 0;
+                       musb->xceiv.state = OTG_STATE_B_IDLE;
+                       portstate(musb->port1_status &= ~USB_PORT_STAT_POWER);
+               }
+
+               /* NOTE:  this must complete poweron within 100 msec */
+               davinci_source_power(musb, drvvbus, 0);
+               DBG(2, "VBUS %s (%s)%s, devctl %02x\n",
+                               drvvbus ? "on" : "off",
+                               otg_state_string(musb),
+                               err ? " ERROR" : "",
+                               devctl);
+               retval = IRQ_HANDLED;
+       }
+
+       if (musb->int_tx || musb->int_rx || musb->int_usb)
+               retval |= musb_interrupt(musb);
+
+       /* irq stays asserted until EOI is written */
+       musb_writel(tibase, DAVINCI_USB_EOI_REG, 0);
+
+       /* poll for ID change */
+       if (is_otg_enabled(musb)
+                       && musb->xceiv.state == OTG_STATE_B_IDLE)
+               mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
+
+       spin_unlock_irqrestore(&musb->Lock, flags);
+
+       /* REVISIT we sometimes get unhandled IRQs
+        * (e.g. ep0).  not clear why...
+        */
+       if (retval != IRQ_HANDLED)
+               DBG(5, "unhandled? %08x\n", tmp);
+       return IRQ_HANDLED;
+}
+
+int __init musb_platform_init(struct musb *musb)
+{
+       void    *__iomem tibase = musb->ctrl_base;
+       u32     revision;
+
+       musb->pRegs += DAVINCI_BASE_OFFSET;
+#if 0
+       /* REVISIT there's something odd about clocking, this
+        * didn't appear do the job ...
+        */
+       musb->clock = clk_get(pDevice, "usb");
+       if (IS_ERR(musb->clock))
+               return PTR_ERR(musb->clock);
+
+       status = clk_enable(musb->clock);
+       if (status < 0)
+               return -ENODEV;
+#endif
+
+       /* returns zero if e.g. not clocked */
+       revision = musb_readl(tibase, DAVINCI_USB_VERSION_REG);
+       if (revision == 0)
+               return -ENODEV;
+
+       if (is_host_enabled(musb))
+               setup_timer(&otg_workaround, otg_timer, (unsigned long) musb);
+
+       musb->board_set_vbus = davinci_set_vbus;
+       davinci_source_power(musb, 0, 1);
+
+       /* reset the controller */
+       musb_writel(tibase, DAVINCI_USB_CTRL_REG, 0x1);
+
+       /* start the on-chip PHY and its PLL */
+       phy_on();
+
+       msleep(5);
+
+       /* NOTE:  irqs are in mixed mode, not bypass to pure-musb */
+       pr_debug("DaVinci OTG revision %08x phy %03x control %02x\n",
+               revision,
+               __raw_readl((void *__iomem) IO_ADDRESS(USBPHY_CTL_PADDR)),
+               musb_readb(tibase, DAVINCI_USB_CTRL_REG));
+
+       musb->isr = davinci_interrupt;
+       return 0;
+}
+
+int musb_platform_exit(struct musb *musb)
+{
+       if (is_host_enabled(musb))
+               del_timer_sync(&otg_workaround);
+
+       davinci_source_power(musb, 0 /*off*/, 1);
+
+       /* delay, to avoid problems with module reload */
+       if (is_host_enabled(musb) && musb->xceiv.default_a) {
+               int     maxdelay = 30;
+               u8      devctl, warn = 0;
+
+               /* if there's no peripheral connected, this can take a
+                * long time to fall, especially on EVM with huge C133.
+                */
+               do {
+                       devctl = musb_readb(musb->pRegs, MGC_O_HDRC_DEVCTL);
+                       if (!(devctl & MGC_M_DEVCTL_VBUS))
+                               break;
+                       if ((devctl & MGC_M_DEVCTL_VBUS) != warn) {
+                               warn = devctl & MGC_M_DEVCTL_VBUS;
+                               DBG(1, "VBUS %d\n", warn >> MGC_S_DEVCTL_VBUS);
+                       }
+                       msleep(1000);
+                       maxdelay--;
+               } while (maxdelay > 0);
+
+               /* in OTG mode, another host might be connected */
+               if (devctl & MGC_M_DEVCTL_VBUS)
+                       DBG(1, "VBUS off timeout (devctl %02x)\n", devctl);
+       }
+
+       phy_off();
+       return 0;
+}
diff --git a/drivers/usb/musb/davinci.h b/drivers/usb/musb/davinci.h
new file mode 100644 (file)
index 0000000..b5910ed
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2005-2006 by Texas Instruments
+ *
+ * The Inventra Controller Driver for Linux is free software; you
+ * can redistribute it and/or modify it under the terms of the GNU
+ * General Public License version 2 as published by the Free Software
+ * Foundation.
+ */
+
+#ifndef __MUSB_HDRDF_H__
+#define __MUSB_HDRDF_H__
+
+/*
+ * DaVinci-specific definitions
+ */
+
+/* Integrated highspeed/otg PHY */
+#define        USBPHY_CTL_PADDR        (DAVINCI_SYSTEM_MODULE_BASE + 0x34)
+#define        USBPHY_PHYCLKGD         (1 << 8)
+#define        USBPHY_SESNDEN          (1 << 7)        /* v(sess_end) comparator */
+#define        USBPHY_VBDTCTEN         (1 << 6)        /* v(bus) comparator */
+#define        USBPHY_PHYPLLON         (1 << 4)        /* override pll suspend */
+#define        USBPHY_CLKO1SEL         (1 << 3)
+#define        USBPHY_OSCPDWN          (1 << 2)
+#define        USBPHY_PHYPDWN          (1 << 0)
+
+/* For now include usb OTG module registers here */
+#define DAVINCI_USB_VERSION_REG                0x00
+#define DAVINCI_USB_CTRL_REG           0x04
+#define DAVINCI_USB_STAT_REG           0x08
+#define DAVINCI_RNDIS_REG              0x10
+#define DAVINCI_AUTOREQ_REG            0x14
+#define DAVINCI_USB_INT_SOURCE_REG     0x20
+#define DAVINCI_USB_INT_SET_REG                0x24
+#define DAVINCI_USB_INT_SRC_CLR_REG    0x28
+#define DAVINCI_USB_INT_MASK_REG       0x2c
+#define DAVINCI_USB_INT_MASK_SET_REG   0x30
+#define DAVINCI_USB_INT_MASK_CLR_REG   0x34
+#define DAVINCI_USB_INT_SRC_MASKED_REG 0x38
+#define DAVINCI_USB_EOI_REG            0x3c
+#define DAVINCI_USB_EOI_INTVEC         0x40
+
+/* CPPI related registers */
+#define DAVINCI_TXCPPI_CTRL_REG                0x80
+#define DAVINCI_TXCPPI_TEAR_REG                0x84
+#define DAVINCI_CPPI_EOI_REG           0x88
+#define DAVINCI_CPPI_INTVEC_REG                0x8c
+#define DAVINCI_TXCPPI_MASKED_REG      0x90
+#define DAVINCI_TXCPPI_RAW_REG         0x94
+#define DAVINCI_TXCPPI_INTENAB_REG     0x98
+#define DAVINCI_TXCPPI_INTCLR_REG      0x9c
+
+#define DAVINCI_RXCPPI_CTRL_REG                0xC0
+#define DAVINCI_RXCPPI_MASKED_REG      0xD0
+#define DAVINCI_RXCPPI_RAW_REG         0xD4
+#define DAVINCI_RXCPPI_INTENAB_REG     0xD8
+#define DAVINCI_RXCPPI_INTCLR_REG      0xDC
+
+#define DAVINCI_RXCPPI_BUFCNT0_REG     0xE0
+#define DAVINCI_RXCPPI_BUFCNT1_REG     0xE4
+#define DAVINCI_RXCPPI_BUFCNT2_REG     0xE8
+#define DAVINCI_RXCPPI_BUFCNT3_REG     0xEC
+
+/* CPPI state RAM entries */
+#define DAVINCI_CPPI_STATERAM_BASE_OFFSET   0x100
+
+#define DAVINCI_TXCPPI_STATERAM_OFFSET(channelNum) \
+       (DAVINCI_CPPI_STATERAM_BASE_OFFSET +       ((channelNum)* 0x40))
+#define DAVINCI_RXCPPI_STATERAM_OFFSET(channelNum) \
+       (DAVINCI_CPPI_STATERAM_BASE_OFFSET + 0x20 +((channelNum)* 0x40))
+
+/* CPPI masks */
+#define DAVINCI_DMA_CTRL_ENABLE                1
+#define DAVINCI_DMA_CTRL_DISABLE       0
+
+#define DAVINCI_DMA_ALL_CHANNELS_ENABLE        0xF
+#define DAVINCI_DMA_ALL_CHANNELS_DISABLE 0xF
+
+/* REVISIT relying on "volatile" here is wrong ... */
+
+/* define structures of Rx/Tx stateRam entries */
+struct cppi_tx_stateram {
+       volatile u32 headPtr;
+       volatile u32 sopDescPtr;
+       volatile u32 currDescPtr;
+       volatile u32 currBuffPtr;
+       volatile u32 flags;
+       volatile u32 remLength;
+       volatile u32 dummy;
+       volatile u32 completionPtr;
+};
+
+struct cppi_rx_stateram {
+       volatile u32 buffOffset;
+       volatile u32 headPtr;
+       volatile u32 sopDescPtr;
+       volatile u32 currDescPtr;
+       volatile u32 currBuffPtr;
+       volatile u32 pktLength;
+       volatile u32 byteCount;
+       volatile u32 completionPtr;
+};
+
+#define DAVINCI_USB_TX_ENDPTS_MASK     0x1f            /* ep0 + 4 tx */
+#define DAVINCI_USB_RX_ENDPTS_MASK     0x1e            /* 4 rx */
+
+#define DAVINCI_USB_USBINT_SHIFT       16
+#define DAVINCI_USB_TXINT_SHIFT                0
+#define DAVINCI_USB_RXINT_SHIFT                8
+
+#define DAVINCI_INTR_DRVVBUS           0x0100
+
+#define DAVINCI_USB_USBINT_MASK                0x01ff0000      /* 8 Mentor, DRVVBUS */
+#define DAVINCI_USB_TXINT_MASK \
+       (DAVINCI_USB_TX_ENDPTS_MASK << DAVINCI_USB_TXINT_SHIFT)
+#define DAVINCI_USB_RXINT_MASK \
+       (DAVINCI_USB_RX_ENDPTS_MASK << DAVINCI_USB_RXINT_SHIFT)
+
+#define DAVINCI_BASE_OFFSET            0x400
+
+#endif /* __MUSB_HDRDF_H__ */
diff --git a/drivers/usb/musb/debug.h b/drivers/usb/musb/debug.h
new file mode 100644 (file)
index 0000000..ef0c4a7
--- /dev/null
@@ -0,0 +1,65 @@
+/******************************************************************
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * The Inventra Controller Driver for Linux is free software; you
+ * can redistribute it and/or modify it under the terms of the GNU
+ * General Public License version 2 as published by the Free Software
+ * Foundation.
+ *
+ * The Inventra Controller Driver for Linux is distributed in
+ * the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Inventra Controller Driver for Linux ; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ANY DOWNLOAD, USE, REPRODUCTION, MODIFICATION OR DISTRIBUTION
+ * OF THIS DRIVER INDICATES YOUR COMPLETE AND UNCONDITIONAL ACCEPTANCE
+ * OF THOSE TERMS.THIS DRIVER IS PROVIDED "AS IS" AND MENTOR GRAPHICS
+ * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, RELATED TO THIS DRIVER.
+ * MENTOR GRAPHICS SPECIFICALLY DISCLAIMS ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY; FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT.  MENTOR GRAPHICS DOES NOT PROVIDE SUPPORT
+ * SERVICES OR UPDATES FOR THIS DRIVER, EVEN IF YOU ARE A MENTOR
+ * GRAPHICS SUPPORT CUSTOMER.
+ ******************************************************************/
+
+#ifndef __MUSB_LINUX_DEBUG_H__
+#define __MUSB_LINUX_DEBUG_H__
+
+#define yprintk(facility, format, args...) \
+       do { printk(facility "%s %d: " format , \
+       __FUNCTION__, __LINE__ , ## args); } while (0)
+#define WARN(fmt, args...) yprintk(KERN_WARNING,fmt, ## args)
+#define INFO(fmt,args...) yprintk(KERN_INFO,fmt, ## args)
+#define ERR(fmt,args...) yprintk(KERN_ERR,fmt, ## args)
+
+#define xprintk(level, facility, format, args...) do { \
+       if ( _dbg_level(level) ) { \
+               printk(facility "%s %d: " format , \
+                               __FUNCTION__, __LINE__ , ## args); \
+       } } while (0)
+
+#if MUSB_DEBUG > 0
+extern unsigned debug;
+#else
+#define debug  0
+#endif
+
+static inline int _dbg_level(unsigned l)
+{
+       return debug >= l;
+}
+
+#define DBG(level,fmt,args...) xprintk(level,KERN_DEBUG,fmt, ## args)
+
+extern const char *otg_state_string(struct musb *);
+
+#endif                         //  __MUSB_LINUX_DEBUG_H__
diff --git a/drivers/usb/musb/dma.h b/drivers/usb/musb/dma.h
new file mode 100644 (file)
index 0000000..cececd9
--- /dev/null
@@ -0,0 +1,186 @@
+/******************************************************************
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * The Inventra Controller Driver for Linux is free software; you
+ * can redistribute it and/or modify it under the terms of the GNU
+ * General Public License version 2 as published by the Free Software
+ * Foundation.
+ *
+ * The Inventra Controller Driver for Linux is distributed in
+ * the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Inventra Controller Driver for Linux ; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ANY DOWNLOAD, USE, REPRODUCTION, MODIFICATION OR DISTRIBUTION
+ * OF THIS DRIVER INDICATES YOUR COMPLETE AND UNCONDITIONAL ACCEPTANCE
+ * OF THOSE TERMS.THIS DRIVER IS PROVIDED "AS IS" AND MENTOR GRAPHICS
+ * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, RELATED TO THIS DRIVER.
+ * MENTOR GRAPHICS SPECIFICALLY DISCLAIMS ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY; FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT.  MENTOR GRAPHICS DOES NOT PROVIDE SUPPORT
+ * SERVICES OR UPDATES FOR THIS DRIVER, EVEN IF YOU ARE A MENTOR
+ * GRAPHICS SUPPORT CUSTOMER.
+ ******************************************************************/
+
+#ifndef __MUSB_DMA_H__
+#define __MUSB_DMA_H__
+
+struct musb_hw_ep;
+
+/*
+ * DMA Controller Abstraction
+ *
+ * DMA Controllers are abstracted to allow use of a variety of different
+ * implementations of DMA, as allowed by the Inventra USB cores.  On the
+ * host side, usbcore sets up the DMA mappings and flushes caches; on the
+ * peripheral side, the gadget controller driver does.  Responsibilities
+ * of a DMA controller driver include:
+ *
+ *  - Handling the details of moving multiple USB packets
+ *    in cooperation with the Inventra USB core, including especially
+ *    the correct RX side treatment of short packets and buffer-full
+ *    states (both of which terminate transfers).
+ *
+ *  - Knowing the correlation between dma channels and the
+ *    Inventra core's local endpoint resources and data direction.
+ *
+ *  - Maintaining a list of allocated/available channels.
+ *
+ *  - Updating channel status on interrupts,
+ *    whether shared with the Inventra core or separate.
+ */
+
+#define        DMA_ADDR_INVALID        (~(dma_addr_t)0)
+
+#ifndef CONFIG_USB_INVENTRA_FIFO
+#define        is_dma_capable()        (1)
+#else
+#define        is_dma_capable()        (0)
+#endif
+
+#ifdef CONFIG_USB_TI_CPPI_DMA
+#define        is_cppi_enabled()       1
+#else
+#define        is_cppi_enabled()       0
+#endif
+
+
+/*
+ * DMA channel status ... updated by the dma controller driver whenever that
+ * status changes, and protected by the overall controller spinlock.
+ */
+enum dma_channel_status {
+       /* unallocated */
+       MGC_DMA_STATUS_UNKNOWN,
+       /* allocated ... but not busy, no errors */
+       MGC_DMA_STATUS_FREE,
+       /* busy ... transactions are active */
+       MGC_DMA_STATUS_BUSY,
+       /* transaction(s) aborted due to ... dma or memory bus error */
+       MGC_DMA_STATUS_BUS_ABORT,
+       /* transaction(s) aborted due to ... core error or USB fault */
+       MGC_DMA_STATUS_CORE_ABORT
+};
+
+struct dma_controller;
+
+/**
+ * struct dma_channel - A DMA channel.
+ * @pPrivateData: channel-private data
+ * @wMaxLength: the maximum number of bytes the channel can move in one
+ *     transaction (typically representing many USB maximum-sized packets)
+ * @dwActualLength: how many bytes have been transferred
+ * @bStatus: current channel status (updated e.g. on interrupt)
+ * @bDesiredMode: TRUE if mode 1 is desired; FALSE if mode 0 is desired
+ *
+ * channels are associated with an endpoint for the duration of at least
+ * one usb transfer.
+ */
+struct dma_channel {
+       void                    *pPrivateData;
+       // FIXME not void* private_data, but a dma_controller *
+       size_t                  dwMaxLength;
+       size_t                  dwActualLength;
+       enum dma_channel_status bStatus;
+       u8                      bDesiredMode;
+};
+
+/*
+ * Program a DMA channel to move data at the core's request.
+ * The local core endpoint and direction should already be known,
+ * since they are specified in the channel_alloc call.
+ *
+ * @channel: pointer to a channel obtained by channel_alloc
+ * @maxpacket: the maximum packet size
+ * @bMode: TRUE if mode 1; FALSE if mode 0
+ * @dma_addr: base address of data (in DMA space)
+ * @length: the number of bytes to transfer; no larger than the channel's
+ *     reported dwMaxLength
+ *
+ * Returns TRUE on success, else FALSE
+ */
+typedef int (*MGC_pfDmaProgramChannel) (
+               struct dma_channel      *channel,
+               u16                     maxpacket,
+               u8                      bMode,
+               dma_addr_t              dma_addr,
+               u32                     length);
+
+/*
+ * dma_channel_status - return status of dma channel
+ * @c: the channel
+ *
+ * Returns the software's view of the channel status.  If that status is BUSY
+ * then it's possible that the hardware has completed (or aborted) a transfer,
+ * so the driver needs to update that status.
+ */
+static inline enum dma_channel_status
+dma_channel_status(struct dma_channel *c)
+{
+       return (is_dma_capable() && c) ? c->bStatus : MGC_DMA_STATUS_UNKNOWN;
+}
+
+/**
+ * struct dma_controller - A DMA Controller.
+ * @pPrivateData: controller-private data;
+ * @start: call this to start a DMA controller;
+ *     return 0 on success, else negative errno
+ * @stop: call this to stop a DMA controller
+ *     return 0 on success, else negative errno
+ * @channel_alloc: call this to allocate a DMA channel
+ * @channel_release: call this to release a DMA channel
+ * @channel_abort: call this to abort a pending DMA transaction,
+ *     returning it to FREE (but allocated) state
+ *
+ * Controllers manage dma channels.
+ */
+struct dma_controller {
+       void                    *pPrivateData;
+       int                     (*start)(struct dma_controller *);
+       int                     (*stop)(struct dma_controller *);
+       struct dma_channel      *(*channel_alloc)(struct dma_controller *,
+                                       struct musb_hw_ep *, u8 is_tx);
+       void                    (*channel_release)(struct dma_channel *);
+       MGC_pfDmaProgramChannel channel_program;
+       int                     (*channel_abort)(struct dma_channel *);
+};
+
+/* called after channel_program(), may indicate a fault */
+extern void musb_dma_completion(struct musb *musb, u8 bLocalEnd, u8 bTransmit);
+
+
+extern struct dma_controller *__init
+dma_controller_create(struct musb *, void __iomem *);
+
+extern void dma_controller_destroy(struct dma_controller *);
+
+#endif /* __MUSB_DMA_H__ */
diff --git a/drivers/usb/musb/g_ep0.c b/drivers/usb/musb/g_ep0.c
new file mode 100644 (file)
index 0000000..c4cb544
--- /dev/null
@@ -0,0 +1,970 @@
+/******************************************************************
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * The Inventra Controller Driver for Linux is free software; you
+ * can redistribute it and/or modify it under the terms of the GNU
+ * General Public License version 2 as published by the Free Software
+ * Foundation.
+ *
+ * The Inventra Controller Driver for Linux is distributed in
+ * the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Inventra Controller Driver for Linux ; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ANY DOWNLOAD, USE, REPRODUCTION, MODIFICATION OR DISTRIBUTION
+ * OF THIS DRIVER INDICATES YOUR COMPLETE AND UNCONDITIONAL ACCEPTANCE
+ * OF THOSE TERMS.THIS DRIVER IS PROVIDED "AS IS" AND MENTOR GRAPHICS
+ * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, RELATED TO THIS DRIVER.
+ * MENTOR GRAPHICS SPECIFICALLY DISCLAIMS ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY; FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT.  MENTOR GRAPHICS DOES NOT PROVIDE SUPPORT
+ * SERVICES OR UPDATES FOR THIS DRIVER, EVEN IF YOU ARE A MENTOR
+ * GRAPHICS SUPPORT CUSTOMER.
+ ******************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+
+#include "musbdefs.h"
+
+/* ep0 is always musb->aLocalEnd[0].ep_in */
+#define        next_ep0_request(musb)  next_in_request(&(musb)->aLocalEnd[0])
+
+/*
+ * Locking note:  we use only the controller lock, for simpler correctness.
+ * It's always held with IRQs blocked.
+ *
+ * It protects the ep0 request queue as well as ep0_state, not just the
+ * controller and indexed registers.  And that lock stays held unless it
+ * needs to be dropped to allow reentering this driver ... like upcalls to
+ * the gadget driver, or adjusting endpoint halt status.
+ */
+
+static char *decode_ep0stage(u8 stage)
+{
+       switch(stage) {
+       case MGC_END0_STAGE_SETUP:      return "idle";
+       case MGC_END0_STAGE_TX:         return "in";
+       case MGC_END0_STAGE_RX:         return "out";
+       case MGC_END0_STAGE_ACKWAIT:    return "wait";
+       case MGC_END0_STAGE_STATUSIN:   return "in/status";
+       case MGC_END0_STAGE_STATUSOUT:  return "out/status";
+       default:                        return "?";
+       }
+}
+
+/* handle a standard GET_STATUS request
+ * Context:  caller holds controller lock
+ */
+static int service_tx_status_request(
+       struct musb *pThis,
+       const struct usb_ctrlrequest *pControlRequest)
+{
+       void __iomem    *pBase = pThis->pRegs;
+       int handled = 1;
+       u8 bResult[2], bEnd = 0;
+       const u8 bRecip = pControlRequest->bRequestType & USB_RECIP_MASK;
+
+       bResult[1] = 0;
+
+       switch (bRecip) {
+       case USB_RECIP_DEVICE:
+               bResult[0] = pThis->bIsSelfPowered << USB_DEVICE_SELF_POWERED;
+               bResult[0] |= pThis->bMayWakeup << USB_DEVICE_REMOTE_WAKEUP;
+#ifdef CONFIG_USB_MUSB_OTG
+               if (pThis->g.is_otg) {
+                       bResult[0] |= pThis->g.b_hnp_enable
+                               << USB_DEVICE_B_HNP_ENABLE;
+                       bResult[0] |= pThis->g.a_alt_hnp_support
+                               << USB_DEVICE_A_ALT_HNP_SUPPORT;
+                       bResult[0] |= pThis->g.a_hnp_support
+                               << USB_DEVICE_A_HNP_SUPPORT;
+               }
+#endif
+               break;
+
+       case USB_RECIP_INTERFACE:
+               bResult[0] = 0;
+               break;
+
+       case USB_RECIP_ENDPOINT: {
+               int             is_in;
+               struct musb_ep  *ep;
+               u16             tmp;
+               void __iomem    *regs;
+
+               bEnd = (u8) pControlRequest->wIndex;
+               if (!bEnd) {
+                       bResult[0] = 0;
+                       break;
+               }
+
+               is_in = bEnd & USB_DIR_IN;
+               if (is_in) {
+                       bEnd &= 0x0f;
+                       ep = &pThis->aLocalEnd[bEnd].ep_in;
+               } else {
+                       ep = &pThis->aLocalEnd[bEnd].ep_out;
+               }
+               regs = pThis->aLocalEnd[bEnd].regs;
+
+               if (bEnd >= MUSB_C_NUM_EPS || !ep->desc) {
+                       handled = -EINVAL;
+                       break;
+               }
+
+               MGC_SelectEnd(pBase, bEnd);
+               if (is_in)
+                       tmp = musb_readw(regs, MGC_O_HDRC_TXCSR)
+                                               & MGC_M_TXCSR_P_SENDSTALL;
+               else
+                       tmp = musb_readw(regs, MGC_O_HDRC_RXCSR)
+                                               & MGC_M_RXCSR_P_SENDSTALL;
+               MGC_SelectEnd(pBase, 0);
+
+               bResult[0] = tmp ? 1 : 0;
+               } break;
+
+       default:
+               /* class, vendor, etc ... delegate */
+               handled = 0;
+               break;
+       }
+
+       /* fill up the fifo; caller updates csr0 */
+       if (handled > 0) {
+               u16     len = le16_to_cpu(pControlRequest->wLength);
+
+               if (len > 2)
+                       len = 2;
+               musb_write_fifo(&pThis->aLocalEnd[0], len, bResult);
+       }
+
+       return handled;
+}
+
+/*
+ * handle a control-IN request, the end0 buffer contains the current request
+ * that is supposed to be a standard control request. Assumes the fifo to
+ * be at least 2 bytes long.
+ *
+ * @return 0 if the request was NOT HANDLED,
+ * < 0 when error
+ * > 0 when the request is processed
+ *
+ * Context:  caller holds controller lock
+ */
+static int
+service_in_request(struct musb *pThis,
+               const struct usb_ctrlrequest *pControlRequest)
+{
+       int handled = 0;        /* not handled */
+
+       if ((pControlRequest->bRequestType & USB_TYPE_MASK)
+                       == USB_TYPE_STANDARD) {
+               switch (pControlRequest->bRequest) {
+               case USB_REQ_GET_STATUS:
+                       handled = service_tx_status_request(pThis,
+                                       pControlRequest);
+                       break;
+
+               /* case USB_REQ_SYNC_FRAME: */
+
+               default:
+                       break;
+               }
+       }
+       return handled;
+}
+
+/*
+ * Context:  caller holds controller lock
+ */
+static void musb_g_ep0_giveback(struct musb *pThis, struct usb_request *req)
+{
+       pThis->ep0_state = MGC_END0_STAGE_SETUP;
+       musb_g_giveback(&pThis->aLocalEnd[0].ep_in, req, 0);
+}
+
+/*
+ * Handle all control requests with no DATA stage, including standard
+ * requests such as:
+ * USB_REQ_SET_CONFIGURATION, USB_REQ_SET_INTERFACE, unrecognized
+ *     always delegated to the gadget driver
+ * USB_REQ_SET_ADDRESS, USB_REQ_CLEAR_FEATURE, USB_REQ_SET_FEATURE
+ *     always handled here, except for class/vendor/... features
+ *
+ * Context:  caller holds controller lock
+ */
+static int
+service_zero_data_request(struct musb *pThis,
+               struct usb_ctrlrequest *pControlRequest)
+__releases(pThis->Lock)
+__acquires(pThis->Lock)
+{
+       int handled = -EINVAL;
+       void __iomem *pBase = pThis->pRegs;
+       const u8 bRecip = pControlRequest->bRequestType & USB_RECIP_MASK;
+
+       /* the gadget driver handles everything except what we MUST handle */
+       if ((pControlRequest->bRequestType & USB_TYPE_MASK)
+                       == USB_TYPE_STANDARD) {
+               switch (pControlRequest->bRequest) {
+               case USB_REQ_SET_ADDRESS:
+                       /* change it after the status stage */
+                       pThis->bSetAddress = TRUE;
+                       pThis->bAddress = (u8) (pControlRequest->wValue & 0x7f);
+                       handled = 1;
+                       break;
+
+               case USB_REQ_CLEAR_FEATURE:
+                       switch (bRecip) {
+                       case USB_RECIP_DEVICE:
+                               if (pControlRequest->wValue
+                                               != USB_DEVICE_REMOTE_WAKEUP)
+                                       break;
+                               pThis->bMayWakeup = 0;
+                               handled = 1;
+                               break;
+                       case USB_RECIP_INTERFACE:
+                               break;
+                       case USB_RECIP_ENDPOINT:{
+                               const u8 bEnd = pControlRequest->wIndex & 0x0f;
+                               struct musb_ep *pEnd;
+
+                               if (bEnd == 0
+                                               || bEnd >= MUSB_C_NUM_EPS
+                                               || pControlRequest->wValue
+                                                       != USB_ENDPOINT_HALT)
+                                       break;
+
+                               if (pControlRequest->wIndex & USB_DIR_IN)
+                                       pEnd = &pThis->aLocalEnd[bEnd].ep_in;
+                               else
+                                       pEnd = &pThis->aLocalEnd[bEnd].ep_out;
+                               if (!pEnd->desc)
+                                       break;
+
+                               /* REVISIT do it directly, no locking games */
+                               spin_unlock(&pThis->Lock);
+                               musb_gadget_set_halt(&pEnd->end_point, 0);
+                               spin_lock(&pThis->Lock);
+
+                               /* select ep0 again */
+                               MGC_SelectEnd(pBase, 0);
+                               handled = 1;
+                               } break;
+                       default:
+                               /* class, vendor, etc ... delegate */
+                               handled = 0;
+                               break;
+                       }
+                       break;
+
+               case USB_REQ_SET_FEATURE:
+                       switch (bRecip) {
+                       case USB_RECIP_DEVICE:
+                               handled = 1;
+                               switch (pControlRequest->wValue) {
+                               case USB_DEVICE_REMOTE_WAKEUP:
+                                       pThis->bMayWakeup = 1;
+                                       break;
+                               case USB_DEVICE_TEST_MODE:
+                                       if (pThis->g.speed != USB_SPEED_HIGH)
+                                               goto stall;
+                                       if (pControlRequest->wIndex & 0xff)
+                                               goto stall;
+
+                                       switch (pControlRequest->wIndex >> 8) {
+                                       case 1:
+                                               pr_debug("TEST_J\n");
+                                               /* TEST_J */
+                                               pThis->bTestModeValue =
+                                                       MGC_M_TEST_J;
+                                               break;
+                                       case 2:
+                                               /* TEST_K */
+                                               pr_debug("TEST_K\n");
+                                               pThis->bTestModeValue =
+                                                       MGC_M_TEST_K;
+                                               break;
+                                       case 3:
+                                               /* TEST_SE0_NAK */
+                                               pr_debug("TEST_SE0_NAK\n");
+                                               pThis->bTestModeValue =
+                                                       MGC_M_TEST_SE0_NAK;
+                                               break;
+                                       case 4:
+                                               /* TEST_PACKET */
+                                               pr_debug("TEST_PACKET\n");
+                                               pThis->bTestModeValue =
+                                                       MGC_M_TEST_PACKET;
+                                               break;
+                                       default:
+                                               goto stall;
+                                       }
+
+                                       /* enter test mode after irq */
+                                       if (handled > 0)
+                                               pThis->bTestMode = TRUE;
+                                       break;
+#ifdef CONFIG_USB_MUSB_OTG
+                               case USB_DEVICE_B_HNP_ENABLE:
+                                       if (!pThis->g.is_otg)
+                                               goto stall;
+                                       { u8 devctl;
+                                       pThis->g.b_hnp_enable = 1;
+                                       devctl = musb_readb(pBase,
+                                                       MGC_O_HDRC_DEVCTL);
+                                       musb_writeb(pBase, MGC_O_HDRC_DEVCTL,
+                                               devctl | MGC_M_DEVCTL_HR);
+                                       }
+                                       break;
+                               case USB_DEVICE_A_HNP_SUPPORT:
+                                       if (!pThis->g.is_otg)
+                                               goto stall;
+                                       pThis->g.a_hnp_support = 1;
+                                       break;
+                               case USB_DEVICE_A_ALT_HNP_SUPPORT:
+                                       if (!pThis->g.is_otg)
+                                               goto stall;
+                                       pThis->g.a_alt_hnp_support = 1;
+                                       break;
+#endif
+stall:
+                               default:
+                                       handled = -EINVAL;
+                                       break;
+                               }
+                               break;
+
+                       case USB_RECIP_INTERFACE:
+                               break;
+
+                       case USB_RECIP_ENDPOINT:{
+                               const u8                bEnd =
+                                       pControlRequest->wIndex & 0x0f;
+                               struct musb_ep          *pEnd;
+                               struct musb_hw_ep       *ep;
+                               void __iomem            *regs;
+                               int                     is_in;
+                               u16                     csr;
+
+                               if (bEnd == 0
+                                               || bEnd >= MUSB_C_NUM_EPS
+                                               || pControlRequest->wValue
+                                                       != USB_ENDPOINT_HALT)
+                                       break;
+
+                               ep = pThis->aLocalEnd + bEnd;
+                               regs = ep->regs;
+                               is_in = pControlRequest->wIndex & USB_DIR_IN;
+                               if (is_in)
+                                       pEnd = &ep->ep_in;
+                               else
+                                       pEnd = &ep->ep_out;
+                               if (!pEnd->desc)
+                                       break;
+
+                               MGC_SelectEnd(pBase, bEnd);
+                               if (is_in) {
+                                       csr = musb_readw(regs,
+                                                       MGC_O_HDRC_TXCSR);
+                                       if (csr & MGC_M_TXCSR_FIFONOTEMPTY)
+                                               csr |= MGC_M_TXCSR_FLUSHFIFO;
+                                       csr |= MGC_M_TXCSR_P_SENDSTALL
+                                               | MGC_M_TXCSR_CLRDATATOG
+                                               | MGC_M_TXCSR_P_WZC_BITS;
+                                       musb_writew(regs, MGC_O_HDRC_TXCSR,
+                                                       csr);
+                               } else {
+                                       csr = musb_readw(regs,
+                                                       MGC_O_HDRC_RXCSR);
+                                       csr |= MGC_M_RXCSR_P_SENDSTALL
+                                               | MGC_M_RXCSR_FLUSHFIFO
+                                               | MGC_M_RXCSR_CLRDATATOG
+                                               | MGC_M_TXCSR_P_WZC_BITS;
+                                       musb_writew(regs, MGC_O_HDRC_RXCSR,
+                                                       csr);
+                               }
+
+                               /* select ep0 again */
+                               MGC_SelectEnd(pBase, 0);
+                               handled = 1;
+                               } break;
+
+                       default:
+                               /* class, vendor, etc ... delegate */
+                               handled = 0;
+                               break;
+                       }
+                       break;
+               default:
+                       /* delegate SET_CONFIGURATION, etc */
+                       handled = 0;
+               }
+       } else
+               handled = 0;
+       return handled;
+}
+
+/* we have an ep0out data packet
+ * Context:  caller holds controller lock
+ */
+static void ep0_rxstate(struct musb *this)
+{
+       void __iomem            *regs = this->control_ep->regs;
+       struct usb_request      *req;
+       u16                     tmp;
+
+       req = next_ep0_request(this);
+
+       /* read packet and ack; or stall because of gadget driver bug:
+        * should have provided the rx buffer before setup() returned.
+        */
+       if (req) {
+               void            *buf = req->buf + req->actual;
+               unsigned        len = req->length - req->actual;
+
+               /* read the buffer */
+               tmp = musb_readb(regs, MGC_O_HDRC_COUNT0);
+               if (tmp > len) {
+                       req->status = -EOVERFLOW;
+                       tmp = len;
+               }
+               musb_read_fifo(&this->aLocalEnd[0], tmp, buf);
+               req->actual += tmp;
+               tmp = MGC_M_CSR0_P_SVDRXPKTRDY;
+               if (tmp < 64 || req->actual == req->length) {
+                       this->ep0_state = MGC_END0_STAGE_STATUSIN;
+                       tmp |= MGC_M_CSR0_P_DATAEND;
+               } else
+                       req = NULL;
+       } else
+               tmp = MGC_M_CSR0_P_SVDRXPKTRDY | MGC_M_CSR0_P_SENDSTALL;
+       musb_writew(regs, MGC_O_HDRC_CSR0, tmp);
+
+
+       /* NOTE:  we "should" hold off reporting DATAEND and going to
+        * STATUSIN until after the completion handler decides whether
+        * to issue a stall instead, since this hardware can do that.
+        */
+       if (req)
+               musb_g_ep0_giveback(this, req);
+}
+
+/*
+ * transmitting to the host (IN), this code might be called from IRQ
+ * and from kernel thread.
+ *
+ * Context:  caller holds controller lock
+ */
+static void ep0_txstate(struct musb *pThis)
+{
+       void __iomem            *regs = pThis->control_ep->regs;
+       struct usb_request      *pRequest = next_ep0_request(pThis);
+       u16                     wCsrVal = MGC_M_CSR0_TXPKTRDY;
+       u8                      *pFifoSource;
+       u8                      wFifoCount;
+
+       if (!pRequest) {
+               // WARN_ON(1);
+               DBG(2, "odd; csr0 %04x\n", musb_readw(regs, MGC_O_HDRC_CSR0));
+               return;
+       }
+
+       /* load the data */
+       pFifoSource = (u8 *) pRequest->buf + pRequest->actual;
+       wFifoCount = min((unsigned) MGC_END0_FIFOSIZE,
+               pRequest->length - pRequest->actual);
+       musb_write_fifo(&pThis->aLocalEnd[0], wFifoCount, pFifoSource);
+       pRequest->actual += wFifoCount;
+
+       /* update the flags */
+       if (wFifoCount < MUSB_MAX_END0_PACKET
+                       || pRequest->actual == pRequest->length) {
+               pThis->ep0_state = MGC_END0_STAGE_STATUSOUT;
+               wCsrVal |= MGC_M_CSR0_P_DATAEND;
+       } else
+               pRequest = NULL;
+
+       /* send it out, triggering a "txpktrdy cleared" irq */
+       musb_writew(regs, MGC_O_HDRC_CSR0, wCsrVal);
+
+       /* report completions as soon as the fifo's loaded; there's no
+        * win in waiting till this last packet gets acked.  (other than
+        * very precise fault reporting, needed by USB TMC; possible with
+        * this hardware, but not usable from portable gadget drivers.)
+        */
+       if (pRequest)
+               musb_g_ep0_giveback(pThis, pRequest);
+}
+
+/*
+ * Read a SETUP packet (struct usb_ctrlrequest) from the hardware.
+ * Fields are left in USB byte-order.
+ *
+ * Context:  caller holds controller lock.
+ */
+static void
+musb_read_setup(struct musb *pThis, struct usb_ctrlrequest *req)
+{
+       struct usb_request      *r;
+       void __iomem            *regs = pThis->control_ep->regs;
+
+       musb_read_fifo(&pThis->aLocalEnd[0], sizeof *req, (u8 *)req);
+
+       /* NOTE:  earlier 2.6 versions changed setup packets to host
+        * order, but now USB packets always stay in USB byte order.
+        */
+       DBG(3, "SETUP req%02x.%02x v%04x i%04x l%d\n",
+               req->bRequestType,
+               req->bRequest,
+               le16_to_cpu(req->wValue),
+               le16_to_cpu(req->wIndex),
+               le16_to_cpu(req->wLength));
+
+       /* clean up any leftover transfers */
+       r = next_ep0_request(pThis);
+       if (r)
+               musb_g_ep0_giveback(pThis, r);
+
+       /* For zero-data requests we want to delay the STATUS stage to
+        * avoid SETUPEND errors.  If we read data (OUT), delay accepting
+        * packets until there's a buffer to store them in.
+        *
+        * If we write data, the controller acts happier if we enable
+        * the TX FIFO right away, and give the controller a moment
+        * to switch modes...
+        */
+       pThis->bSetAddress = FALSE;
+       pThis->ackpend = MGC_M_CSR0_P_SVDRXPKTRDY;
+       if (req->wLength == 0) {
+               if (req->bRequestType & USB_DIR_IN)
+                       pThis->ackpend |= MGC_M_CSR0_TXPKTRDY;
+               pThis->ep0_state = MGC_END0_STAGE_ACKWAIT;
+       } else if (req->bRequestType & USB_DIR_IN) {
+               pThis->ep0_state = MGC_END0_STAGE_TX;
+               musb_writew(regs, MGC_O_HDRC_CSR0, MGC_M_CSR0_P_SVDRXPKTRDY);
+               while ((musb_readw(regs, MGC_O_HDRC_CSR0)
+                               & MGC_M_CSR0_RXPKTRDY) != 0)
+                       cpu_relax();
+               pThis->ackpend = 0;
+       } else
+               pThis->ep0_state = MGC_END0_STAGE_RX;
+}
+
+static int
+forward_to_driver(struct musb *musb,
+               const struct usb_ctrlrequest *pControlRequest)
+__releases(musb->Lock)
+__acquires(musb->Lock)
+{
+       int retval;
+       if (!musb->pGadgetDriver)
+               return -EOPNOTSUPP;
+       spin_unlock(&musb->Lock);
+       retval = musb->pGadgetDriver->setup(&musb->g, pControlRequest);
+       spin_lock(&musb->Lock);
+       return retval;
+}
+
+/*
+ * Handle peripheral ep0 interrupt
+ * @param pThis this
+ *
+ * Context: irq handler; we won't re-enter the driver that way.
+ */
+irqreturn_t musb_g_ep0_irq(struct musb *pThis)
+{
+       u16             wCsrVal;
+       u16             wCount;
+       void __iomem    *pBase = pThis->pRegs;
+       void __iomem    *regs = pThis->aLocalEnd[0].regs;
+       irqreturn_t     retval = IRQ_NONE;
+
+       MGC_SelectEnd(pBase, 0);        /* select ep0 */
+       wCsrVal = musb_readw(regs, MGC_O_HDRC_CSR0);
+       wCount = musb_readb(regs, MGC_O_HDRC_COUNT0);
+
+       DBG(4, "csr %04x, count %d, myaddr %d, ep0stage %s\n",
+                       wCsrVal, wCount,
+                       musb_readb(pBase, MGC_O_HDRC_FADDR),
+                       decode_ep0stage(pThis->ep0_state));
+
+       /* I sent a stall.. need to acknowledge it now.. */
+       if (wCsrVal & MGC_M_CSR0_P_SENTSTALL) {
+               musb_writew(regs, MGC_O_HDRC_CSR0,
+                               wCsrVal & ~MGC_M_CSR0_P_SENTSTALL);
+               retval = IRQ_HANDLED;
+               pThis->ep0_state = MGC_END0_STAGE_SETUP;
+               wCsrVal = musb_readw(regs, MGC_O_HDRC_CSR0);
+       }
+
+       /* request ended "early" */
+       if (wCsrVal & MGC_M_CSR0_P_SETUPEND) {
+               musb_writew(regs, MGC_O_HDRC_CSR0, MGC_M_CSR0_P_SVDSETUPEND);
+               retval = IRQ_HANDLED;
+               pThis->ep0_state = MGC_END0_STAGE_SETUP;
+               wCsrVal = musb_readw(regs, MGC_O_HDRC_CSR0);
+               /* NOTE:  request may need completion */
+       }
+
+       /* docs from Mentor only describe tx, rx, and idle/setup states.
+        * we need to handle nuances around status stages, and also the
+        * case where status and setup stages come back-to-back ...
+        */
+       switch (pThis->ep0_state) {
+
+       case MGC_END0_STAGE_TX:
+               /* irq on clearing txpktrdy */
+               if ((wCsrVal & MGC_M_CSR0_TXPKTRDY) == 0) {
+                       ep0_txstate(pThis);
+                       retval = IRQ_HANDLED;
+               }
+               break;
+
+       case MGC_END0_STAGE_RX:
+               /* irq on set rxpktrdy */
+               if (wCsrVal & MGC_M_CSR0_RXPKTRDY) {
+                       ep0_rxstate(pThis);
+                       retval = IRQ_HANDLED;
+               }
+               break;
+
+       case MGC_END0_STAGE_STATUSIN:
+               /* end of sequence #2 (OUT/RX state) or #3 (no data) */
+
+               /* update address (if needed) only @ the end of the
+                * status phase per usb spec, which also guarantees
+                * we get 10 msec to receive this irq... until this
+                * is done we won't see the next packet.
+                */
+               if (pThis->bSetAddress) {
+                       pThis->bSetAddress = FALSE;
+                       musb_writeb(pBase, MGC_O_HDRC_FADDR, pThis->bAddress);
+               }
+
+               /* enter test mode if needed (exit by reset) */
+               else if (pThis->bTestMode) {
+                       DBG(1, "entering TESTMODE\n");
+
+                       if (MGC_M_TEST_PACKET == pThis->bTestModeValue)
+                               musb_load_testpacket(pThis);
+
+                       musb_writeb(pBase, MGC_O_HDRC_TESTMODE,
+                                       pThis->bTestModeValue);
+               }
+               /* FALLTHROUGH */
+
+       case MGC_END0_STAGE_STATUSOUT:
+               /* end of sequence #1: write to host (TX state) */
+               {
+                       struct usb_request      *req;
+
+                       req = next_ep0_request(pThis);
+                       if (req)
+                               musb_g_ep0_giveback(pThis, req);
+               }
+               retval = IRQ_HANDLED;
+               pThis->ep0_state = MGC_END0_STAGE_SETUP;
+               /* FALLTHROUGH */
+
+       case MGC_END0_STAGE_SETUP:
+               if (wCsrVal & MGC_M_CSR0_RXPKTRDY) {
+                       struct usb_ctrlrequest  setup;
+                       int                     handled = 0;
+
+                       if (wCount != 8) {
+                               ERR("SETUP packet len %d != 8 ?\n", wCount);
+                               break;
+                       }
+                       musb_read_setup(pThis, &setup);
+                       retval = IRQ_HANDLED;
+
+                       /* sometimes the RESET won't be reported */
+                       if (unlikely(pThis->g.speed == USB_SPEED_UNKNOWN)) {
+                               u8      power;
+
+                               printk(KERN_NOTICE "%s: peripheral reset "
+                                               "irq lost!\n",
+                                               musb_driver_name);
+                               power = musb_readb(pBase, MGC_O_HDRC_POWER);
+                               pThis->g.speed = (power & MGC_M_POWER_HSMODE)
+                                       ? USB_SPEED_HIGH : USB_SPEED_FULL;
+
+                       }
+
+                       switch (pThis->ep0_state) {
+
+                       /* sequence #3 (no data stage), includes requests
+                        * we can't forward (notably SET_ADDRESS and the
+                        * device/endpoint feature set/clear operations)
+                        * plus SET_CONFIGURATION and others we must
+                        */
+                       case MGC_END0_STAGE_ACKWAIT:
+                               handled = service_zero_data_request(
+                                               pThis, &setup);
+
+                               /* status stage might be immediate */
+                               if (handled > 0) {
+                                       pThis->ackpend |= MGC_M_CSR0_P_DATAEND;
+                                       pThis->ep0_state =
+                                               MGC_END0_STAGE_STATUSIN;
+                               }
+                               break;
+
+                       /* sequence #1 (IN to host), includes GET_STATUS
+                        * requests that we can't forward, GET_DESCRIPTOR
+                        * and others that we must
+                        */
+                       case MGC_END0_STAGE_TX:
+                               handled = service_in_request(pThis, &setup);
+                               if (handled > 0) {
+                                       pThis->ackpend = MGC_M_CSR0_TXPKTRDY
+                                               | MGC_M_CSR0_P_DATAEND;
+                                       pThis->ep0_state =
+                                               MGC_END0_STAGE_STATUSOUT;
+                               }
+                               break;
+
+                       /* sequence #2 (OUT from host), always forward */
+                       default:                /* MGC_END0_STAGE_RX */
+                               break;
+                       }
+
+                       DBG(3, "handled %d, csr %04x, ep0stage %s\n",
+                               handled, wCsrVal,
+                               decode_ep0stage(pThis->ep0_state));
+
+                       /* unless we need to delegate this to the gadget
+                        * driver, we know how to wrap this up:  csr0 has
+                        * not yet been written.
+                        */
+                       if (handled < 0)
+                               goto stall;
+                       else if (handled > 0)
+                               goto finish;
+
+                       handled = forward_to_driver(pThis, &setup);
+                       if (handled < 0) {
+                               MGC_SelectEnd(pBase, 0);
+stall:
+                               DBG(3, "stall (%d)\n", handled);
+                               pThis->ackpend |= MGC_M_CSR0_P_SENDSTALL;
+                               pThis->ep0_state = MGC_END0_STAGE_SETUP;
+finish:
+                               musb_writew(regs, MGC_O_HDRC_CSR0,
+                                               pThis->ackpend);
+                               pThis->ackpend = 0;
+                       }
+               }
+               break;
+
+       case MGC_END0_STAGE_ACKWAIT:
+               /* This should not happen. But happens with tusb6010 with
+                * g_file_storage and high speed. Do nothing.
+                */
+               retval = IRQ_HANDLED;
+               break;
+
+       default:
+               /* "can't happen" */
+               WARN_ON(1);
+               musb_writew(regs, MGC_O_HDRC_CSR0, MGC_M_CSR0_P_SENDSTALL);
+               pThis->ep0_state = MGC_END0_STAGE_SETUP;
+               break;
+       }
+
+       return retval;
+}
+
+
+static int
+musb_g_ep0_enable(struct usb_ep *ep, const struct usb_endpoint_descriptor *desc)
+{
+       /* always enabled */
+       return -EINVAL;
+}
+
+static int musb_g_ep0_disable(struct usb_ep *e)
+{
+       /* always enabled */
+       return -EINVAL;
+}
+
+static void *musb_g_ep0_alloc_buffer(struct usb_ep *ep, unsigned bytes,
+                       dma_addr_t * dma, gfp_t gfp_flags)
+{
+       *dma = DMA_ADDR_INVALID;
+       return kmalloc(bytes, gfp_flags);
+}
+
+static void musb_g_ep0_free_buffer(struct usb_ep *ep, void *address,
+                       dma_addr_t dma, unsigned bytes)
+{
+       kfree(address);
+}
+
+static int
+musb_g_ep0_queue(struct usb_ep *e, struct usb_request *r, gfp_t gfp_flags)
+{
+       struct musb_ep          *ep;
+       struct musb_request     *req;
+       struct musb             *musb;
+       int                     status;
+       unsigned long           lockflags;
+       void __iomem            *regs;
+
+       if (!e || !r)
+               return -EINVAL;
+
+       ep = to_musb_ep(e);
+       musb = ep->pThis;
+       regs = musb->control_ep->regs;
+
+       req = to_musb_request(r);
+       req->musb = musb;
+       req->request.actual = 0;
+       req->request.status = -EINPROGRESS;
+       req->bTx = ep->is_in;
+
+       spin_lock_irqsave(&musb->Lock, lockflags);
+
+       if (!list_empty(&ep->req_list)) {
+               status = -EBUSY;
+               goto cleanup;
+       }
+
+       switch (musb->ep0_state) {
+       case MGC_END0_STAGE_RX:         /* control-OUT data */
+       case MGC_END0_STAGE_TX:         /* control-IN data */
+       case MGC_END0_STAGE_ACKWAIT:    /* zero-length data */
+               status = 0;
+               break;
+       default:
+               DBG(1, "ep0 request queued in state %d\n",
+                               musb->ep0_state);
+               status = -EINVAL;
+               goto cleanup;
+       }
+
+       /* add request to the list */
+       list_add_tail(&(req->request.list), &(ep->req_list));
+
+       DBG(3, "queue to %s (%s), length=%d\n",
+                       ep->name, ep->is_in ? "IN/TX" : "OUT/RX",
+                       req->request.length);
+
+       MGC_SelectEnd(musb->pRegs, 0);
+
+       /* sequence #1, IN ... start writing the data */
+       if (musb->ep0_state == MGC_END0_STAGE_TX)
+               ep0_txstate(musb);
+
+       /* sequence #3, no-data ... issue IN status */
+       else if (musb->ep0_state == MGC_END0_STAGE_ACKWAIT) {
+               if (req->request.length)
+                       status = -EINVAL;
+               else {
+                       musb->ep0_state = MGC_END0_STAGE_STATUSIN;
+                       musb_writew(regs, MGC_O_HDRC_CSR0,
+                                       musb->ackpend | MGC_M_CSR0_P_DATAEND);
+                       musb->ackpend = 0;
+                       musb_g_ep0_giveback(ep->pThis, r);
+               }
+
+       /* else for sequence #2 (OUT), caller provides a buffer
+        * before the next packet arrives.  deferred responses
+        * (after SETUP is acked) are racey.
+        */
+       } else if (musb->ackpend) {
+               musb_writew(regs, MGC_O_HDRC_CSR0, musb->ackpend);
+               musb->ackpend = 0;
+       }
+
+cleanup:
+       spin_unlock_irqrestore(&musb->Lock, lockflags);
+       return status;
+}
+
+static int
+musb_g_ep0_dequeue(struct usb_ep *ep, struct usb_request *req)
+{
+       /* we just won't support this */
+       return -EINVAL;
+}
+
+static int musb_g_ep0_halt(struct usb_ep *e, int value)
+{
+       struct musb_ep          *ep;
+       struct musb             *musb;
+       void __iomem            *base, *regs;
+       unsigned long           flags;
+       int                     status;
+       u16                     csr;
+
+       if (!e || !value)
+               return -EINVAL;
+
+       ep = to_musb_ep(e);
+       musb = ep->pThis;
+       base = musb->pRegs;
+       regs = musb->control_ep->regs;
+
+       spin_lock_irqsave(&musb->Lock, flags);
+
+       if (!list_empty(&ep->req_list)) {
+               status = -EBUSY;
+               goto cleanup;
+       }
+
+       switch (musb->ep0_state) {
+       case MGC_END0_STAGE_TX:         /* control-IN data */
+       case MGC_END0_STAGE_ACKWAIT:    /* STALL for zero-length data */
+       case MGC_END0_STAGE_RX:         /* control-OUT data */
+               status = 0;
+
+               MGC_SelectEnd(base, 0);
+               csr = musb_readw(regs, MGC_O_HDRC_CSR0);
+               csr |= MGC_M_CSR0_P_SENDSTALL;
+               musb_writew(regs, MGC_O_HDRC_CSR0, csr);
+               musb->ep0_state = MGC_END0_STAGE_SETUP;
+               break;
+       default:
+               DBG(1, "ep0 can't halt in state %d\n", musb->ep0_state);
+               status = -EINVAL;
+       }
+
+cleanup:
+       spin_unlock_irqrestore(&musb->Lock, flags);
+       return status;
+}
+
+const struct usb_ep_ops musb_g_ep0_ops = {
+       .enable         = musb_g_ep0_enable,
+       .disable        = musb_g_ep0_disable,
+       .alloc_request  = musb_alloc_request,
+       .free_request   = musb_free_request,
+       .alloc_buffer   = musb_g_ep0_alloc_buffer,
+       .free_buffer    = musb_g_ep0_free_buffer,
+       .queue          = musb_g_ep0_queue,
+       .dequeue        = musb_g_ep0_dequeue,
+       .set_halt       = musb_g_ep0_halt,
+       .fifo_status    = NULL,
+       .fifo_flush     = NULL,
+};
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
new file mode 100644 (file)
index 0000000..da70ee1
--- /dev/null
@@ -0,0 +1,2045 @@
+/******************************************************************
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * The Inventra Controller Driver for Linux is free software; you
+ * can redistribute it and/or modify it under the terms of the GNU
+ * General Public License version 2 as published by the Free Software
+ * Foundation.
+ *
+ * The Inventra Controller Driver for Linux is distributed in
+ * the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Inventra Controller Driver for Linux ; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ANY DOWNLOAD, USE, REPRODUCTION, MODIFICATION OR DISTRIBUTION
+ * OF THIS DRIVER INDICATES YOUR COMPLETE AND UNCONDITIONAL ACCEPTANCE
+ * OF THOSE TERMS.THIS DRIVER IS PROVIDED "AS IS" AND MENTOR GRAPHICS
+ * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, RELATED TO THIS DRIVER.
+ * MENTOR GRAPHICS SPECIFICALLY DISCLAIMS ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY; FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT.  MENTOR GRAPHICS DOES NOT PROVIDE SUPPORT
+ * SERVICES OR UPDATES FOR THIS DRIVER, EVEN IF YOU ARE A MENTOR
+ * GRAPHICS SUPPORT CUSTOMER.
+ ******************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/module.h>
+#include <linux/smp.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/moduleparam.h>
+#include <linux/stat.h>
+#include <linux/dma-mapping.h>
+
+#include "musbdefs.h"
+
+
+/* MUSB PERIPHERAL status 3-mar:
+ *
+ * - EP0 seems solid.  It passes both USBCV and usbtest control cases.
+ *   Minor glitches:
+ *
+ *     + remote wakeup to Linux hosts work, but saw USBCV failures;
+ *       in one test run (operator error?)
+ *     + endpoint halt tests -- in both usbtest and usbcv -- seem
+ *       to break when dma is enabled ... is something wrongly
+ *       clearing SENDSTALL?
+ *
+ * - Mass storage behaved ok when last tested.  Network traffic patterns
+ *   (with lots of short transfers etc) need retesting; they turn up the
+ *   worst cases of the DMA, since short packets are typical but are not
+ *   required.
+ *
+ * - TX/IN
+ *     + both pio and dma behave in with network and g_zero tests
+ *     + no cppi throughput issues other than no-hw-queueing
+ *     + failed with FLAT_REG (DaVinci)
+ *     + seems to behave with double buffering, PIO -and- CPPI
+ *     + with gadgetfs + AIO, requests got lost?
+ *
+ * - RX/OUT
+ *     + both pio and dma behave in with network and g_zero tests
+ *     + dma is slow in typical case (short_not_ok is clear)
+ *     + double buffering ok with PIO
+ *     + double buffering *FAILS* with CPPI, wrong data bytes sometimes
+ *     + request lossage observed with gadgetfs
+ *
+ * - ISO not tested ... might work, but only weakly isochronous
+ *
+ * - Gadget driver disabling of softconnect during bind() is ignored; so
+ *   drivers can't hold off host requests until userspace is ready.
+ *   (Workaround:  they can turn it off later.)
+ *
+ * - PORTABILITY (assumes PIO works):
+ *     + DaVinci, basically works with cppi dma
+ *     + OMAP 2430, ditto with mentor dma
+ *     + TUSB 6010, platform-specific dma in the works
+ */
+
+/**************************************************************************
+Handling completion
+**************************************************************************/
+
+/*
+ * Immediately complete a request.
+ *
+ * @param pRequest the request to complete
+ * @param status the status to complete the request with
+ * Context: controller locked, IRQs blocked.
+ */
+void musb_g_giveback(
+       struct musb_ep          *ep,
+       struct usb_request      *pRequest,
+       int status)
+__releases(ep->musb->Lock)
+__acquires(ep->musb->Lock)
+{
+       struct musb_request     *req;
+       struct musb             *musb;
+       int                     busy = ep->busy;
+
+       req = to_musb_request(pRequest);
+
+       list_del(&pRequest->list);
+       if (req->request.status == -EINPROGRESS)
+               req->request.status = status;
+       musb = req->musb;
+
+       ep->busy = 1;
+       spin_unlock(&musb->Lock);
+       if (is_dma_capable()) {
+               if (req->mapped) {
+                       dma_unmap_single(musb->controller,
+                                       req->request.dma,
+                                       req->request.length,
+                                       req->bTx
+                                               ? DMA_TO_DEVICE
+                                               : DMA_FROM_DEVICE);
+                       req->request.dma = DMA_ADDR_INVALID;
+                       req->mapped = 0;
+               } else if (req->request.dma != DMA_ADDR_INVALID)
+                       dma_sync_single_for_cpu(musb->controller,
+                                       req->request.dma,
+                                       req->request.length,
+                                       req->bTx
+                                               ? DMA_TO_DEVICE
+                                               : DMA_FROM_DEVICE);
+       }
+       if (pRequest->status == 0)
+               DBG(5, "%s done request %p,  %d/%d\n",
+                               ep->end_point.name, pRequest,
+                               req->request.actual, req->request.length);
+       else
+               DBG(2, "%s request %p, %d/%d fault %d\n",
+                               ep->end_point.name, pRequest,
+                               req->request.actual, req->request.length,
+                               pRequest->status);
+       req->request.complete(&req->ep->end_point, &req->request);
+       spin_lock(&musb->Lock);
+       ep->busy = busy;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/*
+ * Abort requests queued to an endpoint using the status. Synchronous.
+ * caller locked controller and blocked irqs, and selected this ep.
+ */
+static void nuke(struct musb_ep *ep, const int status)
+{
+       struct musb_request     *req = NULL;
+
+       ep->busy = 1;
+
+       if (is_dma_capable() && ep->dma) {
+               struct dma_controller   *c = ep->pThis->pDmaController;
+               int value;
+
+               value = c->channel_abort(ep->dma);
+               DBG(value ? 1 : 6, "%s: abort DMA --> %d\n", ep->name, value);
+               c->channel_release(ep->dma);
+               ep->dma = NULL;
+       }
+
+       while (!list_empty(&(ep->req_list))) {
+               req = container_of(ep->req_list.next, struct musb_request,
+                               request.list);
+               musb_g_giveback(ep, &req->request, status);
+       }
+}
+
+/**************************************************************************
+ * TX/IN and RX/OUT Data transfers
+ **************************************************************************/
+
+/*
+ * This assumes the separate CPPI engine is responding to DMA requests
+ * from the usb core ... sequenced a bit differently from mentor dma.
+ */
+
+static inline int max_ep_writesize(struct musb *pThis, struct musb_ep *ep)
+{
+       if (can_bulk_split(pThis, ep->type))
+               return ep->hw_ep->wMaxPacketSizeTx;
+       else
+               return ep->wPacketSize;
+}
+
+
+#ifdef CONFIG_USB_INVENTRA_DMA
+
+/* Peripheral tx (IN) using Mentor DMA works as follows:
+       Only mode 0 is used for transfers <= wPktSize,
+       mode 1 is used for larger transfers,
+
+       One of the following happens:
+       - Host sends IN token which causes an endpoint interrupt
+               -> TxAvail
+                       -> if DMA is currently busy, exit.
+                       -> if queue is non-empty, txstate().
+
+       - Request is queued by the gadget driver.
+               -> if queue was previously empty, txstate()
+
+       txstate()
+               -> start
+                 /\    -> setup DMA
+                 |     (data is transferred to the FIFO, then sent out when
+                 |     IN token(s) are recd from Host.
+                 |             -> DMA interrupt on completion
+                 |                calls TxAvail.
+                 |                   -> stop DMA, ~DmaEenab,
+                 |                   -> set TxPktRdy for last short pkt or zlp
+                 |                   -> Complete Request
+                 |                   -> Continue next request (call txstate)
+                 |___________________________________|
+
+ * Non-Mentor DMA engines can of course work differently, such as by
+ * upleveling from irq-per-packet to irq-per-buffer.
+ */
+
+#endif
+
+/*
+ * An endpoint is transmitting data. This can be called either from
+ * the IRQ routine or from ep.queue() to kickstart a request on an
+ * endpoint.
+ *
+ * Context: controller locked, IRQs blocked, endpoint selected
+ */
+static void txstate(struct musb *pThis, struct musb_request *req)
+{
+       u8                      bEnd = req->bEnd;
+       struct musb_ep          *pEnd;
+       void __iomem            *epio = pThis->aLocalEnd[bEnd].regs;
+       struct usb_request      *pRequest;
+       u16                     wFifoCount = 0, wCsrVal;
+       int                     use_dma = 0;
+
+       pEnd = req->ep;
+
+       /* we shouldn't get here while DMA is active ... but we do ... */
+       if (dma_channel_status(pEnd->dma) == MGC_DMA_STATUS_BUSY) {
+               DBG(4, "dma pending...\n");
+               return;
+       }
+
+       /* read TXCSR before */
+       wCsrVal = musb_readw(epio, MGC_O_HDRC_TXCSR);
+
+       pRequest = &req->request;
+       wFifoCount = min(max_ep_writesize(pThis, pEnd),
+                       (int)(pRequest->length - pRequest->actual));
+
+       if (wCsrVal & MGC_M_TXCSR_TXPKTRDY) {
+               DBG(5, "%s old packet still ready , txcsr %03x\n",
+                               pEnd->end_point.name, wCsrVal);
+               return;
+       }
+
+       if (wCsrVal & MGC_M_TXCSR_P_SENDSTALL) {
+               DBG(5, "%s stalling, txcsr %03x\n",
+                               pEnd->end_point.name, wCsrVal);
+               return;
+       }
+
+       DBG(4, "hw_ep%d, maxpacket %d, fifo count %d, txcsr %03x\n",
+                       bEnd, pEnd->wPacketSize, wFifoCount,
+                       wCsrVal);
+
+#ifndef        CONFIG_USB_INVENTRA_FIFO
+       if (is_dma_capable() && pEnd->dma) {
+               struct dma_controller   *c = pThis->pDmaController;
+
+               use_dma = (pRequest->dma != DMA_ADDR_INVALID);
+
+               /* MGC_M_TXCSR_P_ISO is still set correctly */
+
+#ifdef CONFIG_USB_INVENTRA_DMA
+               {
+                       size_t request_size;
+
+                       /* setup DMA, then program endpoint CSR */
+                       request_size = min(pRequest->length,
+                                               pEnd->dma->dwMaxLength);
+                       if (request_size <= pEnd->wPacketSize)
+                               pEnd->dma->bDesiredMode = 0;
+                       else
+                               pEnd->dma->bDesiredMode = 1;
+
+                       use_dma = use_dma && c->channel_program(
+                                       pEnd->dma, pEnd->wPacketSize,
+                                       pEnd->dma->bDesiredMode,
+                                       pRequest->dma, request_size);
+                       if (use_dma) {
+                               if (pEnd->dma->bDesiredMode == 0) {
+                                       /* ASSERT: DMAENAB is clear */
+                                       wCsrVal &= ~(MGC_M_TXCSR_AUTOSET |
+                                                       MGC_M_TXCSR_DMAMODE);
+                                       wCsrVal |= (MGC_M_TXCSR_DMAENAB |
+                                                       MGC_M_TXCSR_MODE);
+                                       // against programming guide
+                               }
+                               else
+                                       wCsrVal |= (MGC_M_TXCSR_AUTOSET
+                                                       | MGC_M_TXCSR_DMAENAB
+                                                       | MGC_M_TXCSR_DMAMODE
+                                                       | MGC_M_TXCSR_MODE);
+
+                               wCsrVal &= ~MGC_M_TXCSR_P_UNDERRUN;
+                               musb_writew(epio, MGC_O_HDRC_TXCSR, wCsrVal);
+                       }
+               }
+
+#elif defined(CONFIG_USB_TI_CPPI_DMA)
+               /* program endpoint CSR first, then setup DMA */
+               wCsrVal &= ~(MGC_M_TXCSR_AUTOSET
+                               | MGC_M_TXCSR_DMAMODE
+                               | MGC_M_TXCSR_P_UNDERRUN
+                               | MGC_M_TXCSR_TXPKTRDY);
+               wCsrVal |= MGC_M_TXCSR_MODE | MGC_M_TXCSR_DMAENAB;
+               musb_writew(epio, MGC_O_HDRC_TXCSR,
+                       (MGC_M_TXCSR_P_WZC_BITS & ~MGC_M_TXCSR_P_UNDERRUN)
+                               | wCsrVal);
+
+               /* ensure writebuffer is empty */
+               wCsrVal = musb_readw(epio, MGC_O_HDRC_TXCSR);
+
+               /* NOTE host side sets DMAENAB later than this; both are
+                * OK since the transfer dma glue (between CPPI and Mentor
+                * fifos) just tells CPPI it could start.  Data only moves
+                * to the USB TX fifo when both fifos are ready.
+                */
+
+               /* "mode" is irrelevant here; handle terminating ZLPs like
+                * PIO does, since the hardware RNDIS mode seems unreliable
+                * except for the last-packet-is-already-short case.
+                */
+               use_dma = use_dma && c->channel_program(
+                               pEnd->dma, pEnd->wPacketSize,
+                               0,
+                               pRequest->dma,
+                               pRequest->length);
+               if (!use_dma) {
+                       c->channel_release(pEnd->dma);
+                       pEnd->dma = NULL;
+                       /* ASSERT: DMAENAB clear */
+                       wCsrVal &= ~(MGC_M_TXCSR_DMAMODE | MGC_M_TXCSR_MODE);
+                       /* invariant: prequest->buf is non-null */
+               }
+#elif defined(CONFIG_USB_TUSB_OMAP_DMA)
+               use_dma = use_dma && c->channel_program(
+                               pEnd->dma, pEnd->wPacketSize,
+                               pRequest->zero,
+                               pRequest->dma,
+                               pRequest->length);
+#endif
+       }
+#endif
+
+       if (!use_dma) {
+               musb_write_fifo(pEnd->hw_ep, wFifoCount,
+                               (u8 *) (pRequest->buf + pRequest->actual));
+               pRequest->actual += wFifoCount;
+               wCsrVal |= MGC_M_TXCSR_TXPKTRDY;
+               wCsrVal &= ~MGC_M_TXCSR_P_UNDERRUN;
+               musb_writew(epio, MGC_O_HDRC_TXCSR, wCsrVal);
+       }
+
+       /* host may already have the data when this message shows... */
+       DBG(3, "%s TX/IN %s len %d/%d, txcsr %04x, fifo %d/%d\n",
+                       pEnd->end_point.name, use_dma ? "dma" : "pio",
+                       pRequest->actual, pRequest->length,
+                       musb_readw(epio, MGC_O_HDRC_TXCSR),
+                       wFifoCount,
+                       musb_readw(epio, MGC_O_HDRC_TXMAXP));
+}
+
+/*
+ * FIFO state update (e.g. data ready).
+ * Called from IRQ,  with controller locked.
+ */
+void musb_g_tx(struct musb *pThis, u8 bEnd)
+{
+       u16                     wCsrVal;
+       struct usb_request      *pRequest;
+       u8 __iomem              *pBase = pThis->pRegs;
+       struct musb_ep          *pEnd = &pThis->aLocalEnd[bEnd].ep_in;
+       void __iomem            *epio = pThis->aLocalEnd[bEnd].regs;
+       struct dma_channel      *dma;
+
+       MGC_SelectEnd(pBase, bEnd);
+       pRequest = next_request(pEnd);
+
+       wCsrVal = musb_readw(epio, MGC_O_HDRC_TXCSR);
+       DBG(4, "<== %s, txcsr %04x\n", pEnd->end_point.name, wCsrVal);
+
+       dma = is_dma_capable() ? pEnd->dma : NULL;
+       do {
+               /* REVISIT for high bandwidth, MGC_M_TXCSR_P_INCOMPTX
+                * probably rates reporting as a host error
+                */
+               if (wCsrVal & MGC_M_TXCSR_P_SENTSTALL) {
+                       wCsrVal |= MGC_M_TXCSR_P_WZC_BITS;
+                       wCsrVal &= ~MGC_M_TXCSR_P_SENTSTALL;
+                       musb_writew(epio, MGC_O_HDRC_TXCSR, wCsrVal);
+                       if (dma_channel_status(dma) == MGC_DMA_STATUS_BUSY) {
+                               dma->bStatus = MGC_DMA_STATUS_CORE_ABORT;
+                               pThis->pDmaController->channel_abort(dma);
+                       }
+
+                       if (pRequest)
+                               musb_g_giveback(pEnd, pRequest, -EPIPE);
+
+                       break;
+               }
+
+               if (wCsrVal & MGC_M_TXCSR_P_UNDERRUN) {
+                       /* we NAKed, no big deal ... little reason to care */
+                       wCsrVal |= MGC_M_TXCSR_P_WZC_BITS;
+                       wCsrVal &= ~(MGC_M_TXCSR_P_UNDERRUN
+                                       | MGC_M_TXCSR_TXPKTRDY);
+                       musb_writew(epio, MGC_O_HDRC_TXCSR, wCsrVal);
+                       DBG(20, "underrun on ep%d, req %p\n", bEnd, pRequest);
+               }
+
+               if (dma_channel_status(dma) == MGC_DMA_STATUS_BUSY) {
+                       /* SHOULD NOT HAPPEN ... has with cppi though, after
+                        * changing SENDSTALL (and other cases); harmless?
+                        */
+                       DBG(5, "%s dma still busy?\n", pEnd->end_point.name);
+                       break;
+               }
+
+               if (pRequest) {
+                       u8      is_dma = 0;
+
+                       if (dma && (wCsrVal & MGC_M_TXCSR_DMAENAB)) {
+                               is_dma = 1;
+                               wCsrVal |= MGC_M_TXCSR_P_WZC_BITS;
+                               wCsrVal &= ~(MGC_M_TXCSR_DMAENAB
+                                               | MGC_M_TXCSR_P_UNDERRUN
+                                               | MGC_M_TXCSR_TXPKTRDY);
+                               musb_writew(epio, MGC_O_HDRC_TXCSR, wCsrVal);
+                               /* ensure writebuffer is empty */
+                               wCsrVal = musb_readw(epio, MGC_O_HDRC_TXCSR);
+                               DBG(4, "TXCSR%d %04x, dma off, "
+                                               "len %Zd, req %p\n",
+                                       bEnd, wCsrVal,
+                                       pEnd->dma->dwActualLength,
+                                       pRequest);
+                               pRequest->actual += pEnd->dma->dwActualLength;
+                       }
+
+                       if (is_dma || pRequest->actual == pRequest->length) {
+
+                               /* First, maybe a terminating short packet.
+                                * Some DMA engines might handle this by
+                                * themselves.
+                                */
+                               if ((pRequest->zero
+                                               && pRequest->length
+                                               && (pRequest->length
+                                                       % pEnd->wPacketSize)
+                                                       == 0)
+#ifdef CONFIG_USB_INVENTRA_DMA
+                                       || (is_dma &&
+                                               (pRequest->actual
+                                                       < pEnd->wPacketSize))
+#endif
+                               ) {
+                                       /* on dma completion, fifo may not
+                                        * be available yet ...
+                                        */
+                                       if (wCsrVal & MGC_M_TXCSR_TXPKTRDY)
+                                               break;
+
+                                       DBG(4, "sending zero pkt\n");
+                                       musb_writew(epio, MGC_O_HDRC_TXCSR,
+                                                       MGC_M_TXCSR_MODE
+                                                       | MGC_M_TXCSR_TXPKTRDY);
+                               }
+
+                               /* ... or if not, then complete it */
+                               musb_g_giveback(pEnd, pRequest, 0);
+
+                               /* kickstart next transfer if appropriate;
+                                * the packet that just completed might not
+                                * be transmitted for hours or days.
+                                * REVISIT for double buffering...
+                                * FIXME revisit for stalls too...
+                                */
+                               MGC_SelectEnd(pBase, bEnd);
+                               wCsrVal = musb_readw(epio, MGC_O_HDRC_TXCSR);
+                               if (wCsrVal & MGC_M_TXCSR_FIFONOTEMPTY)
+                                       break;
+                               pRequest = pEnd->desc
+                                               ? next_request(pEnd)
+                                               : NULL;
+                               if (!pRequest) {
+                                       DBG(4, "%s idle now\n",
+                                                       pEnd->end_point.name);
+                                       break;
+                               }
+                       }
+
+                       txstate(pThis, to_musb_request(pRequest));
+               }
+
+       } while (0);
+}
+
+/* ------------------------------------------------------------ */
+
+#ifdef CONFIG_USB_INVENTRA_DMA
+
+/* Peripheral rx (OUT) using Mentor DMA works as follows:
+       - Only mode 0 is used.
+
+       - Request is queued by the gadget class driver.
+               -> if queue was previously empty, rxstate()
+
+       - Host sends OUT token which causes an endpoint interrupt
+         /\      -> RxReady
+         |           -> if request queued, call rxstate
+         |             /\      -> setup DMA
+         |             |            -> DMA interrupt on completion
+         |             |               -> RxReady
+         |             |                     -> stop DMA
+         |             |                     -> ack the read
+         |             |                     -> if data recd = max expected
+         |             |                               by the request, or host
+         |             |                               sent a short packet,
+         |             |                               complete the request,
+         |             |                               and start the next one.
+         |             |_____________________________________|
+         |                                      else just wait for the host
+         |                                         to send the next OUT token.
+         |__________________________________________________|
+
+ * Non-Mentor DMA engines can of course work differently.
+ */
+
+#endif
+
+/*
+ * Context: controller locked, IRQs blocked, endpoint selected
+ */
+static void rxstate(struct musb *pThis, struct musb_request *req)
+{
+       u16                     wCsrVal = 0;
+       const u8                bEnd = req->bEnd;
+       struct usb_request      *pRequest = &req->request;
+       struct musb_ep          *pEnd = &pThis->aLocalEnd[bEnd].ep_out;
+       void __iomem            *epio = pThis->aLocalEnd[bEnd].regs;
+       u16                     wFifoCount = 0;
+       u16                     wCount = pEnd->wPacketSize;
+
+       wCsrVal = musb_readw(epio, MGC_O_HDRC_RXCSR);
+
+       if (is_cppi_enabled() && pEnd->dma) {
+               struct dma_controller   *c = pThis->pDmaController;
+               struct dma_channel      *channel = pEnd->dma;
+
+               /* NOTE:  CPPI won't actually stop advancing the DMA
+                * queue after short packet transfers, so this is almost
+                * always going to run as IRQ-per-packet DMA so that
+                * faults will be handled correctly.
+                */
+               if (c->channel_program(channel,
+                               pEnd->wPacketSize,
+                               !pRequest->short_not_ok,
+                               pRequest->dma + pRequest->actual,
+                               pRequest->length - pRequest->actual)) {
+
+                       /* make sure that if an rxpkt arrived after the irq,
+                        * the cppi engine will be ready to take it as soon
+                        * as DMA is enabled
+                        */
+                       wCsrVal &= ~(MGC_M_RXCSR_AUTOCLEAR
+                                       | MGC_M_RXCSR_DMAMODE);
+                       wCsrVal |= MGC_M_RXCSR_DMAENAB | MGC_M_RXCSR_P_WZC_BITS;
+                       musb_writew(epio, MGC_O_HDRC_RXCSR, wCsrVal);
+                       return;
+               }
+       }
+
+       if (wCsrVal & MGC_M_RXCSR_RXPKTRDY) {
+               wCount = musb_readw(epio, MGC_O_HDRC_RXCOUNT);
+               if (pRequest->actual < pRequest->length) {
+#ifdef CONFIG_USB_INVENTRA_DMA
+                       if (is_dma_capable() && pEnd->dma) {
+                               struct dma_controller   *c;
+                               struct dma_channel      *channel;
+                               int                     use_dma = 0;
+
+                               c = pThis->pDmaController;
+                               channel = pEnd->dma;
+
+       /* We use DMA Req mode 0 in RxCsr, and DMA controller operates in
+        * mode 0 only. So we do not get endpoint interrupts due to DMA
+        * completion. We only get interrupts from DMA controller.
+        *
+        * We could operate in DMA mode 1 if we knew the size of the tranfer
+        * in advance. For mass storage class, request->length = what the host
+        * sends, so that'd work.  But for pretty much everything else,
+        * request->length is routinely more than what the host sends. For
+        * most these gadgets, end of is signified either by a short packet,
+        * or filling the last byte of the buffer.  (Sending extra data in
+        * that last pckate should trigger an overflow fault.)  But in mode 1,
+        * we don't get DMA completion interrrupt for short packets.
+        *
+        * Theoretically, we could enable DMAReq interrupt (RxCsr_DMAMODE = 1),
+        * to get endpoint interrupt on every DMA req, but that didn't seem
+        * to work reliably.
+        *
+        * REVISIT an updated g_file_storage can set req->short_not_ok, which
+        * then becomes usable as a runtime "use mode 1" hint...
+        */
+
+                               wCsrVal |= MGC_M_RXCSR_DMAENAB;
+#ifdef USE_MODE1
+                               wCsrVal |= MGC_M_RXCSR_AUTOCLEAR;
+//                             wCsrVal |= MGC_M_RXCSR_DMAMODE;
+
+                               /* this special sequence (enabling and then
+                                  disabling MGC_M_RXCSR_DMAMODE) is required
+                                  to get DMAReq to activate
+                                */
+                               musb_writew(epio, MGC_O_HDRC_RXCSR,
+                                       wCsrVal | MGC_M_RXCSR_DMAMODE);
+#endif
+                               musb_writew(epio, MGC_O_HDRC_RXCSR,
+                                               wCsrVal);
+
+                               if (pRequest->actual < pRequest->length) {
+                                       int transfer_size = 0;
+#ifdef USE_MODE1
+                                       transfer_size = min(pRequest->length,
+                                                       channel->dwMaxLength);
+#else
+                                       transfer_size = wCount;
+#endif
+                                       if (transfer_size <= pEnd->wPacketSize)
+                                               pEnd->dma->bDesiredMode = 0;
+                                       else
+                                               pEnd->dma->bDesiredMode = 1;
+
+                                       use_dma = c->channel_program(
+                                                       channel,
+                                                       pEnd->wPacketSize,
+                                                       channel->bDesiredMode,
+                                                       pRequest->dma
+                                                       + pRequest->actual,
+                                                       transfer_size);
+                               }
+
+                               if (use_dma)
+                                       return;
+                       }
+#endif /* Mentor's USB */
+
+                       wFifoCount = pRequest->length - pRequest->actual;
+                       DBG(3, "%s OUT/RX pio fifo %d/%d, maxpacket %d\n",
+                                       pEnd->end_point.name,
+                                       wCount, wFifoCount,
+                                       pEnd->wPacketSize);
+
+                       wFifoCount = min(wCount, wFifoCount);
+
+#ifdef CONFIG_USB_TUSB_OMAP_DMA
+                       if (tusb_dma_omap() && pEnd->dma) {
+                               struct dma_controller *c = pThis->pDmaController;
+                               struct dma_channel *channel = pEnd->dma;
+                               u32 dma_addr = pRequest->dma + pRequest->actual;
+                               int ret;
+
+                               ret = c->channel_program(channel,
+                                               pEnd->wPacketSize,
+                                               channel->bDesiredMode,
+                                               dma_addr,
+                                               wFifoCount);
+                               if (ret == TRUE)
+                                       return;
+                       }
+#endif
+
+                       musb_read_fifo(pEnd->hw_ep, wFifoCount, (u8 *)
+                                       (pRequest->buf + pRequest->actual));
+                       pRequest->actual += wFifoCount;
+
+                       /* REVISIT if we left anything in the fifo, flush
+                        * it and report -EOVERFLOW
+                        */
+
+                       /* ack the read! */
+                       wCsrVal |= MGC_M_RXCSR_P_WZC_BITS;
+                       wCsrVal &= ~MGC_M_RXCSR_RXPKTRDY;
+                       musb_writew(epio, MGC_O_HDRC_RXCSR, wCsrVal);
+               }
+       }
+
+       /* reach the end or short packet detected */
+       if (pRequest->actual == pRequest->length || wCount < pEnd->wPacketSize)
+               musb_g_giveback(pEnd, pRequest, 0);
+}
+
+/*
+ * Data ready for a request; called from IRQ
+ * @param pThis the controller
+ * @param req the request
+ */
+void musb_g_rx(struct musb *pThis, u8 bEnd)
+{
+       u16                     wCsrVal;
+       struct usb_request      *pRequest;
+       void __iomem            *pBase = pThis->pRegs;
+       struct musb_ep          *pEnd = &pThis->aLocalEnd[bEnd].ep_out;
+       void __iomem            *epio = pThis->aLocalEnd[bEnd].regs;
+       struct dma_channel      *dma;
+
+       MGC_SelectEnd(pBase, bEnd);
+
+       pRequest = next_request(pEnd);
+
+       wCsrVal = musb_readw(epio, MGC_O_HDRC_RXCSR);
+       dma = is_dma_capable() ? pEnd->dma : NULL;
+
+       DBG(4, "<== %s, rxcsr %04x%s %p\n", pEnd->end_point.name,
+                       wCsrVal, dma ? " (dma)" : "", pRequest);
+
+       if (wCsrVal & MGC_M_RXCSR_P_SENTSTALL) {
+               if (dma_channel_status(dma) == MGC_DMA_STATUS_BUSY) {
+                       dma->bStatus = MGC_DMA_STATUS_CORE_ABORT;
+                       (void) pThis->pDmaController->channel_abort(dma);
+                       pRequest->actual += pEnd->dma->dwActualLength;
+               }
+
+               wCsrVal |= MGC_M_RXCSR_P_WZC_BITS;
+               wCsrVal &= ~MGC_M_RXCSR_P_SENTSTALL;
+               musb_writew(epio, MGC_O_HDRC_RXCSR, wCsrVal);
+
+               if (pRequest)
+                       musb_g_giveback(pEnd, pRequest, -EPIPE);
+               goto done;
+       }
+
+       if (wCsrVal & MGC_M_RXCSR_P_OVERRUN) {
+               // wCsrVal |= MGC_M_RXCSR_P_WZC_BITS;
+               wCsrVal &= ~MGC_M_RXCSR_P_OVERRUN;
+               musb_writew(epio, MGC_O_HDRC_RXCSR, wCsrVal);
+
+               DBG(3, "%s iso overrun on %p\n", pEnd->name, pRequest);
+               if (pRequest && pRequest->status == -EINPROGRESS)
+                       pRequest->status = -EOVERFLOW;
+       }
+       if (wCsrVal & MGC_M_RXCSR_INCOMPRX) {
+               /* REVISIT not necessarily an error */
+               DBG(4, "%s, incomprx\n", pEnd->end_point.name);
+       }
+
+       if (dma_channel_status(dma) == MGC_DMA_STATUS_BUSY) {
+               /* "should not happen"; likely RXPKTRDY pending for DMA */
+               DBG((wCsrVal & MGC_M_RXCSR_DMAENAB) ? 4 : 1,
+                       "%s busy, csr %04x\n",
+                       pEnd->end_point.name, wCsrVal);
+               goto done;
+       }
+
+       if (dma && (wCsrVal & MGC_M_RXCSR_DMAENAB)) {
+               wCsrVal &= ~(MGC_M_RXCSR_AUTOCLEAR
+                               | MGC_M_RXCSR_DMAENAB
+                               | MGC_M_RXCSR_DMAMODE);
+               musb_writew(epio, MGC_O_HDRC_RXCSR,
+                       MGC_M_RXCSR_P_WZC_BITS | wCsrVal);
+
+               pRequest->actual += pEnd->dma->dwActualLength;
+
+               DBG(4, "RXCSR%d %04x, dma off, %04x, len %Zd, req %p\n",
+                       bEnd, wCsrVal,
+                       musb_readw(epio, MGC_O_HDRC_RXCSR),
+                       pEnd->dma->dwActualLength, pRequest);
+
+#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_TUSB_OMAP_DMA)
+               /* Autoclear doesn't clear RxPktRdy for short packets */
+               if ((dma->bDesiredMode == 0)
+                               || (dma->dwActualLength
+                                       & (pEnd->wPacketSize - 1))) {
+                       /* ack the read! */
+                       wCsrVal &= ~MGC_M_RXCSR_RXPKTRDY;
+                       musb_writew(epio, MGC_O_HDRC_RXCSR, wCsrVal);
+               }
+
+               /* incomplete, and not short? wait for next IN packet */
+                if ((pRequest->actual < pRequest->length)
+                               && (pEnd->dma->dwActualLength
+                                       == pEnd->wPacketSize))
+                       goto done;
+#endif
+               musb_g_giveback(pEnd, pRequest, 0);
+
+               pRequest = next_request(pEnd);
+               if (!pRequest)
+                       goto done;
+
+               /* don't start more i/o till the stall clears */
+               MGC_SelectEnd(pBase, bEnd);
+               wCsrVal = musb_readw(epio, MGC_O_HDRC_RXCSR);
+               if (wCsrVal & MGC_M_RXCSR_P_SENDSTALL)
+                       goto done;
+       }
+
+
+       /* analyze request if the ep is hot */
+       if (pRequest)
+               rxstate(pThis, to_musb_request(pRequest));
+       else
+               DBG(3, "packet waiting for %s%s request\n",
+                               pEnd->desc ? "" : "inactive ",
+                               pEnd->end_point.name);
+
+done:
+       return;
+}
+
+/* ------------------------------------------------------------ */
+
+static int musb_gadget_enable(struct usb_ep *ep,
+                       const struct usb_endpoint_descriptor *desc)
+{
+       unsigned long           flags;
+       struct musb_ep          *pEnd;
+       struct musb_hw_ep       *hw_ep;
+       void __iomem            *regs;
+       struct musb     *pThis;
+       void __iomem    *pBase;
+       u8              bEnd;
+       u16             csr;
+       unsigned        tmp;
+       int             status = -EINVAL;
+
+       if (!ep || !desc)
+               return -EINVAL;
+
+       pEnd = to_musb_ep(ep);
+       hw_ep = pEnd->hw_ep;
+       regs = hw_ep->regs;
+       pThis = pEnd->pThis;
+       pBase = pThis->pRegs;
+       bEnd = pEnd->bEndNumber;
+
+       spin_lock_irqsave(&pThis->Lock, flags);
+
+       if (pEnd->desc) {
+               status = -EBUSY;
+               goto fail;
+       }
+       pEnd->type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+
+       /* check direction and (later) maxpacket size against endpoint */
+       if ((desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) != bEnd)
+               goto fail;
+
+       /* REVISIT this rules out high bandwidth periodic transfers */
+       tmp = le16_to_cpu(desc->wMaxPacketSize);
+       if (tmp & ~0x07ff)
+               goto fail;
+       pEnd->wPacketSize = tmp;
+
+       /* enable the interrupts for the endpoint, set the endpoint
+        * packet size (or fail), set the mode, clear the fifo
+        */
+       MGC_SelectEnd(pBase, bEnd);
+       if (desc->bEndpointAddress & USB_DIR_IN) {
+               u16 wIntrTxE = musb_readw(pBase, MGC_O_HDRC_INTRTXE);
+
+               if (hw_ep->bIsSharedFifo)
+                       pEnd->is_in = 1;
+               if (!pEnd->is_in)
+                       goto fail;
+               if (tmp > hw_ep->wMaxPacketSizeTx)
+                       goto fail;
+
+               wIntrTxE |= (1 << bEnd);
+               musb_writew(pBase, MGC_O_HDRC_INTRTXE, wIntrTxE);
+
+               /* REVISIT if can_bulk_split(), use by updating "tmp";
+                * likewise high bandwidth periodic tx
+                */
+               musb_writew(regs, MGC_O_HDRC_TXMAXP, tmp);
+
+               csr = MGC_M_TXCSR_MODE | MGC_M_TXCSR_CLRDATATOG;
+               if (musb_readw(regs, MGC_O_HDRC_TXCSR)
+                               & MGC_M_TXCSR_FIFONOTEMPTY)
+                       csr |= MGC_M_TXCSR_FLUSHFIFO;
+               if (pEnd->type == USB_ENDPOINT_XFER_ISOC)
+                       csr |= MGC_M_TXCSR_P_ISO;
+
+               /* set twice in case of double buffering */
+               musb_writew(regs, MGC_O_HDRC_TXCSR, csr);
+               /* REVISIT may be inappropriate w/o FIFONOTEMPTY ... */
+               musb_writew(regs, MGC_O_HDRC_TXCSR, csr);
+
+       } else {
+               u16 wIntrRxE = musb_readw(pBase, MGC_O_HDRC_INTRRXE);
+
+               if (hw_ep->bIsSharedFifo)
+                       pEnd->is_in = 0;
+               if (pEnd->is_in)
+                       goto fail;
+               if (tmp > hw_ep->wMaxPacketSizeRx)
+                       goto fail;
+
+               wIntrRxE |= (1 << bEnd);
+               musb_writew(pBase, MGC_O_HDRC_INTRRXE, wIntrRxE);
+
+               /* REVISIT if can_bulk_combine() use by updating "tmp"
+                * likewise high bandwidth periodic rx
+                */
+               musb_writew(regs, MGC_O_HDRC_RXMAXP, tmp);
+
+               /* force shared fifo to OUT-only mode */
+               if (hw_ep->bIsSharedFifo) {
+                       csr = musb_readw(regs, MGC_O_HDRC_TXCSR);
+                       csr &= ~(MGC_M_TXCSR_MODE | MGC_M_TXCSR_TXPKTRDY);
+                       musb_writew(regs, MGC_O_HDRC_TXCSR, csr);
+               }
+
+               csr = MGC_M_RXCSR_FLUSHFIFO | MGC_M_RXCSR_CLRDATATOG;
+               if (pEnd->type == USB_ENDPOINT_XFER_ISOC)
+                       csr |= MGC_M_RXCSR_P_ISO;
+               else if (pEnd->type == USB_ENDPOINT_XFER_INT)
+                       csr |= MGC_M_RXCSR_DISNYET;
+
+               /* set twice in case of double buffering */
+               musb_writew(regs, MGC_O_HDRC_RXCSR, csr);
+               musb_writew(regs, MGC_O_HDRC_RXCSR, csr);
+       }
+
+       /* NOTE:  all the I/O code _should_ work fine without DMA, in case
+        * for some reason you run out of channels here.
+        */
+       if (is_dma_capable() && pThis->pDmaController) {
+               struct dma_controller   *c = pThis->pDmaController;
+
+               pEnd->dma = c->channel_alloc(c, hw_ep,
+                               (desc->bEndpointAddress & USB_DIR_IN));
+       } else
+               pEnd->dma = NULL;
+
+       pEnd->desc = desc;
+       pEnd->busy = 0;
+       status = 0;
+
+       pr_debug("%s periph: enabled %s for %s %s, %smaxpacket %d\n",
+                       musb_driver_name, pEnd->end_point.name,
+                       ({ char *s; switch (pEnd->type) {
+                       case USB_ENDPOINT_XFER_BULK:    s = "bulk"; break;
+                       case USB_ENDPOINT_XFER_INT:     s = "int"; break;
+                       default:                        s = "iso"; break;
+                       }; s; }),
+                       pEnd->is_in ? "IN" : "OUT",
+                       pEnd->dma ? "dma, " : "",
+                       pEnd->wPacketSize);
+
+       schedule_work(&pThis->irq_work);
+
+fail:
+       spin_unlock_irqrestore(&pThis->Lock, flags);
+       return status;
+}
+
+/*
+ * Disable an endpoint flushing all requests queued.
+ */
+static int musb_gadget_disable(struct usb_ep *ep)
+{
+       unsigned long   flags;
+       struct musb     *pThis;
+       u8              bEnd;
+       struct musb_ep  *pEnd;
+       void __iomem    *epio;
+       int             status = 0;
+
+       pEnd = to_musb_ep(ep);
+       pThis = pEnd->pThis;
+       bEnd = pEnd->bEndNumber;
+       epio = pThis->aLocalEnd[bEnd].regs;
+
+       spin_lock_irqsave(&pThis->Lock, flags);
+       MGC_SelectEnd(pThis->pRegs, bEnd);
+
+       /* zero the endpoint sizes */
+       if (pEnd->is_in) {
+               u16 wIntrTxE = musb_readw(pThis->pRegs, MGC_O_HDRC_INTRTXE);
+               wIntrTxE &= ~(1 << bEnd);
+               musb_writew(pThis->pRegs, MGC_O_HDRC_INTRTXE, wIntrTxE);
+               musb_writew(epio, MGC_O_HDRC_TXMAXP, 0);
+       } else {
+               u16 wIntrRxE = musb_readw(pThis->pRegs, MGC_O_HDRC_INTRRXE);
+               wIntrRxE &= ~(1 << bEnd);
+               musb_writew(pThis->pRegs, MGC_O_HDRC_INTRRXE, wIntrRxE);
+               musb_writew(epio, MGC_O_HDRC_RXMAXP, 0);
+       }
+
+       pEnd->desc = NULL;
+
+       /* abort all pending DMA and requests */
+       nuke(pEnd, -ESHUTDOWN);
+
+       schedule_work(&pThis->irq_work);
+
+       spin_unlock_irqrestore(&(pThis->Lock), flags);
+
+       DBG(2, "%s\n", pEnd->end_point.name);
+
+       return status;
+}
+
+/*
+ * Allocate a request for an endpoint.
+ * Reused by ep0 code.
+ */
+struct usb_request *musb_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
+{
+       struct musb_ep          *musb_ep = to_musb_ep(ep);
+       struct musb_request     *pRequest = NULL;
+
+       pRequest = kzalloc(sizeof *pRequest, gfp_flags);
+       if (pRequest) {
+               INIT_LIST_HEAD(&pRequest->request.list);
+               pRequest->request.dma = DMA_ADDR_INVALID;
+               pRequest->bEnd = musb_ep->bEndNumber;
+               pRequest->ep = musb_ep;
+       }
+
+       return &pRequest->request;
+}
+
+/*
+ * Free a request
+ * Reused by ep0 code.
+ */
+void musb_free_request(struct usb_ep *ep, struct usb_request *req)
+{
+       kfree(to_musb_request(req));
+}
+
+/*
+ * dma-coherent memory allocation (for dma-capable endpoints)
+ *
+ * NOTE: the dma_*_coherent() API calls suck; most implementations are
+ * (a) page-oriented, so small buffers lose big, and (b) asymmetric with
+ * respect to calls with irqs disabled:  alloc is safe, free is not.
+ */
+static void *musb_gadget_alloc_buffer(struct usb_ep *ep, unsigned bytes,
+                       dma_addr_t * dma, gfp_t gfp_flags)
+{
+       struct musb_ep *musb_ep = to_musb_ep(ep);
+
+       return dma_alloc_coherent(musb_ep->pThis->controller,
+                       bytes, dma, gfp_flags);
+}
+
+static DEFINE_SPINLOCK(buflock);
+static LIST_HEAD(buffers);
+
+struct free_record {
+       struct list_head        list;
+       struct device           *dev;
+       unsigned                bytes;
+       dma_addr_t              dma;
+};
+
+static void do_free(unsigned long ignored)
+{
+       spin_lock_irq(&buflock);
+       while (!list_empty(&buffers)) {
+               struct free_record      *buf;
+
+               buf = list_entry(buffers.next, struct free_record, list);
+               list_del(&buf->list);
+               spin_unlock_irq(&buflock);
+
+               dma_free_coherent(buf->dev, buf->bytes, buf, buf->dma);
+
+               spin_lock_irq(&buflock);
+       }
+       spin_unlock_irq(&buflock);
+}
+
+static DECLARE_TASKLET(deferred_free, do_free, 0);
+
+static void musb_gadget_free_buffer(struct usb_ep *ep,
+               void *address, dma_addr_t dma, unsigned bytes)
+{
+       struct musb_ep          *musb_ep = to_musb_ep(ep);
+       struct free_record      *buf = address;
+       unsigned long           flags;
+
+       buf->dev = musb_ep->pThis->controller;
+       buf->bytes = bytes;
+       buf->dma = dma;
+
+       spin_lock_irqsave(&buflock, flags);
+       list_add_tail(&buf->list, &buffers);
+       tasklet_schedule(&deferred_free);
+       spin_unlock_irqrestore(&buflock, flags);
+}
+
+/*
+ * Context: controller locked, IRQs blocked.
+ */
+static void musb_ep_restart(struct musb *pThis, struct musb_request *req)
+{
+       DBG(3, "<== %s request %p len %u on hw_ep%d\n",
+               req->bTx ? "TX/IN" : "RX/OUT",
+               &req->request, req->request.length, req->bEnd);
+
+       MGC_SelectEnd(pThis->pRegs, req->bEnd);
+       if (req->bTx)
+               txstate(pThis, req);
+       else
+               rxstate(pThis, req);
+}
+
+static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req,
+                       gfp_t gfp_flags)
+{
+       struct musb_ep          *pEnd;
+       struct musb_request     *pRequest;
+       struct musb             *musb;
+       int                     status = 0;
+       unsigned long           lockflags;
+
+       if (!ep || !req)
+               return -EINVAL;
+
+       pEnd = to_musb_ep(ep);
+       musb = pEnd->pThis;
+
+       pRequest = to_musb_request(req);
+       pRequest->musb = musb;
+
+       if (pRequest->ep != pEnd)
+               return -EINVAL;
+
+       DBG(4, "<== to %s request=%p\n", ep->name, req);
+
+       /* request is mine now... */
+       pRequest->request.actual = 0;
+       pRequest->request.status = -EINPROGRESS;
+       pRequest->bEnd = pEnd->bEndNumber;
+       pRequest->bTx = pEnd->is_in;
+
+       if (is_dma_capable() && pEnd->dma) {
+               if (pRequest->request.dma == DMA_ADDR_INVALID) {
+                       pRequest->request.dma = dma_map_single(
+                                       musb->controller,
+                                       pRequest->request.buf,
+                                       pRequest->request.length,
+                                       pRequest->bTx
+                                               ? DMA_TO_DEVICE
+                                               : DMA_FROM_DEVICE);
+                       pRequest->mapped = 1;
+               } else {
+                       dma_sync_single_for_device(musb->controller,
+                                       pRequest->request.dma,
+                                       pRequest->request.length,
+                                       pRequest->bTx
+                                               ? DMA_TO_DEVICE
+                                               : DMA_FROM_DEVICE);
+                       pRequest->mapped = 0;
+               }
+       } else if (!req->buf) {
+               return -ENODATA;
+       } else
+               pRequest->mapped = 0;
+
+       spin_lock_irqsave(&musb->Lock, lockflags);
+
+       /* don't queue if the ep is down */
+       if (!pEnd->desc) {
+               DBG(4, "req %p queued to %s while ep %s\n",
+                               req, ep->name, "disabled");
+               status = -ESHUTDOWN;
+               goto cleanup;
+       }
+
+       /* add pRequest to the list */
+       list_add_tail(&(pRequest->request.list), &(pEnd->req_list));
+
+       /* it this is the head of the queue, start i/o ... */
+       if (!pEnd->busy && &pRequest->request.list == pEnd->req_list.next)
+               musb_ep_restart(musb, pRequest);
+
+cleanup:
+       spin_unlock_irqrestore(&musb->Lock, lockflags);
+       return status;
+}
+
+static int musb_gadget_dequeue(struct usb_ep *ep, struct usb_request *pRequest)
+{
+       struct musb_ep          *pEnd = to_musb_ep(ep);
+       struct usb_request      *r;
+       unsigned long           flags;
+       int                     status = 0;
+
+       if (!ep || !pRequest || to_musb_request(pRequest)->ep != pEnd)
+               return -EINVAL;
+
+       spin_lock_irqsave(&pEnd->pThis->Lock, flags);
+
+       list_for_each_entry(r, &pEnd->req_list, list) {
+               if (r == pRequest)
+                       break;
+       }
+       if (r != pRequest) {
+               DBG(3, "request %p not queued to %s\n", pRequest, ep->name);
+               status = -EINVAL;
+               goto done;
+       }
+
+       /* if the hardware doesn't have the request, easy ... */
+       if (pEnd->req_list.next != &pRequest->list || pEnd->busy)
+               musb_g_giveback(pEnd, pRequest, -ECONNRESET);
+
+       /* ... else abort the dma transfer ... */
+       else if (is_dma_capable() && pEnd->dma) {
+               struct dma_controller   *c = pEnd->pThis->pDmaController;
+
+               MGC_SelectEnd(pEnd->pThis->pRegs, pEnd->bEndNumber);
+               if (c->channel_abort)
+                       status = c->channel_abort(pEnd->dma);
+               else
+                       status = -EBUSY;
+               if (status == 0)
+                       musb_g_giveback(pEnd, pRequest, -ECONNRESET);
+       } else {
+               /* NOTE: by sticking to easily tested hardware/driver states,
+                * we leave counting of in-flight packets imprecise.
+                */
+               musb_g_giveback(pEnd, pRequest, -ECONNRESET);
+       }
+
+done:
+       spin_unlock_irqrestore(&pEnd->pThis->Lock, flags);
+       return status;
+}
+
+/*
+ * Set or clear the halt bit of an endpoint. A halted enpoint won't tx/rx any
+ * data but will queue requests.
+ *
+ * exported to ep0 code
+ */
+int musb_gadget_set_halt(struct usb_ep *ep, int value)
+{
+       struct musb_ep          *pEnd = to_musb_ep(ep);
+       u8                      bEnd = pEnd->bEndNumber;
+       struct musb             *pThis = pEnd->pThis;
+       void __iomem            *epio = pThis->aLocalEnd[bEnd].regs;
+       void __iomem            *pBase;
+       unsigned long           flags;
+       u16                     wCsr;
+       struct musb_request     *pRequest = NULL;
+       int                     status = 0;
+
+       pBase = pThis->pRegs;
+
+       spin_lock_irqsave(&pThis->Lock, flags);
+
+       if ((USB_ENDPOINT_XFER_ISOC == pEnd->type)) {
+               status = -EINVAL;
+               goto done;
+       }
+
+       MGC_SelectEnd(pBase, bEnd);
+
+       /* cannot portably stall with non-empty FIFO */
+       pRequest = to_musb_request(next_request(pEnd));
+       if (value && pEnd->is_in) {
+               wCsr = musb_readw(epio, MGC_O_HDRC_TXCSR);
+               if (wCsr & MGC_M_TXCSR_FIFONOTEMPTY) {
+                       DBG(3, "%s fifo busy, cannot halt\n", ep->name);
+                       spin_unlock_irqrestore(&pThis->Lock, flags);
+                       return -EAGAIN;
+               }
+
+       }
+
+       /* set/clear the stall and toggle bits */
+       DBG(2, "%s: %s stall\n", ep->name, value ? "set" : "clear");
+       if (pEnd->is_in) {
+               wCsr = musb_readw(epio, MGC_O_HDRC_TXCSR);
+               if (wCsr & MGC_M_TXCSR_FIFONOTEMPTY)
+                       wCsr |= MGC_M_TXCSR_FLUSHFIFO;
+               wCsr |= MGC_M_TXCSR_P_WZC_BITS
+                       | MGC_M_TXCSR_CLRDATATOG;
+               if (value)
+                       wCsr |= MGC_M_TXCSR_P_SENDSTALL;
+               else
+                       wCsr &= ~(MGC_M_TXCSR_P_SENDSTALL
+                               | MGC_M_TXCSR_P_SENTSTALL);
+               wCsr &= ~MGC_M_TXCSR_TXPKTRDY;
+               musb_writew(epio, MGC_O_HDRC_TXCSR, wCsr);
+       } else {
+               wCsr = musb_readw(epio, MGC_O_HDRC_RXCSR);
+               wCsr |= MGC_M_RXCSR_P_WZC_BITS
+                       | MGC_M_RXCSR_FLUSHFIFO
+                       | MGC_M_RXCSR_CLRDATATOG;
+               if (value)
+                       wCsr |= MGC_M_RXCSR_P_SENDSTALL;
+               else
+                       wCsr &= ~(MGC_M_RXCSR_P_SENDSTALL
+                               | MGC_M_RXCSR_P_SENTSTALL);
+               musb_writew(epio, MGC_O_HDRC_RXCSR, wCsr);
+       }
+
+done:
+
+       /* maybe start the first request in the queue */
+       if (!pEnd->busy && !value && pRequest) {
+               DBG(3, "restarting the request\n");
+               musb_ep_restart(pThis, pRequest);
+       }
+
+       spin_unlock_irqrestore(&pThis->Lock, flags);
+       return status;
+}
+
+static int musb_gadget_fifo_status(struct usb_ep *ep)
+{
+       struct musb_ep          *musb_ep = to_musb_ep(ep);
+       void __iomem            *epio = musb_ep->hw_ep->regs;
+       int                     retval = -EINVAL;
+
+       if (musb_ep->desc && !musb_ep->is_in) {
+               struct musb             *musb = musb_ep->pThis;
+               int                     bEnd = musb_ep->bEndNumber;
+               void __iomem            *mbase = musb->pRegs;
+               unsigned long           flags;
+
+               spin_lock_irqsave(&musb->Lock, flags);
+
+               MGC_SelectEnd(mbase, bEnd);
+               /* FIXME return zero unless RXPKTRDY is set */
+               retval = musb_readw(epio, MGC_O_HDRC_RXCOUNT);
+
+               spin_unlock_irqrestore(&musb->Lock, flags);
+       }
+       return retval;
+}
+
+static void musb_gadget_fifo_flush(struct usb_ep *ep)
+{
+       struct musb_ep  *musb_ep = to_musb_ep(ep);
+       struct musb     *musb = musb_ep->pThis;
+       u8              nEnd = musb_ep->bEndNumber;
+       void __iomem    *epio = musb->aLocalEnd[nEnd].regs;
+       void __iomem    *mbase;
+       unsigned long   flags;
+       u16             wCsr, wIntrTxE;
+
+       mbase = musb->pRegs;
+
+       spin_lock_irqsave(&musb->Lock, flags);
+       MGC_SelectEnd(mbase, (u8) nEnd);
+
+       /* disable interrupts */
+       wIntrTxE = musb_readw(mbase, MGC_O_HDRC_INTRTXE);
+       musb_writew(mbase, MGC_O_HDRC_INTRTXE, wIntrTxE & ~(1 << nEnd));
+
+       if (musb_ep->is_in) {
+               wCsr = musb_readw(epio, MGC_O_HDRC_TXCSR);
+               if (wCsr & MGC_M_TXCSR_FIFONOTEMPTY) {
+                       wCsr |= MGC_M_TXCSR_FLUSHFIFO | MGC_M_TXCSR_P_WZC_BITS;
+                       musb_writew(epio, MGC_O_HDRC_TXCSR, wCsr);
+                       /* REVISIT may be inappropriate w/o FIFONOTEMPTY ... */
+                       musb_writew(epio, MGC_O_HDRC_TXCSR, wCsr);
+               }
+       } else {
+               wCsr = musb_readw(epio, MGC_O_HDRC_RXCSR);
+               wCsr |= MGC_M_RXCSR_FLUSHFIFO | MGC_M_RXCSR_P_WZC_BITS;
+               musb_writew(epio, MGC_O_HDRC_RXCSR, wCsr);
+               musb_writew(epio, MGC_O_HDRC_RXCSR, wCsr);
+       }
+
+       /* re-enable interrupt */
+       musb_writew(mbase, MGC_O_HDRC_INTRTXE, wIntrTxE);
+       spin_unlock_irqrestore(&musb->Lock, flags);
+}
+
+static const struct usb_ep_ops musb_ep_ops = {
+       .enable         = musb_gadget_enable,
+       .disable        = musb_gadget_disable,
+       .alloc_request  = musb_alloc_request,
+       .free_request   = musb_free_request,
+       .alloc_buffer   = musb_gadget_alloc_buffer,
+       .free_buffer    = musb_gadget_free_buffer,
+       .queue          = musb_gadget_queue,
+       .dequeue        = musb_gadget_dequeue,
+       .set_halt       = musb_gadget_set_halt,
+       .fifo_status    = musb_gadget_fifo_status,
+       .fifo_flush     = musb_gadget_fifo_flush
+};
+
+/***********************************************************************/
+
+static int musb_gadget_get_frame(struct usb_gadget *gadget)
+{
+       struct musb     *pThis = gadget_to_musb(gadget);
+
+       return (int)musb_readw(pThis->pRegs, MGC_O_HDRC_FRAME);
+}
+
+static int musb_gadget_wakeup(struct usb_gadget *gadget)
+{
+       struct musb     *musb = gadget_to_musb(gadget);
+       unsigned long   flags;
+       int             status = -EINVAL;
+       u8              power;
+
+       spin_lock_irqsave(&musb->Lock, flags);
+
+       /* fail if we're not suspended */
+       power = musb_readb(musb->pRegs, MGC_O_HDRC_POWER);
+       if (!(power & MGC_M_POWER_SUSPENDM))
+               goto done;
+
+       switch (musb->xceiv.state) {
+       case OTG_STATE_B_PERIPHERAL:
+               /* NOTE:  OTG state machine doesn't include B_SUSPENDED;
+                * that's part of the standard usb 1.1 state machine, and
+                * doesn't affect OTG transitions.
+                */
+               if (musb->bMayWakeup)
+                       break;
+               goto done;
+       case OTG_STATE_B_IDLE:
+               /* REVISIT we might be able to do SRP even without OTG,
+                * though Linux doesn't yet expose that capability.  SRP
+                * starts by setting DEVCTL.SESSION (not POWER.RESUME);
+                * though DaVinci can't do it.
+                */
+               if (is_otg_enabled(musb)) {
+                       musb->xceiv.state = OTG_STATE_B_SRP_INIT;
+                       break;
+               }
+               /* FALLTHROUGH */
+       default:
+               goto done;
+       }
+
+       status = 0;
+       power |= MGC_M_POWER_RESUME;
+       musb_writeb(musb->pRegs, MGC_O_HDRC_POWER, power);
+
+       /* FIXME do this next chunk in a timer callback, no udelay */
+       mdelay(2);
+
+       power = musb_readb(musb->pRegs, MGC_O_HDRC_POWER);
+       power &= ~MGC_M_POWER_RESUME;
+       musb_writeb(musb->pRegs, MGC_O_HDRC_POWER, power);
+
+       if (musb->xceiv.state == OTG_STATE_B_SRP_INIT)
+               musb->xceiv.state = OTG_STATE_B_IDLE;
+done:
+       spin_unlock_irqrestore(&musb->Lock, flags);
+       return status;
+}
+
+static int
+musb_gadget_set_self_powered(struct usb_gadget *gadget, int is_selfpowered)
+{
+       struct musb     *pThis = gadget_to_musb(gadget);
+
+       pThis->bIsSelfPowered = !!is_selfpowered;
+       return 0;
+}
+
+static void musb_pullup(struct musb *musb, int is_on)
+{
+       u8 power;
+
+       power = musb_readb(musb->pRegs, MGC_O_HDRC_POWER);
+       if (is_on)
+               power |= MGC_M_POWER_SOFTCONN;
+       else
+               power &= ~MGC_M_POWER_SOFTCONN;
+
+       /* FIXME if on, HdrcStart; if off, HdrcStop */
+
+       DBG(3, "gadget %s D+ pullup %s\n",
+               musb->pGadgetDriver->function, is_on ? "on" : "off");
+       musb_writeb(musb->pRegs, MGC_O_HDRC_POWER, power);
+}
+
+#if 0
+static int musb_gadget_vbus_session(struct usb_gadget *gadget, int is_active)
+{
+       DBG(2, "<= %s =>\n", __FUNCTION__);
+
+       // FIXME iff driver's softconnect flag is set (as it is during probe,
+       // though that can clear it), just musb_pullup().
+
+       return -EINVAL;
+}
+
+static int musb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA)
+{
+       /* FIXME -- delegate to otg_transciever logic */
+
+       DBG(2, "<= vbus_draw %u =>\n", mA);
+       return 0;
+}
+#endif
+
+static int musb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA)
+{
+       struct musb     *musb = gadget_to_musb(gadget);
+
+       if (!musb->xceiv.set_power)
+               return -EOPNOTSUPP;
+       return otg_set_power(&musb->xceiv, mA);
+}
+
+static int musb_gadget_pullup(struct usb_gadget *gadget, int is_on)
+{
+       struct musb     *musb = gadget_to_musb(gadget);
+       unsigned long   flags;
+
+       is_on = !!is_on;
+
+       /* NOTE: this assumes we are sensing vbus; we'd rather
+        * not pullup unless the B-session is active.
+        */
+       spin_lock_irqsave(&musb->Lock, flags);
+       if (is_on != musb->softconnect) {
+               musb->softconnect = is_on;
+               musb_pullup(musb, is_on);
+       }
+       spin_unlock_irqrestore(&musb->Lock, flags);
+       return 0;
+}
+
+static const struct usb_gadget_ops musb_gadget_operations = {
+       .get_frame              = musb_gadget_get_frame,
+       .wakeup                 = musb_gadget_wakeup,
+       .set_selfpowered        = musb_gadget_set_self_powered,
+       //.vbus_session         = musb_gadget_vbus_session,
+       .vbus_draw              = musb_gadget_vbus_draw,
+       .pullup                 = musb_gadget_pullup,
+};
+
+/****************************************************************
+ * Registration operations
+ ****************************************************************/
+
+/* Only this registration code "knows" the rule (from USB standards)
+ * about there being only one external upstream port.  It assumes
+ * all peripheral ports are external...
+ */
+static struct musb *the_gadget;
+
+static void musb_gadget_release(struct device *dev)
+{
+       // kref_put(WHAT)
+       dev_dbg(dev, "%s\n", __FUNCTION__);
+}
+
+
+static void __init
+init_peripheral_ep(struct musb *musb, struct musb_ep *ep, u8 bEnd, int is_in)
+{
+       struct musb_hw_ep       *hw_ep = musb->aLocalEnd + bEnd;
+
+       memset(ep, 0, sizeof *ep);
+
+       ep->bEndNumber = bEnd;
+       ep->pThis = musb;
+       ep->hw_ep = hw_ep;
+       ep->is_in = is_in;
+
+       INIT_LIST_HEAD(&ep->req_list);
+
+       sprintf(ep->name, "ep%d%s", bEnd,
+                       (!bEnd || hw_ep->bIsSharedFifo) ? "" : (
+                               is_in ? "in" : "out"));
+       ep->end_point.name = ep->name;
+       INIT_LIST_HEAD(&ep->end_point.ep_list);
+       if (!bEnd) {
+               ep->end_point.maxpacket = 64;
+               ep->end_point.ops = &musb_g_ep0_ops;
+               musb->g.ep0 = &ep->end_point;
+       } else {
+               if (is_in)
+                       ep->end_point.maxpacket = hw_ep->wMaxPacketSizeTx;
+               else
+                       ep->end_point.maxpacket = hw_ep->wMaxPacketSizeRx;
+               ep->end_point.ops = &musb_ep_ops;
+               list_add_tail(&ep->end_point.ep_list, &musb->g.ep_list);
+       }
+}
+
+/*
+ * Initialize the endpoints exposed to peripheral drivers, with backlinks
+ * to the rest of the driver state.
+ */
+static inline void __init musb_g_init_endpoints(struct musb *pThis)
+{
+       u8                      bEnd;
+       struct musb_hw_ep       *hw_ep;
+       unsigned                count = 0;
+
+       /* intialize endpoint list just once */
+       INIT_LIST_HEAD(&(pThis->g.ep_list));
+
+       for (bEnd = 0, hw_ep = pThis->aLocalEnd;
+                       bEnd < pThis->bEndCount;
+                       bEnd++, hw_ep++) {
+               if (hw_ep->bIsSharedFifo /* || !bEnd */) {
+                       init_peripheral_ep(pThis, &hw_ep->ep_in, bEnd, 0);
+                       count++;
+               } else {
+                       if (hw_ep->wMaxPacketSizeTx) {
+                               init_peripheral_ep(pThis, &hw_ep->ep_in,
+                                                       bEnd, 1);
+                               count++;
+                       }
+                       if (hw_ep->wMaxPacketSizeRx) {
+                               init_peripheral_ep(pThis, &hw_ep->ep_out,
+                                                       bEnd, 0);
+                               count++;
+                       }
+               }
+       }
+}
+
+/* called once during driver setup to initialize and link into
+ * the driver model; memory is zeroed.
+ */
+int __init musb_gadget_setup(struct musb *musb)
+{
+       int status;
+
+       /* REVISIT minor race:  if (erroneously) setting up two
+        * musb peripherals at the same time, only the bus lock
+        * is probably held.
+        */
+       if (the_gadget)
+               return -EBUSY;
+       the_gadget = musb;
+
+       musb->g.ops = &musb_gadget_operations;
+       musb->g.is_dualspeed = 1;
+       musb->g.speed = USB_SPEED_UNKNOWN;
+
+       /* this "gadget" abstracts/virtualizes the controller */
+       strcpy(musb->g.dev.bus_id, "gadget");
+       musb->g.dev.parent = musb->controller;
+       musb->g.dev.dma_mask = musb->controller->dma_mask;
+       musb->g.dev.release = musb_gadget_release;
+       musb->g.name = musb_driver_name;
+
+       if (is_otg_enabled(musb))
+               musb->g.is_otg = 1;
+
+       musb_g_init_endpoints(musb);
+
+       musb->is_active = 0;
+       musb_platform_try_idle(musb);
+
+       status = device_register(&musb->g.dev);
+       if (status != 0)
+               the_gadget = NULL;
+       return status;
+}
+
+void musb_gadget_cleanup(struct musb *musb)
+{
+       if (musb != the_gadget)
+               return;
+
+       device_unregister(&musb->g.dev);
+       the_gadget = NULL;
+}
+
+/*
+ * Register the gadget driver. Used by gadget drivers when
+ * registering themselves with the controller.
+ *
+ * -EINVAL something went wrong (not driver)
+ * -EBUSY another gadget is already using the controller
+ * -ENOMEM no memeory to perform the operation
+ *
+ * @param driver the gadget driver
+ * @return <0 if error, 0 if everything is fine
+ */
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+       int retval;
+       unsigned long flags;
+       struct musb *pThis = the_gadget;
+
+       if (!driver
+                       || driver->speed != USB_SPEED_HIGH
+                       || !driver->bind
+                       || !driver->setup)
+               return -EINVAL;
+
+       /* driver must be initialized to support peripheral mode */
+       if (!pThis || !(pThis->board_mode == MUSB_OTG
+                               || pThis->board_mode != MUSB_OTG)) {
+               DBG(1,"%s, no dev??\n", __FUNCTION__);
+               return -ENODEV;
+       }
+
+       DBG(3, "registering driver %s\n", driver->function);
+       spin_lock_irqsave(&pThis->Lock, flags);
+
+       if (pThis->pGadgetDriver) {
+               DBG(1, "%s is already bound to %s\n",
+                               musb_driver_name,
+                               pThis->pGadgetDriver->driver.name);
+               retval = -EBUSY;
+       } else {
+               pThis->pGadgetDriver = driver;
+               pThis->g.dev.driver = &driver->driver;
+               driver->driver.bus = NULL;
+               pThis->softconnect = 1;
+               retval = 0;
+       }
+
+       spin_unlock_irqrestore(&pThis->Lock, flags);
+
+       if (retval == 0)
+               retval = driver->bind(&pThis->g);
+       if (retval != 0) {
+               DBG(3, "bind to driver %s failed --> %d\n",
+                       driver->driver.name, retval);
+               pThis->pGadgetDriver = NULL;
+               pThis->g.dev.driver = NULL;
+       }
+
+       /* start peripheral and/or OTG engines */
+       if (retval == 0) {
+               spin_lock_irqsave(&pThis->Lock, flags);
+
+               /* REVISIT always use otg_set_peripheral(), handling
+                * issues including the root hub one below ...
+                */
+               pThis->xceiv.gadget = &pThis->g;
+               pThis->xceiv.state = OTG_STATE_B_IDLE;
+               pThis->is_active = 1;
+
+               /* FIXME this ignores the softconnect flag.  Drivers are
+                * allowed hold the peripheral inactive until for example
+                * userspace hooks up printer hardware or DSP codecs, so
+                * hosts only see fully functional devices.
+                */
+
+               if (!is_otg_enabled(pThis))
+                       musb_start(pThis);
+
+               spin_unlock_irqrestore(&pThis->Lock, flags);
+
+               if (is_otg_enabled(pThis)) {
+                       DBG(3, "OTG startup...\n");
+
+                       /* REVISIT:  funcall to other code, which also
+                        * handles power budgeting ... this way also
+                        * ensures HdrcStart is indirectly called.
+                        */
+                       retval = usb_add_hcd(musb_to_hcd(pThis), -1, 0);
+                       if (retval < 0) {
+                               DBG(1, "add_hcd failed, %d\n", retval);
+                               spin_lock_irqsave(&pThis->Lock, flags);
+                               pThis->xceiv.gadget = NULL;
+                               pThis->xceiv.state = OTG_STATE_UNDEFINED;
+                               pThis->pGadgetDriver = NULL;
+                               pThis->g.dev.driver = NULL;
+                               spin_unlock_irqrestore(&pThis->Lock, flags);
+                       }
+               }
+       }
+
+       return retval;
+}
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+static void
+stop_activity(struct musb *musb, struct usb_gadget_driver *driver)
+{
+       int                     i;
+       struct musb_hw_ep       *hw_ep;
+
+       /* don't disconnect if it's not connected */
+       if (musb->g.speed == USB_SPEED_UNKNOWN)
+               driver = NULL;
+       else
+               musb->g.speed = USB_SPEED_UNKNOWN;
+
+       /* deactivate the hardware */
+       if (musb->softconnect) {
+               musb->softconnect = 0;
+               musb_pullup(musb, 0);
+       }
+       musb_stop(musb);
+
+       /* killing any outstanding requests will quiesce the driver;
+        * then report disconnect
+        */
+       if (driver) {
+               for (i = 0, hw_ep = musb->aLocalEnd;
+                               i < musb->bEndCount;
+                               i++, hw_ep++) {
+                       MGC_SelectEnd(musb->pRegs, i);
+                       if (hw_ep->bIsSharedFifo /* || !bEnd */) {
+                               nuke(&hw_ep->ep_in, -ESHUTDOWN);
+                       } else {
+                               if (hw_ep->wMaxPacketSizeTx)
+                                       nuke(&hw_ep->ep_in, -ESHUTDOWN);
+                               if (hw_ep->wMaxPacketSizeRx)
+                                       nuke(&hw_ep->ep_out, -ESHUTDOWN);
+                       }
+               }
+
+               spin_unlock(&musb->Lock);
+               driver->disconnect (&musb->g);
+               spin_lock(&musb->Lock);
+       }
+}
+
+/*
+ * Unregister the gadget driver. Used by gadget drivers when
+ * unregistering themselves from the controller.
+ *
+ * @param driver the gadget driver to unregister
+ */
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+       unsigned long   flags;
+       int             retval = 0;
+       struct musb     *musb = the_gadget;
+
+       if (!driver || !driver->unbind || !musb)
+               return -EINVAL;
+
+       /* REVISIT always use otg_set_peripheral() here too;
+        * this needs to shut down the OTG engine.
+        */
+
+       spin_lock_irqsave(&musb->Lock, flags);
+       if (musb->pGadgetDriver == driver) {
+               musb->xceiv.state = OTG_STATE_UNDEFINED;
+               stop_activity(musb, driver);
+
+               DBG(3, "unregistering driver %s\n", driver->function);
+               spin_unlock_irqrestore(&musb->Lock, flags);
+               driver->unbind(&musb->g);
+               spin_lock_irqsave(&musb->Lock, flags);
+
+               musb->pGadgetDriver = NULL;
+               musb->g.dev.driver = NULL;
+
+               musb->is_active = 0;
+               musb_platform_try_idle(musb);
+       } else
+               retval = -EINVAL;
+       spin_unlock_irqrestore(&musb->Lock, flags);
+
+       if (is_otg_enabled(musb) && retval == 0) {
+               usb_remove_hcd(musb_to_hcd(musb));
+               /* FIXME we need to be able to register another
+                * gadget driver here and have everything work;
+                * that currently misbehaves.
+                */
+       }
+
+       return retval;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+
+/***********************************************************************/
+
+/* lifecycle operations called through plat_uds.c */
+
+void musb_g_resume(struct musb *pThis)
+{
+       switch (pThis->xceiv.state) {
+       case OTG_STATE_B_IDLE:
+               break;
+       case OTG_STATE_B_WAIT_ACON:
+       case OTG_STATE_B_PERIPHERAL:
+               pThis->is_active = 1;
+               if (pThis->pGadgetDriver && pThis->pGadgetDriver->resume) {
+                       spin_unlock(&pThis->Lock);
+                       pThis->pGadgetDriver->resume(&pThis->g);
+                       spin_lock(&pThis->Lock);
+               }
+               break;
+       default:
+               WARN("unhandled RESUME transition (%s)\n",
+                               otg_state_string(pThis));
+       }
+}
+
+/* called when SOF packets stop for 3+ msec */
+void musb_g_suspend(struct musb *pThis)
+{
+       u8      devctl;
+
+       devctl = musb_readb(pThis->pRegs, MGC_O_HDRC_DEVCTL);
+       DBG(3, "devctl %02x\n", devctl);
+
+       switch (pThis->xceiv.state) {
+       case OTG_STATE_B_IDLE:
+               if ((devctl & MGC_M_DEVCTL_VBUS) == MGC_M_DEVCTL_VBUS)
+                       pThis->xceiv.state = OTG_STATE_B_PERIPHERAL;
+               break;
+       case OTG_STATE_B_PERIPHERAL:
+               if (pThis->pGadgetDriver && pThis->pGadgetDriver->suspend) {
+                       spin_unlock(&pThis->Lock);
+                       pThis->pGadgetDriver->suspend(&pThis->g);
+                       spin_lock(&pThis->Lock);
+               }
+               break;
+       default:
+               /* REVISIT if B_HOST, clear DEVCTL.HOSTREQ;
+                * A_PERIPHERAL may need care too
+                */
+               WARN("unhandled SUSPEND transition (%s)\n",
+                               otg_state_string(pThis));
+       }
+}
+
+/* called when VBUS drops below session threshold, and in other cases */
+void musb_g_disconnect(struct musb *pThis)
+{
+       void __iomem    *mregs = pThis->pRegs;
+       u8      devctl = musb_readb(mregs, MGC_O_HDRC_DEVCTL);
+
+       DBG(3, "devctl %02x\n", devctl);
+
+       /* clear HR */
+       musb_writeb(mregs, MGC_O_HDRC_DEVCTL, devctl & MGC_M_DEVCTL_SESSION);
+
+       /* don't draw vbus until new b-default session */
+       (void) musb_gadget_vbus_draw(&pThis->g, 0);
+
+       pThis->g.speed = USB_SPEED_UNKNOWN;
+       if (pThis->pGadgetDriver && pThis->pGadgetDriver->disconnect) {
+               spin_unlock(&pThis->Lock);
+               pThis->pGadgetDriver->disconnect(&pThis->g);
+               spin_lock(&pThis->Lock);
+       }
+
+       switch (pThis->xceiv.state) {
+       default:
+#ifdef CONFIG_USB_MUSB_OTG
+               pThis->xceiv.state = OTG_STATE_A_IDLE;
+               break;
+       case OTG_STATE_B_WAIT_ACON:
+       case OTG_STATE_B_HOST:
+#endif
+       case OTG_STATE_B_PERIPHERAL:
+               pThis->xceiv.state = OTG_STATE_B_IDLE;
+               break;
+       case OTG_STATE_B_SRP_INIT:
+               break;
+       }
+
+       pThis->is_active = 0;
+}
+
+void musb_g_reset(struct musb *pThis)
+__releases(pThis->Lock)
+__acquires(pThis->Lock)
+{
+       void __iomem    *pBase = pThis->pRegs;
+       u8              devctl = musb_readb(pBase, MGC_O_HDRC_DEVCTL);
+       u8              power;
+
+       DBG(3, "<== %s addr=%x driver '%s'\n",
+                       (devctl & MGC_M_DEVCTL_BDEVICE)
+                               ? "B-Device" : "A-Device",
+                       musb_readb(pBase, MGC_O_HDRC_FADDR),
+                       pThis->pGadgetDriver
+                               ? pThis->pGadgetDriver->driver.name
+                               : NULL
+                       );
+
+       /* report disconnect, if we didn't already (flushing EP state) */
+       if (pThis->g.speed != USB_SPEED_UNKNOWN)
+               musb_g_disconnect(pThis);
+
+       /* clear HR */
+       else if (devctl & MGC_M_DEVCTL_HR)
+               musb_writeb(pBase, MGC_O_HDRC_DEVCTL, MGC_M_DEVCTL_SESSION);
+
+
+       /* what speed did we negotiate? */
+       power = musb_readb(pBase, MGC_O_HDRC_POWER);
+       pThis->g.speed = (power & MGC_M_POWER_HSMODE)
+                       ? USB_SPEED_HIGH : USB_SPEED_FULL;
+
+       /* start in USB_STATE_DEFAULT */
+       pThis->is_active = 1;
+       MUSB_DEV_MODE(pThis);
+       pThis->bAddress = 0;
+       pThis->ep0_state = MGC_END0_STAGE_SETUP;
+
+       pThis->bMayWakeup = 0;
+       pThis->g.b_hnp_enable = 0;
+       pThis->g.a_alt_hnp_support = 0;
+       pThis->g.a_hnp_support = 0;
+
+       /* Normal reset, as B-Device;
+        * or else after HNP, as A-Device
+        */
+       if (devctl & MGC_M_DEVCTL_BDEVICE) {
+               pThis->xceiv.state = OTG_STATE_B_PERIPHERAL;
+               pThis->g.is_a_peripheral = 0;
+       } else if (is_otg_enabled(pThis)) {
+               pThis->xceiv.state = OTG_STATE_A_PERIPHERAL;
+               pThis->g.is_a_peripheral = 1;
+       } else
+               WARN_ON(1);
+
+       /* start with default limits on VBUS power draw */
+       (void) musb_gadget_vbus_draw(&pThis->g,
+                       is_otg_enabled(pThis) ? 8 : 100);
+}
diff --git a/drivers/usb/musb/musb_gadget.h b/drivers/usb/musb/musb_gadget.h
new file mode 100644 (file)
index 0000000..5c7c7c3
--- /dev/null
@@ -0,0 +1,107 @@
+/******************************************************************
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * The Inventra Controller Driver for Linux is free software; you
+ * can redistribute it and/or modify it under the terms of the GNU
+ * General Public License version 2 as published by the Free Software
+ * Foundation.
+ *
+ * The Inventra Controller Driver for Linux is distributed in
+ * the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Inventra Controller Driver for Linux ; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ANY DOWNLOAD, USE, REPRODUCTION, MODIFICATION OR DISTRIBUTION
+ * OF THIS DRIVER INDICATES YOUR COMPLETE AND UNCONDITIONAL ACCEPTANCE
+ * OF THOSE TERMS.THIS DRIVER IS PROVIDED "AS IS" AND MENTOR GRAPHICS
+ * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, RELATED TO THIS DRIVER.
+ * MENTOR GRAPHICS SPECIFICALLY DISCLAIMS ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY; FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT.  MENTOR GRAPHICS DOES NOT PROVIDE SUPPORT
+ * SERVICES OR UPDATES FOR THIS DRIVER, EVEN IF YOU ARE A MENTOR
+ * GRAPHICS SUPPORT CUSTOMER.
+ ******************************************************************/
+
+#ifndef __MUSB_GADGET_H
+#define __MUSB_GADGET_H
+
+struct musb_request {
+       struct usb_request      request;
+       struct musb_ep          *ep;
+       struct musb             *musb;
+       u8 bTx;                 /* endpoint direction */
+       u8 bEnd;
+       u8 mapped;
+};
+
+static inline struct musb_request *to_musb_request(struct usb_request *req)
+{
+       return req ? container_of(req, struct musb_request, request) : NULL;
+}
+
+extern struct usb_request *
+musb_alloc_request(struct usb_ep *ep, gfp_t gfp_flags);
+extern void musb_free_request(struct usb_ep *ep, struct usb_request *req);
+
+
+/*
+ * struct musb_ep - peripheral side view of endpoint rx or tx side
+ */
+struct musb_ep {
+       /* stuff towards the head is basically write-once. */
+       struct usb_ep                   end_point;
+       char                            name[12];
+       struct musb_hw_ep               *hw_ep;
+       struct musb                     *pThis;
+       u8                              bEndNumber;
+
+       /* ... when enabled/disabled ... */
+       u8                              type;
+       u8                              is_in;
+       u16                             wPacketSize;
+       const struct usb_endpoint_descriptor    *desc;
+       struct dma_channel              *dma;
+
+       /* later things are modified based on usage */
+       struct list_head                req_list;
+
+       /* true if lock must be dropped but req_list may not be advanced */
+       u8                              busy;
+};
+
+static inline struct musb_ep *to_musb_ep(struct usb_ep *ep)
+{
+       return ep ? container_of(ep, struct musb_ep, end_point) : NULL;
+}
+
+static inline struct usb_request *next_request(struct musb_ep *ep)
+{
+       struct list_head        *queue = &ep->req_list;
+
+       if (list_empty(queue))
+               return NULL;
+       return container_of(queue->next, struct usb_request, list);
+}
+
+extern void musb_g_tx(struct musb *pThis, u8 bEnd);
+extern void musb_g_rx(struct musb *pThis, u8 bEnd);
+
+extern const struct usb_ep_ops musb_g_ep0_ops;
+
+extern int musb_gadget_setup(struct musb *);
+extern void musb_gadget_cleanup(struct musb *);
+
+extern void musb_g_giveback(struct musb_ep *, struct usb_request *, int);
+
+extern int musb_gadget_set_halt(struct usb_ep *ep, int value);
+
+#endif         /* __MUSB_GADGET_H */
diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
new file mode 100644 (file)
index 0000000..848575c
--- /dev/null
@@ -0,0 +1,2173 @@
+/******************************************************************
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ * Copyright (C) 2006 by Nokia Corporation
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * The Inventra Controller Driver for Linux is free software; you
+ * can redistribute it and/or modify it under the terms of the GNU
+ * General Public License version 2 as published by the Free Software
+ * Foundation.
+ *
+ * The Inventra Controller Driver for Linux is distributed in
+ * the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Inventra Controller Driver for Linux ; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ANY DOWNLOAD, USE, REPRODUCTION, MODIFICATION OR DISTRIBUTION
+ * OF THIS DRIVER INDICATES YOUR COMPLETE AND UNCONDITIONAL ACCEPTANCE
+ * OF THOSE TERMS.THIS DRIVER IS PROVIDED "AS IS" AND MENTOR GRAPHICS
+ * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, RELATED TO THIS DRIVER.
+ * MENTOR GRAPHICS SPECIFICALLY DISCLAIMS ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY; FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT.  MENTOR GRAPHICS DOES NOT PROVIDE SUPPORT
+ * SERVICES OR UPDATES FOR THIS DRIVER, EVEN IF YOU ARE A MENTOR
+ * GRAPHICS SUPPORT CUSTOMER.
+ ******************************************************************/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/list.h>
+
+#include "musbdefs.h"
+#include "musb_host.h"
+
+
+/* MUSB HOST status 22-mar-2006
+ *
+ * - There's still lots of partial code duplication for fault paths, so
+ *   they aren't handled as consistently as they need to be.
+ *
+ * - PIO mostly behaved when last tested.
+ *     + including ep0, with all usbtest cases 9, 10
+ *     + usbtest 14 (ep0out) doesn't seem to run at all
+ *     + double buffered OUT/TX endpoints saw stalls(!) with certain usbtest
+ *       configurations, but otherwise double buffering passes basic tests.
+ *     + for 2.6.N, for N > ~10, needs API changes for hcd framework.
+ *
+ * - DMA (CPPI) ... partially behaves, not currently recommended
+ *     + about 1/15 the speed of typical EHCI implementations (PCI)
+ *     + RX, all too often reqpkt seems to misbehave after tx
+ *     + TX, no known issues (other than evident silicon issue)
+ *
+ * - DMA (Mentor/OMAP) ...has at least toggle update problems
+ *
+ * - Still no traffic scheduling code to make NAKing for bulk or control
+ *   transfers unable to starve other requests; or to make efficient use
+ *   of hardware with periodic transfers.  (Note that network drivers
+ *   commonly post bulk reads that stay pending for a long time; these
+ *   would make very visible trouble.)
+ *
+ * - Not tested with HNP, but some SRP paths seem to behave.
+ *
+ * NOTE 24-August:
+ *
+ * - Bulk traffic finally uses both sides of hardware ep1, freeing up an
+ *   extra endpoint for periodic use enabling hub + keybd + mouse.  That
+ *   mostly works, except that with "usbnet" it's easy to trigger cases
+ *   with "ping" where RX loses.  (a) ping to davinci, even "ping -f",
+ *   fine; but (b) ping _from_ davinci, even "ping -c 1", ICMP RX loses
+ *   although ARP RX wins.  (That test was done with a full speed link.)
+ */
+
+
+/*
+ * NOTE on endpoint usage:
+ *
+ * CONTROL transfers all go through ep0.  BULK ones go through dedicated IN
+ * and OUT endpoints ... hardware is dedicated for those "async" queue(s).
+ *
+ * (Yes, bulk _could_ use more of the endpoints than that, and would even
+ * benefit from it ... one remote device may easily be NAKing while others
+ * need to perform transfers in that same direction.  The same thing could
+ * be done in software though, assuming dma cooperates.)
+ *
+ * INTERUPPT and ISOCHRONOUS transfers are scheduled to the other endpoints.
+ * So far that scheduling is both dumb and optimistic:  the endpoint will be
+ * "claimed" until its software queue is no longer refilled.  No multiplexing
+ * of transfers between endpoints, or anything clever.
+ */
+
+
+/*************************** Forwards ***************************/
+
+static void musb_ep_program(struct musb *pThis, u8 bEnd,
+                       struct urb *pUrb, unsigned int nOut,
+                       u8 * pBuffer, u32 dwLength);
+
+/*
+ * Start transmit. Caller is responsible for locking shared resources.
+ * pThis must be locked.
+ */
+static inline void musb_h_tx_start(struct musb_hw_ep *ep)
+{
+       u16     txcsr;
+
+       /* NOTE: no locks here; caller should lock and select EP */
+       if (ep->bLocalEnd) {
+               txcsr = musb_readw(ep->regs, MGC_O_HDRC_TXCSR);
+               txcsr |= MGC_M_TXCSR_TXPKTRDY | MGC_M_TXCSR_H_WZC_BITS;
+               musb_writew(ep->regs, MGC_O_HDRC_TXCSR, txcsr);
+       } else {
+               txcsr = MGC_M_CSR0_H_SETUPPKT | MGC_M_CSR0_TXPKTRDY;
+               musb_writew(ep->regs, MGC_O_HDRC_CSR0, txcsr);
+       }
+
+}
+
+static inline void cppi_host_txdma_start(struct musb_hw_ep *ep)
+{
+       u16     txcsr;
+
+       /* NOTE: no locks here; caller should lock and select EP */
+       txcsr = musb_readw(ep->regs, MGC_O_HDRC_TXCSR);
+       txcsr |= MGC_M_TXCSR_DMAENAB | MGC_M_TXCSR_H_WZC_BITS;
+       musb_writew(ep->regs, MGC_O_HDRC_TXCSR, txcsr);
+}
+
+/*
+ * Start the URB at the front of an endpoint's queue
+ * end must be claimed from the caller.
+ *
+ * Context: controller locked, irqs blocked
+ */
+static void
+musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh)
+{
+       u16                     wFrame;
+       u32                     dwLength;
+       void                    *pBuffer;
+       void __iomem            *pBase =  musb->pRegs;
+       struct urb              *urb = next_urb(qh);
+       struct musb_hw_ep       *pEnd = qh->hw_ep;
+       unsigned                nPipe = urb->pipe;
+       u8                      bAddress = usb_pipedevice(nPipe);
+       int                     bEnd = pEnd->bLocalEnd;
+
+       /* initialize software qh state */
+       qh->offset = 0;
+       qh->segsize = 0;
+
+       /* gather right source of data */
+       switch (qh->type) {
+       case USB_ENDPOINT_XFER_CONTROL:
+               /* control transfers always start with SETUP */
+               is_in = 0;
+               pEnd->out_qh = qh;
+               musb->bEnd0Stage = MGC_END0_START;
+               pBuffer = urb->setup_packet;
+               dwLength = 8;
+               break;
+       case USB_ENDPOINT_XFER_ISOC:
+               qh->iso_idx = 0;
+               qh->frame = 0;
+               pBuffer = urb->transfer_buffer + urb->iso_frame_desc[0].offset;
+               dwLength = urb->iso_frame_desc[0].length;
+               break;
+       default:                /* bulk, interrupt */
+               pBuffer = urb->transfer_buffer;
+               dwLength = urb->transfer_buffer_length;
+       }
+
+       DBG(4, "qh %p urb %p dev%d ep%d%s%s, hw_ep %d, %p/%d\n",
+                       qh, urb, bAddress, qh->epnum,
+                       is_in ? "in" : "out",
+                       ({char *s; switch (qh->type) {
+                       case USB_ENDPOINT_XFER_CONTROL: s = ""; break;
+                       case USB_ENDPOINT_XFER_BULK:    s = "-bulk"; break;
+                       case USB_ENDPOINT_XFER_ISOC:    s = "-iso"; break;
+                       default:                        s = "-intr"; break;
+                       }; s;}),
+                       bEnd, pBuffer, dwLength);
+
+       /* Configure endpoint */
+       if (is_in || pEnd->bIsSharedFifo)
+               pEnd->in_qh = qh;
+       else
+               pEnd->out_qh = qh;
+       musb_ep_program(musb, bEnd, urb, !is_in, pBuffer, dwLength);
+
+       /* transmit may have more work: start it when it is time */
+       if (is_in)
+               return;
+
+       /* determine if the time is right for a periodic transfer */
+       switch (qh->type) {
+       case USB_ENDPOINT_XFER_ISOC:
+       case USB_ENDPOINT_XFER_INT:
+               DBG(3, "check whether there's still time for periodic Tx\n");
+               qh->iso_idx = 0;
+               wFrame = musb_readw(pBase, MGC_O_HDRC_FRAME);
+               /* FIXME this doesn't implement that scheduling policy ...
+                * or handle framecounter wrapping
+                */
+               if ((urb->transfer_flags & URB_ISO_ASAP)
+                               || (wFrame >= urb->start_frame)) {
+                       /* REVISIT the SOF irq handler shouldn't duplicate
+                        * this code; and we don't init urb->start_frame...
+                        */
+                       qh->frame = 0;
+                       goto start;
+               } else {
+                       qh->frame = urb->start_frame;
+                       /* enable SOF interrupt so we can count down */
+DBG(1,"SOF for %d\n", bEnd);
+#if 1 // ifndef        CONFIG_ARCH_DAVINCI
+                       musb_writeb(pBase, MGC_O_HDRC_INTRUSBE, 0xff);
+#endif
+               }
+               break;
+       default:
+start:
+               DBG(4, "Start TX%d %s\n", bEnd,
+                       pEnd->tx_channel ? "dma" : "pio");
+
+               if (!pEnd->tx_channel)
+                       musb_h_tx_start(pEnd);
+               else if (is_cppi_enabled())
+                       cppi_host_txdma_start(pEnd);
+       }
+}
+
+/* caller owns controller lock, irqs are blocked */
+static void
+__musb_giveback(struct musb *musb, struct urb *urb, int status)
+__releases(musb->Lock)
+__acquires(musb->Lock)
+{
+       if ((urb->transfer_flags & URB_SHORT_NOT_OK)
+                       && (urb->actual_length < urb->transfer_buffer_length)
+                       && status == 0
+                       && usb_pipein(urb->pipe))
+               status = -EREMOTEIO;
+
+       spin_lock(&urb->lock);
+       urb->hcpriv = NULL;
+       if (urb->status == -EINPROGRESS)
+               urb->status = status;
+       spin_unlock(&urb->lock);
+
+       DBG(({ int level; switch (urb->status) {
+                               case 0:
+                                       level = 4;
+                                       break;
+                               /* common/boring faults */
+                               case -EREMOTEIO:
+                               case -ESHUTDOWN:
+                               case -ECONNRESET:
+                               case -EPIPE:
+                                       level = 3;
+                                       break;
+                               default:
+                                       level = 2;
+                                       break;
+                               }; level; }),
+                       "complete %p (%d), dev%d ep%d%s, %d/%d\n",
+                       urb, urb->status,
+                       usb_pipedevice(urb->pipe),
+                       usb_pipeendpoint(urb->pipe),
+                       usb_pipein(urb->pipe) ? "in" : "out",
+                       urb->actual_length, urb->transfer_buffer_length
+                       );
+
+       spin_unlock(&musb->Lock);
+       usb_hcd_giveback_urb(musb_to_hcd(musb), urb);
+       spin_lock(&musb->Lock);
+}
+
+/* for bulk/interrupt endpoints only */
+static inline void musb_save_toggle(struct musb_hw_ep *ep, int is_in, struct urb *urb)
+{
+       struct usb_device       *udev = urb->dev;
+       u16                     csr;
+       void __iomem            *epio = ep->regs;
+       struct musb_qh          *qh;
+
+       /* FIXME:  the current Mentor DMA code seems to have
+        * problems getting toggle correct.
+        */
+
+       if (is_in || ep->bIsSharedFifo)
+               qh = ep->in_qh;
+       else
+               qh = ep->out_qh;
+
+       if (!is_in) {
+               csr = musb_readw(epio, MGC_O_HDRC_TXCSR);
+               usb_settoggle(udev, qh->epnum, 1,
+                       (csr & MGC_M_TXCSR_H_DATATOGGLE)
+                               ? 1 : 0);
+       } else {
+               csr = musb_readw(epio, MGC_O_HDRC_RXCSR);
+               usb_settoggle(udev, qh->epnum, 0,
+                       (csr & MGC_M_RXCSR_H_DATATOGGLE)
+                               ? 1 : 0);
+       }
+}
+
+/* caller owns controller lock, irqs are blocked */
+static struct musb_qh *
+musb_giveback(struct musb_qh *qh, struct urb *urb, int status)
+{
+       int                     is_in;
+       struct musb_hw_ep       *ep = qh->hw_ep;
+       struct musb             *musb = ep->musb;
+       int                     ready = qh->is_ready;
+
+       if (ep->bIsSharedFifo)
+               is_in = 1;
+       else
+               is_in = usb_pipein(urb->pipe);
+
+       /* save toggle eagerly, for paranoia */
+       switch (qh->type) {
+       case USB_ENDPOINT_XFER_BULK:
+       case USB_ENDPOINT_XFER_INT:
+               musb_save_toggle(ep, is_in, urb);
+               break;
+       case USB_ENDPOINT_XFER_ISOC:
+               if (status == 0 && urb->error_count)
+                       status = -EXDEV;
+               break;
+       }
+
+       qh->is_ready = 0;
+       __musb_giveback(musb, urb, status);
+       qh->is_ready = ready;
+
+       /* reclaim resources (and bandwidth) ASAP; deschedule it, and
+        * invalidate qh as soon as list_empty(&hep->urb_list)
+        */
+       if (list_empty(&qh->hep->urb_list)) {
+               struct list_head        *head;
+
+               if (is_in)
+                       ep->rx_reinit = 1;
+               else
+                       ep->tx_reinit = 1;
+
+               /* clobber old pointers to this qh */
+               if (is_in || ep->bIsSharedFifo)
+                       ep->in_qh = NULL;
+               else
+                       ep->out_qh = NULL;
+               qh->hep->hcpriv = NULL;
+
+               switch (qh->type) {
+
+               case USB_ENDPOINT_XFER_ISOC:
+               case USB_ENDPOINT_XFER_INT:
+                       /* this is where periodic bandwidth should be
+                        * de-allocated if it's tracked and allocated;
+                        * and where we'd update the schedule tree...
+                        */
+                       musb->periodic[ep->bLocalEnd] = NULL;
+                       kfree(qh);
+                       qh = NULL;
+                       break;
+
+               case USB_ENDPOINT_XFER_CONTROL:
+               case USB_ENDPOINT_XFER_BULK:
+                       /* fifo policy for these lists, except that NAKing
+                        * should rotate a qh to the end (for fairness).
+                        */
+                       head = qh->ring.prev;
+                       list_del(&qh->ring);
+                       kfree(qh);
+                       qh = first_qh(head);
+                       break;
+               }
+       }
+       return qh;
+}
+
+/*
+ * Advance this hardware endpoint's queue, completing the specified urb and
+ * advancing to either the next urb queued to that qh, or else invalidating
+ * that qh and advancing to the next qh scheduled after the current one.
+ *
+ * Context: caller owns controller lock, irqs are blocked
+ */
+static void
+musb_advance_schedule(struct musb *pThis, struct urb *urb,
+               struct musb_hw_ep *pEnd, int is_in)
+{
+       struct musb_qh  *qh;
+
+       if (is_in || pEnd->bIsSharedFifo)
+               qh = pEnd->in_qh;
+       else
+               qh = pEnd->out_qh;
+       qh = musb_giveback(qh, urb, 0);
+
+#ifdef CONFIG_USB_INVENTRA_DMA
+       /* REVISIT udelay reportedly works around issues in unmodified
+        * Mentor RTL before v1.5, where it doesn't disable the pull-up
+        * resisters in high speed mode.  That causes signal reflection
+        * and errors because inter packet IDLE time vanishes.
+        *
+        * Yes, this delay makes DMA-OUT a bit slower than PIO.  But
+        * without it, some devices are unusable.  But there seem to be
+        * other issues too, at least on DaVinci; the delay improves
+        * some full speed cases, and being DMA-coupled is strange...
+        */
+       if (is_dma_capable() && !is_in && pEnd->tx_channel)
+               udelay(15);     /* 10 usec ~= 1x 512byte packet */
+#endif
+
+       if (qh && qh->is_ready && !list_empty(&qh->hep->urb_list)) {
+               DBG(4, "... next ep%d %cX urb %p\n",
+                               pEnd->bLocalEnd, is_in ? 'R' : 'T',
+                               next_urb(qh));
+               musb_start_urb(pThis, is_in, qh);
+       }
+}
+
+static inline u16 musb_h_flush_rxfifo(struct musb_hw_ep *hw_ep, u16 csr)
+{
+       /* we don't want fifo to fill itself again;
+        * ignore dma (various models),
+        * leave toggle alone (may not have been saved yet)
+        */
+       csr |= MGC_M_RXCSR_FLUSHFIFO | MGC_M_RXCSR_RXPKTRDY;
+       csr &= ~( MGC_M_RXCSR_H_REQPKT
+               | MGC_M_RXCSR_H_AUTOREQ
+               | MGC_M_RXCSR_AUTOCLEAR
+               );
+
+       /* write 2x to allow double buffering */
+       musb_writew(hw_ep->regs, MGC_O_HDRC_RXCSR, csr);
+       musb_writew(hw_ep->regs, MGC_O_HDRC_RXCSR, csr);
+
+       /* flush writebuffer */
+       return musb_readw(hw_ep->regs, MGC_O_HDRC_RXCSR);
+}
+
+/*
+ * PIO RX for a packet (or part of it).
+ */
+static u8 musb_host_packet_rx(struct musb *pThis, struct urb *pUrb,
+               u8 bEnd, u8 bIsochError)
+{
+       u16 wRxCount;
+       u8 *pBuffer;
+       u16 wCsr;
+       u8 bDone = FALSE;
+       u32                     length;
+       int                     do_flush = 0;
+       struct musb_hw_ep       *pEnd = pThis->aLocalEnd + bEnd;
+       void __iomem            *epio = pEnd->regs;
+       struct musb_qh          *qh = pEnd->in_qh;
+       int                     nPipe = pUrb->pipe;
+       void                    *buffer = pUrb->transfer_buffer;
+
+       // MGC_SelectEnd(pBase, bEnd);
+       wRxCount = musb_readw(epio, MGC_O_HDRC_RXCOUNT);
+
+       /* unload FIFO */
+       if (usb_pipeisoc(nPipe)) {
+               int                                     status = 0;
+               struct usb_iso_packet_descriptor        *d;
+
+               if (bIsochError) {
+                       status = -EILSEQ;
+                       pUrb->error_count++;
+               }
+
+               d = pUrb->iso_frame_desc + qh->iso_idx;
+               pBuffer = buffer + d->offset;
+               length = d->length;
+               if (wRxCount > length) {
+                       if (status == 0) {
+                               status = -EOVERFLOW;
+                               pUrb->error_count++;
+                       }
+                       DBG(2, "** OVERFLOW %d into %d\n", wRxCount, length);
+                       do_flush = 1;
+               } else
+                       length = wRxCount;
+               pUrb->actual_length += length;
+               d->actual_length = length;
+
+               d->status = status;
+
+               /* see if we are done */
+               bDone = (++qh->iso_idx >= pUrb->number_of_packets);
+       } else {
+               /* non-isoch */
+               pBuffer = buffer + qh->offset;
+               length = pUrb->transfer_buffer_length - qh->offset;
+               if (wRxCount > length) {
+                       if (pUrb->status == -EINPROGRESS)
+                               pUrb->status = -EOVERFLOW;
+                       DBG(2, "** OVERFLOW %d into %d\n", wRxCount, length);
+                       do_flush = 1;
+               } else
+                       length = wRxCount;
+               pUrb->actual_length += length;
+               qh->offset += length;
+
+               /* see if we are done */
+               bDone = (pUrb->actual_length == pUrb->transfer_buffer_length)
+                       || (wRxCount < qh->maxpacket)
+                       || (pUrb->status != -EINPROGRESS);
+               if (bDone
+                               && (pUrb->status == -EINPROGRESS)
+                               && (pUrb->transfer_flags & URB_SHORT_NOT_OK)
+                               && (pUrb->actual_length
+                                       < pUrb->transfer_buffer_length))
+                       pUrb->status = -EREMOTEIO;
+       }
+
+       musb_read_fifo(pEnd, length, pBuffer);
+
+       wCsr = musb_readw(epio, MGC_O_HDRC_RXCSR);
+       wCsr |= MGC_M_RXCSR_H_WZC_BITS;
+       if (unlikely(do_flush))
+               musb_h_flush_rxfifo(pEnd, wCsr);
+       else {
+               /* REVISIT this assumes AUTOCLEAR is never set */
+               wCsr &= ~(MGC_M_RXCSR_RXPKTRDY | MGC_M_RXCSR_H_REQPKT);
+               if (!bDone)
+                       wCsr |= MGC_M_RXCSR_H_REQPKT;
+               musb_writew(epio, MGC_O_HDRC_RXCSR, wCsr);
+       }
+
+       return bDone;
+}
+
+/* we don't always need to reinit a given side of an endpoint...
+ * when we do, use tx/rx reinit routine and then construct a new CSR
+ * to address data toggle, NYET, and DMA or PIO.
+ *
+ * it's possible that driver bugs (especially for DMA) or aborting a
+ * transfer might have left the endpoint busier than it should be.
+ * the busy/not-empty tests are basically paranoia.
+ */
+static void
+musb_rx_reinit(struct musb *musb, struct musb_qh *qh, struct musb_hw_ep *ep)
+{
+       u16     csr;
+
+       /* NOTE:  we know the "rx" fifo reinit never triggers for ep0.
+        * That always uses tx_reinit since ep0 repurposes TX register
+        * offsets; the initial SETUP packet is also a kind of OUT.
+        */
+
+       /* if programmed for Tx, put it in RX mode */
+       if (ep->bIsSharedFifo) {
+               csr = musb_readw(ep->regs, MGC_O_HDRC_TXCSR);
+               if (csr & MGC_M_TXCSR_MODE) {
+                       if (csr & MGC_M_TXCSR_FIFONOTEMPTY) {
+                               /* this shouldn't happen; irq?? */
+                               ERR("shared fifo not empty?\n");
+                               musb_writew(ep->regs, MGC_O_HDRC_TXCSR,
+                                               MGC_M_TXCSR_FLUSHFIFO);
+                               musb_writew(ep->regs, MGC_O_HDRC_TXCSR,
+                                               MGC_M_TXCSR_FRCDATATOG);
+                       }
+               }
+               /* clear mode (and everything else) to enable Rx */
+               musb_writew(ep->regs, MGC_O_HDRC_TXCSR, 0);
+
+       /* scrub all previous state, clearing toggle */
+       } else {
+               csr = musb_readw(ep->regs, MGC_O_HDRC_RXCSR);
+               if (csr & MGC_M_RXCSR_RXPKTRDY)
+                       WARN("rx%d, packet/%d ready?\n", ep->bLocalEnd,
+                               musb_readw(ep->regs, MGC_O_HDRC_RXCOUNT));
+
+               musb_h_flush_rxfifo(ep, MGC_M_RXCSR_CLRDATATOG);
+       }
+
+       /* target addr and (for multipoint) hub addr/port */
+       if (musb->bIsMultipoint) {
+               musb_writeb(ep->target_regs, MGC_O_HDRC_RXFUNCADDR,
+                       qh->addr_reg);
+               musb_writeb(ep->target_regs, MGC_O_HDRC_RXHUBADDR,
+                       qh->h_addr_reg);
+               musb_writeb(ep->target_regs, MGC_O_HDRC_RXHUBPORT,
+                       qh->h_port_reg);
+       } else
+               musb_writeb(musb->pRegs, MGC_O_HDRC_FADDR, qh->addr_reg);
+
+       /* protocol/endpoint, interval/NAKlimit, i/o size */
+       musb_writeb(ep->regs, MGC_O_HDRC_RXTYPE, qh->type_reg);
+       musb_writeb(ep->regs, MGC_O_HDRC_RXINTERVAL, qh->intv_reg);
+       /* NOTE: bulk combining rewrites high bits of maxpacket */
+       musb_writew(ep->regs, MGC_O_HDRC_RXMAXP, qh->maxpacket);
+
+       ep->rx_reinit = 0;
+}
+
+
+/*
+ * Program an HDRC endpoint as per the given URB
+ * Context: irqs blocked, controller lock held
+ */
+static void musb_ep_program(struct musb *pThis, u8 bEnd,
+                       struct urb *pUrb, unsigned int is_out,
+                       u8 * pBuffer, u32 dwLength)
+{
+       struct dma_controller   *pDmaController;
+       struct dma_channel      *pDmaChannel;
+       u8                      bDmaOk;
+       void __iomem            *pBase = pThis->pRegs;
+       struct musb_hw_ep       *pEnd = pThis->aLocalEnd + bEnd;
+       void __iomem            *epio = pEnd->regs;
+       struct musb_qh          *qh;
+       u16                     wPacketSize;
+
+       if (!is_out || pEnd->bIsSharedFifo)
+               qh = pEnd->in_qh;
+       else
+               qh = pEnd->out_qh;
+
+       wPacketSize = qh->maxpacket;
+
+       DBG(3, "%s hw%d urb %p spd%d dev%d ep%d%s "
+                               "h_addr%02x h_port%02x bytes %d\n",
+                       is_out ? "-->" : "<--",
+                       bEnd, pUrb, pUrb->dev->speed,
+                       qh->addr_reg, qh->epnum, is_out ? "out" : "in",
+                       qh->h_addr_reg, qh->h_port_reg,
+                       dwLength);
+
+       MGC_SelectEnd(pBase, bEnd);
+
+       /* candidate for DMA? */
+       pDmaController = pThis->pDmaController;
+       if (is_dma_capable() && bEnd && pDmaController) {
+               pDmaChannel = is_out ? pEnd->tx_channel : pEnd->rx_channel;
+               if (!pDmaChannel) {
+                       pDmaChannel = pDmaController->channel_alloc(
+                                       pDmaController, pEnd, is_out);
+                       if (is_out)
+                               pEnd->tx_channel = pDmaChannel;
+                       else
+                               pEnd->rx_channel = pDmaChannel;
+               }
+       } else
+               pDmaChannel = NULL;
+
+       /* make sure we clear DMAEnab, autoSet bits from previous run */
+
+       /* OUT/transmit/EP0 or IN/receive? */
+       if (is_out) {
+               u16     wCsr;
+               u16     wIntrTxE;
+               u16     wLoadCount;
+
+               wCsr = musb_readw(epio, MGC_O_HDRC_TXCSR);
+
+               /* disable interrupt in case we flush */
+               wIntrTxE = musb_readw(pBase, MGC_O_HDRC_INTRTXE);
+               musb_writew(pBase, MGC_O_HDRC_INTRTXE, wIntrTxE & ~(1 << bEnd));
+
+               /* general endpoint setup */
+               if (bEnd) {
+                       u16     csr = wCsr;
+
+                       /* ASSERT:  TXCSR_DMAENAB was already cleared */
+
+                       /* flush all old state, set default */
+                       if (csr & MGC_M_TXCSR_FIFONOTEMPTY)
+                               csr |= MGC_M_TXCSR_FLUSHFIFO;
+                       csr &= ~(MGC_M_TXCSR_H_NAKTIMEOUT
+                                       | MGC_M_TXCSR_DMAMODE
+                                       | MGC_M_TXCSR_FRCDATATOG
+                                       | MGC_M_TXCSR_H_RXSTALL
+                                       | MGC_M_TXCSR_H_ERROR
+                                       | MGC_M_TXCSR_FIFONOTEMPTY
+                                       | MGC_M_TXCSR_TXPKTRDY
+                                       );
+                       csr |= MGC_M_TXCSR_MODE;
+
+                       if (usb_gettoggle(pUrb->dev,
+                                       qh->epnum, 1))
+                               csr |= MGC_M_TXCSR_H_WR_DATATOGGLE
+                                       | MGC_M_TXCSR_H_DATATOGGLE;
+                       else
+                               csr |= MGC_M_TXCSR_CLRDATATOG;
+
+                       /* twice in case of double packet buffering */
+                       musb_writew(epio, MGC_O_HDRC_TXCSR, csr);
+                       /* REVISIT may need to clear FLUSHFIFO ... */
+                       musb_writew(epio, MGC_O_HDRC_TXCSR, csr);
+                       wCsr = musb_readw(epio, MGC_O_HDRC_TXCSR);
+               } else {
+                       /* endpoint 0: just flush */
+                       musb_writew(epio, MGC_O_HDRC_CSR0,
+                               wCsr | MGC_M_CSR0_FLUSHFIFO);
+                       musb_writew(epio, MGC_O_HDRC_CSR0,
+                               wCsr | MGC_M_CSR0_FLUSHFIFO);
+               }
+
+               /* target addr and (for multipoint) hub addr/port */
+               if (pThis->bIsMultipoint) {
+                       musb_writeb(pBase,
+                               MGC_BUSCTL_OFFSET(bEnd, MGC_O_HDRC_TXFUNCADDR),
+                               qh->addr_reg);
+                       musb_writeb(pBase,
+                               MGC_BUSCTL_OFFSET(bEnd, MGC_O_HDRC_TXHUBADDR),
+                               qh->h_addr_reg);
+                       musb_writeb(pBase,
+                               MGC_BUSCTL_OFFSET(bEnd, MGC_O_HDRC_TXHUBPORT),
+                               qh->h_port_reg);
+/* FIXME if !bEnd, do the same for RX ... */
+               } else
+                       musb_writeb(pBase, MGC_O_HDRC_FADDR, qh->addr_reg);
+
+               /* protocol/endpoint/interval/NAKlimit */
+               if (bEnd) {
+                       musb_writeb(epio, MGC_O_HDRC_TXTYPE, qh->type_reg);
+                       if (can_bulk_split(pThis, qh->type))
+                               musb_writew(epio, MGC_O_HDRC_TXMAXP,
+                                       wPacketSize
+                                       | ((pEnd->wMaxPacketSizeTx /
+                                               wPacketSize) - 1) << 11);
+                       else
+                               musb_writew(epio, MGC_O_HDRC_TXMAXP,
+                                       wPacketSize);
+                       musb_writeb(epio, MGC_O_HDRC_TXINTERVAL, qh->intv_reg);
+               } else {
+                       musb_writeb(epio, MGC_O_HDRC_NAKLIMIT0, qh->intv_reg);
+                       if (pThis->bIsMultipoint)
+                               musb_writeb(epio, MGC_O_HDRC_TYPE0,
+                                               qh->type_reg);
+               }
+
+               if (can_bulk_split(pThis, qh->type))
+                       wLoadCount = min((u32) pEnd->wMaxPacketSizeTx,
+                                               dwLength);
+               else
+                       wLoadCount = min((u32) wPacketSize, dwLength);
+
+#ifdef CONFIG_USB_INVENTRA_DMA
+               if (pDmaChannel) {
+
+                       /* clear previous state */
+                       wCsr = musb_readw(epio, MGC_O_HDRC_TXCSR);
+                       wCsr &= ~(MGC_M_TXCSR_AUTOSET
+                               | MGC_M_TXCSR_DMAMODE
+                               | MGC_M_TXCSR_DMAENAB);
+                        wCsr |= MGC_M_TXCSR_MODE;
+                       musb_writew(epio, MGC_O_HDRC_TXCSR,
+                               wCsr | MGC_M_TXCSR_MODE);
+
+                       qh->segsize = min(dwLength, pDmaChannel->dwMaxLength);
+
+                       if (qh->segsize <= wPacketSize)
+                               pDmaChannel->bDesiredMode = 0;
+                       else
+                               pDmaChannel->bDesiredMode = 1;
+
+
+                       if (pDmaChannel->bDesiredMode == 0) {
+                               wCsr &= ~(MGC_M_TXCSR_AUTOSET
+                                       | MGC_M_TXCSR_DMAMODE);
+                               wCsr |= (MGC_M_TXCSR_DMAENAB);
+                                       // against programming guide
+                       } else
+                               wCsr |= (MGC_M_TXCSR_AUTOSET
+                                       | MGC_M_TXCSR_DMAENAB
+                                       | MGC_M_TXCSR_DMAMODE);
+
+                       musb_writew(epio, MGC_O_HDRC_TXCSR, wCsr);
+
+                       bDmaOk = pDmaController->channel_program(
+                                       pDmaChannel, wPacketSize,
+                                       pDmaChannel->bDesiredMode,
+                                       pUrb->transfer_dma,
+                                       qh->segsize);
+                       if (bDmaOk) {
+                               wLoadCount = 0;
+                       } else {
+                               pDmaController->channel_release(pDmaChannel);
+                               if (is_out)
+                                       pEnd->tx_channel = NULL;
+                               else
+                                       pEnd->rx_channel = NULL;
+                               pDmaChannel = NULL;
+                       }
+               }
+#endif
+
+               /* candidate for DMA */
+               if (is_cppi_enabled() && pDmaChannel) {
+
+                       /* program endpoint CSRs first, then setup DMA.
+                        * assume CPPI setup succeeds.
+                        * defer enabling dma.
+                        */
+                       wCsr = musb_readw(epio, MGC_O_HDRC_TXCSR);
+                       wCsr &= ~(MGC_M_TXCSR_AUTOSET
+                                       | MGC_M_TXCSR_DMAMODE
+                                       | MGC_M_TXCSR_DMAENAB);
+                       wCsr |= MGC_M_TXCSR_MODE;
+                       musb_writew(epio, MGC_O_HDRC_TXCSR,
+                               wCsr | MGC_M_TXCSR_MODE);
+
+                       pDmaChannel->dwActualLength = 0L;
+                       qh->segsize = dwLength;
+
+                       /* TX uses "rndis" mode automatically, but needs help
+                        * to identify the zero-length-final-packet case.
+                        */
+                       bDmaOk = pDmaController->channel_program(
+                                       pDmaChannel, wPacketSize,
+                                       (pUrb->transfer_flags
+                                                       & URB_ZERO_PACKET)
+                                               == URB_ZERO_PACKET,
+                                       pUrb->transfer_dma,
+                                       qh->segsize);
+                       if (bDmaOk) {
+                               wLoadCount = 0;
+                       } else {
+                               pDmaController->channel_release(pDmaChannel);
+                               pDmaChannel = pEnd->tx_channel = NULL;
+
+                               /* REVISIT there's an error path here that
+                                * needs handling:  can't do dma, but
+                                * there's no pio buffer address...
+                                */
+                       }
+               }
+
+               if (wLoadCount) {
+                       /* ASSERT:  TXCSR_DMAENAB was already cleared */
+
+                       /* PIO to load FIFO */
+                       qh->segsize = wLoadCount;
+                       musb_write_fifo(pEnd, wLoadCount, pBuffer);
+                       wCsr = musb_readw(epio, MGC_O_HDRC_TXCSR);
+                       wCsr &= ~(MGC_M_TXCSR_DMAENAB
+                               | MGC_M_TXCSR_DMAMODE
+                               | MGC_M_TXCSR_AUTOSET);
+                       /* write CSR */
+                       wCsr |= MGC_M_TXCSR_MODE;
+
+                       if (bEnd)
+                               musb_writew(epio, MGC_O_HDRC_TXCSR, wCsr);
+               }
+
+               /* re-enable interrupt */
+               musb_writew(pBase, MGC_O_HDRC_INTRTXE, wIntrTxE);
+
+       /* IN/receive */
+       } else {
+               u16     csr;
+
+               if (pEnd->rx_reinit) {
+                       musb_rx_reinit(pThis, qh, pEnd);
+
+                       /* init new state: toggle and NYET, maybe DMA later */
+                       if (usb_gettoggle(pUrb->dev, qh->epnum, 0))
+                               csr = MGC_M_RXCSR_H_WR_DATATOGGLE
+                                       | MGC_M_RXCSR_H_DATATOGGLE;
+                       else
+                               csr = 0;
+                       if (qh->type == USB_ENDPOINT_XFER_INT)
+                               csr |= MGC_M_RXCSR_DISNYET;
+
+               } else {
+                       csr = musb_readw(pEnd->regs, MGC_O_HDRC_RXCSR);
+
+                       if (csr & (MGC_M_RXCSR_RXPKTRDY
+                                       | MGC_M_RXCSR_DMAENAB
+                                       | MGC_M_RXCSR_H_REQPKT))
+                               ERR("broken !rx_reinit, ep%d csr %04x\n",
+                                               pEnd->bLocalEnd, csr);
+
+                       /* scrub any stale state, leaving toggle alone */
+                       csr &= MGC_M_RXCSR_DISNYET;
+               }
+
+               /* kick things off */
+
+               if (is_cppi_enabled()) {
+                       /* candidate for DMA */
+                       if (pDmaChannel) {
+                               pDmaChannel->dwActualLength = 0L;
+                               qh->segsize = dwLength;
+
+                               /* AUTOREQ is in a DMA register */
+                               musb_writew(pEnd->regs, MGC_O_HDRC_RXCSR, csr);
+                               csr = musb_readw(pEnd->regs,
+                                               MGC_O_HDRC_RXCSR);
+
+                               /* unless caller treats short rx transfers as
+                                * errors, we dare not queue multiple transfers.
+                                */
+                               bDmaOk = pDmaController->channel_program(
+                                               pDmaChannel, wPacketSize,
+                                               !(pUrb->transfer_flags
+                                                       & URB_SHORT_NOT_OK),
+                                               pUrb->transfer_dma,
+                                               qh->segsize);
+                               if (!bDmaOk) {
+                                       pDmaController->channel_release(
+                                                       pDmaChannel);
+                                       pDmaChannel = pEnd->rx_channel = NULL;
+                               } else
+                                       csr |= MGC_M_RXCSR_DMAENAB;
+                       }
+               }
+
+               csr |= MGC_M_RXCSR_H_REQPKT;
+               DBG(7, "RXCSR%d := %04x\n", bEnd, csr);
+               musb_writew(pEnd->regs, MGC_O_HDRC_RXCSR, csr);
+               csr = musb_readw(pEnd->regs, MGC_O_HDRC_RXCSR);
+       }
+}
+
+
+/*
+ * Service the default endpoint (ep0) as host.
+ * return TRUE if more packets are required for this transaction
+ */
+static u8 musb_h_ep0_continue(struct musb *pThis,
+                               u16 wCount, struct urb *pUrb)
+{
+       u8 bMore = FALSE;
+       u8 *pFifoDest = NULL;
+       u16 wFifoCount = 0;
+       struct musb_hw_ep       *pEnd = pThis->control_ep;
+       struct musb_qh          *qh = pEnd->in_qh;
+       struct usb_ctrlrequest  *pRequest;
+
+       pRequest = (struct usb_ctrlrequest *) pUrb->setup_packet;
+       if (MGC_END0_IN == pThis->bEnd0Stage) {
+               /* we are receiving from peripheral */
+               pFifoDest = pUrb->transfer_buffer + pUrb->actual_length;
+               wFifoCount = min(wCount, ((u16) (pUrb->transfer_buffer_length
+                                       - pUrb->actual_length)));
+               if (wFifoCount < wCount)
+                       pUrb->status = -EOVERFLOW;
+
+               musb_read_fifo(pEnd, wFifoCount, pFifoDest);
+
+               pUrb->actual_length += wFifoCount;
+               if (wCount < qh->maxpacket) {
+                       /* always terminate on short read; it's
+                        * rarely reported as an error.
+                        */
+                       if ((pUrb->transfer_flags & URB_SHORT_NOT_OK)
+                                       && (pUrb->actual_length <
+                                               pUrb->transfer_buffer_length))
+                               pUrb->status = -EREMOTEIO;
+               } else if (pUrb->actual_length <
+                               pUrb->transfer_buffer_length)
+                       bMore = TRUE;
+       } else {
+/*
+       DBG(3, "%s hw%d urb %p spd%d dev%d ep%d%s "
+                               "hub%d port%d%s bytes %d\n",
+                       is_out ? "-->" : "<--",
+                       bEnd, pUrb, pUrb->dev->speed,
+                       bAddress, qh->epnum, is_out ? "out" : "in",
+                       bHubAddr, bHubPort + 1,
+                       bIsMulti ? " multi" : "",
+                       dwLength);
+*/
+               if ((MGC_END0_START == pThis->bEnd0Stage)
+                               && (pRequest->bRequestType & USB_DIR_IN)) {
+                       /* this means we just did setup; switch to IN */
+                       DBG(4, "start IN-DATA\n");
+                       pThis->bEnd0Stage = MGC_END0_IN;
+                       bMore = TRUE;
+
+               } else if (pRequest->wLength
+                               && (MGC_END0_START == pThis->bEnd0Stage)) {
+                       pThis->bEnd0Stage = MGC_END0_OUT;
+                       pFifoDest = (u8 *) (pUrb->transfer_buffer
+                                       + pUrb->actual_length);
+                       wFifoCount = min(qh->maxpacket, ((u16)
+                                       (pUrb->transfer_buffer_length
+                                       - pUrb->actual_length)));
+                       DBG(3, "Sending %d bytes to %p\n",
+                                       wFifoCount, pFifoDest);
+                       musb_write_fifo(pEnd, wFifoCount, pFifoDest);
+
+                       qh->segsize = wFifoCount;
+                       pUrb->actual_length += wFifoCount;
+                       if (pUrb->actual_length
+                                       < pUrb->transfer_buffer_length) {
+                               bMore = TRUE;
+                       }
+               }
+       }
+
+       return bMore;
+}
+
+/*
+ * Handle default endpoint interrupt as host. Only called in IRQ time
+ * from the LinuxIsr() interrupt service routine.
+ *
+ * called with controller irqlocked
+ */
+irqreturn_t musb_h_ep0_irq(struct musb *pThis)
+{
+       struct urb              *pUrb;
+       u16                     wCsrVal, wCount;
+       int                     status = 0;
+       void __iomem            *pBase = pThis->pRegs;
+       struct musb_hw_ep       *pEnd = pThis->control_ep;
+       void __iomem            *epio = pEnd->regs;
+       struct musb_qh          *qh = pEnd->in_qh;
+       u8                      bComplete = FALSE;
+       irqreturn_t             retval = IRQ_NONE;
+
+       /* ep0 only has one queue, "in" */
+       pUrb = next_urb(qh);
+
+       MGC_SelectEnd(pBase, 0);
+       wCsrVal = musb_readw(epio, MGC_O_HDRC_CSR0);
+       wCount = musb_readb(epio, MGC_O_HDRC_COUNT0);
+
+       DBG(4, "<== csr0 %04x, qh %p, count %d, urb %p, stage %d\n",
+               wCsrVal, qh, wCount, pUrb, pThis->bEnd0Stage);
+
+       /* if we just did status stage, we are done */
+       if (MGC_END0_STATUS == pThis->bEnd0Stage) {
+               retval = IRQ_HANDLED;
+               bComplete = TRUE;
+       }
+
+       /* prepare status */
+       if (wCsrVal & MGC_M_CSR0_H_RXSTALL) {
+               DBG(6, "STALLING ENDPOINT\n");
+               status = -EPIPE;
+
+       } else if (wCsrVal & MGC_M_CSR0_H_ERROR) {
+               DBG(2, "no response, csr0 %04x\n", wCsrVal);
+               status = -EPROTO;
+
+       } else if (wCsrVal & MGC_M_CSR0_H_NAKTIMEOUT) {
+               DBG(2, "control NAK timeout\n");
+
+               /* NOTE:  this code path would be a good place to PAUSE a
+                * control transfer, if another one is queued, so that
+                * ep0 is more likely to stay busy.
+                *
+                * if (qh->ring.next != &musb->control), then
+                * we have a candidate... NAKing is *NOT* an error
+                */
+               musb_writew(epio, MGC_O_HDRC_CSR0, 0);
+               retval = IRQ_HANDLED;
+       }
+
+       if (status) {
+               DBG(6, "aborting\n");
+               retval = IRQ_HANDLED;
+               if (pUrb)
+                       pUrb->status = status;
+               bComplete = TRUE;
+
+               /* use the proper sequence to abort the transfer */
+               if (wCsrVal & MGC_M_CSR0_H_REQPKT) {
+                       wCsrVal &= ~MGC_M_CSR0_H_REQPKT;
+                       musb_writew(epio, MGC_O_HDRC_CSR0, wCsrVal);
+                       wCsrVal &= ~MGC_M_CSR0_H_NAKTIMEOUT;
+                       musb_writew(epio, MGC_O_HDRC_CSR0, wCsrVal);
+               } else {
+                       wCsrVal |= MGC_M_CSR0_FLUSHFIFO;
+                       musb_writew(epio, MGC_O_HDRC_CSR0, wCsrVal);
+                       musb_writew(epio, MGC_O_HDRC_CSR0, wCsrVal);
+                       wCsrVal &= ~MGC_M_CSR0_H_NAKTIMEOUT;
+                       musb_writew(epio, MGC_O_HDRC_CSR0, wCsrVal);
+               }
+
+               musb_writeb(epio, MGC_O_HDRC_NAKLIMIT0, 0);
+
+               /* clear it */
+               musb_writew(epio, MGC_O_HDRC_CSR0, 0);
+       }
+
+       if (unlikely(!pUrb)) {
+               /* stop endpoint since we have no place for its data, this
+                * SHOULD NEVER HAPPEN! */
+               ERR("no URB for end 0\n");
+
+               musb_writew(epio, MGC_O_HDRC_CSR0, MGC_M_CSR0_FLUSHFIFO);
+               musb_writew(epio, MGC_O_HDRC_CSR0, MGC_M_CSR0_FLUSHFIFO);
+               musb_writew(epio, MGC_O_HDRC_CSR0, 0);
+
+               goto done;
+       }
+
+       if (!bComplete) {
+               /* call common logic and prepare response */
+               if (musb_h_ep0_continue(pThis, wCount, pUrb)) {
+                       /* more packets required */
+                       wCsrVal = (MGC_END0_IN == pThis->bEnd0Stage)
+                               ?  MGC_M_CSR0_H_REQPKT : MGC_M_CSR0_TXPKTRDY;
+               } else {
+                       /* data transfer complete; perform status phase */
+                       wCsrVal = MGC_M_CSR0_H_STATUSPKT
+                               | (usb_pipeout(pUrb->pipe)
+                                       ? MGC_M_CSR0_H_REQPKT
+                                       : MGC_M_CSR0_TXPKTRDY);
+                       /* flag status stage */
+                       pThis->bEnd0Stage = MGC_END0_STATUS;
+
+                       DBG(5, "ep0 STATUS, csr %04x\n", wCsrVal);
+
+               }
+               musb_writew(epio, MGC_O_HDRC_CSR0, wCsrVal);
+               retval = IRQ_HANDLED;
+       }
+
+       /* call completion handler if done */
+       if (bComplete)
+               musb_advance_schedule(pThis, pUrb, pEnd, 1);
+done:
+       return retval;
+}
+
+
+#ifdef CONFIG_USB_INVENTRA_DMA
+
+/* Host side TX (OUT) using Mentor DMA works as follows:
+       submit_urb ->
+               - if queue was empty, Program Endpoint
+               - ... which starts DMA to fifo in mode 1 or 0
+
+       DMA Isr (transfer complete) -> TxAvail()
+               - Stop DMA (~DmaEnab)   (<--- Alert ... currently happens
+                                       only in musb_cleanup_urb)
+               - TxPktRdy has to be set in mode 0 or for
+                       short packets in mode 1.
+*/
+
+#endif
+
+/* Service a Tx-Available or dma completion irq for the endpoint */
+void musb_host_tx(struct musb *pThis, u8 bEnd)
+{
+       int                     nPipe;
+       u8                      bDone = FALSE;
+       u16                     wTxCsrVal;
+       size_t                  wLength = 0;
+       u8                      *pBuffer = NULL;
+       struct urb              *pUrb;
+       struct musb_hw_ep       *pEnd = pThis->aLocalEnd + bEnd;
+       void __iomem            *epio = pEnd->regs;
+       struct musb_qh          *qh = pEnd->out_qh;
+       u32                     status = 0;
+       void __iomem            *pBase = pThis->pRegs;
+       struct dma_channel      *dma;
+
+       pUrb = next_urb(qh);
+
+       MGC_SelectEnd(pBase, bEnd);
+       wTxCsrVal = musb_readw(epio, MGC_O_HDRC_TXCSR);
+
+       /* with CPPI, DMA sometimes triggers "extra" irqs */
+       if (!pUrb) {
+               DBG(4, "extra TX%d ready, csr %04x\n", bEnd, wTxCsrVal);
+               goto finish;
+       }
+
+       nPipe = pUrb->pipe;
+       dma = is_dma_capable() ? pEnd->tx_channel : NULL;
+       DBG(4, "OUT/TX%d end, csr %04x%s\n", bEnd, wTxCsrVal,
+                       dma ? ", dma" : "");
+
+       /* check for errors */
+       if (wTxCsrVal & MGC_M_TXCSR_H_RXSTALL) {
+               /* dma was disabled, fifo flushed */
+               DBG(3, "TX end %d stall\n", bEnd);
+
+               /* stall; record URB status */
+               status = -EPIPE;
+
+       } else if (wTxCsrVal & MGC_M_TXCSR_H_ERROR) {
+               /* (NON-ISO) dma was disabled, fifo flushed */
+               DBG(3, "TX 3strikes on ep=%d\n", bEnd);
+
+               status = -ETIMEDOUT;
+
+       } else if (wTxCsrVal & MGC_M_TXCSR_H_NAKTIMEOUT) {
+               DBG(6, "TX end=%d device not responding\n", bEnd);
+
+               /* NOTE:  this code path would be a good place to PAUSE a
+                * transfer, if there's some other (nonperiodic) tx urb
+                * that could use this fifo.  (dma complicates it...)
+                *
+                * if (bulk && qh->ring.next != &musb->out_bulk), then
+                * we have a candidate... NAKing is *NOT* an error
+                */
+               MGC_SelectEnd(pBase, bEnd);
+               musb_writew(epio, MGC_O_HDRC_CSR0,
+                               MGC_M_TXCSR_H_WZC_BITS
+                               | MGC_M_TXCSR_TXPKTRDY);
+               goto finish;
+       }
+
+       if (status) {
+               if (dma_channel_status(dma) == MGC_DMA_STATUS_BUSY) {
+                       dma->bStatus = MGC_DMA_STATUS_CORE_ABORT;
+                       (void) pThis->pDmaController->channel_abort(dma);
+               }
+
+               /* do the proper sequence to abort the transfer in the
+                * usb core; the dma engine should already be stopped.
+                */
+// SCRUB (TX)
+               if (wTxCsrVal & MGC_M_TXCSR_FIFONOTEMPTY)
+                       wTxCsrVal |= MGC_M_TXCSR_FLUSHFIFO;
+               wTxCsrVal &= ~(MGC_M_TXCSR_FIFONOTEMPTY
+                               | MGC_M_TXCSR_AUTOSET
+                               | MGC_M_TXCSR_DMAENAB
+                               | MGC_M_TXCSR_H_ERROR
+                               | MGC_M_TXCSR_H_RXSTALL
+                               | MGC_M_TXCSR_H_NAKTIMEOUT
+                               );
+
+               MGC_SelectEnd(pBase, bEnd);
+               musb_writew(epio, MGC_O_HDRC_TXCSR, wTxCsrVal);
+               /* REVISIT may need to clear FLUSHFIFO ... */
+               musb_writew(epio, MGC_O_HDRC_TXCSR, wTxCsrVal);
+               musb_writeb(epio, MGC_O_HDRC_TXINTERVAL, 0);
+
+               bDone = TRUE;
+       }
+
+       /* second cppi case */
+       if (dma_channel_status(dma) == MGC_DMA_STATUS_BUSY) {
+               DBG(4, "extra TX%d ready, csr %04x\n", bEnd, wTxCsrVal);
+               goto finish;
+
+       }
+
+       /* REVISIT this looks wrong... */
+       if (!status || dma || usb_pipeisoc(nPipe)) {
+
+#ifdef CONFIG_USB_INVENTRA_DMA
+               /* mode 0 or last short packet)
+                * REVISIT how about ZLP?
+                */
+               if ((dma->bDesiredMode == 0)
+                               || (dma->dwActualLength
+                                       & (qh->maxpacket - 1))) {
+                       /* Send out the packet first ... */
+                       MGC_SelectEnd(pBase, bEnd);
+                       musb_writew(epio, MGC_O_HDRC_TXCSR,
+                                       MGC_M_TXCSR_TXPKTRDY);
+               }
+#endif
+               if (dma)
+                       wLength = dma->dwActualLength;
+               else
+                       wLength = qh->segsize;
+               qh->offset += wLength;
+
+               if (usb_pipeisoc(nPipe)) {
+                       struct usb_iso_packet_descriptor        *d;
+
+                       d = pUrb->iso_frame_desc + qh->iso_idx;
+                       d->actual_length = qh->segsize;
+                       if (++qh->iso_idx >= pUrb->number_of_packets) {
+                               bDone = TRUE;
+                       } else if (!dma) {
+                               d++;
+                               pBuffer = pUrb->transfer_buffer + d->offset;
+                               wLength = d->length;
+                       }
+               } else if (dma) {
+                       bDone = TRUE;
+               } else {
+                       /* see if we need to send more data, or ZLP */
+                       if (qh->segsize < qh->maxpacket)
+                               bDone = TRUE;
+                       else if (qh->offset == pUrb->transfer_buffer_length
+                                       && !(pUrb-> transfer_flags
+                                                       & URB_ZERO_PACKET))
+                               bDone = TRUE;
+                       if (!bDone) {
+                               pBuffer = pUrb->transfer_buffer
+                                               + qh->offset;
+                               wLength = pUrb->transfer_buffer_length
+                                               - qh->offset;
+                       }
+               }
+       }
+
+       /* urb->status != -EINPROGRESS means request has been faulted,
+        * so we must abort this transfer after cleanup
+        */
+       if (pUrb->status != -EINPROGRESS) {
+               bDone = TRUE;
+               if (status == 0)
+                       status = pUrb->status;
+       }
+
+       if (bDone) {
+               /* set status */
+               pUrb->status = status;
+               pUrb->actual_length = qh->offset;
+               musb_advance_schedule(pThis, pUrb, pEnd, USB_DIR_OUT);
+
+       } else if (!(wTxCsrVal & MGC_M_TXCSR_DMAENAB)) {
+               // WARN_ON(!pBuffer);
+
+               /* REVISIT:  some docs say that when pEnd->tx_double_buffered,
+                * (and presumably, fifo is not half-full) we should write TWO
+                * packets before updating TXCSR ... other docs disagree ...
+                */
+               /* PIO:  start next packet in this URB */
+               wLength = min(qh->maxpacket, (u16) wLength);
+               musb_write_fifo(pEnd, wLength, pBuffer);
+               qh->segsize = wLength;
+
+               MGC_SelectEnd(pBase, bEnd);
+               musb_writew(epio, MGC_O_HDRC_TXCSR,
+                               MGC_M_TXCSR_H_WZC_BITS | MGC_M_TXCSR_TXPKTRDY);
+       } else
+               DBG(1, "not complete, but dma enabled?\n");
+
+finish:
+       return;
+}
+
+
+#ifdef CONFIG_USB_INVENTRA_DMA
+
+/* Host side RX (IN) using Mentor DMA works as follows:
+       submit_urb ->
+               - if queue was empty, ProgramEndpoint
+               - first IN token is sent out (by setting ReqPkt)
+       LinuxIsr -> RxReady()
+       /\      => first packet is received
+       |       - Set in mode 0 (DmaEnab, ~ReqPkt)
+       |               -> DMA Isr (transfer complete) -> RxReady()
+       |                   - Ack receive (~RxPktRdy), turn off DMA (~DmaEnab)
+       |                   - if urb not complete, send next IN token (ReqPkt)
+       |                          |            else complete urb.
+       |                          |
+       ---------------------------
+ *
+ * Nuances of mode 1:
+ *     For short packets, no ack (+RxPktRdy) is sent automatically
+ *     (even if AutoClear is ON)
+ *     For full packets, ack (~RxPktRdy) and next IN token (+ReqPkt) is sent
+ *     automatically => major problem, as collecting the next packet becomes
+ *     difficult. Hence mode 1 is not used.
+ *
+ * REVISIT
+ *     All we care about at this driver level is that
+ *       (a) all URBs terminate with REQPKT cleared and fifo(s) empty;
+ *       (b) termination conditions are: short RX, or buffer full;
+ *       (c) fault modes include
+ *           - iff URB_SHORT_NOT_OK, short RX status is -EREMOTEIO.
+ *             (and that endpoint's dma queue stops immediately)
+ *           - overflow (full, PLUS more bytes in the terminal packet)
+ *
+ *     So for example, usb-storage sets URB_SHORT_NOT_OK, and would
+ *     thus be a great candidate for using mode 1 ... for all but the
+ *     last packet of one URB's transfer.
+ */
+
+#endif
+
+/*
+ * Service an RX interrupt for the given IN endpoint; docs cover bulk, iso,
+ * and high-bandwidth IN transfer cases.
+ */
+void musb_host_rx(struct musb *pThis, u8 bEnd)
+{
+       struct urb              *pUrb;
+       struct musb_hw_ep       *pEnd = pThis->aLocalEnd + bEnd;
+       void __iomem            *epio = pEnd->regs;
+       struct musb_qh          *qh = pEnd->in_qh;
+       size_t                  xfer_len;
+       void __iomem            *pBase = pThis->pRegs;
+       int                     nPipe;
+       u16                     wRxCsrVal, wVal;
+       u8                      bIsochError = FALSE;
+       u8                      bDone = FALSE;
+       u32                     status;
+       struct dma_channel      *dma;
+
+       MGC_SelectEnd(pBase, bEnd);
+
+       pUrb = next_urb(qh);
+       dma = is_dma_capable() ? pEnd->rx_channel : NULL;
+       status = 0;
+       xfer_len = 0;
+
+       wVal = wRxCsrVal = musb_readw(epio, MGC_O_HDRC_RXCSR);
+
+       if (unlikely(!pUrb)) {
+               /* REVISIT -- THIS SHOULD NEVER HAPPEN ... but, at least
+                * usbtest #11 (unlinks) triggers it regularly, sometimes
+                * with fifo full.  (Only with DMA??)
+                */
+               DBG(3, "BOGUS RX%d ready, csr %04x, count %d\n", bEnd, wVal,
+                       musb_readw(epio, MGC_O_HDRC_RXCOUNT));
+               musb_h_flush_rxfifo(pEnd, MGC_M_RXCSR_CLRDATATOG);
+               return;
+       }
+
+       nPipe = pUrb->pipe;
+
+       DBG(5, "<== hw %d rxcsr %04x, urb actual %d (+dma %zd)\n",
+               bEnd, wRxCsrVal, pUrb->actual_length,
+               dma ? dma->dwActualLength : 0);
+
+       /* check for errors, concurrent stall & unlink is not really
+        * handled yet! */
+       if (wRxCsrVal & MGC_M_RXCSR_H_RXSTALL) {
+               DBG(3, "RX end %d STALL\n", bEnd);
+
+               /* stall; record URB status */
+               status = -EPIPE;
+
+       } else if (wRxCsrVal & MGC_M_RXCSR_H_ERROR) {
+               DBG(3, "end %d RX proto error\n", bEnd);
+
+               status = -EPROTO;
+               musb_writeb(epio, MGC_O_HDRC_RXINTERVAL, 0);
+
+       } else if (wRxCsrVal & MGC_M_RXCSR_DATAERROR) {
+
+               if (USB_ENDPOINT_XFER_ISOC != qh->type) {
+                       /* NOTE this code path would be a good place to PAUSE a
+                        * transfer, if there's some other (nonperiodic) rx urb
+                        * that could use this fifo.  (dma complicates it...)
+                        *
+                        * if (bulk && qh->ring.next != &musb->in_bulk), then
+                        * we have a candidate... NAKing is *NOT* an error
+                        */
+                       DBG(6, "RX end %d NAK timeout\n", bEnd);
+                       MGC_SelectEnd(pBase, bEnd);
+                       musb_writew(epio, MGC_O_HDRC_RXCSR,
+                                       MGC_M_RXCSR_H_WZC_BITS
+                                       | MGC_M_RXCSR_H_REQPKT);
+
+                       goto finish;
+               } else {
+                       DBG(4, "RX end %d ISO data error\n", bEnd);
+                       /* packet error reported later */
+                       bIsochError = TRUE;
+               }
+       }
+
+       /* faults abort the transfer */
+       if (status) {
+               /* clean up dma and collect transfer count */
+               if (dma_channel_status(dma) == MGC_DMA_STATUS_BUSY) {
+                       dma->bStatus = MGC_DMA_STATUS_CORE_ABORT;
+                       (void) pThis->pDmaController->channel_abort(dma);
+                       xfer_len = dma->dwActualLength;
+               }
+               musb_h_flush_rxfifo(pEnd, 0);
+               musb_writeb(epio, MGC_O_HDRC_RXINTERVAL, 0);
+               bDone = TRUE;
+               goto finish;
+       }
+
+       if (unlikely(dma_channel_status(dma) == MGC_DMA_STATUS_BUSY)) {
+               /* SHOULD NEVER HAPPEN ... but at least DaVinci has done it */
+               ERR("RX%d dma busy, csr %04x\n", bEnd, wRxCsrVal);
+               goto finish;
+       }
+
+       /* thorough shutdown for now ... given more precise fault handling
+        * and better queueing support, we might keep a DMA pipeline going
+        * while processing this irq for earlier completions.
+        */
+
+       /* FIXME this is _way_ too much in-line logic for Mentor DMA */
+
+#ifndef CONFIG_USB_INVENTRA_DMA
+       if (wRxCsrVal & MGC_M_RXCSR_H_REQPKT)  {
+               /* REVISIT this happened for a while on some short reads...
+                * the cleanup still needs investigation... looks bad...
+                * and also duplicates dma cleanup code above ... plus,
+                * shouldn't this be the "half full" double buffer case?
+                */
+               if (dma_channel_status(dma) == MGC_DMA_STATUS_BUSY) {
+                       dma->bStatus = MGC_DMA_STATUS_CORE_ABORT;
+                       (void) pThis->pDmaController->channel_abort(dma);
+                       xfer_len = dma->dwActualLength;
+                       bDone = TRUE;
+               }
+
+               DBG(2, "RXCSR%d %04x, reqpkt, len %zd%s\n", bEnd, wRxCsrVal,
+                               xfer_len, dma ? ", dma" : "");
+               wRxCsrVal &= ~MGC_M_RXCSR_H_REQPKT;
+
+               MGC_SelectEnd(pBase, bEnd);
+               musb_writew(epio, MGC_O_HDRC_RXCSR,
+                               MGC_M_RXCSR_H_WZC_BITS | wRxCsrVal);
+       }
+#endif
+       if (dma && (wRxCsrVal & MGC_M_RXCSR_DMAENAB)) {
+               xfer_len = dma->dwActualLength;
+
+               wVal &= ~(MGC_M_RXCSR_DMAENAB
+                       | MGC_M_RXCSR_H_AUTOREQ
+                       | MGC_M_RXCSR_AUTOCLEAR
+                       | MGC_M_RXCSR_RXPKTRDY);
+               musb_writew(pEnd->regs, MGC_O_HDRC_RXCSR, wVal);
+
+#ifdef CONFIG_USB_INVENTRA_DMA
+               pUrb->actual_length += xfer_len;
+               qh->offset += xfer_len;
+
+               /* bDone if pUrb buffer is full or short packet is recd */
+               bDone = (pUrb->actual_length >= pUrb->transfer_buffer_length)
+                       || (dma->dwActualLength & (qh->maxpacket - 1));
+
+               /* send IN token for next packet, without AUTOREQ */
+               if (!bDone) {
+                       wVal |= MGC_M_RXCSR_H_REQPKT;
+                       musb_writew(epio, MGC_O_HDRC_RXCSR,
+                               MGC_M_RXCSR_H_WZC_BITS | wVal);
+               }
+
+               DBG(4, "ep %d dma %s, rxcsr %04x, rxcount %d\n", bEnd,
+                       bDone ? "off" : "reset",
+                       musb_readw(epio, MGC_O_HDRC_RXCSR),
+                       musb_readw(epio, MGC_O_HDRC_RXCOUNT));
+#else
+               bDone = TRUE;
+#endif
+       } else if (pUrb->status == -EINPROGRESS) {
+               /* if no errors, be sure a packet is ready for unloading */
+               if (unlikely(!(wRxCsrVal & MGC_M_RXCSR_RXPKTRDY))) {
+                       status = -EPROTO;
+                       ERR("Rx interrupt with no errors or packet!\n");
+
+                       // FIXME this is another "SHOULD NEVER HAPPEN"
+
+// SCRUB (RX)
+                       /* do the proper sequence to abort the transfer */
+                       MGC_SelectEnd(pBase, bEnd);
+                       wVal &= ~MGC_M_RXCSR_H_REQPKT;
+                       musb_writew(epio, MGC_O_HDRC_RXCSR, wVal);
+                       goto finish;
+               }
+
+               /* we are expecting IN packets */
+#ifdef CONFIG_USB_INVENTRA_DMA
+               if (dma) {
+                       struct dma_controller   *c;
+                       u16                     wRxCount;
+                       int                     status;
+
+                       wRxCount = musb_readw(epio, MGC_O_HDRC_RXCOUNT);
+
+                       DBG(2, "RX%d count %d, buffer 0x%x len %d/%d\n",
+                                       bEnd, wRxCount,
+                                       pUrb->transfer_dma
+                                               + pUrb->actual_length,
+                                       qh->offset,
+                                       pUrb->transfer_buffer_length);
+
+                       c = pThis->pDmaController;
+
+                       dma->bDesiredMode = 0;
+#ifdef USE_MODE1
+                       /* because of the issue below, mode 1 will
+                        * only rarely behave with correct semantics.
+                        */
+                       if ((pUrb->transfer_flags &
+                                               URB_SHORT_NOT_OK)
+                               && (pUrb->transfer_buffer_length -
+                                               pUrb->actual_length)
+                                       > qh->maxpacket)
+                               dma->bDesiredMode = 1;
+#endif
+
+/* Disadvantage of using mode 1:
+ *     It's basically usable only for mass storage class; essentially all
+ *     other protocols also terminate transfers on short packets.
+ *
+ * Details:
+ *     An extra IN token is sent at the end of the transfer (due to AUTOREQ)
+ *     If you try to use mode 1 for (transfer_buffer_length - 512), and try
+ *     to use the extra IN token to grab the last packet using mode 0, then
+ *     the problem is that you cannot be sure when the device will send the
+ *     last packet and RxPktRdy set. Sometimes the packet is recd too soon
+ *     such that it gets lost when RxCSR is re-set at the end of the mode 1
+ *     transfer, while sometimes it is recd just a little late so that if you
+ *     try to configure for mode 0 soon after the mode 1 transfer is
+ *     completed, you will find rxcount 0. Okay, so you might think why not
+ *     wait for an interrupt when the pkt is recd. Well, you won't get any!
+ */
+
+                       wVal = musb_readw(epio, MGC_O_HDRC_RXCSR);
+                       wVal &= ~MGC_M_RXCSR_H_REQPKT;
+
+                       if (dma->bDesiredMode == 0)
+                               wVal &= ~MGC_M_RXCSR_H_AUTOREQ;
+                       else
+                               wVal |= MGC_M_RXCSR_H_AUTOREQ;
+                       wVal |= MGC_M_RXCSR_AUTOCLEAR | MGC_M_RXCSR_DMAENAB;
+
+                       musb_writew(epio, MGC_O_HDRC_RXCSR,
+                               MGC_M_RXCSR_H_WZC_BITS | wVal);
+
+                       /* REVISIT if when actual_length != 0,
+                        * transfer_buffer_length needs to be
+                        * adjusted first...
+                        */
+                       status = c->channel_program(
+                               dma, qh->maxpacket,
+                               dma->bDesiredMode,
+                               pUrb->transfer_dma
+                                       + pUrb->actual_length,
+                               (dma->bDesiredMode == 0)
+                                       ? wRxCount
+                                       : pUrb->transfer_buffer_length);
+
+                       if (!status) {
+                               c->channel_release(dma);
+                               dma = pEnd->rx_channel = NULL;
+                               /* REVISIT reset CSR */
+                       }
+               }
+#endif /* Mentor DMA */
+
+               if (!dma) {
+                       bDone = musb_host_packet_rx(pThis, pUrb,
+                                       bEnd, bIsochError);
+                       DBG(6, "read %spacket\n", bDone ? "last " : "");
+               }
+       }
+
+finish:
+       pUrb->actual_length += xfer_len;
+       qh->offset += xfer_len;
+       if (bDone) {
+               if (pUrb->status == -EINPROGRESS)
+                       pUrb->status = status;
+               musb_advance_schedule(pThis, pUrb, pEnd, USB_DIR_IN);
+       }
+}
+
+/* schedule nodes correspond to peripheral endpoints, like an OHCI QH.
+ * the software schedule associates multiple such nodes with a given
+ * host side hardware endpoint + direction; scheduling may activate
+ * that hardware endpoint.
+ */
+static int musb_schedule(
+       struct musb             *musb,
+       struct musb_qh          *qh,
+       int                     is_in)
+{
+       int                     idle;
+       int                     wBestDiff;
+       int                     nBestEnd, nEnd;
+       struct musb_hw_ep       *hw_ep = NULL;
+       struct list_head        *head = NULL;
+
+       /* use fixed hardware for control and bulk */
+       switch (qh->type) {
+       case USB_ENDPOINT_XFER_CONTROL:
+               head = &musb->control;
+               hw_ep = musb->control_ep;
+               break;
+       case USB_ENDPOINT_XFER_BULK:
+               hw_ep = musb->bulk_ep;
+               if (is_in)
+                       head = &musb->in_bulk;
+               else
+                       head = &musb->out_bulk;
+               break;
+       }
+       if (head) {
+               idle = list_empty(head);
+               list_add_tail(&qh->ring, head);
+               goto success;
+       }
+
+       /* else, periodic transfers get muxed to other endpoints */
+
+       /* FIXME this doesn't consider direction, so it can only
+        * work for one half of the endpoint hardware, and assumes
+        * the previous cases handled all non-shared endpoints...
+        */
+
+       /* we know this qh hasn't been scheduled, so all we need to do
+        * is choose which hardware endpoint to put it on ...
+        *
+        * REVISIT what we really want here is a regular schedule tree
+        * like e.g. OHCI uses, but for now musb->periodic is just an
+        * array of the _single_ logical endpoint associated with a
+        * given physical one (identity mapping logical->physical).
+        *
+        * that simplistic approach makes TT scheduling a lot simpler;
+        * there is none, and thus none of its complexity...
+        */
+       wBestDiff = 4096;
+       nBestEnd = -1;
+
+       for (nEnd = 1; nEnd < musb->bEndCount; nEnd++) {
+               int     diff;
+
+               if (musb->periodic[nEnd])
+                       continue;
+               hw_ep = &musb->aLocalEnd[nEnd];
+               if (hw_ep == musb->bulk_ep)
+                       continue;
+
+               if (is_in)
+                       diff = hw_ep->wMaxPacketSizeRx - qh->maxpacket;
+               else
+                       diff = hw_ep->wMaxPacketSizeTx - qh->maxpacket;
+
+               if (diff > 0 && wBestDiff > diff) {
+                       wBestDiff = diff;
+                       nBestEnd = nEnd;
+               }
+       }
+       if (nBestEnd < 0)
+               return -ENOSPC;
+
+       idle = 1;
+       hw_ep = musb->aLocalEnd + nBestEnd;
+       musb->periodic[nBestEnd] = qh;
+       DBG(4, "qh %p periodic slot %d\n", qh, nBestEnd);
+success:
+       qh->hw_ep = hw_ep;
+       qh->hep->hcpriv = qh;
+       if (idle)
+               musb_start_urb(musb, is_in, qh);
+       return 0;
+}
+
+static int musb_urb_enqueue(
+       struct usb_hcd                  *hcd,
+       struct usb_host_endpoint        *hep,
+       struct urb                      *urb,
+       gfp_t                           mem_flags)
+{
+       unsigned long                   flags;
+       struct musb                     *musb = hcd_to_musb(hcd);
+       struct musb_qh                  *qh = hep->hcpriv;
+       struct usb_endpoint_descriptor  *epd = &hep->desc;
+       int                             status;
+       unsigned                        type_reg;
+       unsigned                        interval;
+
+       /* host role must be active */
+       if (!is_host_active(musb) || !musb->is_active)
+               return -ENODEV;
+
+       /* DMA mapping was already done, if needed, and this urb is on
+        * hep->urb_list ... so there's little to do unless hep wasn't
+        * yet scheduled onto a live qh.
+        *
+        * REVISIT best to keep hep->hcpriv valid until the endpoint gets
+        * disabled, testing for empty qh->ring and avoiding qh setup costs
+        * except for the first urb queued after a config change.
+        */
+       if (qh) {
+               urb->hcpriv = qh;
+               return 0;
+       }
+
+       /* Allocate and initialize qh, minimizing the work done each time
+        * hw_ep gets reprogrammed, or with irqs blocked.  Then schedule it.
+        *
+        * REVISIT consider a dedicated qh kmem_cache, so it's harder
+        * for bugs in other kernel code to break this driver...
+        */
+       qh = kzalloc(sizeof *qh, mem_flags);
+       if (!qh)
+               return -ENOMEM;
+
+       qh->hep = hep;
+       qh->dev = urb->dev;
+       INIT_LIST_HEAD(&qh->ring);
+       qh->is_ready = 1;
+
+       qh->maxpacket = le16_to_cpu(epd->wMaxPacketSize);
+
+       /* no high bandwidth support yet */
+       if (qh->maxpacket & ~0x7ff) {
+               status = -EMSGSIZE;
+               goto done;
+       }
+
+       qh->epnum = epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+       qh->type = epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+
+       /* NOTE: urb->dev->devnum is wrong during SET_ADDRESS */
+       qh->addr_reg = (u8) usb_pipedevice(urb->pipe);
+
+       /* precompute rxtype/txtype/type0 register */
+       type_reg = (qh->type << 4) | qh->epnum;
+       switch (urb->dev->speed) {
+       case USB_SPEED_LOW:
+               type_reg |= 0xc0;
+               break;
+       case USB_SPEED_FULL:
+               type_reg |= 0x80;
+               break;
+       default:
+               type_reg |= 0x40;
+       }
+       qh->type_reg = type_reg;
+
+       /* precompute rxinterval/txinterval register */
+       interval = min((u8)16, epd->bInterval); /* log encoding */
+       switch (qh->type) {
+       case USB_ENDPOINT_XFER_INT:
+               /* fullspeed uses linear encoding */
+               if (USB_SPEED_FULL == urb->dev->speed) {
+                       interval = epd->bInterval;
+                       if (!interval)
+                               interval = 1;
+               }
+               /* FALLTHROUGH */
+       case USB_ENDPOINT_XFER_ISOC:
+               /* iso always uses log encoding */
+               break;
+       default:
+               /* REVISIT we actually want to use NAK limits, hinting to the
+                * transfer scheduling logic to try some other qh, e.g. try
+                * for 2 msec first:
+                *
+                * interval = (USB_SPEED_HIGH == pUrb->dev->speed) ? 16 : 2;
+                *
+                * The downside of disabling this is that transfer scheduling
+                * gets VERY unfair for nonperiodic transfers; a misbehaving
+                * peripheral could make that hurt.  Or for reads, one that's
+                * perfectly normal:  network and other drivers keep reads
+                * posted at all times, having one pending for a week should
+                * be perfectly safe.
+                *
+                * The upside of disabling it is avoidng transfer scheduling
+                * code to put this aside for while.
+                */
+               interval = 0;
+       }
+       qh->intv_reg = interval;
+
+       /* precompute addressing for external hub/tt ports */
+       if (musb->bIsMultipoint) {
+               struct usb_device       *parent = urb->dev->parent;
+
+               if (parent != hcd->self.root_hub) {
+                       qh->h_addr_reg = (u8) parent->devnum;
+
+                       /* set up tt info if needed */
+                       if (urb->dev->tt) {
+                               qh->h_port_reg = (u8) urb->dev->ttport;
+                               qh->h_addr_reg |= 0x80;
+                       }
+               }
+       }
+
+       /* invariant: hep->hcpriv is null OR the qh that's already scheduled.
+        * until we get real dma queues (with an entry for each urb/buffer),
+        * we only have work to do in the former case.
+        */
+       spin_lock_irqsave(&musb->Lock, flags);
+       if (hep->hcpriv) {
+               /* some concurrent activity submitted another urb to hep...
+                * odd, rare, error prone, but legal.
+                */
+               kfree(qh);
+               status = 0;
+       } else
+               status = musb_schedule(musb, qh,
+                               epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK);
+
+       if (status == 0) {
+               urb->hcpriv = qh;
+               /* FIXME set urb->start_frame for iso/intr, it's tested in
+                * musb_start_urb(), but otherwise only konicawc cares ...
+                */
+       }
+       spin_unlock_irqrestore(&musb->Lock, flags);
+
+done:
+       if (status != 0)
+               kfree(qh);
+       return status;
+}
+
+
+/*
+ * abort a transfer that's at the head of a hardware queue.
+ * called with controller locked, irqs blocked
+ * that hardware queue advances to the next transfer, unless prevented
+ */
+static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh, int is_in)
+{
+       struct musb_hw_ep       *ep = qh->hw_ep;
+       void __iomem            *epio = ep->regs;
+       unsigned                hw_end = ep->bLocalEnd;
+       void __iomem            *regs = ep->musb->pRegs;
+       u16                     csr;
+       int                     status = 0;
+
+       MGC_SelectEnd(regs, hw_end);
+
+       if (is_dma_capable()) {
+               struct dma_channel      *dma;
+
+               dma = is_in ? ep->rx_channel : ep->tx_channel;
+               if (dma) {
+                       status = ep->musb->pDmaController->channel_abort(dma);
+                       DBG(status ? 1 : 3,
+                               "abort %cX%d DMA for urb %p --> %d\n",
+                               is_in ? 'R' : 'T', ep->bLocalEnd,
+                               urb, status);
+                       urb->actual_length += dma->dwActualLength;
+               }
+       }
+
+       /* turn off DMA requests, discard state, stop polling ... */
+       if (is_in) {
+               /* giveback saves bulk toggle */
+               csr = musb_h_flush_rxfifo(ep, 0);
+
+               /* REVISIT we still get an irq; should likely clear the
+                * endpoint's irq status here to avoid bogus irqs.
+                * clearing that status is platform-specific...
+                */
+       } else {
+// SCRUB (TX)
+               csr = musb_readw(epio, MGC_O_HDRC_TXCSR);
+               if (csr & MGC_M_TXCSR_FIFONOTEMPTY)
+                       csr |= MGC_M_TXCSR_FLUSHFIFO;
+               csr &= ~( MGC_M_TXCSR_AUTOSET
+                       | MGC_M_TXCSR_DMAENAB
+                       | MGC_M_TXCSR_H_RXSTALL
+                       | MGC_M_TXCSR_H_NAKTIMEOUT
+                       | MGC_M_TXCSR_H_ERROR
+                       | MGC_M_TXCSR_FIFONOTEMPTY
+                       );
+               musb_writew(epio, MGC_O_HDRC_TXCSR, csr);
+               /* REVISIT may need to clear FLUSHFIFO ... */
+               musb_writew(epio, MGC_O_HDRC_TXCSR, csr);
+               /* flush cpu writebuffer */
+               csr = musb_readw(epio, MGC_O_HDRC_TXCSR);
+       }
+       if (status == 0)
+               musb_advance_schedule(ep->musb, urb, ep, is_in);
+       return status;
+}
+
+static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+{
+       struct musb             *musb = hcd_to_musb(hcd);
+       struct musb_qh          *qh;
+       struct list_head        *sched;
+       struct urb              *tmp;
+       unsigned long           flags;
+       int                     status = -ENOENT;
+
+       DBG(4, "urb=%p, dev%d ep%d%s\n", urb,
+                       usb_pipedevice(urb->pipe),
+                       usb_pipeendpoint(urb->pipe),
+                       usb_pipein(urb->pipe) ? "in" : "out");
+
+       spin_lock_irqsave(&musb->Lock, flags);
+
+       /* make sure the urb is still queued and not completed */
+       spin_lock(&urb->lock);
+       qh = urb->hcpriv;
+       if (qh) {
+               struct usb_host_endpoint        *hep;
+
+               hep = qh->hep;
+               list_for_each_entry(tmp, &hep->urb_list, urb_list) {
+                       if (urb == tmp) {
+                               status = 0;
+                               break;
+                       }
+               }
+       }
+       spin_unlock(&urb->lock);
+       if (status)
+               goto done;
+
+       /* Any URB not actively programmed into endpoint hardware can be
+        * immediately given back.  Such an URB must be at the head of its
+        * endpoint queue, unless someday we get real DMA queues.  And even
+        * then, it might not be known to the hardware...
+        *
+        * Otherwise abort current transfer, pending dma, etc.; urb->status
+        * has already been updated.  This is a synchronous abort; it'd be
+        * OK to hold off until after some IRQ, though.
+        */
+       if (!qh->is_ready || urb->urb_list.prev != &qh->hep->urb_list)
+               status = -EINPROGRESS;
+       else {
+               switch (qh->type) {
+               case USB_ENDPOINT_XFER_CONTROL:
+                       sched = &musb->control;
+                       break;
+               case USB_ENDPOINT_XFER_BULK:
+                       if (usb_pipein(urb->pipe))
+                               sched = &musb->in_bulk;
+                       else
+                               sched = &musb->out_bulk;
+                       break;
+               default:
+                       /* REVISIT when we get a schedule tree, periodic
+                        * transfers won't always be at the head of a
+                        * singleton queue...
+                        */
+                       sched = NULL;
+                       break;
+               }
+       }
+
+       /* NOTE:  qh is invalid unless !list_empty(&hep->urb_list) */
+       if (status < 0 || (sched && qh != first_qh(sched))) {
+               int     ready = qh->is_ready;
+
+               status = 0;
+               qh->is_ready = 0;
+               __musb_giveback(musb, urb, 0);
+               qh->is_ready = ready;
+       } else
+               status = musb_cleanup_urb(urb, qh, urb->pipe & USB_DIR_IN);
+done:
+       spin_unlock_irqrestore(&musb->Lock, flags);
+       return status;
+}
+
+/* disable an endpoint */
+static void
+musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep)
+{
+       u8                      epnum = hep->desc.bEndpointAddress;
+       unsigned long           flags;
+       struct musb             *musb = hcd_to_musb(hcd);
+       u8                      is_in = epnum & USB_DIR_IN;
+       struct musb_qh          *qh = hep->hcpriv;
+       struct urb              *urb, *tmp;
+       struct list_head        *sched;
+
+       if (!qh)
+               return;
+
+       spin_lock_irqsave(&musb->Lock, flags);
+
+       switch (qh->type) {
+       case USB_ENDPOINT_XFER_CONTROL:
+               sched = &musb->control;
+               break;
+       case USB_ENDPOINT_XFER_BULK:
+               if (is_in)
+                       sched = &musb->in_bulk;
+               else
+                       sched = &musb->out_bulk;
+               break;
+       default:
+               /* REVISIT when we get a schedule tree, periodic transfers
+                * won't always be at the head of a singleton queue...
+                */
+               sched = NULL;
+               break;
+       }
+
+       /* NOTE:  qh is invalid unless !list_empty(&hep->urb_list) */
+
+       /* kick first urb off the hardware, if needed */
+       qh->is_ready = 0;
+       if (!sched || qh == first_qh(sched)) {
+               urb = next_urb(qh);
+
+               /* make software (then hardware) stop ASAP */
+               spin_lock(&urb->lock);
+               if (urb->status == -EINPROGRESS)
+                       urb->status = -ESHUTDOWN;
+               spin_unlock(&urb->lock);
+
+               /* cleanup */
+               musb_cleanup_urb(urb, qh, urb->pipe & USB_DIR_IN);
+       } else
+               urb = NULL;
+
+       /* then just nuke all the others */
+       list_for_each_entry_safe_from(urb, tmp, &hep->urb_list, urb_list)
+               musb_giveback(qh, urb, -ESHUTDOWN);
+
+       spin_unlock_irqrestore(&musb->Lock, flags);
+}
+
+static int musb_h_get_frame_number(struct usb_hcd *hcd)
+{
+       struct musb     *musb = hcd_to_musb(hcd);
+
+       return musb_readw(musb->pRegs, MGC_O_HDRC_FRAME);
+}
+
+static int musb_h_start(struct usb_hcd *hcd)
+{
+       /* NOTE: musb_start() is called when the hub driver turns
+        * on port power, or when (OTG) peripheral starts.
+        */
+       hcd->state = HC_STATE_RUNNING;
+       return 0;
+}
+
+static void musb_h_stop(struct usb_hcd *hcd)
+{
+       musb_stop(hcd_to_musb(hcd));
+       hcd->state = HC_STATE_HALT;
+}
+
+static int musb_bus_suspend(struct usb_hcd *hcd)
+{
+       struct musb     *musb = hcd_to_musb(hcd);
+
+       return musb->is_active ? -EBUSY : 0;
+}
+
+static int musb_bus_resume(struct usb_hcd *hcd)
+{
+       /* resuming child port does the work */
+       return 0;
+}
+
+const struct hc_driver musb_hc_driver = {
+       .description            = "musb-hcd",
+       .product_desc           = "MUSB HDRC host driver",
+       .hcd_priv_size          = sizeof (struct musb),
+       .flags                  = HCD_USB2 | HCD_MEMORY,
+
+       /* not using irq handler or reset hooks from usbcore, since
+        * those must be shared with peripheral code for OTG configs
+        */
+
+       .start                  = musb_h_start,
+       .stop                   = musb_h_stop,
+
+       .get_frame_number       = musb_h_get_frame_number,
+
+       .urb_enqueue            = musb_urb_enqueue,
+       .urb_dequeue            = musb_urb_dequeue,
+       .endpoint_disable       = musb_h_disable,
+
+       .hub_status_data        = musb_hub_status_data,
+       .hub_control            = musb_hub_control,
+       .bus_suspend            = musb_bus_suspend,
+       .bus_resume             = musb_bus_resume,
+//     .start_port_reset       = NULL,
+//     .hub_irq_enable         = NULL,
+};
diff --git a/drivers/usb/musb/musb_host.h b/drivers/usb/musb/musb_host.h
new file mode 100644 (file)
index 0000000..556db74
--- /dev/null
@@ -0,0 +1,111 @@
+/******************************************************************
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * The Inventra Controller Driver for Linux is free software; you
+ * can redistribute it and/or modify it under the terms of the GNU
+ * General Public License version 2 as published by the Free Software
+ * Foundation.
+ *
+ * The Inventra Controller Driver for Linux is distributed in
+ * the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Inventra Controller Driver for Linux ; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ANY DOWNLOAD, USE, REPRODUCTION, MODIFICATION OR DISTRIBUTION
+ * OF THIS DRIVER INDICATES YOUR COMPLETE AND UNCONDITIONAL ACCEPTANCE
+ * OF THOSE TERMS.THIS DRIVER IS PROVIDED "AS IS" AND MENTOR GRAPHICS
+ * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, RELATED TO THIS DRIVER.
+ * MENTOR GRAPHICS SPECIFICALLY DISCLAIMS ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY; FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT.  MENTOR GRAPHICS DOES NOT PROVIDE SUPPORT
+ * SERVICES OR UPDATES FOR THIS DRIVER, EVEN IF YOU ARE A MENTOR
+ * GRAPHICS SUPPORT CUSTOMER.
+ ******************************************************************/
+
+#ifndef _MUSB_HOST_H
+#define _MUSB_HOST_H
+
+static inline struct usb_hcd *musb_to_hcd(struct musb *musb)
+{
+       return (struct usb_hcd *) (((void *)musb)
+                       - offsetof(struct usb_hcd, hcd_priv));
+}
+
+static inline struct musb *hcd_to_musb(struct usb_hcd *hcd)
+{
+       return (void *) hcd->hcd_priv;
+}
+
+/* stored in "usb_host_endpoint.hcpriv" for scheduled endpoints
+ */
+struct musb_qh {
+       struct usb_host_endpoint *hep;          /* usbcore info */
+       struct usb_device       *dev;
+       struct musb_hw_ep       *hw_ep;         /* current binding */
+
+       struct list_head        ring;           /* of musb_qh */
+       //struct musb_qh                *next;          /* for periodic tree */
+
+       unsigned                offset;         /* in urb->transfer_buffer */
+       unsigned                segsize;        /* current xfer fragment */
+
+       u8                      type_reg;       /* {rx,tx} type register */
+       u8                      intv_reg;       /* {rx,tx} interval register */
+       u8                      addr_reg;       /* device address register */
+       u8                      h_addr_reg;     /* hub address register */
+       u8                      h_port_reg;     /* hub port register */
+
+       u8                      is_ready;       /* safe to modify hw_ep */
+       u8                      type;           /* XFERTYPE_* */
+       u8                      epnum;
+       u16                     maxpacket;
+       u16                     frame;          /* for periodic schedule */
+       unsigned                iso_idx;        /* in urb->iso_frame_desc[] */
+};
+
+/* map from control or bulk queue head to the first qh on that ring */
+static inline struct musb_qh *first_qh(struct list_head *q)
+{
+       if (list_empty(q))
+               return NULL;
+       return container_of(q->next, struct musb_qh, ring);
+}
+
+
+extern void musb_root_disconnect(struct musb *musb);
+
+struct usb_hcd;
+
+extern int musb_hub_status_data(struct usb_hcd *hcd, char *buf);
+extern int musb_hub_control(struct usb_hcd *hcd,
+                       u16 typeReq, u16 wValue, u16 wIndex,
+                       char *buf, u16 wLength);
+
+extern const struct hc_driver musb_hc_driver;
+
+static inline struct urb *next_urb(struct musb_qh *qh)
+{
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+       struct list_head        *queue;
+
+       if (!qh)
+               return NULL;
+       queue = &qh->hep->urb_list;
+       if (list_empty(queue))
+               return NULL;
+       return container_of(queue->next, struct urb, urb_list);
+#else
+       return NULL;
+#endif
+}
+
+#endif                         /* _MUSB_HOST_H */
diff --git a/drivers/usb/musb/musb_procfs.c b/drivers/usb/musb/musb_procfs.c
new file mode 100644 (file)
index 0000000..e5c69d7
--- /dev/null
@@ -0,0 +1,843 @@
+/******************************************************************
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * The Inventra Controller Driver for Linux is free software; you
+ * can redistribute it and/or modify it under the terms of the GNU
+ * General Public License version 2 as published by the Free Software
+ * Foundation.
+ *
+ * The Inventra Controller Driver for Linux is distributed in
+ * the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Inventra Controller Driver for Linux ; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ANY DOWNLOAD, USE, REPRODUCTION, MODIFICATION OR DISTRIBUTION
+ * OF THIS DRIVER INDICATES YOUR COMPLETE AND UNCONDITIONAL ACCEPTANCE
+ * OF THOSE TERMS.THIS DRIVER IS PROVIDED "AS IS" AND MENTOR GRAPHICS
+ * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, RELATED TO THIS DRIVER.
+ * MENTOR GRAPHICS SPECIFICALLY DISCLAIMS ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY; FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT.  MENTOR GRAPHICS DOES NOT PROVIDE SUPPORT
+ * SERVICES OR UPDATES FOR THIS DRIVER, EVEN IF YOU ARE A MENTOR
+ * GRAPHICS SUPPORT CUSTOMER.
+ ******************************************************************/
+
+/*
+ * Inventra Controller Driver (ICD) for Linux.
+ *
+ * The code managing debug files (currently in procfs).
+ */
+
+#include <linux/kernel.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <asm/uaccess.h>       /* FIXME remove procfs writes */
+#include <asm/arch/hardware.h>
+
+#include "musbdefs.h"
+
+#include "davinci.h"
+
+
+const char *otg_state_string(struct musb *musb)
+{
+       switch (musb->xceiv.state) {
+       case OTG_STATE_A_IDLE:          return "a_idle";
+       case OTG_STATE_A_WAIT_VRISE:    return "a_wait_vrise";
+       case OTG_STATE_A_WAIT_BCON:     return "a_wait_bcon";
+       case OTG_STATE_A_HOST:          return "a_host";
+       case OTG_STATE_A_SUSPEND:       return "a_suspend";
+       case OTG_STATE_A_PERIPHERAL:    return "a_peripheral";
+       case OTG_STATE_A_WAIT_VFALL:    return "a_wait_vfall";
+       case OTG_STATE_A_VBUS_ERR:      return "a_vbus_err";
+       case OTG_STATE_B_IDLE:          return "b_idle";
+       case OTG_STATE_B_SRP_INIT:      return "b_srp_init";
+       case OTG_STATE_B_PERIPHERAL:    return "b_peripheral";
+       case OTG_STATE_B_WAIT_ACON:     return "b_wait_acon";
+       case OTG_STATE_B_HOST:          return "b_host";
+       default:                        return "UNDEFINED";
+       }
+}
+
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+
+static int dump_qh(struct musb_qh *qh, char *buf, unsigned max)
+{
+       int                             count;
+       int                             tmp;
+       struct usb_host_endpoint        *hep = qh->hep;
+       struct urb                      *urb;
+
+       count = snprintf(buf, max, "    qh %p dev%d ep%d%s max%d\n",
+                       qh, qh->dev->devnum, qh->epnum,
+                       ({ char *s; switch (qh->type) {
+                       case USB_ENDPOINT_XFER_BULK:
+                               s = "-bulk"; break;
+                       case USB_ENDPOINT_XFER_INT:
+                               s = "-int"; break;
+                       case USB_ENDPOINT_XFER_CONTROL:
+                               s = ""; break;
+                       default:
+                               s = "iso"; break;
+                       }; s; }),
+                       qh->maxpacket);
+       if (count <= 0)
+               return 0;
+       buf += count;
+       max -= count;
+
+       list_for_each_entry(urb, &hep->urb_list, urb_list) {
+               tmp = snprintf(buf, max, "\t%s urb %p %d/%d\n",
+                               usb_pipein(urb->pipe) ? "in" : "out",
+                               urb, urb->actual_length,
+                               urb->transfer_buffer_length);
+               if (tmp <= 0)
+                       break;
+               tmp = min(tmp, (int)max);
+               count += tmp;
+               buf += tmp;
+               max -= tmp;
+       }
+       return count;
+}
+
+static int
+dump_queue(struct list_head *q, char *buf, unsigned max)
+{
+       int             count = 0;
+       struct musb_qh  *qh;
+
+       list_for_each_entry(qh, q, ring) {
+               int     tmp;
+
+               tmp = dump_qh(qh, buf, max);
+               if (tmp <= 0)
+                       break;
+               tmp = min(tmp, (int)max);
+               count += tmp;
+               buf += tmp;
+               max -= tmp;
+       }
+       return count;
+}
+
+#endif /* HCD */
+
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+static int dump_ep(struct musb_ep *ep, char *buffer, unsigned max)
+{
+       char            *buf = buffer;
+       int             code = 0;
+       void __iomem    *regs = ep->hw_ep->regs;
+       char            *mode = "1buf";
+
+       if (ep->is_in) {
+               if (ep->hw_ep->tx_double_buffered)
+                       mode = "2buf";
+       } else {
+               if (ep->hw_ep->rx_double_buffered)
+                       mode = "2buf";
+       }
+
+       do {
+               struct usb_request      *req;
+
+               code = snprintf(buf, max,
+                               "\n%s (hw%d): %s%s, csr %04x maxp %04x\n",
+                               ep->name, ep->bEndNumber,
+                               mode, ep->dma ? " dma" : "",
+                               musb_readw(regs,
+                                       (ep->is_in || !ep->bEndNumber)
+                                               ? MGC_O_HDRC_TXCSR
+                                               : MGC_O_HDRC_RXCSR),
+                               musb_readw(regs, ep->is_in
+                                               ? MGC_O_HDRC_TXMAXP
+                                               : MGC_O_HDRC_RXMAXP)
+                               );
+               if (code <= 0)
+                       break;
+               code = min(code, (int) max);
+               buf += code;
+               max -= code;
+
+               if (is_cppi_enabled() && ep->bEndNumber) {
+                       unsigned        cppi = ep->bEndNumber - 1;
+                       void __iomem    *base = ep->pThis->ctrl_base;
+                       unsigned        off1 = cppi << 2;
+                       void __iomem    *ram = base;
+                       char            tmp[16];
+
+                       if (ep->is_in) {
+                               ram += DAVINCI_TXCPPI_STATERAM_OFFSET(cppi);
+                               tmp[0] = 0;
+                       } else {
+                               ram += DAVINCI_RXCPPI_STATERAM_OFFSET(cppi);
+                               snprintf(tmp, sizeof tmp, "%d left, ",
+                                       musb_readl(base,
+                                       DAVINCI_RXCPPI_BUFCNT0_REG + off1));
+                       }
+
+                       code = snprintf(buf, max, "%cX DMA%d: %s"
+                                       "%08x %08x, %08x %08x; "
+                                       "%08x %08x %08x .. %08x\n",
+                               ep->is_in ? 'T' : 'R',
+                               ep->bEndNumber - 1, tmp,
+                               musb_readl(ram, 0 * 4),
+                               musb_readl(ram, 1 * 4),
+                               musb_readl(ram, 2 * 4),
+                               musb_readl(ram, 3 * 4),
+                               musb_readl(ram, 4 * 4),
+                               musb_readl(ram, 5 * 4),
+                               musb_readl(ram, 6 * 4),
+                               musb_readl(ram, 7 * 4));
+                       if (code <= 0)
+                               break;
+                       code = min(code, (int) max);
+                       buf += code;
+                       max -= code;
+               }
+
+               if (list_empty(&ep->req_list)) {
+                       code = snprintf(buf, max, "\t(queue empty)\n");
+                       if (code <= 0)
+                               break;
+                       code = min(code, (int) max);
+                       buf += code;
+                       max -= code;
+                       break;
+               }
+               list_for_each_entry (req, &ep->req_list, list) {
+                       code = snprintf(buf, max, "\treq %p, %s%s%d/%d\n",
+                                       req,
+                                       req->zero ? "zero, " : "",
+                                       req->short_not_ok ? "!short, " : "",
+                                       req->actual, req->length);
+                       if (code <= 0)
+                               break;
+                       code = min(code, (int) max);
+                       buf += code;
+                       max -= code;
+               }
+       } while(0);
+       return buf - buffer;
+}
+#endif
+
+static int
+dump_end_info(struct musb *pThis, u8 bEnd, char *aBuffer, unsigned max)
+{
+       int                     code = 0;
+       char                    *buf = aBuffer;
+       struct musb_hw_ep       *pEnd = &pThis->aLocalEnd[bEnd];
+
+       do {
+               MGC_SelectEnd(pThis->pRegs, bEnd);
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+               if (is_host_active(pThis)) {
+                       int             dump_rx, dump_tx;
+                       void __iomem    *regs = pEnd->regs;
+
+                       /* TEMPORARY (!) until we have a real periodic
+                        * schedule tree ...
+                        */
+                       if (!bEnd) {
+                               /* control is shared, uses RX queue
+                                * but (mostly) shadowed tx registers
+                                */
+                               dump_tx = !list_empty(&pThis->control);
+                               dump_rx = 0;
+                       } else if (pEnd == pThis->bulk_ep) {
+                               dump_tx = !list_empty(&pThis->out_bulk);
+                               dump_rx = !list_empty(&pThis->in_bulk);
+                       } else if (pThis->periodic[bEnd]) {
+                               struct usb_host_endpoint        *hep;
+
+                               hep = pThis->periodic[bEnd]->hep;
+                               dump_rx = hep->desc.bEndpointAddress
+                                               & USB_ENDPOINT_DIR_MASK;
+                               dump_tx = !dump_rx;
+                       } else
+                               break;
+                       /* END TEMPORARY */
+
+
+                       if (dump_rx) {
+                               code = snprintf(buf, max,
+                                       "\nRX%d: %s rxcsr %04x interval %02x "
+                                       "max %04x type %02x; "
+                                       "dev %d hub %d port %d"
+                                       "\n",
+                                       bEnd,
+                                       pEnd->rx_double_buffered
+                                               ? "2buf" : "1buf",
+                                       musb_readw(regs, MGC_O_HDRC_RXCSR),
+                                       musb_readb(regs, MGC_O_HDRC_RXINTERVAL),
+                                       musb_readw(regs, MGC_O_HDRC_RXMAXP),
+                                       musb_readb(regs, MGC_O_HDRC_RXTYPE),
+                                       /* FIXME:  assumes multipoint */
+                                       musb_readb(pThis->pRegs,
+                                               MGC_BUSCTL_OFFSET(bEnd,
+                                               MGC_O_HDRC_RXFUNCADDR)),
+                                       musb_readb(pThis->pRegs,
+                                               MGC_BUSCTL_OFFSET(bEnd,
+                                               MGC_O_HDRC_RXHUBADDR)),
+                                       musb_readb(pThis->pRegs,
+                                               MGC_BUSCTL_OFFSET(bEnd,
+                                               MGC_O_HDRC_RXHUBPORT))
+                                       );
+                               if (code <= 0)
+                                       break;
+                               code = min(code, (int) max);
+                               buf += code;
+                               max -= code;
+
+                               if (is_cppi_enabled()
+                                               && bEnd
+                                               && pEnd->rx_channel) {
+                                       unsigned        cppi = bEnd - 1;
+                                       unsigned        off1 = cppi << 2;
+                                       void __iomem    *base;
+                                       void __iomem    *ram;
+                                       char            tmp[16];
+
+                                       base = pThis->ctrl_base;
+                                       ram = DAVINCI_RXCPPI_STATERAM_OFFSET(
+                                                       cppi) + base;
+                                       snprintf(tmp, sizeof tmp, "%d left, ",
+                                               musb_readl(base,
+                                               DAVINCI_RXCPPI_BUFCNT0_REG
+                                                               + off1));
+
+                                       code = snprintf(buf, max,
+                                               "    rx dma%d: %s"
+                                               "%08x %08x, %08x %08x; "
+                                               "%08x %08x %08x .. %08x\n",
+                                               cppi, tmp,
+                                               musb_readl(ram, 0 * 4),
+                                               musb_readl(ram, 1 * 4),
+                                               musb_readl(ram, 2 * 4),
+                                               musb_readl(ram, 3 * 4),
+                                               musb_readl(ram, 4 * 4),
+                                               musb_readl(ram, 5 * 4),
+                                               musb_readl(ram, 6 * 4),
+                                               musb_readl(ram, 7 * 4));
+                                       if (code <= 0)
+                                               break;
+                                       code = min(code, (int) max);
+                                       buf += code;
+                                       max -= code;
+                               }
+
+                               if (pEnd == pThis->bulk_ep
+                                               && !list_empty(
+                                                       &pThis->in_bulk)) {
+                                       code = dump_queue(&pThis->in_bulk,
+                                                       buf, max);
+                                       if (code <= 0)
+                                               break;
+                                       code = min(code, (int) max);
+                                       buf += code;
+                                       max -= code;
+                               } else if (pThis->periodic[bEnd]) {
+                                       code = dump_qh(pThis->periodic[bEnd],
+                                                       buf, max);
+                                       if (code <= 0)
+                                               break;
+                                       code = min(code, (int) max);
+                                       buf += code;
+                                       max -= code;
+                               }
+                       }
+
+                       if (dump_tx) {
+                               code = snprintf(buf, max,
+                                       "\nTX%d: %s txcsr %04x interval %02x "
+                                       "max %04x type %02x; "
+                                       "dev %d hub %d port %d"
+                                       "\n",
+                                       bEnd,
+                                       pEnd->tx_double_buffered
+                                               ? "2buf" : "1buf",
+                                       musb_readw(regs, MGC_O_HDRC_TXCSR),
+                                       musb_readb(regs, MGC_O_HDRC_TXINTERVAL),
+                                       musb_readw(regs, MGC_O_HDRC_TXMAXP),
+                                       musb_readb(regs, MGC_O_HDRC_TXTYPE),
+                                       /* FIXME:  assumes multipoint */
+                                       musb_readb(pThis->pRegs,
+                                               MGC_BUSCTL_OFFSET(bEnd,
+                                               MGC_O_HDRC_TXFUNCADDR)),
+                                       musb_readb(pThis->pRegs,
+                                               MGC_BUSCTL_OFFSET(bEnd,
+                                               MGC_O_HDRC_TXHUBADDR)),
+                                       musb_readb(pThis->pRegs,
+                                               MGC_BUSCTL_OFFSET(bEnd,
+                                               MGC_O_HDRC_TXHUBPORT))
+                                       );
+                               if (code <= 0)
+                                       break;
+                               code = min(code, (int) max);
+                               buf += code;
+                               max -= code;
+
+                               if (is_cppi_enabled()
+                                               && bEnd
+                                               && pEnd->tx_channel) {
+                                       unsigned        cppi = bEnd - 1;
+                                       void __iomem    *base;
+                                       void __iomem    *ram;
+
+                                       base = pThis->ctrl_base;
+                                       ram = DAVINCI_RXCPPI_STATERAM_OFFSET(
+                                                       cppi) + base;
+                                       code = snprintf(buf, max,
+                                               "    tx dma%d: "
+                                               "%08x %08x, %08x %08x; "
+                                               "%08x %08x %08x .. %08x\n",
+                                               cppi,
+                                               musb_readl(ram, 0 * 4),
+                                               musb_readl(ram, 1 * 4),
+                                               musb_readl(ram, 2 * 4),
+                                               musb_readl(ram, 3 * 4),
+                                               musb_readl(ram, 4 * 4),
+                                               musb_readl(ram, 5 * 4),
+                                               musb_readl(ram, 6 * 4),
+                                               musb_readl(ram, 7 * 4));
+                                       if (code <= 0)
+                                               break;
+                                       code = min(code, (int) max);
+                                       buf += code;
+                                       max -= code;
+                               }
+
+                               if (pEnd == pThis->control_ep
+                                               && !list_empty(
+                                                       &pThis->control)) {
+                                       code = dump_queue(&pThis->control,
+                                                       buf, max);
+                                       if (code <= 0)
+                                               break;
+                                       code = min(code, (int) max);
+                                       buf += code;
+                                       max -= code;
+                               } else if (pEnd == pThis->bulk_ep
+                                               && !list_empty(
+                                                       &pThis->out_bulk)) {
+                                       code = dump_queue(&pThis->out_bulk,
+                                                       buf, max);
+                                       if (code <= 0)
+                                               break;
+                                       code = min(code, (int) max);
+                                       buf += code;
+                                       max -= code;
+                               } else if (pThis->periodic[bEnd]) {
+                                       code = dump_qh(pThis->periodic[bEnd],
+                                                       buf, max);
+                                       if (code <= 0)
+                                               break;
+                                       code = min(code, (int) max);
+                                       buf += code;
+                                       max -= code;
+                               }
+                       }
+               }
+#endif
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+               if (is_peripheral_active(pThis)) {
+                       code = 0;
+
+                       if (pEnd->ep_in.desc || !bEnd) {
+                               code = dump_ep(&pEnd->ep_in, buf, max);
+                               if (code <= 0)
+                                       break;
+                               code = min(code, (int) max);
+                               buf += code;
+                               max -= code;
+                       }
+                       if (pEnd->ep_out.desc) {
+                               code = dump_ep(&pEnd->ep_out, buf, max);
+                               if (code <= 0)
+                                       break;
+                               code = min(code, (int) max);
+                               buf += code;
+                               max -= code;
+                       }
+               }
+#endif
+       } while (0);
+
+       return buf - aBuffer;
+}
+
+/** Dump the current status and compile options.
+ * @param pThis the device driver instance
+ * @param buffer where to dump the status; it must be big enough hold the
+ * result otherwise "BAD THINGS HAPPENS(TM)".
+ */
+static int dump_header_stats(struct musb *pThis, char *buffer)
+{
+       int code, count = 0;
+       const void __iomem *pBase = pThis->pRegs;
+
+       *buffer = 0;
+       count = sprintf(buffer, "Status: %sHDRC, Mode=%s "
+                               "(Power=%02x, DevCtl=%02x)\n",
+                       (pThis->bIsMultipoint ? "M" : ""), MUSB_MODE(pThis),
+                       musb_readb(pBase, MGC_O_HDRC_POWER),
+                       musb_readb(pBase, MGC_O_HDRC_DEVCTL));
+       if (count <= 0)
+               return 0;
+       buffer += count;
+
+       code = sprintf(buffer, "OTG state: %s; %sactive\n",
+                       otg_state_string(pThis),
+                       pThis->is_active ? "" : "in");
+       if (code <= 0)
+               goto done;
+       buffer += code;
+       count += code;
+
+       code = sprintf(buffer,
+                       "Options: "
+#ifdef CONFIG_USB_INVENTRA_FIFO
+                       "pio"
+#elif defined(CONFIG_USB_TI_CPPI_DMA)
+                       "cppi-dma"
+#elif defined(CONFIG_USB_INVENTRA_DMA)
+                       "musb-dma"
+#elif defined(CONFIG_USB_TUSB_OMAP_DMA)
+                       "tusb-omap-dma"
+#else
+                       "?dma?"
+#endif
+                       ", "
+#ifdef CONFIG_USB_MUSB_OTG
+                       "otg (peripheral+host)"
+#elif defined(CONFIG_USB_GADGET_MUSB_HDRC)
+                       "peripheral"
+#elif defined(CONFIG_USB_MUSB_HDRC_HCD)
+                       "host"
+#endif
+                       ", debug=%d [eps=%d]\n",
+               debug,
+               pThis->bEndCount);
+       if (code <= 0)
+               goto done;
+       count += code;
+       buffer += code;
+
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+       code = sprintf(buffer, "Root port status: %08x\n",
+                       pThis->port1_status);
+       if (code <= 0)
+               goto done;
+       buffer += code;
+       count += code;
+#endif
+
+#ifdef CONFIG_ARCH_DAVINCI
+       code = sprintf(buffer,
+                       "DaVinci: ctrl=%02x stat=%1x phy=%03x\n"
+                       "\trndis=%05x auto=%04x intsrc=%08x intmsk=%08x"
+                       "\n",
+                       musb_readl(pThis->ctrl_base, DAVINCI_USB_CTRL_REG),
+                       musb_readl(pThis->ctrl_base, DAVINCI_USB_STAT_REG),
+                       __raw_readl(IO_ADDRESS(USBPHY_CTL_PADDR)),
+                       musb_readl(pThis->ctrl_base, DAVINCI_RNDIS_REG),
+                       musb_readl(pThis->ctrl_base, DAVINCI_AUTOREQ_REG),
+                       musb_readl(pThis->ctrl_base,
+                                       DAVINCI_USB_INT_SOURCE_REG),
+                       musb_readl(pThis->ctrl_base,
+                                       DAVINCI_USB_INT_MASK_REG));
+       if (code <= 0)
+               goto done;
+       count += code;
+       buffer += code;
+#endif /* DAVINCI */
+
+#ifdef CONFIG_USB_TUSB6010
+       code = sprintf(buffer,
+                       "TUSB6010: devconf %08x, phy enable %08x drive %08x"
+                       "\n\totg %03x timer %08x"
+                       "\n\tprcm conf %08x mgmt %08x; int src %08x mask %08x"
+                       "\n",
+                       musb_readl(pThis->ctrl_base, TUSB_DEV_CONF),
+                       musb_readl(pThis->ctrl_base, TUSB_PHY_OTG_CTRL_ENABLE),
+                       musb_readl(pThis->ctrl_base, TUSB_PHY_OTG_CTRL),
+                       musb_readl(pThis->ctrl_base, TUSB_DEV_OTG_STAT),
+                       musb_readl(pThis->ctrl_base, TUSB_DEV_OTG_TIMER),
+                       musb_readl(pThis->ctrl_base, TUSB_PRCM_CONF),
+                       musb_readl(pThis->ctrl_base, TUSB_PRCM_MNGMT),
+                       musb_readl(pThis->ctrl_base, TUSB_INT_SRC),
+                       musb_readl(pThis->ctrl_base, TUSB_INT_MASK));
+       if (code <= 0)
+               goto done;
+       count += code;
+       buffer += code;
+#endif /* DAVINCI */
+
+       if (is_cppi_enabled() && pThis->pDmaController) {
+               code = sprintf(buffer,
+                               "CPPI: txcr=%d txsrc=%01x txena=%01x; "
+                               "rxcr=%d rxsrc=%01x rxena=%01x "
+                               "\n",
+                               musb_readl(pThis->ctrl_base,
+                                               DAVINCI_TXCPPI_CTRL_REG),
+                               musb_readl(pThis->ctrl_base,
+                                               DAVINCI_TXCPPI_RAW_REG),
+                               musb_readl(pThis->ctrl_base,
+                                               DAVINCI_TXCPPI_INTENAB_REG),
+                               musb_readl(pThis->ctrl_base,
+                                               DAVINCI_RXCPPI_CTRL_REG),
+                               musb_readl(pThis->ctrl_base,
+                                               DAVINCI_RXCPPI_RAW_REG),
+                               musb_readl(pThis->ctrl_base,
+                                               DAVINCI_RXCPPI_INTENAB_REG));
+               if (code <= 0)
+                       goto done;
+               count += code;
+               buffer += code;
+       }
+
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+       if (is_peripheral_enabled(pThis)) {
+               code = sprintf(buffer, "Gadget driver: %s\n",
+                               pThis->pGadgetDriver
+                                       ? pThis->pGadgetDriver->driver.name
+                                       : "(none)");
+               if (code <= 0)
+                       goto done;
+               count += code;
+               buffer += code;
+       }
+#endif
+
+done:
+       return count;
+}
+
+/* Write to ProcFS
+ *
+ * C soft-connect
+ * c soft-disconnect
+ * I enable HS
+ * i disable HS
+ * s stop session
+ * F force session (OTG-unfriendly)
+ * E rElinquish bus (OTG)
+ * H request host mode
+ * h cancel host request
+ * T start sending TEST_PACKET
+ * D<num> set/query the debug level
+ */
+static int musb_proc_write(struct file *file, const char __user *buffer,
+                       unsigned long count, void *data)
+{
+       char cmd;
+       u8 bReg;
+       struct musb *musb = (struct musb *)data;
+       void __iomem *pBase = musb->pRegs;
+
+       /* MOD_INC_USE_COUNT; */
+
+       copy_from_user(&cmd, buffer, 1);
+       switch (cmd) {
+       case 'C':
+               if (pBase) {
+                       bReg = musb_readb(pBase, MGC_O_HDRC_POWER)
+                                       | MGC_M_POWER_SOFTCONN;
+                       musb_writeb(pBase, MGC_O_HDRC_POWER, bReg);
+               }
+               break;
+
+       case 'c':
+               if (pBase) {
+                       bReg = musb_readb(pBase, MGC_O_HDRC_POWER)
+                                       & ~MGC_M_POWER_SOFTCONN;
+                       musb_writeb(pBase, MGC_O_HDRC_POWER, bReg);
+               }
+               break;
+
+       case 'I':
+               if (pBase) {
+                       bReg = musb_readb(pBase, MGC_O_HDRC_POWER)
+                                       | MGC_M_POWER_HSENAB;
+                       musb_writeb(pBase, MGC_O_HDRC_POWER, bReg);
+               }
+               break;
+
+       case 'i':
+               if (pBase) {
+                       bReg = musb_readb(pBase, MGC_O_HDRC_POWER)
+                                       & ~MGC_M_POWER_HSENAB;
+                       musb_writeb(pBase, MGC_O_HDRC_POWER, bReg);
+               }
+               break;
+
+       case 'F':
+               bReg = musb_readb(pBase, MGC_O_HDRC_DEVCTL);
+               bReg |= MGC_M_DEVCTL_SESSION;
+               musb_writeb(pBase, MGC_O_HDRC_DEVCTL, bReg);
+               break;
+
+       case 'H':
+               if (pBase) {
+                       bReg = musb_readb(pBase, MGC_O_HDRC_DEVCTL);
+                       bReg |= MGC_M_DEVCTL_HR;
+                       musb_writeb(pBase, MGC_O_HDRC_DEVCTL, bReg);
+                       //MUSB_HST_MODE( ((struct musb*)data) );
+                       //WARN("Host Mode\n");
+               }
+               break;
+
+       case 'h':
+               if (pBase) {
+                       bReg = musb_readb(pBase, MGC_O_HDRC_DEVCTL);
+                       bReg &= ~MGC_M_DEVCTL_HR;
+                       musb_writeb(pBase, MGC_O_HDRC_DEVCTL, bReg);
+               }
+               break;
+
+       case 'T':
+               if (pBase) {
+                       musb_load_testpacket(musb);
+                       musb_writeb(pBase, MGC_O_HDRC_TESTMODE,
+                                       MGC_M_TEST_PACKET);
+               }
+               break;
+
+#if (MUSB_DEBUG>0)
+               /* set/read debug level */
+       case 'D':{
+                       if (count > 1) {
+                               char digits[8], *p = digits;
+                               int i = 0, level = 0, sign = 1;
+                               int len = min(count - 1, (unsigned long)8);
+
+                               copy_from_user(&digits, &buffer[1], len);
+
+                               /* optional sign */
+                               if (*p == '-') {
+                                       len -= 1;
+                                       sign = -sign;
+                                       p++;
+                               }
+
+                               /* read it */
+                               while (i++ < len && *p > '0' && *p < '9') {
+                                       level = level * 10 + (*p - '0');
+                                       p++;
+                               }
+
+                               level *= sign;
+                               DBG(1, "debug level %d\n", level);
+                               debug = level;
+                       }
+               }
+               break;
+
+
+       case '?':
+               INFO("?: you are seeing it\n");
+               INFO("C/c: soft connect enable/disable\n");
+               INFO("I/i: hispeed enable/disable\n");
+               INFO("F: force session start\n");
+               INFO("H: host mode\n");
+               INFO("T: start sending TEST_PACKET\n");
+               INFO("D: set/read dbug level\n");
+               break;
+#endif
+
+       default:
+               ERR("Command %c not implemented\n", cmd);
+               break;
+       }
+
+       musb_platform_try_idle(musb);
+
+       return count;
+}
+
+static int musb_proc_read(char *page, char **start,
+                       off_t off, int count, int *eof, void *data)
+{
+       char *buffer = page;
+       int code = 0;
+       unsigned long   flags;
+       struct musb     *pThis = data;
+       unsigned        bEnd;
+
+       count -= off;
+       count -= 1;             /* for NUL at end */
+       if (count <= 0)
+               return -EINVAL;
+
+       spin_lock_irqsave(&pThis->Lock, flags);
+
+       code = dump_header_stats(pThis, buffer);
+       if (code > 0) {
+               buffer += code;
+               count -= code;
+       }
+
+       /* generate the report for the end points */
+       // REVISIT ... not unless something's connected!
+       for (bEnd = 0; count >= 0 && bEnd < pThis->bEndCount;
+                       bEnd++) {
+               code = dump_end_info(pThis, bEnd, buffer, count);
+               if (code > 0) {
+                       buffer += code;
+                       count -= code;
+               }
+       }
+
+       musb_platform_try_idle(pThis);
+
+       spin_unlock_irqrestore(&pThis->Lock, flags);
+       *eof = 1;
+
+       return buffer - page;
+}
+
+void __devexit musb_debug_delete(char *name, struct musb *musb)
+{
+       if (musb->pProcEntry)
+               remove_proc_entry(name, NULL);
+}
+
+struct proc_dir_entry *__init
+musb_debug_create(char *name, struct musb *data)
+{
+       struct proc_dir_entry   *pde;
+
+       /* FIXME convert everything to seq_file; then later, debugfs */
+
+       if (!name)
+               return NULL;
+
+       data->pProcEntry = pde = create_proc_entry(name,
+                                       S_IFREG | S_IRUGO | S_IWUSR, NULL);
+       if (pde) {
+               pde->data = data;
+               // pde->owner = THIS_MODULE;
+
+               pde->read_proc = musb_proc_read;
+               pde->write_proc = musb_proc_write;
+
+               pde->size = 0;
+
+               pr_debug("Registered /proc/%s\n", name);
+       } else {
+               pr_debug("Cannot create a valid proc file entry");
+       }
+
+       return pde;
+}
diff --git a/drivers/usb/musb/musbdefs.h b/drivers/usb/musb/musbdefs.h
new file mode 100644 (file)
index 0000000..59b2eb9
--- /dev/null
@@ -0,0 +1,520 @@
+/******************************************************************
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * The Inventra Controller Driver for Linux is free software; you
+ * can redistribute it and/or modify it under the terms of the GNU
+ * General Public License version 2 as published by the Free Software
+ * Foundation.
+ *
+ * The Inventra Controller Driver for Linux is distributed in
+ * the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Inventra Controller Driver for Linux ; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ANY DOWNLOAD, USE, REPRODUCTION, MODIFICATION OR DISTRIBUTION
+ * OF THIS DRIVER INDICATES YOUR COMPLETE AND UNCONDITIONAL ACCEPTANCE
+ * OF THOSE TERMS.THIS DRIVER IS PROVIDED "AS IS" AND MENTOR GRAPHICS
+ * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, RELATED TO THIS DRIVER.
+ * MENTOR GRAPHICS SPECIFICALLY DISCLAIMS ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY; FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT.  MENTOR GRAPHICS DOES NOT PROVIDE SUPPORT
+ * SERVICES OR UPDATES FOR THIS DRIVER, EVEN IF YOU ARE A MENTOR
+ * GRAPHICS SUPPORT CUSTOMER.
+ ******************************************************************/
+
+#ifndef __MUSB_MUSBDEFS_H__
+#define __MUSB_MUSBDEFS_H__
+
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/usb_ch9.h>
+#include <linux/usb_gadget.h>
+#include <linux/usb.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/musb.h>
+
+struct musb;
+struct musb_hw_ep;
+struct musb_ep;
+
+
+#include "debug.h"
+#include "dma.h"
+
+#ifdef CONFIG_USB_MUSB_SOC
+/*
+ * Get core configuration from a header converted (by cfg_conv)
+ * from the Verilog config file generated by the core config utility
+ *
+ * For now we assume that header is provided along with other
+ * arch-specific files.  Discrete chips will need a build tweak.
+ * So will using AHB IDs from silicon that provides them.
+ */
+#include <asm/arch/hdrc_cnf.h>
+#endif
+
+#include "plat_arc.h"
+#include "musbhdrc.h"
+
+#include "musb_gadget.h"
+#include "../core/hcd.h"
+#include "musb_host.h"
+
+
+
+#ifdef CONFIG_USB_MUSB_OTG
+
+#define        is_peripheral_enabled(musb)     ((musb)->board_mode != MUSB_HOST)
+#define        is_host_enabled(musb)           ((musb)->board_mode != MUSB_PERIPHERAL)
+#define        is_otg_enabled(musb)            ((musb)->board_mode == MUSB_OTG)
+
+/* NOTE:  otg and peripheral-only state machines start at B_IDLE.
+ * OTG or host-only go to A_IDLE when ID is sensed.
+ */
+#define is_peripheral_active(m)                (!(m)->bIsHost)
+#define is_host_active(m)              ((m)->bIsHost)
+
+#else
+#define        is_peripheral_enabled(musb)     is_peripheral_capable()
+#define        is_host_enabled(musb)           is_host_capable()
+#define        is_otg_enabled(musb)            0
+
+#define        is_peripheral_active(musb)      is_peripheral_capable()
+#define        is_host_active(musb)            is_host_capable()
+#endif
+
+#if defined(CONFIG_USB_MUSB_OTG) || defined(CONFIG_USB_MUSB_PERIPHERAL)
+/* for some reason, the "select USB_GADGET_MUSB_HDRC" doesn't always
+ * override that choice selection (often USB_GADGET_DUMMY_HCD).
+ */
+#ifndef CONFIG_USB_GADGET_MUSB_HDRC
+#error bogus Kconfig output ... select CONFIG_USB_GADGET_MUSB_HDRC
+#endif
+#endif /* need MUSB gadget selection */
+
+
+#ifdef CONFIG_PROC_FS
+#include <linux/fs.h>
+#define MUSB_CONFIG_PROC_FS
+#endif
+
+/****************************** PERIPHERAL ROLE *****************************/
+
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+
+#define        is_peripheral_capable() (1)
+
+extern irqreturn_t musb_g_ep0_irq(struct musb *);
+extern void musb_g_tx(struct musb *, u8);
+extern void musb_g_rx(struct musb *, u8);
+extern void musb_g_reset(struct musb *);
+extern void musb_g_suspend(struct musb *);
+extern void musb_g_resume(struct musb *);
+extern void musb_g_disconnect(struct musb *);
+
+#else
+
+#define        is_peripheral_capable() (0)
+
+static inline irqreturn_t musb_g_ep0_irq(struct musb *m) { return IRQ_NONE; }
+static inline void musb_g_reset(struct musb *m) {}
+static inline void musb_g_suspend(struct musb *m) {}
+static inline void musb_g_resume(struct musb *m) {}
+static inline void musb_g_disconnect(struct musb *m) {}
+
+#endif
+
+/****************************** HOST ROLE ***********************************/
+
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+
+#define        is_host_capable()       (1)
+
+extern irqreturn_t musb_h_ep0_irq(struct musb *);
+extern void musb_host_tx(struct musb *, u8);
+extern void musb_host_rx(struct musb *, u8);
+
+#else
+
+#define        is_host_capable()       (0)
+
+static inline irqreturn_t musb_h_ep0_irq(struct musb *m) { return IRQ_NONE; }
+static inline void musb_host_tx(struct musb *m, u8 e) {}
+static inline void musb_host_rx(struct musb *m, u8 e) {}
+
+#endif
+
+
+/****************************** CONSTANTS ********************************/
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef MUSB_C_NUM_EPS
+#define MUSB_C_NUM_EPS ((u8)16)
+#endif
+
+#ifndef MUSB_MAX_END0_PACKET
+#define MUSB_MAX_END0_PACKET ((u16)MGC_END0_FIFOSIZE)
+#endif
+
+/* host side ep0 states */
+#define MGC_END0_START  0x0
+#define MGC_END0_OUT    0x2
+#define MGC_END0_IN     0x4
+#define MGC_END0_STATUS 0x8
+
+/* peripheral side ep0 states */
+enum musb_g_ep0_state {
+       MGC_END0_STAGE_SETUP,           /* idle, waiting for setup */
+       MGC_END0_STAGE_TX,              /* IN data */
+       MGC_END0_STAGE_RX,              /* OUT data */
+       MGC_END0_STAGE_STATUSIN,        /* (after OUT data) */
+       MGC_END0_STAGE_STATUSOUT,       /* (after IN data) */
+       MGC_END0_STAGE_ACKWAIT,         /* after zlp, before statusin */
+} __attribute__ ((packed));
+
+/* OTG protocol constants */
+#define OTG_TIME_A_WAIT_VRISE  100             /* msec (max) */
+#define OTG_TIME_A_WAIT_BCON   0               /* 0=infinite; min 1000 msec */
+#define OTG_TIME_A_IDLE_BDIS   200             /* msec (min) */
+
+/*************************** REGISTER ACCESS ********************************/
+
+/* Endpoint registers (other than dynfifo setup) can be accessed either
+ * directly with the "flat" model, or after setting up an index register.
+ */
+
+#if defined(CONFIG_ARCH_DAVINCI) || defined(CONFIG_ARCH_OMAP243X)
+/* REVISIT indexed access seemed to
+ * misbehave (on DaVinci) for at least peripheral IN ...
+ */
+#define        MUSB_FLAT_REG
+#endif
+
+/* TUSB mapping: "flat" plus ep0 special cases */
+#if    defined(CONFIG_USB_TUSB6010)
+#define MGC_SelectEnd(_pBase, _bEnd) \
+       musb_writeb((_pBase), MGC_O_HDRC_INDEX, (_bEnd))
+#define        MGC_END_OFFSET                  MGC_TUSB_OFFSET
+
+/* "flat" mapping: each endpoint has its own i/o address */
+#elif  defined(MUSB_FLAT_REG)
+#define MGC_SelectEnd(_pBase, _bEnd)   (((void)(_pBase)),((void)(_bEnd)))
+#define        MGC_END_OFFSET                  MGC_FLAT_OFFSET
+
+/* "indexed" mapping: INDEX register controls register bank select */
+#else
+#define MGC_SelectEnd(_pBase, _bEnd) \
+       musb_writeb((_pBase), MGC_O_HDRC_INDEX, (_bEnd))
+#define        MGC_END_OFFSET                  MGC_INDEXED_OFFSET
+#endif
+
+/****************************** FUNCTIONS ********************************/
+
+#define MUSB_HST_MODE(_pthis)\
+       { (_pthis)->bIsHost=TRUE; }
+#define MUSB_DEV_MODE(_pthis) \
+       { (_pthis)->bIsHost=FALSE; }
+
+#define test_devctl_hst_mode(_x) \
+       (musb_readb((_x)->pRegs, MGC_O_HDRC_DEVCTL)&MGC_M_DEVCTL_HM)
+
+#define MUSB_MODE(musb) ((musb)->bIsHost ? "Host" : "Peripheral")
+
+/************************** Ep Configuration ********************************/
+
+/** The End point descriptor */
+struct MUSB_EpFifoDescriptor {
+       u8 bType;               /* 0 for autoconfig, CNTR, ISOC, BULK, INTR */
+       u8 bDir;                /* 0 for autoconfig, INOUT, IN, OUT */
+       int wSize;              /* 0 for autoconfig, or the size */
+};
+
+#define MUSB_EPD_AUTOCONFIG    0
+
+#define MUSB_EPD_T_CNTRL       1
+#define MUSB_EPD_T_ISOC                2
+#define MUSB_EPD_T_BULK                3
+#define MUSB_EPD_T_INTR                4
+
+#define MUSB_EPD_D_INOUT       0
+#define MUSB_EPD_D_TX          1
+#define MUSB_EPD_D_RX          2
+
+/******************************** TYPES *************************************/
+
+/*
+ * struct musb_hw_ep - endpoint hardware (bidirectional)
+ *
+ * Ordered slightly for better cacheline locality.
+ */
+struct musb_hw_ep {
+       struct musb             *musb;
+       void __iomem            *fifo;
+       void __iomem            *regs;
+
+#ifdef CONFIG_USB_TUSB6010
+       void __iomem            *conf;
+#endif
+
+       /* index in musb->aLocalEnd[]  */
+       u8                      bLocalEnd;
+
+       /* hardware configuration, possibly dynamic */
+       u8                      bIsSharedFifo;
+       u8                      tx_double_buffered;
+       u8                      rx_double_buffered;
+       u16                     wMaxPacketSizeTx;
+       u16                     wMaxPacketSizeRx;
+
+       struct dma_channel      *tx_channel;
+       struct dma_channel      *rx_channel;
+
+#ifdef CONFIG_USB_TUSB6010
+       /* TUSB has "asynchronous" and "synchronous" dma modes */
+       dma_addr_t              fifo_async;
+       dma_addr_t              fifo_sync;
+#endif
+
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+       void __iomem            *target_regs;
+
+       /* currently scheduled peripheral endpoint */
+       struct musb_qh          *in_qh;
+       struct musb_qh          *out_qh;
+
+       u8                      rx_reinit;
+       u8                      tx_reinit;
+#endif
+
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+       /* peripheral side */
+       struct musb_ep          ep_in;                  /* TX */
+       struct musb_ep          ep_out;                 /* RX */
+#endif
+};
+
+static inline struct usb_request *next_in_request(struct musb_hw_ep *hw_ep)
+{
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+       return next_request(&hw_ep->ep_in);
+#else
+       return NULL;
+#endif
+}
+
+static inline struct usb_request *next_out_request(struct musb_hw_ep *hw_ep)
+{
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+       return next_request(&hw_ep->ep_out);
+#else
+       return NULL;
+#endif
+}
+
+/*
+ * struct musb - Driver instance data.
+ */
+struct musb {
+       spinlock_t              Lock;
+       struct clk              *clock;
+       irqreturn_t             (*isr)(int, void *);
+       struct work_struct      irq_work;
+
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+
+/* this hub status bit is reserved by USB 2.0 and not seen by usbcore */
+#define MUSB_PORT_STAT_RESUME  (1 << 31)
+
+       u32                     port1_status;
+       unsigned long           rh_timer;
+
+       u8 bEnd0Stage;          /* end0 stage while in host */
+
+       /* bulk traffic normally dedicates endpoint hardware, and each
+        * direction has its own ring of host side endpoints.
+        * we try to progress the transfer at the head of each endpoint's
+        * queue until it completes or NAKs too much; then we try the next
+        * endpoint.
+        */
+       struct musb_hw_ep       *bulk_ep;
+
+       struct list_head        control;        /* of musb_qh */
+       struct list_head        in_bulk;        /* of musb_qh */
+       struct list_head        out_bulk;       /* of musb_qh */
+       struct musb_qh          *periodic[32];  /* tree of interrupt+iso */
+#endif
+
+       /* called with IRQs blocked; ON/nonzero implies starting a session,
+        * and waiting at least a_wait_vrise_tmout.
+        */
+       void                    (*board_set_vbus)(struct musb *, int is_on);
+
+       struct dma_controller   *pDmaController;
+
+       struct device           *controller;
+       void __iomem            *ctrl_base;
+       void __iomem            *pRegs;
+
+#ifdef CONFIG_USB_TUSB6010
+       dma_addr_t              async;
+       dma_addr_t              sync;
+#endif
+
+       /* passed down from chip/board specific irq handlers */
+       u8                      int_usb;
+       u16                     int_rx;
+       u16                     int_tx;
+
+       struct otg_transceiver  xceiv;
+
+       int nIrq;
+
+       struct musb_hw_ep        aLocalEnd[MUSB_C_NUM_EPS];
+#define control_ep             aLocalEnd
+
+#define VBUSERR_RETRY_COUNT    3
+       u16                     vbuserr_retry;
+       u16 wEndMask;
+       u8 bEndCount;
+
+       u8 board_mode;          /* enum musb_mode */
+       int                     (*board_set_power)(int state);
+
+       u8                      min_power;      /* vbus for periph, in mA/2 */
+
+       /* active means connected and not suspended */
+       unsigned is_active:1;
+
+       unsigned bIsMultipoint:1;
+       unsigned bIsHost:1;
+       unsigned bIgnoreDisconnect:1;   /* during bus resets */
+
+#ifdef C_MP_TX
+       unsigned bBulkSplit:1;
+#define        can_bulk_split(musb,type) \
+               (((type) == USB_ENDPOINT_XFER_BULK) && (musb)->bBulkSplit)
+#else
+#define        can_bulk_split(musb,type)       0
+#endif
+
+#ifdef C_MP_RX
+       unsigned bBulkCombine:1;
+       /* REVISIT allegedly doesn't work reliably */
+#if 0
+#define        can_bulk_combine(musb,type) \
+               (((type) == USB_ENDPOINT_XFER_BULK) && (musb)->bBulkCombine)
+#else
+#define        can_bulk_combine(musb,type)     0
+#endif
+#else
+#define        can_bulk_combine(musb,type)     0
+#endif
+
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+       unsigned bIsSelfPowered:1;
+       unsigned bMayWakeup:1;
+       unsigned bSetAddress:1;
+       unsigned bTestMode:1;
+       unsigned softconnect:1;
+
+       enum musb_g_ep0_state   ep0_state;
+       u8                      bAddress;
+       u8                      bTestModeValue;
+       u16                     ackpend;                /* ep0 */
+       struct usb_gadget       g;                      /* the gadget */
+       struct usb_gadget_driver *pGadgetDriver;        /* its driver */
+#endif
+
+#ifdef CONFIG_USB_MUSB_OTG
+       /* FIXME this can't be OTG-specific ... ? */
+       u8 bDelayPortPowerOff;
+#endif
+
+#ifdef MUSB_CONFIG_PROC_FS
+       struct proc_dir_entry *pProcEntry;
+#endif
+};
+
+static inline void musb_set_vbus(struct musb *musb, int is_on)
+{
+       musb->board_set_vbus(musb, is_on);
+}
+
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+static inline struct musb *gadget_to_musb(struct usb_gadget *g)
+{
+       return container_of(g, struct musb, g);
+}
+#endif
+
+
+/***************************** Glue it together *****************************/
+
+extern const char musb_driver_name[];
+
+extern void musb_start(struct musb *pThis);
+extern void musb_stop(struct musb *pThis);
+
+extern void musb_write_fifo(struct musb_hw_ep *ep,
+                            u16 wCount, const u8 * pSource);
+extern void musb_read_fifo(struct musb_hw_ep *ep,
+                              u16 wCount, u8 * pDest);
+
+extern void musb_load_testpacket(struct musb *);
+
+extern irqreturn_t musb_interrupt(struct musb *);
+
+extern void musb_platform_enable(struct musb *musb);
+extern void musb_platform_disable(struct musb *musb);
+
+#ifdef CONFIG_USB_TUSB6010
+extern void musb_platform_try_idle(struct musb *musb);
+extern int musb_platform_get_vbus_status(struct musb *musb);
+#else
+#define musb_platform_try_idle(x)              do {} while (0)
+#define musb_platform_get_vbus_status(x)       0
+#endif
+
+extern int __init musb_platform_init(struct musb *musb);
+extern int musb_platform_exit(struct musb *musb);
+
+/*-------------------------- ProcFS definitions ---------------------*/
+
+struct proc_dir_entry;
+
+#if (MUSB_DEBUG > 0) && defined(MUSB_CONFIG_PROC_FS)
+extern struct proc_dir_entry *musb_debug_create(char *name,
+                                                   struct musb *data);
+extern void musb_debug_delete(char *name, struct musb *data);
+
+#else
+static inline struct proc_dir_entry *musb_debug_create(char *name,
+                                                          struct musb *data)
+{
+       return NULL;
+}
+static inline void musb_debug_delete(char *name, struct musb *data)
+{
+}
+#endif
+
+#endif /* __MUSB_MUSBDEFS_H__ */
diff --git a/drivers/usb/musb/musbhdrc.h b/drivers/usb/musb/musbhdrc.h
new file mode 100644 (file)
index 0000000..59fbbd7
--- /dev/null
@@ -0,0 +1,321 @@
+/******************************************************************
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * The Inventra Controller Driver for Linux is free software; you
+ * can redistribute it and/or modify it under the terms of the GNU
+ * General Public License version 2 as published by the Free Software
+ * Foundation.
+ *
+ * The Inventra Controller Driver for Linux is distributed in
+ * the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Inventra Controller Driver for Linux ; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ANY DOWNLOAD, USE, REPRODUCTION, MODIFICATION OR DISTRIBUTION
+ * OF THIS DRIVER INDICATES YOUR COMPLETE AND UNCONDITIONAL ACCEPTANCE
+ * OF THOSE TERMS.THIS DRIVER IS PROVIDED "AS IS" AND MENTOR GRAPHICS
+ * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, RELATED TO THIS DRIVER.
+ * MENTOR GRAPHICS SPECIFICALLY DISCLAIMS ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY; FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT.  MENTOR GRAPHICS DOES NOT PROVIDE SUPPORT
+ * SERVICES OR UPDATES FOR THIS DRIVER, EVEN IF YOU ARE A MENTOR
+ * GRAPHICS SUPPORT CUSTOMER.
+ ******************************************************************/
+
+#ifndef __MUSB_HDRC_DEFS_H__
+#define __MUSB_HDRC_DEFS_H__
+
+/*
+ * HDRC-specific definitions
+ */
+
+#define MGC_MAX_USB_ENDS       16
+
+#define MGC_END0_FIFOSIZE      64      /* this is non-configurable */
+
+/*
+ *     MUSBMHDRC Register map
+ */
+
+/* Common USB registers */
+
+#define MGC_O_HDRC_FADDR       0x00    /* 8-bit */
+#define MGC_O_HDRC_POWER       0x01    /* 8-bit */
+
+#define MGC_O_HDRC_INTRTX      0x02    /* 16-bit */
+#define MGC_O_HDRC_INTRRX       0x04
+#define MGC_O_HDRC_INTRTXE      0x06
+#define MGC_O_HDRC_INTRRXE      0x08
+#define MGC_O_HDRC_INTRUSB      0x0A   /* 8 bit */
+#define MGC_O_HDRC_INTRUSBE     0x0B   /* 8 bit */
+#define MGC_O_HDRC_FRAME        0x0C
+#define MGC_O_HDRC_INDEX        0x0E   /* 8 bit */
+#define MGC_O_HDRC_TESTMODE     0x0F   /* 8 bit */
+
+/* Get offset for a given FIFO from musb->pRegs */
+#ifdef CONFIG_USB_TUSB6010
+#define MUSB_FIFO_OFFSET(epnum)        (0x200 + ((epnum) * 0x20))
+#else
+#define MUSB_FIFO_OFFSET(epnum)        (0x20 + ((epnum) * 4))
+#endif
+
+/* Additional Control Registers */
+
+#define MGC_O_HDRC_DEVCTL      0x60    /* 8 bit */
+
+/* These are always controlled through the INDEX register */
+#define MGC_O_HDRC_TXFIFOSZ    0x62    /* 8-bit (see masks) */
+#define MGC_O_HDRC_RXFIFOSZ    0x63    /* 8-bit (see masks) */
+#define MGC_O_HDRC_TXFIFOADD   0x64    /* 16-bit offset shifted right 3 */
+#define MGC_O_HDRC_RXFIFOADD   0x66    /* 16-bit offset shifted right 3 */
+
+// vctrl/vstatus:  optional vendor utmi+phy register at 0x68
+#define MGC_O_HDRC_HWVERS      0x6C    /* 8 bit */
+
+#define MGC_O_HDRC_EPINFO      0x78    /* 8 bit */
+#define MGC_O_HDRC_RAMINFO     0x79    /* 8 bit */
+#define MGC_O_HDRC_LINKINFO    0x7a    /* 8 bit */
+#define MGC_O_HDRC_VPLEN       0x7b    /* 8 bit */
+#define MGC_O_HDRC_HS_EOF1     0x7c    /* 8 bit */
+#define MGC_O_HDRC_FS_EOF1     0x7d    /* 8 bit */
+#define MGC_O_HDRC_LS_EOF1     0x7e    /* 8 bit */
+
+/* offsets to endpoint registers */
+#define MGC_O_HDRC_TXMAXP      0x00
+#define MGC_O_HDRC_TXCSR       0x02
+#define MGC_O_HDRC_CSR0                MGC_O_HDRC_TXCSR        /* re-used for EP0 */
+#define MGC_O_HDRC_RXMAXP      0x04
+#define MGC_O_HDRC_RXCSR       0x06
+#define MGC_O_HDRC_RXCOUNT     0x08
+#define MGC_O_HDRC_COUNT0      MGC_O_HDRC_RXCOUNT      /* re-used for EP0 */
+#define MGC_O_HDRC_TXTYPE      0x0A
+#define MGC_O_HDRC_TYPE0       MGC_O_HDRC_TXTYPE       /* re-used for EP0 */
+#define MGC_O_HDRC_TXINTERVAL  0x0B
+#define MGC_O_HDRC_NAKLIMIT0   MGC_O_HDRC_TXINTERVAL   /* re-used for EP0 */
+#define MGC_O_HDRC_RXTYPE      0x0C
+#define MGC_O_HDRC_RXINTERVAL  0x0D
+#define MGC_O_HDRC_FIFOSIZE    0x0F
+#define MGC_O_HDRC_CONFIGDATA  MGC_O_HDRC_FIFOSIZE     /* re-used for EP0 */
+
+/* offsets to endpoint registers in indexed model (using INDEX register) */
+#define MGC_INDEXED_OFFSET(_bEnd, _bOffset)    \
+       (0x10                   + (_bOffset))
+
+/* offsets to endpoint registers in flat models */
+#define MGC_FLAT_OFFSET(_bEnd, _bOffset)       \
+       (0x100 + (0x10*(_bEnd)) + (_bOffset))
+
+#ifdef CONFIG_USB_TUSB6010
+/* TUSB6010 EP0 configuration register is special */
+#define MGC_TUSB_OFFSET(_bEnd, _bOffset)       \
+       (0x10 + _bOffset)
+#include "tusb6010.h"          /* needed "only" for TUSB_EP0_CONF */
+#endif
+
+/* "bus control"/target registers, for host side multipoint (external hubs) */
+#define MGC_O_HDRC_TXFUNCADDR  0x00
+#define MGC_O_HDRC_TXHUBADDR   0x02
+#define MGC_O_HDRC_TXHUBPORT   0x03
+
+#define MGC_O_HDRC_RXFUNCADDR  0x04
+#define MGC_O_HDRC_RXHUBADDR   0x06
+#define MGC_O_HDRC_RXHUBPORT   0x07
+
+#define MGC_BUSCTL_OFFSET(_bEnd, _bOffset) \
+       (0x80 + (8*(_bEnd)) + (_bOffset))
+
+/*
+ *     MUSBHDRC Register bit masks
+ */
+
+/* POWER */
+
+#define MGC_M_POWER_ISOUPDATE   0x80
+#define MGC_M_POWER_SOFTCONN    0x40
+#define MGC_M_POWER_HSENAB     0x20
+#define MGC_M_POWER_HSMODE     0x10
+#define MGC_M_POWER_RESET       0x08
+#define MGC_M_POWER_RESUME      0x04
+#define MGC_M_POWER_SUSPENDM    0x02
+#define MGC_M_POWER_ENSUSPEND   0x01
+
+/* INTRUSB */
+#define MGC_M_INTR_SUSPEND    0x01
+#define MGC_M_INTR_RESUME     0x02
+#define MGC_M_INTR_RESET      0x04
+#define MGC_M_INTR_BABBLE     0x04
+#define MGC_M_INTR_SOF        0x08
+#define MGC_M_INTR_CONNECT    0x10
+#define MGC_M_INTR_DISCONNECT 0x20
+#define MGC_M_INTR_SESSREQ    0x40
+#define MGC_M_INTR_VBUSERROR  0x80     /* FOR SESSION END */
+
+/* DEVCTL */
+#define MGC_M_DEVCTL_BDEVICE    0x80
+#define MGC_M_DEVCTL_FSDEV      0x40
+#define MGC_M_DEVCTL_LSDEV      0x20
+#define MGC_M_DEVCTL_VBUS       0x18
+#define MGC_S_DEVCTL_VBUS       3
+#define MGC_M_DEVCTL_HM         0x04
+#define MGC_M_DEVCTL_HR         0x02
+#define MGC_M_DEVCTL_SESSION    0x01
+
+/* TESTMODE */
+
+#define MGC_M_TEST_FORCE_HOST   0x80
+#define MGC_M_TEST_FIFO_ACCESS  0x40
+#define MGC_M_TEST_FORCE_FS     0x20
+#define MGC_M_TEST_FORCE_HS     0x10
+#define MGC_M_TEST_PACKET       0x08
+#define MGC_M_TEST_K            0x04
+#define MGC_M_TEST_J            0x02
+#define MGC_M_TEST_SE0_NAK      0x01
+
+/* allocate for double-packet buffering (effectively doubles assigned _SIZE) */
+#define MGC_M_FIFOSZ_DPB       0x10
+/* allocation size (8, 16, 32, ... 4096) */
+#define MGC_M_FIFOSZ_SIZE      0x0f
+
+/* CSR0 */
+#define MGC_M_CSR0_FLUSHFIFO      0x0100
+#define MGC_M_CSR0_TXPKTRDY       0x0002
+#define MGC_M_CSR0_RXPKTRDY       0x0001
+
+/* CSR0 in Peripheral mode */
+#define MGC_M_CSR0_P_SVDSETUPEND  0x0080
+#define MGC_M_CSR0_P_SVDRXPKTRDY  0x0040
+#define MGC_M_CSR0_P_SENDSTALL    0x0020
+#define MGC_M_CSR0_P_SETUPEND     0x0010
+#define MGC_M_CSR0_P_DATAEND      0x0008
+#define MGC_M_CSR0_P_SENTSTALL    0x0004
+
+/* CSR0 in Host mode */
+#define MGC_M_CSR0_H_DIS_PING  0x0800
+#define MGC_M_CSR0_H_WR_DATATOGGLE   0x0400    /* set to allow setting: */
+#define MGC_M_CSR0_H_DATATOGGLE            0x0200      /* data toggle control */
+#define MGC_M_CSR0_H_NAKTIMEOUT   0x0080
+#define MGC_M_CSR0_H_STATUSPKT    0x0040
+#define MGC_M_CSR0_H_REQPKT       0x0020
+#define MGC_M_CSR0_H_ERROR        0x0010
+#define MGC_M_CSR0_H_SETUPPKT     0x0008
+#define MGC_M_CSR0_H_RXSTALL      0x0004
+
+/* CSR0 bits to avoid zeroing (write zero clears, write 1 ignored) */
+#define MGC_M_CSR0_P_WZC_BITS  \
+       ( MGC_M_CSR0_P_SENTSTALL )
+#define MGC_M_CSR0_H_WZC_BITS  \
+       ( MGC_M_CSR0_H_NAKTIMEOUT | MGC_M_CSR0_H_RXSTALL \
+       | MGC_M_CSR0_RXPKTRDY )
+
+
+/* TxType/RxType */
+#define MGC_M_TYPE_SPEED       0xc0
+#define MGC_S_TYPE_SPEED       6
+#define MGC_TYPE_SPEED_HIGH    1
+#define MGC_TYPE_SPEED_FULL    2
+#define MGC_TYPE_SPEED_LOW     3
+#define MGC_M_TYPE_PROTO       0x30    /* implicitly zero for ep0 */
+#define MGC_S_TYPE_PROTO       4
+#define MGC_M_TYPE_REMOTE_END  0xf     /* implicitly zero for ep0 */
+
+/* CONFIGDATA */
+
+#define MGC_M_CONFIGDATA_MPRXE      0x80       /* auto bulk pkt combining */
+#define MGC_M_CONFIGDATA_MPTXE      0x40       /* auto bulk pkt splitting */
+#define MGC_M_CONFIGDATA_BIGENDIAN  0x20
+#define MGC_M_CONFIGDATA_HBRXE      0x10       /* HB-ISO for RX */
+#define MGC_M_CONFIGDATA_HBTXE      0x08       /* HB-ISO for TX */
+#define MGC_M_CONFIGDATA_DYNFIFO    0x04       /* dynamic FIFO sizing */
+#define MGC_M_CONFIGDATA_SOFTCONE   0x02       /* SoftConnect */
+#define MGC_M_CONFIGDATA_UTMIDW     0x01       /* data width 0/1 => 8/16bits */
+
+/* TXCSR in Peripheral and Host mode */
+
+#define MGC_M_TXCSR_AUTOSET       0x8000
+#define MGC_M_TXCSR_MODE          0x2000
+#define MGC_M_TXCSR_DMAENAB       0x1000
+#define MGC_M_TXCSR_FRCDATATOG    0x0800
+#define MGC_M_TXCSR_DMAMODE       0x0400
+#define MGC_M_TXCSR_CLRDATATOG    0x0040
+#define MGC_M_TXCSR_FLUSHFIFO     0x0008
+#define MGC_M_TXCSR_FIFONOTEMPTY  0x0002
+#define MGC_M_TXCSR_TXPKTRDY      0x0001
+
+/* TXCSR in Peripheral mode */
+
+#define MGC_M_TXCSR_P_ISO         0x4000
+#define MGC_M_TXCSR_P_INCOMPTX    0x0080
+#define MGC_M_TXCSR_P_SENTSTALL   0x0020
+#define MGC_M_TXCSR_P_SENDSTALL   0x0010
+#define MGC_M_TXCSR_P_UNDERRUN    0x0004
+
+/* TXCSR in Host mode */
+
+#define MGC_M_TXCSR_H_WR_DATATOGGLE   0x0200
+#define MGC_M_TXCSR_H_DATATOGGLE      0x0100
+#define MGC_M_TXCSR_H_NAKTIMEOUT  0x0080
+#define MGC_M_TXCSR_H_RXSTALL     0x0020
+#define MGC_M_TXCSR_H_ERROR       0x0004
+
+/* TXCSR bits to avoid zeroing (write zero clears, write 1 ignored) */
+#define MGC_M_TXCSR_P_WZC_BITS \
+       ( MGC_M_TXCSR_P_INCOMPTX | MGC_M_TXCSR_P_SENTSTALL \
+       | MGC_M_TXCSR_P_UNDERRUN | MGC_M_TXCSR_FIFONOTEMPTY )
+#define MGC_M_TXCSR_H_WZC_BITS \
+       ( MGC_M_TXCSR_H_NAKTIMEOUT | MGC_M_TXCSR_H_RXSTALL \
+       | MGC_M_TXCSR_H_ERROR | MGC_M_TXCSR_FIFONOTEMPTY )
+
+
+/* RXCSR in Peripheral and Host mode */
+
+#define MGC_M_RXCSR_AUTOCLEAR     0x8000
+#define MGC_M_RXCSR_DMAENAB       0x2000
+#define MGC_M_RXCSR_DISNYET       0x1000
+#define MGC_M_RXCSR_PID_ERR       0x1000
+#define MGC_M_RXCSR_DMAMODE       0x0800
+#define MGC_M_RXCSR_INCOMPRX      0x0100
+#define MGC_M_RXCSR_CLRDATATOG    0x0080
+#define MGC_M_RXCSR_FLUSHFIFO     0x0010
+#define MGC_M_RXCSR_DATAERROR     0x0008
+#define MGC_M_RXCSR_FIFOFULL      0x0002
+#define MGC_M_RXCSR_RXPKTRDY      0x0001
+
+/* RXCSR in Peripheral mode */
+
+#define MGC_M_RXCSR_P_ISO         0x4000
+#define MGC_M_RXCSR_P_SENTSTALL   0x0040
+#define MGC_M_RXCSR_P_SENDSTALL   0x0020
+#define MGC_M_RXCSR_P_OVERRUN     0x0004
+
+/* RXCSR in Host mode */
+
+#define MGC_M_RXCSR_H_AUTOREQ     0x4000
+#define MGC_M_RXCSR_H_WR_DATATOGGLE   0x0400
+#define MGC_M_RXCSR_H_DATATOGGLE        0x0200
+#define MGC_M_RXCSR_H_RXSTALL     0x0040
+#define MGC_M_RXCSR_H_REQPKT      0x0020
+#define MGC_M_RXCSR_H_ERROR       0x0004
+
+/* RXCSR bits to avoid zeroing (write zero clears, write 1 ignored) */
+#define MGC_M_RXCSR_P_WZC_BITS \
+       ( MGC_M_RXCSR_P_SENTSTALL | MGC_M_RXCSR_P_OVERRUN \
+       | MGC_M_RXCSR_RXPKTRDY )
+#define MGC_M_RXCSR_H_WZC_BITS \
+       ( MGC_M_RXCSR_H_RXSTALL | MGC_M_RXCSR_H_ERROR \
+       | MGC_M_RXCSR_DATAERROR | MGC_M_RXCSR_RXPKTRDY )
+
+
+/* HUBADDR */
+#define MGC_M_HUBADDR_MULTI_TT         0x80
+
+
+#endif /* __MUSB_HDRC_DEFS_H__ */
diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c
new file mode 100644 (file)
index 0000000..ea39d0c
--- /dev/null
@@ -0,0 +1,393 @@
+/******************************************************************
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * The Inventra Controller Driver for Linux is free software; you
+ * can redistribute it and/or modify it under the terms of the GNU
+ * General Public License version 2 as published by the Free Software
+ * Foundation.
+ *
+ * The Inventra Controller Driver for Linux is distributed in
+ * the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Inventra Controller Driver for Linux ; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ANY DOWNLOAD, USE, REPRODUCTION, MODIFICATION OR DISTRIBUTION
+ * OF THIS DRIVER INDICATES YOUR COMPLETE AND UNCONDITIONAL ACCEPTANCE
+ * OF THOSE TERMS.THIS DRIVER IS PROVIDED "AS IS" AND MENTOR GRAPHICS
+ * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, RELATED TO THIS DRIVER.
+ * MENTOR GRAPHICS SPECIFICALLY DISCLAIMS ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY; FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT.  MENTOR GRAPHICS DOES NOT PROVIDE SUPPORT
+ * SERVICES OR UPDATES FOR THIS DRIVER, EVEN IF YOU ARE A MENTOR
+ * GRAPHICS SUPPORT CUSTOMER.
+ ******************************************************************/
+
+/*
+ * Interface to Mentor's DMA engine
+ */
+
+#include <linux/platform_device.h>
+
+#include "musbdefs.h"
+
+
+/****************************** CONSTANTS ********************************/
+
+#define MGC_O_HSDMA_BASE    0x200
+#define MGC_O_HSDMA_INTR    0x200
+
+#define MGC_O_HSDMA_CONTROL 4
+#define MGC_O_HSDMA_ADDRESS 8
+#define MGC_O_HSDMA_COUNT   0xc
+
+#define MGC_HSDMA_CHANNEL_OFFSET(_bChannel, _bOffset)          \
+               (MGC_O_HSDMA_BASE + (_bChannel << 4) + _bOffset)
+
+/* control register (16-bit): */
+#define MGC_S_HSDMA_ENABLE     0
+#define MGC_S_HSDMA_TRANSMIT   1
+#define MGC_S_HSDMA_MODE1      2
+#define MGC_S_HSDMA_IRQENABLE  3
+#define MGC_S_HSDMA_ENDPOINT   4
+#define MGC_S_HSDMA_BUSERROR   8
+#define MGC_S_HSDMA_BURSTMODE  9
+#define MGC_M_HSDMA_BURSTMODE  (3 << MGC_S_HSDMA_BURSTMODE)
+#define MGC_HSDMA_BURSTMODE_UNSPEC  0
+#define MGC_HSDMA_BURSTMODE_INCR4   1
+#define MGC_HSDMA_BURSTMODE_INCR8   2
+#define MGC_HSDMA_BURSTMODE_INCR16  3
+
+#define MGC_HSDMA_CHANNELS 8
+
+/******************************* Types ********************************/
+
+struct hsdma_channel {
+       struct dma_channel Channel;
+       struct hsdma *pController;
+       u32 dwStartAddress;
+       u32 dwCount;
+       u8 bIndex;
+       u8 bEnd;
+       u8 bTransmit;
+};
+
+struct hsdma {
+       struct dma_controller Controller;
+       struct hsdma_channel aChannel[MGC_HSDMA_CHANNELS];
+       void *pDmaPrivate;
+       void __iomem *pCoreBase;
+       u8 bChannelCount;
+       u8 bmUsedChannels;
+};
+
+/****************************** FUNCTIONS ********************************/
+
+static int hsdma_start(struct dma_controller *c)
+{
+       /* nothing to do */
+       return 0;
+}
+
+static int hsdma_stop(struct dma_controller *c)
+{
+       /* nothing to do */
+       return 0;
+}
+
+static struct dma_channel *
+hsdma_channel_alloc(struct dma_controller *c,
+               struct musb_hw_ep *hw_ep,
+               u8 bTransmit)
+{
+       u8 bBit;
+       struct dma_channel *pChannel = NULL;
+       struct hsdma_channel *pImplChannel = NULL;
+       struct hsdma *pController;
+
+       pController = container_of(c, struct hsdma, Controller);
+       for (bBit = 0; bBit < MGC_HSDMA_CHANNELS; bBit++) {
+               if (!(pController->bmUsedChannels & (1 << bBit))) {
+                       pController->bmUsedChannels |= (1 << bBit);
+                       pImplChannel = &(pController->aChannel[bBit]);
+                       pImplChannel->pController = pController;
+                       pImplChannel->bIndex = bBit;
+                       pImplChannel->bEnd = hw_ep->bLocalEnd;
+                       pImplChannel->bTransmit = bTransmit;
+                       pChannel = &(pImplChannel->Channel);
+                       pChannel->pPrivateData = pImplChannel;
+                       pChannel->bStatus = MGC_DMA_STATUS_FREE;
+                       pChannel->dwMaxLength = 0x10000;
+                       /* Tx => mode 1; Rx => mode 0 */
+                       pChannel->bDesiredMode = bTransmit;
+                       pChannel->dwActualLength = 0;
+                       break;
+               }
+       }
+       return pChannel;
+}
+
+static void hsdma_channel_release(struct dma_channel *pChannel)
+{
+       struct hsdma_channel *pImplChannel = pChannel->pPrivateData;
+
+       pImplChannel->pController->bmUsedChannels &=
+           ~(1 << pImplChannel->bIndex);
+       pChannel->bStatus = MGC_DMA_STATUS_FREE;
+}
+
+static void clear_state(struct dma_channel *pChannel)
+{
+       struct hsdma_channel *pImplChannel = pChannel->pPrivateData;
+       struct hsdma *pController = pImplChannel->pController;
+       u8 *pBase = pController->pCoreBase;
+       u8 bChannel = pImplChannel->bIndex;
+
+       musb_writew(pBase,
+                   MGC_HSDMA_CHANNEL_OFFSET(bChannel, MGC_O_HSDMA_CONTROL),
+                   0);
+       musb_writel(pBase,
+                   MGC_HSDMA_CHANNEL_OFFSET(bChannel, MGC_O_HSDMA_ADDRESS),
+                   0);
+       musb_writel(pBase,
+                   MGC_HSDMA_CHANNEL_OFFSET(bChannel, MGC_O_HSDMA_COUNT),
+                   0);
+
+       pChannel->dwActualLength = 0L;
+       pImplChannel->dwStartAddress = 0;
+       pImplChannel->dwCount = 0;
+}
+
+static u8 configure_channel(struct dma_channel *pChannel,
+                                 u16 wPacketSize, u8 bMode,
+                                 dma_addr_t dma_addr, u32 dwLength)
+{
+       struct hsdma_channel *pImplChannel = pChannel->pPrivateData;
+       struct hsdma *pController = pImplChannel->pController;
+       u8 *pBase = pController->pCoreBase;
+       u8 bChannel = pImplChannel->bIndex;
+       u16 wCsr = 0;
+
+       DBG(2, "%p, pkt_sz %d, addr 0x%x, len %d, mode %d\n",
+           pChannel, wPacketSize, dma_addr, dwLength, bMode);
+
+       if (bMode) {
+               wCsr |= 1 << MGC_S_HSDMA_MODE1;
+               if (dwLength < wPacketSize) {
+                       return FALSE;
+               }
+               if (wPacketSize >= 64) {
+                       wCsr |=
+                           MGC_HSDMA_BURSTMODE_INCR16 << MGC_S_HSDMA_BURSTMODE;
+               } else if (wPacketSize >= 32) {
+                       wCsr |=
+                           MGC_HSDMA_BURSTMODE_INCR8 << MGC_S_HSDMA_BURSTMODE;
+               } else if (wPacketSize >= 16) {
+                       wCsr |=
+                           MGC_HSDMA_BURSTMODE_INCR4 << MGC_S_HSDMA_BURSTMODE;
+               }
+       }
+
+       wCsr |= (pImplChannel->bEnd << MGC_S_HSDMA_ENDPOINT)
+               | (1 << MGC_S_HSDMA_ENABLE)
+               | (1 << MGC_S_HSDMA_IRQENABLE)
+               | (pImplChannel->bTransmit ? (1 << MGC_S_HSDMA_TRANSMIT) : 0);
+
+       /* address/count */
+       musb_writel(pBase,
+                   MGC_HSDMA_CHANNEL_OFFSET(bChannel, MGC_O_HSDMA_ADDRESS),
+                   dma_addr);
+       musb_writel(pBase,
+                   MGC_HSDMA_CHANNEL_OFFSET(bChannel, MGC_O_HSDMA_COUNT),
+                   dwLength);
+
+       /* control (this should start things) */
+       musb_writew(pBase,
+                   MGC_HSDMA_CHANNEL_OFFSET(bChannel, MGC_O_HSDMA_CONTROL),
+                   wCsr);
+
+       return TRUE;
+}
+
+static int hsdma_channel_program(struct dma_channel * pChannel,
+                                 u16 wPacketSize, u8 bMode,
+                                 dma_addr_t dma_addr, u32 dwLength)
+{
+       struct hsdma_channel *pImplChannel = pChannel->pPrivateData;
+
+       DBG(2, "pkt_sz %d, dma_addr 0x%x length %d, mode %d\n",
+              wPacketSize, dma_addr, dwLength, bMode);
+
+       BUG_ON(pChannel->bStatus != MGC_DMA_STATUS_FREE);
+
+       pChannel->dwActualLength = 0L;
+       pImplChannel->dwStartAddress = dma_addr;
+       pImplChannel->dwCount = dwLength;
+
+       pChannel->bStatus = MGC_DMA_STATUS_BUSY;
+
+       if ((bMode == 1) && (dwLength >= wPacketSize)) {
+
+#if 0
+               /* mode 1 sends an extra IN token at the end of
+                * full packet transfer in host Rx
+                */
+               if (dwLength % wPacketSize == 0)
+                       dwLength -= wPacketSize;
+
+               /* mode 1 doesn't give an interrupt on short packet */
+               configure_channel(pChannel, wPacketSize, 1, dma_addr,
+                                 dwLength & ~(wPacketSize - 1));
+               /* the rest (<= pkt_size) will be transferred in mode 0 */
+#endif
+
+               configure_channel(pChannel, wPacketSize, 1, dma_addr,
+                                 dwLength);
+
+       } else
+               configure_channel(pChannel, wPacketSize, 0, dma_addr,
+                                 dwLength);
+
+       return TRUE;
+}
+
+// REVISIT...
+static int hsdma_channel_abort(struct dma_channel *pChannel)
+{
+       clear_state(pChannel);
+       pChannel->bStatus = MGC_DMA_STATUS_FREE;
+       return 0;
+}
+
+static irqreturn_t hsdma_irq(int irq, void *pPrivateData)
+{
+       u8 bChannel;
+       u16 wCsr;
+       u32 dwAddress;
+       struct hsdma_channel *pImplChannel;
+       struct hsdma *pController = pPrivateData;
+       u8 *pBase = pController->pCoreBase;
+       struct dma_channel *pChannel;
+       u8 bIntr = musb_readb(pBase, MGC_O_HSDMA_INTR);
+
+       if (!bIntr)
+               return IRQ_NONE;
+
+       for (bChannel = 0; bChannel < MGC_HSDMA_CHANNELS; bChannel++) {
+               if (bIntr & (1 << bChannel)) {
+
+                       pImplChannel = &pController->aChannel[bChannel];
+                       pChannel = &pImplChannel->Channel;
+
+                       wCsr = musb_readw(pBase,
+                                      MGC_HSDMA_CHANNEL_OFFSET(bChannel,
+                                                       MGC_O_HSDMA_CONTROL));
+
+                       if (wCsr & (1 << MGC_S_HSDMA_BUSERROR)) {
+                               pImplChannel->Channel.bStatus =
+                                   MGC_DMA_STATUS_BUS_ABORT;
+                       } else {
+                               dwAddress = musb_readl(pBase,
+                                                      MGC_HSDMA_CHANNEL_OFFSET
+                                                      (bChannel,
+                                                       MGC_O_HSDMA_ADDRESS));
+                               pChannel->dwActualLength =
+                                   dwAddress - pImplChannel->dwStartAddress;
+
+                               DBG(2, "ch %p, 0x%x -> 0x%x (%d / %d) %s\n",
+                                   pChannel, pImplChannel->dwStartAddress,
+                                   dwAddress, pChannel->dwActualLength,
+                                   pImplChannel->dwCount,
+                                   (pChannel->dwActualLength <
+                                       pImplChannel->dwCount) ?
+                                       "=> reconfig 0": "=> complete");
+#if 0
+                               if (pChannel->dwActualLength <
+                                   pImplChannel->dwCount) {
+                                       /* mode 1 sends an extra IN request if
+                                       the last packet is a complete packet */
+                                       u16 newcsr = MGC_ReadCsr16(pBase,
+                                                       MGC_O_HDRC_RXCSR,
+                                                       pImplChannel->bEnd);
+                                       newcsr &= ~(MGC_M_RXCSR_H_AUTOREQ |
+                                                   MGC_M_RXCSR_H_REQPKT);
+                                       MGC_WriteCsr16(pBase, MGC_O_HDRC_RXCSR,
+                                                      pImplChannel->bEnd,
+                                                      MGC_M_RXCSR_H_WZC_BITS |
+                                                               newcsr);
+
+                                       configure_channel(pChannel,
+                                               pImplChannel->wMaxPacketSize,
+                                               0, dwAddress,
+                                               pImplChannel->dwCount -
+                                                   pChannel->dwActualLength);
+                               }
+                               else
+#endif
+                               {
+                                       pChannel->bStatus = MGC_DMA_STATUS_FREE;
+                                       /* completed */
+                                       musb_dma_completion(
+                                               pController->pDmaPrivate,
+                                               pImplChannel->bEnd,
+                                               pImplChannel->bTransmit);
+                               }
+                       }
+               }
+       }
+       return IRQ_HANDLED;
+}
+
+void dma_controller_destroy(struct dma_controller *pController)
+{
+       struct hsdma *pHsController = pController->pPrivateData;
+
+       pHsController->Controller.pPrivateData = NULL;
+       kfree(pHsController);
+}
+
+struct dma_controller *__init
+dma_controller_create(struct musb *pThis, void __iomem *pCoreBase)
+{
+       struct hsdma *pController;
+       struct device *dev = pThis->controller;
+       struct platform_device *pdev = to_platform_device(dev);
+       int irq = platform_get_irq(pdev, 1);
+
+       if (irq == 0) {
+               dev_err(dev, "No DMA interrupt line!\n");
+               return NULL;
+       }
+
+       if (!(pController = kzalloc(sizeof *pController, GFP_KERNEL)))
+               return NULL;
+
+       pController->bChannelCount = MGC_HSDMA_CHANNELS;
+       pController->pDmaPrivate = pThis;
+       pController->pCoreBase = pCoreBase;
+
+       pController->Controller.pPrivateData = pController;
+       pController->Controller.start = hsdma_start;
+       pController->Controller.stop = hsdma_stop;
+       pController->Controller.channel_alloc = hsdma_channel_alloc;
+       pController->Controller.channel_release = hsdma_channel_release;
+       pController->Controller.channel_program = hsdma_channel_program;
+       pController->Controller.channel_abort = hsdma_channel_abort;
+
+       if (request_irq(irq, hsdma_irq, IRQF_DISABLED,
+                       pThis->controller->bus_id, &pController->Controller)) {
+               dev_err(dev, "request_irq %d failed!\n", irq);
+               kfree(pController);
+               return NULL;
+       }
+
+       return &pController->Controller;
+}
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
new file mode 100644 (file)
index 0000000..87a7014
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2005-2006 by Texas Instruments
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * The Inventra Controller Driver for Linux is free software; you
+ * can redistribute it and/or modify it under the terms of the GNU
+ * General Public License version 2 as published by the Free Software
+ * Foundation.
+ *
+ * The Inventra Controller Driver for Linux is distributed in
+ * the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Inventra Controller Driver for Linux ; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+#include <asm/mach-types.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/mux.h>
+
+#include "musbdefs.h"
+#include "omap2430.h"
+
+
+static int dma_off;
+
+void musb_platform_enable(struct musb *musb)
+{
+       if (is_dma_capable() && dma_off)
+               printk(KERN_WARNING "%s %s: dma not reactivated\n",
+                               __FILE__, __FUNCTION__);
+       else
+               dma_off = 1;
+}
+
+void musb_platform_disable(struct musb *musb)
+{
+       if (is_dma_capable()) {
+               printk(KERN_WARNING "%s %s: dma still active\n",
+                               __FILE__, __FUNCTION__);
+               dma_off = 1;
+       }
+}
+
+static void omap_vbus_power(struct musb *musb, int is_on, int sleeping)
+{
+}
+
+int __init musb_platform_init(struct musb *musb)
+{
+       /* Erratum - reset value of STP has pull-down.
+          Change it to pull-up. */
+       omap_cfg_reg(AE5_2430_USB0HS_STP);
+
+       /* start clock */
+       musb->clock = clk_get((struct device *)musb->controller, "usbhs_ick");
+       clk_enable(musb->clock);
+
+       omap_writel(omap_readl(OTG_INTERFSEL) | (1<<0), OTG_INTERFSEL);
+       omap_writel(omap_readl(OTG_SYSCONFIG) |
+                   ((1 << 12) | (1 << 3) | (1 << 2)),
+                   OTG_SYSCONFIG);
+
+       pr_debug("HS USB OTG: revision 0x%x, sysconfig 0x%02x, "
+                       "sysstatus 0x%x, intrfsel 0x%x, simenable  0x%x\n",
+                       omap_readl(OTG_REVISION), omap_readl(OTG_SYSCONFIG),
+                       omap_readl(OTG_SYSSTATUS), omap_readl(OTG_INTERFSEL),
+                       omap_readl(OTG_SIMENABLE));
+
+       omap_vbus_power(musb, musb->board_mode == MUSB_HOST, 1);
+
+       return 0;
+}
+
+int __exit musb_platform_exit(struct musb *musb)
+{
+       omap_vbus_power(musb, 0 /*off*/, 1);
+       clk_disable(musb->clock);
+
+       return 0;
+}
diff --git a/drivers/usb/musb/omap2430.h b/drivers/usb/musb/omap2430.h
new file mode 100644 (file)
index 0000000..e634808
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2005-2006 by Texas Instruments
+ *
+ * The Inventra Controller Driver for Linux is free software; you
+ * can redistribute it and/or modify it under the terms of the GNU
+ * General Public License version 2 as published by the Free Software
+ * Foundation.
+ */
+
+#ifndef __MUSB_OMAP243X_H__
+#define __MUSB_OMAP243X_H__
+
+#ifdef CONFIG_ARCH_OMAP2430
+/*
+ * OMAP2430-specific definitions
+ */
+
+#define MENTOR_BASE_OFFSET     0
+#define HS_OTG(offset)         (OMAP243X_HS_BASE + (offset))
+#define OTG_REVISION           HS_OTG(0x400)
+#define OTG_SYSCONFIG          HS_OTG(0x404)
+#define OTG_SYSSTATUS          HS_OTG(0x408)
+#define OTG_INTERFSEL          HS_OTG(0x40c)
+#define OTG_SIMENABLE          HS_OTG(0x410)
+
+#endif /* CONFIG_ARCH_OMAP243X */
+
+#endif /* __MUSB_OMAP243X_H__ */
diff --git a/drivers/usb/musb/plat_arc.h b/drivers/usb/musb/plat_arc.h
new file mode 100644 (file)
index 0000000..06d3f37
--- /dev/null
@@ -0,0 +1,118 @@
+/******************************************************************
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * The Inventra Controller Driver for Linux is free software; you
+ * can redistribute it and/or modify it under the terms of the GNU
+ * General Public License version 2 as published by the Free Software
+ * Foundation.
+ *
+ * The Inventra Controller Driver for Linux is distributed in
+ * the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Inventra Controller Driver for Linux ; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ANY DOWNLOAD, USE, REPRODUCTION, MODIFICATION OR DISTRIBUTION
+ * OF THIS DRIVER INDICATES YOUR COMPLETE AND UNCONDITIONAL ACCEPTANCE
+ * OF THOSE TERMS.THIS DRIVER IS PROVIDED "AS IS" AND MENTOR GRAPHICS
+ * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, RELATED TO THIS DRIVER.
+ * MENTOR GRAPHICS SPECIFICALLY DISCLAIMS ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY; FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT.  MENTOR GRAPHICS DOES NOT PROVIDE SUPPORT
+ * SERVICES OR UPDATES FOR THIS DRIVER, EVEN IF YOU ARE A MENTOR
+ * GRAPHICS SUPPORT CUSTOMER.
+ ******************************************************************/
+
+/*
+ * Linux-specific architecture definitions
+ */
+
+#ifndef __MUSB_LINUX_PLATFORM_ARCH_H__
+#define __MUSB_LINUX_PLATFORM_ARCH_H__
+
+#include <asm/io.h>
+
+#ifndef        CONFIG_ARM
+static inline void readsl(const void __iomem *addr, void *buf, int len)
+       { insl((unsigned long)addr, buf, len); }
+static inline void readsw(const void __iomem *addr, void *buf, int len)
+       { insw((unsigned long)addr, buf, len); }
+static inline void readsb(const void __iomem *addr, void *buf, int len)
+       { insb((unsigned long)addr, buf, len); }
+
+static inline void writesl(const void __iomem *addr, const void *buf, int len)
+       { outsl((unsigned long)addr, buf, len); }
+static inline void writesw(const void __iomem *addr, const void *buf, int len)
+       { outsw((unsigned long)addr, buf, len); }
+static inline void writesb(const void __iomem *addr, const void *buf, int len)
+       { outsb((unsigned long)addr, buf, len); }
+
+#endif
+
+/* NOTE:  these offsets are all in bytes */
+
+static inline u16 musb_readw(const void __iomem *addr, unsigned offset)
+       { return __raw_readw(addr + offset); }
+
+static inline u32 musb_readl(const void __iomem *addr, unsigned offset)
+       { return __raw_readl(addr + offset); }
+
+
+static inline void musb_writew(void __iomem *addr, unsigned offset, u16 data)
+       { __raw_writew(data, addr + offset); }
+
+static inline void musb_writel(void __iomem *addr, unsigned offset, u32 data)
+       { __raw_writel(data, addr + offset); }
+
+
+#ifdef CONFIG_USB_TUSB6010
+
+/*
+ * TUSB6010 doesn't allow 8-bit access; 16-bit access is the minimum.
+ */
+static inline u8 musb_readb(const void __iomem *addr, unsigned offset)
+{
+       u16 tmp;
+       u8 val;
+
+       tmp = __raw_readw(addr + (offset & ~1));
+       if (offset & 1)
+               val = (tmp >> 8);
+       else
+               val = tmp & 0xff;
+
+       return val;
+}
+
+static inline void musb_writeb(void __iomem *addr, unsigned offset, u8 data)
+{
+       u16 tmp;
+
+       tmp = __raw_readw(addr + (offset & ~1));
+       if (offset & 1)
+               tmp = (data << 8) | (tmp & 0xff);
+       else
+               tmp = (tmp & 0xff00) | data;
+
+       __raw_writew(tmp, addr + (offset & ~1));
+}
+
+#else
+
+static inline u8 musb_readb(const void __iomem *addr, unsigned offset)
+       { return __raw_readb(addr + offset); }
+
+static inline void musb_writeb(void __iomem *addr, unsigned offset, u8 data)
+       { __raw_writeb(data, addr + offset); }
+
+#endif /* CONFIG_USB_TUSB6010 */
+
+#endif
diff --git a/drivers/usb/musb/plat_uds.c b/drivers/usb/musb/plat_uds.c
new file mode 100644 (file)
index 0000000..152c979
--- /dev/null
@@ -0,0 +1,2003 @@
+/*****************************************************************
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ * Copyright (C) 2006 by Nokia Corporation
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * The Inventra Controller Driver for Linux is free software; you
+ * can redistribute it and/or modify it under the terms of the GNU
+ * General Public License version 2 as published by the Free Software
+ * Foundation.
+ *
+ * The Inventra Controller Driver for Linux is distributed in
+ * the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Inventra Controller Driver for Linux ; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ANY DOWNLOAD, USE, REPRODUCTION, MODIFICATION OR DISTRIBUTION
+ * OF THIS DRIVER INDICATES YOUR COMPLETE AND UNCONDITIONAL ACCEPTANCE
+ * OF THOSE TERMS.THIS DRIVER IS PROVIDED "AS IS" AND MENTOR GRAPHICS
+ * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, RELATED TO THIS DRIVER.
+ * MENTOR GRAPHICS SPECIFICALLY DISCLAIMS ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY; FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT.  MENTOR GRAPHICS DOES NOT PROVIDE SUPPORT
+ * SERVICES OR UPDATES FOR THIS DRIVER, EVEN IF YOU ARE A MENTOR
+ * GRAPHICS SUPPORT CUSTOMER.
+ ******************************************************************/
+
+/*
+ * Inventra (Multipoint) Dual-Role Controller Driver for Linux.
+ *
+ * This consists of a Host Controller Driver (HCD) and a peripheral
+ * controller driver implementing the "Gadget" API; OTG support is
+ * in the works.  These are normal Linux-USB controller drivers which
+ * use IRQs and have no dedicated thread.
+ *
+ * This version of the driver has only been used with products from
+ * Texas Instruments.  Those products integrate the Inventra logic
+ * with other DMA, IRQ, and bus modules, as well as other logic that
+ * needs to be reflected in this driver.
+ *
+ *
+ * NOTE:  the original Mentor code here was pretty much a collection
+ * of mechanisms that don't seem to have been fully integrated/working
+ * for *any* Linux kernel version.  This version aims at Linux 2.6.now,
+ * Key open issues include:
+ *
+ *  - Lack of host-side transaction scheduling, for all transfer types.
+ *    The hardware doesn't do it; instead, software must.
+ *
+ *    This is not an issue for OTG devices that don't support external
+ *    hubs, but for more "normal" USB hosts it's a user issue that the
+ *    "multipoint" support doesn't scale in the expected ways.  That
+ *    includes DaVinci EVM in a common non-OTG mode.
+ *
+ *      * Control and bulk use dedicated endpoints, and there's as
+ *        yet no mechanism to either (a) reclaim the hardware when
+ *        peripherals are NAKing, which gets complicated with bulk
+ *        endpoints, or (b) use more than a single bulk endpoint in
+ *        each direction.
+ *
+ *        RESULT:  one device may be perceived as blocking another one.
+ *
+ *      * Interrupt and isochronous will dynamically allocate endpoint
+ *        hardware, but (a) there's no record keeping for bandwidth;
+ *        (b) in the common case that few endpoints are available, there
+ *        is no mechanism to reuse endpoints to talk to multiple devices.
+ *
+ *        RESULT:  At one extreme, bandwidth can be overcommitted in
+ *        some hardware configurations, no faults will be reported.
+ *        At the other extreme, the bandwidth capabilities which do
+ *        exist tend to be severely undercommitted.  You can't yet hook
+ *        up both a keyboard and a mouse to an external USB hub.
+ */
+
+/*
+ * This gets many kinds of configuration information:
+ *     - Kconfig for everything user-configurable
+ *     - <asm/arch/hdrc_cnf.h> for SOC or family details
+ *     - platform_device for addressing, irq, and platform_data
+ *     - platform_data is mostly for board-specific informarion
+ *
+ * Most of the conditional compilation will (someday) vanish.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/kobject.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+
+#ifdef CONFIG_ARM
+#include <asm/arch/hardware.h>
+#include <asm/arch/memory.h>
+#include <asm/mach-types.h>
+#endif
+
+#include "musbdefs.h"
+
+
+#ifdef CONFIG_ARCH_DAVINCI
+#include "davinci.h"
+#endif
+
+
+
+#if MUSB_DEBUG > 0
+unsigned debug = MUSB_DEBUG;
+module_param(debug, uint, 0);
+MODULE_PARM_DESC(debug, "initial debug message level");
+
+#define MUSB_VERSION_SUFFIX    "/dbg"
+#else
+
+const char *otg_state_string(struct musb *musb)
+{
+       static char buf[8];
+
+       snprintf(buf, sizeof buf, "otg-%d", musb->xceiv.state);
+       return buf;
+}
+#endif
+
+#define DRIVER_AUTHOR "Mentor Graphics, Texas Instruments, Nokia"
+#define DRIVER_DESC "Inventra Dual-Role USB Controller Driver"
+
+#define MUSB_VERSION_BASE "2.2a/db-0.5.2"
+
+#ifndef MUSB_VERSION_SUFFIX
+#define MUSB_VERSION_SUFFIX    ""
+#endif
+#define MUSB_VERSION   MUSB_VERSION_BASE MUSB_VERSION_SUFFIX
+
+#define DRIVER_INFO DRIVER_DESC ", v" MUSB_VERSION
+
+const char musb_driver_name[] = "musb_hdrc";
+
+MODULE_DESCRIPTION(DRIVER_INFO);
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_LICENSE("GPL");
+
+
+/*-------------------------------------------------------------------------*/
+
+static inline struct musb *dev_to_musb(struct device *dev)
+{
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+       /* usbcore insists dev->driver_data is a "struct hcd *" */
+       return hcd_to_musb(dev_get_drvdata(dev));
+#else
+       return dev_get_drvdata(dev);
+#endif
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifndef CONFIG_USB_TUSB6010
+/*
+ * Load an endpoint's FIFO
+ */
+void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 wCount, const u8 *pSource)
+{
+       void __iomem *fifo = hw_ep->fifo;
+
+       prefetch((u8 *)pSource);
+
+       DBG(4, "%cX ep%d fifo %p count %d buf %p\n",
+                       'T', hw_ep->bLocalEnd, fifo, wCount, pSource);
+
+       /* we can't assume unaligned reads work */
+       if (likely((0x01 & (unsigned long) pSource) == 0)) {
+               u16     index = 0;
+
+               /* best case is 32bit-aligned source address */
+               if ((0x02 & (unsigned long) pSource) == 0) {
+                       if (wCount >= 4) {
+                               writesl(fifo, pSource + index, wCount >> 2);
+                               index += wCount & ~0x03;
+                       }
+                       if (wCount & 0x02) {
+                               musb_writew(fifo, 0, *(u16*)&pSource[index]);
+                               index += 2;
+                       }
+               } else {
+                       if (wCount >= 2) {
+                               writesw(fifo, pSource + index, wCount >> 1);
+                               index += wCount & ~0x01;
+                       }
+               }
+               if (wCount & 0x01)
+                       musb_writeb(fifo, 0, pSource[index]);
+       } else  {
+               /* byte aligned */
+               writesb(fifo, pSource, wCount);
+       }
+}
+
+/*
+ * Unload an endpoint's FIFO
+ */
+void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 wCount, u8 *pDest)
+{
+       void __iomem *fifo = hw_ep->fifo;
+
+       DBG(4, "%cX ep%d fifo %p count %d buf %p\n",
+                       'R', hw_ep->bLocalEnd, fifo, wCount, pDest);
+
+       /* we can't assume unaligned writes work */
+       if (likely((0x01 & (unsigned long) pDest) == 0)) {
+               u16     index = 0;
+
+               /* best case is 32bit-aligned destination address */
+               if ((0x02 & (unsigned long) pDest) == 0) {
+                       if (wCount >= 4) {
+                               readsl(fifo, pDest, wCount >> 2);
+                               index = wCount & ~0x03;
+                       }
+                       if (wCount & 0x02) {
+                               *(u16*)&pDest[index] = musb_readw(fifo, 0);
+                               index += 2;
+                       }
+               } else {
+                       if (wCount >= 2) {
+                               readsw(fifo, pDest, wCount >> 1);
+                               index = wCount & ~0x01;
+                       }
+               }
+               if (wCount & 0x01)
+                       pDest[index] = musb_readb(fifo, 0);
+       } else  {
+               /* byte aligned */
+               readsb(fifo, pDest, wCount);
+       }
+}
+
+#endif /* normal PIO */
+
+
+/*-------------------------------------------------------------------------*/
+
+/* for high speed test mode; see USB 2.0 spec 7.1.20 */
+static const u8 musb_test_packet[53] = {
+       /* implicit SYNC then DATA0 to start */
+
+       /* JKJKJKJK x9 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       /* JJKKJJKK x8 */
+       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+       /* JJJJKKKK x8 */
+       0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+       /* JJJJJJJKKKKKKK x8 */
+       0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       /* JJJJJJJK x8 */
+       0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd,
+       /* JKKKKKKK x10, JK */
+       0xfc, 0x7e, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0x7e
+
+       /* implicit CRC16 then EOP to end */
+};
+
+void musb_load_testpacket(struct musb *musb)
+{
+       void __iomem    *regs = musb->aLocalEnd[0].regs;
+
+       MGC_SelectEnd(musb->pRegs, 0);
+       musb_write_fifo(musb->control_ep,
+                       sizeof(musb_test_packet), musb_test_packet);
+       musb_writew(regs, MGC_O_HDRC_CSR0, MGC_M_CSR0_TXPKTRDY);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Interrupt Service Routine to record USB "global" interrupts.
+ * Since these do not happen often and signify things of
+ * paramount importance, it seems OK to check them individually;
+ * the order of the tests is specified in the manual
+ *
+ * @param pThis instance pointer
+ * @param bIntrUSB register contents
+ * @param devctl
+ * @param power
+ */
+
+#define STAGE0_MASK (MGC_M_INTR_RESUME | MGC_M_INTR_SESSREQ \
+               | MGC_M_INTR_VBUSERROR | MGC_M_INTR_CONNECT \
+               | MGC_M_INTR_RESET )
+
+static irqreturn_t musb_stage0_irq(struct musb * pThis, u8 bIntrUSB,
+                               u8 devctl, u8 power)
+{
+       irqreturn_t handled = IRQ_NONE;
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+       void __iomem *pBase = pThis->pRegs;
+#endif
+
+       DBG(3, "<== Power=%02x, DevCtl=%02x, bIntrUSB=0x%x\n", power, devctl,
+               bIntrUSB);
+
+       /* in host mode, the peripheral may issue remote wakeup.
+        * in peripheral mode, the host may resume the link.
+        * spurious RESUME irqs happen too, paired with SUSPEND.
+        */
+       if (bIntrUSB & MGC_M_INTR_RESUME) {
+               handled = IRQ_HANDLED;
+               DBG(3, "RESUME (%s)\n", otg_state_string(pThis));
+
+               if (devctl & MGC_M_DEVCTL_HM) {
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+                       switch (pThis->xceiv.state) {
+                       case OTG_STATE_A_SUSPEND:
+                               /* remote wakeup?  later, GetPortStatus
+                                * will stop RESUME signaling
+                                */
+                               if (power & MGC_M_POWER_RESUME) {
+                                       power &= ~MGC_M_POWER_SUSPENDM;
+                                       musb_writeb(pBase, MGC_O_HDRC_POWER,
+                                               power | MGC_M_POWER_RESUME);
+
+                                       pThis->port1_status |=
+                                                 MUSB_PORT_STAT_RESUME
+                                               | USB_PORT_STAT_C_SUSPEND;
+                                       pThis->rh_timer = jiffies
+                                               + msecs_to_jiffies(20);
+
+                                       pThis->xceiv.state = OTG_STATE_A_HOST;
+                                       pThis->is_active = 1;
+                                       usb_hcd_resume_root_hub(
+                                                       musb_to_hcd(pThis));
+
+                               } else if (power & MGC_M_POWER_SUSPENDM) {
+                                       /* spurious */
+                                       pThis->int_usb &= ~MGC_M_INTR_SUSPEND;
+                               }
+                               break;
+                       case OTG_STATE_B_WAIT_ACON:
+                               pThis->xceiv.state = OTG_STATE_B_PERIPHERAL;
+                               pThis->is_active = 1;
+                               MUSB_DEV_MODE(pThis);
+                               break;
+                       default:
+                               WARN("bogus %s RESUME (%s)\n",
+                                       "host",
+                                       otg_state_string(pThis));
+                       }
+#endif
+               } else {
+                       switch (pThis->xceiv.state) {
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+                       case OTG_STATE_A_SUSPEND:
+                               /* possibly DISCONNECT is upcoming */
+                               pThis->xceiv.state = OTG_STATE_A_HOST;
+                               usb_hcd_resume_root_hub(musb_to_hcd(pThis));
+                               break;
+#endif
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+                       case OTG_STATE_B_WAIT_ACON:
+                       case OTG_STATE_B_PERIPHERAL:
+                               musb_g_resume(pThis);
+                               break;
+                       case OTG_STATE_B_IDLE:
+                               pThis->int_usb &= ~MGC_M_INTR_SUSPEND;
+                               break;
+#endif
+                       default:
+                               WARN("bogus %s RESUME (%s)\n",
+                                       "peripheral",
+                                       otg_state_string(pThis));
+                       }
+               }
+       }
+
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+       /* see manual for the order of the tests */
+       if (bIntrUSB & MGC_M_INTR_SESSREQ) {
+               DBG(1, "SESSION_REQUEST (%s)\n", otg_state_string(pThis));
+
+               /* IRQ arrives from ID pin sense or (later, if VBUS power
+                * is removed) SRP.  responses are time critical:
+                *  - turn on VBUS (with silicon-specific mechanism)
+                *  - go through A_WAIT_VRISE
+                *  - ... to A_WAIT_BCON.
+                * a_wait_vrise_tmout triggers VBUS_ERROR transitions
+                */
+               musb_writeb(pBase, MGC_O_HDRC_DEVCTL, MGC_M_DEVCTL_SESSION);
+               pThis->bEnd0Stage = MGC_END0_START;
+               pThis->xceiv.state = OTG_STATE_A_IDLE;
+               MUSB_HST_MODE(pThis);
+               musb_set_vbus(pThis, 1);
+
+               handled = IRQ_HANDLED;
+       }
+
+       if (bIntrUSB & MGC_M_INTR_VBUSERROR) {
+               int     ignore = 0;
+
+               /* During connection as an A-Device, we may see a short
+                * current spikes causing voltage drop, because of cable
+                * and peripheral capacitance combined with vbus draw.
+                * (So: less common with truly self-powered devices, where
+                * vbus doesn't act like a power supply.)
+                *
+                * Such spikes are short; usually less than ~500 usec, max
+                * of ~2 msec.  That is, they're not sustained overcurrent
+                * errors, though they're reported using VBUSERROR irqs.
+                *
+                * Workarounds:  (a) hardware: use self powered devices.
+                * (b) software:  ignore non-repeated VBUS errors.
+                *
+                * REVISIT:  do delays from lots of DEBUG_KERNEL checks
+                * make trouble here, keeping VBUS < 4.4V ?
+                */
+               switch (pThis->xceiv.state) {
+               case OTG_STATE_A_HOST:
+                       /* recovery is dicey once we've gotten past the
+                        * initial stages of enumeration, but if VBUS
+                        * stayed ok at the other end of the link, and
+                        * another reset is due (at least for high speed,
+                        * to redo the chirp etc), it might work OK...
+                        */
+               case OTG_STATE_A_WAIT_BCON:
+               case OTG_STATE_A_WAIT_VRISE:
+                       if (pThis->vbuserr_retry) {
+                               pThis->vbuserr_retry--;
+                               ignore = 1;
+                               devctl |= MGC_M_DEVCTL_SESSION;
+                               musb_writeb(pBase, MGC_O_HDRC_DEVCTL, devctl);
+                       } else {
+                               pThis->port1_status |=
+                                         (1 << USB_PORT_FEAT_OVER_CURRENT)
+                                       | (1 << USB_PORT_FEAT_C_OVER_CURRENT);
+                       }
+                       break;
+               default:
+                       break;
+               }
+
+               DBG(1, "VBUS_ERROR in %s (%02x, %s), retry #%d, port1 %08x\n",
+                               otg_state_string(pThis),
+                               devctl,
+                               ({ char *s;
+                               switch (devctl & MGC_M_DEVCTL_VBUS) {
+                               case 0 << MGC_S_DEVCTL_VBUS:
+                                       s = "<SessEnd"; break;
+                               case 1 << MGC_S_DEVCTL_VBUS:
+                                       s = "<AValid"; break;
+                               case 2 << MGC_S_DEVCTL_VBUS:
+                                       s = "<VBusValid"; break;
+                               //case 3 << MGC_S_DEVCTL_VBUS:
+                               default:
+                                       s = "VALID"; break;
+                               }; s; }),
+                               VBUSERR_RETRY_COUNT - pThis->vbuserr_retry,
+                               pThis->port1_status);
+
+               /* go through A_WAIT_VFALL then start a new session */
+               if (!ignore)
+                       musb_set_vbus(pThis, 0);
+               handled = IRQ_HANDLED;
+       }
+
+       if (bIntrUSB & MGC_M_INTR_CONNECT) {
+               struct usb_hcd *hcd = musb_to_hcd(pThis);
+
+               handled = IRQ_HANDLED;
+               pThis->is_active = 1;
+               set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
+
+               pThis->bEnd0Stage = MGC_END0_START;
+
+#ifdef CONFIG_USB_MUSB_OTG
+               /* flush endpoints when transitioning from Device Mode */
+               if (is_peripheral_active(pThis)) {
+                       // REVISIT HNP; just force disconnect
+               }
+               pThis->bDelayPortPowerOff = FALSE;
+#endif
+               pThis->port1_status &= ~(USB_PORT_STAT_LOW_SPEED
+                                       |USB_PORT_STAT_HIGH_SPEED
+                                       |USB_PORT_STAT_ENABLE
+                                       );
+               pThis->port1_status |= USB_PORT_STAT_CONNECTION
+                                       |(USB_PORT_STAT_C_CONNECTION << 16);
+
+               /* high vs full speed is just a guess until after reset */
+               if (devctl & MGC_M_DEVCTL_LSDEV)
+                       pThis->port1_status |= USB_PORT_STAT_LOW_SPEED;
+
+               if (hcd->status_urb)
+                       usb_hcd_poll_rh_status(hcd);
+               else
+                       usb_hcd_resume_root_hub(hcd);
+
+               MUSB_HST_MODE(pThis);
+
+               /* indicate new connection to OTG machine */
+               switch (pThis->xceiv.state) {
+               case OTG_STATE_B_WAIT_ACON:
+                       pThis->xceiv.state = OTG_STATE_B_HOST;
+                       break;
+               default:
+                       if ((devctl & MGC_M_DEVCTL_VBUS)
+                                       == (3 << MGC_S_DEVCTL_VBUS))
+                               pThis->xceiv.state = OTG_STATE_A_HOST;
+                       break;
+               }
+               DBG(1, "CONNECT (%s) devctl %02x\n",
+                               otg_state_string(pThis), devctl);
+       }
+#endif /* CONFIG_USB_MUSB_HDRC_HCD */
+
+       /* mentor saves a bit: bus reset and babble share the same irq.
+        * only host sees babble; only peripheral sees bus reset.
+        */
+       if (bIntrUSB & MGC_M_INTR_RESET) {
+               if (devctl & MGC_M_DEVCTL_HM) {
+                       DBG(1, "BABBLE\n");
+
+                       /* REVISIT it's unclear how to handle this.  Mentor's
+                        * code stopped the whole USB host, which is clearly
+                        * very wrong.  Docs say (15.1) that babble ends the
+                        * current sesssion, so shutdown _with restart_ would
+                        * be appropriate ... except that seems to be wrong,
+                        * at least some lowspeed enumerations trigger the
+                        * babbles without aborting the session!
+                        *
+                        * (A "babble" IRQ seems quite pointless...)
+                        */
+
+               } else {
+                       DBG(1, "BUS RESET\n");
+
+                       musb_g_reset(pThis);
+                       schedule_work(&pThis->irq_work);
+               }
+
+               handled = IRQ_HANDLED;
+       }
+
+       return handled;
+}
+
+/*
+ * Interrupt Service Routine to record USB "global" interrupts.
+ * Since these do not happen often and signify things of
+ * paramount importance, it seems OK to check them individually;
+ * the order of the tests is specified in the manual
+ *
+ * @param pThis instance pointer
+ * @param bIntrUSB register contents
+ * @param devctl
+ * @param power
+ */
+static irqreturn_t musb_stage2_irq(struct musb * pThis, u8 bIntrUSB,
+                               u8 devctl, u8 power)
+{
+       irqreturn_t handled = IRQ_NONE;
+
+#if 0
+/* REVISIT ... this would be for multiplexing periodic endpoints, or
+ * supporting transfer phasing to prevent exceeding ISO bandwidth
+ * limits of a given frame or microframe.
+ *
+ * It's not needed for peripheral side, which dedicates endpoints;
+ * though it _might_ use SOF irqs for other purposes.
+ *
+ * And it's not currently needed for host side, which also dedicates
+ * endpoints, relies on TX/RX interval registers, and isn't claimed
+ * to support ISO transfers yet.
+ */
+       if (bIntrUSB & MGC_M_INTR_SOF) {
+               void __iomem *pBase = pThis->pRegs;
+               struct musb_hw_ep       *ep;
+               u8 bEnd;
+               u16 wFrame;
+
+               DBG(6, "START_OF_FRAME\n");
+               handled = IRQ_HANDLED;
+
+               /* start any periodic Tx transfers waiting for current frame */
+               wFrame = musb_readw(pBase, MGC_O_HDRC_FRAME);
+               ep = pThis->aLocalEnd;
+               for (bEnd = 1; (bEnd < pThis->bEndCount)
+                                       && (pThis->wEndMask >= (1 << bEnd));
+                               bEnd++, ep++) {
+                       // FIXME handle framecounter wraps (12 bits)
+                       // eliminate duplicated StartUrb logic
+                       if (ep->dwWaitFrame >= wFrame) {
+                               ep->dwWaitFrame = 0;
+                               printk("SOF --> periodic TX%s on %d\n",
+                                       ep->tx_channel ? " DMA" : "",
+                                       bEnd);
+                               if (!ep->tx_channel)
+                                       musb_h_tx_start(pThis, bEnd);
+                               else
+                                       cppi_hostdma_start(pThis, bEnd);
+                       }
+               }               /* end of for loop */
+       }
+#endif
+
+       if ((bIntrUSB & MGC_M_INTR_DISCONNECT) && !pThis->bIgnoreDisconnect) {
+               DBG(1, "DISCONNECT (%s) as %s, devctl %02x\n",
+                               otg_state_string(pThis),
+                               MUSB_MODE(pThis), devctl);
+               handled = IRQ_HANDLED;
+
+               switch (pThis->xceiv.state) {
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+               case OTG_STATE_A_HOST:
+               case OTG_STATE_A_SUSPEND:
+                       musb_root_disconnect(pThis);
+                       break;
+#endif /* HOST */
+#ifdef CONFIG_USB_MUSB_OTG
+               case OTG_STATE_A_PERIPHERAL:
+               case OTG_STATE_B_HOST:
+                       musb_root_disconnect(pThis);
+                       /* FALLTHROUGH */
+               case OTG_STATE_B_WAIT_ACON:
+#endif /* OTG */
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+               case OTG_STATE_B_PERIPHERAL:
+                       musb_g_disconnect(pThis);
+                       break;
+#endif /* GADGET */
+               default:
+                       WARN("unhandled DISCONNECT transition (%s)\n",
+                               otg_state_string(pThis));
+                       break;
+               }
+
+               schedule_work(&pThis->irq_work);
+       }
+
+       if (bIntrUSB & MGC_M_INTR_SUSPEND) {
+               DBG(1, "SUSPEND (%s) devctl %02x\n",
+                               otg_state_string(pThis), devctl);
+               handled = IRQ_HANDLED;
+
+               switch (pThis->xceiv.state) {
+               case OTG_STATE_B_PERIPHERAL:
+                       musb_g_suspend(pThis);
+                       pThis->is_active = is_otg_enabled(pThis)
+                                       && pThis->xceiv.gadget->b_hnp_enable;
+                       if (pThis->is_active) {
+                               pThis->xceiv.state = OTG_STATE_B_WAIT_ACON;
+                               /* REVISIT timeout for b_ase0_brst, etc */
+                       }
+                       break;
+               case OTG_STATE_A_HOST:
+                       pThis->xceiv.state = OTG_STATE_A_SUSPEND;
+                       pThis->is_active = is_otg_enabled(pThis)
+                                       && pThis->xceiv.host->b_hnp_enable;
+                       break;
+               default:
+                       /* "should not happen" */
+                       pThis->is_active = 0;
+                       break;
+               }
+       }
+
+
+       return handled;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+* Program the HDRC to start (enable interrupts, dma, etc.).
+*/
+void musb_start(struct musb *musb)
+{
+       void __iomem    *regs = musb->pRegs;
+       u8              devctl = musb_readb(regs, MGC_O_HDRC_DEVCTL);
+
+       DBG(2, "<== devctl %02x\n", devctl);
+
+       /*  Set INT enable registers, enable interrupts */
+       musb_writew(regs, MGC_O_HDRC_INTRTXE, musb->wEndMask);
+       musb_writew(regs, MGC_O_HDRC_INTRRXE, musb->wEndMask & 0xfffe);
+       musb_writeb(regs, MGC_O_HDRC_INTRUSBE, 0xf7);
+
+       musb_writeb(regs, MGC_O_HDRC_TESTMODE, 0);
+
+       /* put into basic highspeed mode and start session */
+       musb_writeb(regs, MGC_O_HDRC_POWER, MGC_M_POWER_ISOUPDATE
+                                               | MGC_M_POWER_SOFTCONN
+                                               | MGC_M_POWER_HSENAB
+                                               /* ENSUSPEND wedges tusb */
+                                               // | MGC_M_POWER_ENSUSPEND
+                                               );
+
+       musb->is_active = 0;
+       devctl = musb_readb(regs, MGC_O_HDRC_DEVCTL);
+       devctl &= ~MGC_M_DEVCTL_SESSION;
+
+       if (is_otg_enabled(musb)) {
+               /* session started after:
+                * (a) ID-grounded irq, host mode;
+                * (b) vbus present/connect IRQ, peripheral mode;
+                * (c) peripheral initiates, using SRP
+                */
+               if ((devctl & MGC_M_DEVCTL_VBUS) == MGC_M_DEVCTL_VBUS)
+                       musb->is_active = 1;
+               else
+                       devctl |= MGC_M_DEVCTL_SESSION;
+
+       } else if (is_host_enabled(musb)) {
+               /* assume ID pin is hard-wired to ground */
+               devctl |= MGC_M_DEVCTL_SESSION;
+
+       } else /* peripheral is enabled */ {
+               if ((devctl & MGC_M_DEVCTL_VBUS) == MGC_M_DEVCTL_VBUS)
+                       musb->is_active = 1;
+       }
+       musb_platform_enable(musb);
+       musb_writeb(regs, MGC_O_HDRC_DEVCTL, devctl);
+}
+
+
+static void musb_generic_disable(struct musb *pThis)
+{
+       void __iomem    *pBase = pThis->pRegs;
+       u16     temp;
+
+       /* disable interrupts */
+       musb_writeb(pBase, MGC_O_HDRC_INTRUSBE, 0);
+       musb_writew(pBase, MGC_O_HDRC_INTRTX, 0);
+       musb_writew(pBase, MGC_O_HDRC_INTRRX, 0);
+
+       /* off */
+       musb_writeb(pBase, MGC_O_HDRC_DEVCTL, 0);
+
+       /*  flush pending interrupts */
+       temp = musb_readb(pBase, MGC_O_HDRC_INTRUSB);
+       temp = musb_readw(pBase, MGC_O_HDRC_INTRTX);
+       temp = musb_readw(pBase, MGC_O_HDRC_INTRRX);
+
+}
+
+/*
+ * Make the HDRC stop (disable interrupts, etc.);
+ * reversible by musb_start
+ * called on gadget driver unregister
+ * with controller locked, irqs blocked
+ * acts as a NOP unless some role activated the hardware
+ */
+void musb_stop(struct musb *musb)
+{
+       /* stop IRQs, timers, ... */
+       musb_platform_disable(musb);
+       musb_generic_disable(musb);
+       DBG(3, "HDRC disabled\n");
+
+       /* FIXME
+        *  - mark host and/or peripheral drivers unusable/inactive
+        *  - disable DMA (and enable it in HdrcStart)
+        *  - make sure we can musb_start() after musb_stop(); with
+        *    OTG mode, gadget driver module rmmod/modprobe cycles that
+        *  - ...
+        */
+       musb_platform_try_idle(musb);
+}
+
+static void musb_shutdown(struct platform_device *pdev)
+{
+       struct musb     *musb = dev_to_musb(&pdev->dev);
+       unsigned long   flags;
+
+       spin_lock_irqsave(&musb->Lock, flags);
+       musb_platform_disable(musb);
+       musb_generic_disable(musb);
+       spin_unlock_irqrestore(&musb->Lock, flags);
+
+       /* FIXME power down */
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * The silicon either has hard-wired endpoint configurations, or else
+ * "dynamic fifo" sizing.  The driver has support for both, though at this
+ * writing only the dynamic sizing is very well tested.   We use normal
+ * idioms to so both modes are compile-tested, but dead code elimination
+ * leaves only the relevant one in the object file.
+ *
+ * We don't currently use dynamic fifo setup capability to do anything
+ * more than selecting one of a bunch of predefined configurations.
+ */
+#ifdef MUSB_C_DYNFIFO_DEF
+#define        can_dynfifo()   1
+#else
+#define        can_dynfifo()   0
+#endif
+
+#ifdef CONFIG_USB_TUSB6010
+static ushort __initdata fifo_mode = 4;
+#else
+static ushort __initdata fifo_mode = 2;
+#endif
+
+/* "modprobe ... fifo_mode=1" etc */
+module_param(fifo_mode, ushort, 0);
+MODULE_PARM_DESC(fifo_mode, "initial endpoint configuration");
+
+
+#define DYN_FIFO_SIZE (1<<(MUSB_C_RAM_BITS+2))
+
+enum fifo_style { FIFO_RXTX, FIFO_TX, FIFO_RX } __attribute__ ((packed));
+enum buf_mode { BUF_SINGLE, BUF_DOUBLE } __attribute__ ((packed));
+
+struct fifo_cfg {
+       u8              hw_ep_num;
+       enum fifo_style style;
+       enum buf_mode   mode;
+       u16             maxpacket;
+};
+
+/*
+ * tables defining fifo_mode values.  define more if you like.
+ * for host side, make sure both halves of ep1 are set up.
+ */
+
+/* mode 0 - fits in 2KB */
+static struct fifo_cfg __initdata mode_0_cfg[] = {
+{ .hw_ep_num = 1, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num = 1, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num = 2, .style = FIFO_RXTX, .maxpacket = 512, },
+{ .hw_ep_num = 3, .style = FIFO_RXTX, .maxpacket = 256, },
+{ .hw_ep_num = 4, .style = FIFO_RXTX, .maxpacket = 256, },
+};
+
+/* mode 1 - fits in 4KB */
+static struct fifo_cfg __initdata mode_1_cfg[] = {
+{ .hw_ep_num = 1, .style = FIFO_TX,   .maxpacket = 512, .mode = BUF_DOUBLE, },
+{ .hw_ep_num = 1, .style = FIFO_RX,   .maxpacket = 512, .mode = BUF_DOUBLE, },
+{ .hw_ep_num = 2, .style = FIFO_RXTX, .maxpacket = 512, .mode = BUF_DOUBLE, },
+{ .hw_ep_num = 3, .style = FIFO_RXTX, .maxpacket = 256, },
+{ .hw_ep_num = 4, .style = FIFO_RXTX, .maxpacket = 256, },
+};
+
+/* mode 2 - fits in 4KB */
+static struct fifo_cfg __initdata mode_2_cfg[] = {
+{ .hw_ep_num = 1, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num = 1, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num = 2, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num = 2, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num = 3, .style = FIFO_RXTX, .maxpacket = 256, },
+{ .hw_ep_num = 4, .style = FIFO_RXTX, .maxpacket = 256, },
+};
+
+/* mode 3 - fits in 4KB */
+static struct fifo_cfg __initdata mode_3_cfg[] = {
+{ .hw_ep_num = 1, .style = FIFO_TX,   .maxpacket = 512, .mode = BUF_DOUBLE, },
+{ .hw_ep_num = 1, .style = FIFO_RX,   .maxpacket = 512, .mode = BUF_DOUBLE, },
+{ .hw_ep_num = 2, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num = 2, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num = 3, .style = FIFO_RXTX, .maxpacket = 256, },
+{ .hw_ep_num = 4, .style = FIFO_RXTX, .maxpacket = 256, },
+};
+
+/* mode 4 - fits in 16KB */
+static struct fifo_cfg __initdata mode_4_cfg[] = {
+{ .hw_ep_num =  1, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num =  1, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num =  2, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num =  2, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num =  3, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num =  3, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num =  4, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num =  4, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num =  5, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num =  5, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num =  6, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num =  6, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num =  7, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num =  7, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num =  8, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num =  8, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num =  9, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num =  9, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num = 10, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num = 10, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num = 11, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num = 11, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num = 12, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num = 12, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num = 13, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num = 13, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num = 14, .style = FIFO_RXTX, .maxpacket = 1024, },
+{ .hw_ep_num = 15, .style = FIFO_RXTX, .maxpacket = 1024, },
+};
+
+
+/*
+ * configure a fifo; for non-shared endpoints, this may be called
+ * once for a tx fifo and once for an rx fifo.
+ *
+ * returns negative errno or offset for next fifo.
+ */
+static int __init
+fifo_setup(struct musb *musb, struct musb_hw_ep  *hw_ep,
+               const struct fifo_cfg *cfg, u16 offset)
+{
+       void __iomem    *mbase = musb->pRegs;
+       int     size = 0;
+       u16     maxpacket = cfg->maxpacket;
+       u16     c_off = offset >> 3;
+       u8      c_size;
+
+       /* expect hw_ep has already been zero-initialized */
+
+       size = ffs(max(maxpacket, (u16) 8)) - 1;
+       maxpacket = 1 << size;
+
+       c_size = size - 3;
+       if (cfg->mode == BUF_DOUBLE) {
+               if ((offset + (maxpacket << 1)) > DYN_FIFO_SIZE)
+                       return -EMSGSIZE;
+               c_size |= MGC_M_FIFOSZ_DPB;
+       } else {
+               if ((offset + maxpacket) > DYN_FIFO_SIZE)
+                       return -EMSGSIZE;
+       }
+
+       /* configure the FIFO */
+       musb_writeb(mbase, MGC_O_HDRC_INDEX, hw_ep->bLocalEnd);
+
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+       /* EP0 reserved endpoint for control, bidirectional;
+        * EP1 reserved for bulk, two unidirection halves.
+        */
+       if (hw_ep->bLocalEnd == 1)
+               musb->bulk_ep = hw_ep;
+       /* REVISIT error check:  be sure ep0 can both rx and tx ... */
+#endif
+       switch (cfg->style) {
+       case FIFO_TX:
+               musb_writeb(mbase, MGC_O_HDRC_TXFIFOSZ, c_size);
+               musb_writew(mbase, MGC_O_HDRC_TXFIFOADD, c_off);
+               hw_ep->tx_double_buffered = !!(c_size & MGC_M_FIFOSZ_DPB);
+               hw_ep->wMaxPacketSizeTx = maxpacket;
+               break;
+       case FIFO_RX:
+               musb_writeb(mbase, MGC_O_HDRC_RXFIFOSZ, c_size);
+               musb_writew(mbase, MGC_O_HDRC_RXFIFOADD, c_off);
+               hw_ep->rx_double_buffered = !!(c_size & MGC_M_FIFOSZ_DPB);
+               hw_ep->wMaxPacketSizeRx = maxpacket;
+               break;
+       case FIFO_RXTX:
+               musb_writeb(mbase, MGC_O_HDRC_TXFIFOSZ, c_size);
+               musb_writew(mbase, MGC_O_HDRC_TXFIFOADD, c_off);
+               hw_ep->rx_double_buffered = !!(c_size & MGC_M_FIFOSZ_DPB);
+               hw_ep->wMaxPacketSizeRx = maxpacket;
+
+               musb_writeb(mbase, MGC_O_HDRC_RXFIFOSZ, c_size);
+               musb_writew(mbase, MGC_O_HDRC_RXFIFOADD, c_off);
+               hw_ep->tx_double_buffered = hw_ep->rx_double_buffered;
+               hw_ep->wMaxPacketSizeTx = maxpacket;
+
+               hw_ep->bIsSharedFifo = TRUE;
+               break;
+       }
+
+       /* NOTE rx and tx endpoint irqs aren't managed separately,
+        * which happens to be ok
+        */
+       musb->wEndMask |= (1 << hw_ep->bLocalEnd);
+
+       return offset + (maxpacket << ((c_size & MGC_M_FIFOSZ_DPB) ? 1 : 0));
+}
+
+static struct fifo_cfg __initdata ep0_cfg = {
+       .style = FIFO_RXTX, .maxpacket = 64,
+};
+
+static int __init ep_config_from_table(struct musb *musb)
+{
+       const struct fifo_cfg   *cfg;
+       unsigned                i, n;
+       int                     offset;
+       struct musb_hw_ep       *hw_ep = musb->aLocalEnd;
+
+       switch (fifo_mode) {
+       default:
+               fifo_mode = 0;
+               /* FALLTHROUGH */
+       case 0:
+               cfg = mode_0_cfg;
+               n = ARRAY_SIZE(mode_0_cfg);
+               break;
+       case 1:
+               cfg = mode_1_cfg;
+               n = ARRAY_SIZE(mode_1_cfg);
+               break;
+       case 2:
+               cfg = mode_2_cfg;
+               n = ARRAY_SIZE(mode_2_cfg);
+               break;
+       case 3:
+               cfg = mode_3_cfg;
+               n = ARRAY_SIZE(mode_3_cfg);
+               break;
+       case 4:
+               cfg = mode_4_cfg;
+               n = ARRAY_SIZE(mode_4_cfg);
+               break;
+       }
+
+       printk(KERN_DEBUG "%s: setup fifo_mode %d\n",
+                       musb_driver_name, fifo_mode);
+
+
+       offset = fifo_setup(musb, hw_ep, &ep0_cfg, 0);
+       // assert(offset > 0)
+
+       /* NOTE:  for RTL versions >= 1.400 EPINFO and RAMINFO would
+        * be better than static MUSB_C_NUM_EPS and DYN_FIFO_SIZE...
+        */
+
+       for (i = 0; i < n; i++) {
+               u8      epn = cfg->hw_ep_num;
+
+               if (epn >= MUSB_C_NUM_EPS) {
+                       pr_debug( "%s: invalid ep %d\n",
+                                       musb_driver_name, epn);
+                       continue;
+               }
+               offset = fifo_setup(musb, hw_ep + epn, cfg++, offset);
+               if (offset < 0) {
+                       pr_debug( "%s: mem overrun, ep %d\n",
+                                       musb_driver_name, epn);
+                       return -EINVAL;
+               }
+               epn++;
+               musb->bEndCount = max(epn, musb->bEndCount);
+       }
+
+       printk(KERN_DEBUG "%s: %d/%d max ep, %d/%d memory\n",
+                       musb_driver_name,
+                       n + 1, MUSB_C_NUM_EPS * 2 - 1,
+                       offset, DYN_FIFO_SIZE);
+
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+       if (!musb->bulk_ep) {
+               pr_debug( "%s: missing bulk\n", musb_driver_name);
+               return -EINVAL;
+       }
+#endif
+
+       return 0;
+}
+
+
+/*
+ * ep_config_from_hw - when MUSB_C_DYNFIFO_DEF is false
+ * @param pThis the controller
+ */
+static int __init ep_config_from_hw(struct musb *musb)
+{
+       u8 bEnd = 0, reg;
+       struct musb_hw_ep *pEnd;
+       void *pBase = musb->pRegs;
+
+       DBG(2, "<== static silicon ep config\n");
+
+       /* FIXME pick up ep0 maxpacket size */
+
+       for (bEnd = 1; bEnd < MUSB_C_NUM_EPS; bEnd++) {
+               MGC_SelectEnd(pBase, bEnd);
+               pEnd = musb->aLocalEnd + bEnd;
+
+               /* read from core using indexed model */
+               reg = musb_readb(pEnd->regs, 0x10 + MGC_O_HDRC_FIFOSIZE);
+               if (!reg) {
+                       /* 0's returned when no more endpoints */
+                       break;
+               }
+               musb->bEndCount++;
+               musb->wEndMask |= (1 << bEnd);
+
+               pEnd->wMaxPacketSizeTx = 1 << (reg & 0x0f);
+
+               /* shared TX/RX FIFO? */
+               if ((reg & 0xf0) == 0xf0) {
+                       pEnd->wMaxPacketSizeRx = pEnd->wMaxPacketSizeTx;
+                       pEnd->bIsSharedFifo = TRUE;
+                       continue;
+               } else {
+                       pEnd->wMaxPacketSizeRx = 1 << ((reg & 0xf0) >> 4);
+                       pEnd->bIsSharedFifo = FALSE;
+               }
+
+               /* FIXME set up pEnd->{rx,tx}_double_buffered */
+
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+               /* pick an RX/TX endpoint for bulk */
+               if (pEnd->wMaxPacketSizeTx < 512
+                               || pEnd->wMaxPacketSizeRx < 512)
+                       continue;
+
+               /* REVISIT:  this algorithm is lazy, we should at least
+                * try to pick a double buffered endpoint.
+                */
+               if (musb->bulk_ep)
+                       continue;
+               musb->bulk_ep = pEnd;
+#endif
+       }
+
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+       if (!musb->bulk_ep) {
+               pr_debug( "%s: missing bulk\n", musb_driver_name);
+               return -EINVAL;
+       }
+#endif
+
+       return 0;
+}
+
+enum { MUSB_CONTROLLER_MHDRC, MUSB_CONTROLLER_HDRC, };
+
+/* Initialize MUSB (M)HDRC part of the USB hardware subsystem;
+ * configure endpoints, or take their config from silicon
+ */
+static int __init musb_core_init(u16 wType, struct musb *pThis)
+{
+#ifdef MUSB_AHB_ID
+       u32 dwData;
+#endif
+       u8 reg;
+       char *type;
+       u16 wRelease, wRelMajor, wRelMinor;
+       char aInfo[78], aRevision[32], aDate[12];
+       void __iomem    *pBase = pThis->pRegs;
+       int             status = 0;
+       int             i;
+
+       /* log core options (read using indexed model) */
+       MGC_SelectEnd(pBase, 0);
+       reg = musb_readb(pBase, 0x10 + MGC_O_HDRC_CONFIGDATA);
+
+       strcpy(aInfo, (reg & MGC_M_CONFIGDATA_UTMIDW) ? "UTMI-16" : "UTMI-8");
+       if (reg & MGC_M_CONFIGDATA_DYNFIFO) {
+               strcat(aInfo, ", dyn FIFOs");
+       }
+       if (reg & MGC_M_CONFIGDATA_MPRXE) {
+               strcat(aInfo, ", bulk combine");
+#ifdef C_MP_RX
+               pThis->bBulkCombine = TRUE;
+#else
+               strcat(aInfo, " (X)");          /* no driver support */
+#endif
+       }
+       if (reg & MGC_M_CONFIGDATA_MPTXE) {
+               strcat(aInfo, ", bulk split");
+#ifdef C_MP_TX
+               pThis->bBulkSplit = TRUE;
+#else
+               strcat(aInfo, " (X)");          /* no driver support */
+#endif
+       }
+       if (reg & MGC_M_CONFIGDATA_HBRXE) {
+               strcat(aInfo, ", HB-ISO Rx");
+               strcat(aInfo, " (X)");          /* no driver support */
+       }
+       if (reg & MGC_M_CONFIGDATA_HBTXE) {
+               strcat(aInfo, ", HB-ISO Tx");
+               strcat(aInfo, " (X)");          /* no driver support */
+       }
+       if (reg & MGC_M_CONFIGDATA_SOFTCONE) {
+               strcat(aInfo, ", SoftConn");
+       }
+
+       printk(KERN_DEBUG "%s: ConfigData=0x%02x (%s)\n",
+                       musb_driver_name, reg, aInfo);
+
+#ifdef MUSB_AHB_ID
+       dwData = musb_readl(pBase, 0x404);
+       sprintf(aDate, "%04d-%02x-%02x", (dwData & 0xffff),
+               (dwData >> 16) & 0xff, (dwData >> 24) & 0xff);
+       /* FIXME ID2 and ID3 are unused */
+       dwData = musb_readl(pBase, 0x408);
+       printk("ID2=%lx\n", (long unsigned)dwData);
+       dwData = musb_readl(pBase, 0x40c);
+       printk("ID3=%lx\n", (long unsigned)dwData);
+       reg = musb_readb(pBase, 0x400);
+       wType = ('M' == reg) ? MUSB_CONTROLLER_MHDRC : MUSB_CONTROLLER_HDRC;
+#else
+       aDate[0] = 0;
+#endif
+       if (MUSB_CONTROLLER_MHDRC == wType) {
+               pThis->bIsMultipoint = 1;
+               type = "M";
+       } else {
+               pThis->bIsMultipoint = 0;
+               type = "";
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+#ifndef        CONFIG_USB_OTG_BLACKLIST_HUB
+               printk(KERN_ERR
+                       "%s: kernel must blacklist external hubs\n",
+                       musb_driver_name);
+#endif
+#endif
+       }
+
+       /* log release info */
+       wRelease = musb_readw(pBase, MGC_O_HDRC_HWVERS);
+       wRelMajor = (wRelease >> 10) & 0x1f;
+       wRelMinor = wRelease & 0x3ff;
+       snprintf(aRevision, 32, "%d.%d%s", wRelMajor,
+               wRelMinor, (wRelease & 0x8000) ? "RC" : "");
+       printk(KERN_DEBUG "%s: %sHDRC RTL version %s %s\n",
+                       musb_driver_name, type, aRevision, aDate);
+
+       /* configure ep0 */
+       pThis->aLocalEnd[0].wMaxPacketSizeTx = MGC_END0_FIFOSIZE;
+       pThis->aLocalEnd[0].wMaxPacketSizeRx = MGC_END0_FIFOSIZE;
+
+       /* discover endpoint configuration */
+       pThis->bEndCount = 1;
+       pThis->wEndMask = 1;
+
+       if (reg & MGC_M_CONFIGDATA_DYNFIFO) {
+               if (can_dynfifo())
+                       status = ep_config_from_table(pThis);
+               else {
+                       ERR("reconfigure software for Dynamic FIFOs\n");
+                       status = -ENODEV;
+               }
+       } else {
+               if (!can_dynfifo())
+                       status = ep_config_from_hw(pThis);
+               else {
+                       ERR("reconfigure software for static FIFOs\n");
+                       return -ENODEV;
+               }
+       }
+
+       if (status < 0)
+               return status;
+
+       /* finish init, and print endpoint config */
+       for (i = 0; i < pThis->bEndCount; i++) {
+               struct musb_hw_ep       *hw_ep = pThis->aLocalEnd + i;
+
+               hw_ep->fifo = MUSB_FIFO_OFFSET(i) + pBase;
+#ifdef CONFIG_USB_TUSB6010
+               hw_ep->fifo_async = pThis->async + 0x400 + MUSB_FIFO_OFFSET(i);
+               hw_ep->fifo_sync = pThis->sync + 0x400 + MUSB_FIFO_OFFSET(i);
+               if (i == 0)
+                       hw_ep->conf = pBase - 0x400 + TUSB_EP0_CONF;
+               else
+                       hw_ep->conf = pBase + 0x400 + (((i - 1) & 0xf) << 2);
+#endif
+
+               hw_ep->regs = MGC_END_OFFSET(i, 0) + pBase;
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+               hw_ep->target_regs = MGC_BUSCTL_OFFSET(i, 0) + pBase;
+               hw_ep->rx_reinit = 1;
+               hw_ep->tx_reinit = 1;
+#endif
+
+               if (hw_ep->wMaxPacketSizeTx) {
+                       printk(KERN_DEBUG
+                               "%s: hw_ep %d%s, %smax %d\n",
+                               musb_driver_name, i,
+                               hw_ep->bIsSharedFifo ? "shared" : "tx",
+                               hw_ep->tx_double_buffered
+                                       ? "doublebuffer, " : "",
+                               hw_ep->wMaxPacketSizeTx);
+               }
+               if (hw_ep->wMaxPacketSizeRx && !hw_ep->bIsSharedFifo) {
+                       printk(KERN_DEBUG
+                               "%s: hw_ep %d%s, %smax %d\n",
+                               musb_driver_name, i,
+                               "rx",
+                               hw_ep->rx_double_buffered
+                                       ? "doublebuffer, " : "",
+                               hw_ep->wMaxPacketSizeRx);
+               }
+               if (!(hw_ep->wMaxPacketSizeTx || hw_ep->wMaxPacketSizeRx))
+                       DBG(1, "hw_ep %d not configured\n", i);
+       }
+
+       return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_ARCH_OMAP243X
+
+static irqreturn_t generic_interrupt(int irq, void *__hci)
+{
+       unsigned long   flags;
+       irqreturn_t     retval = IRQ_NONE;
+       struct musb     *musb = __hci;
+
+       spin_lock_irqsave(&musb->Lock, flags);
+
+       musb->int_usb = musb_readb(musb->pRegs, MGC_O_HDRC_INTRUSB);
+       musb->int_tx = musb_readw(musb->pRegs, MGC_O_HDRC_INTRTX);
+       musb->int_rx = musb_readw(musb->pRegs, MGC_O_HDRC_INTRRX);
+
+       if (musb->int_usb || musb->int_tx || musb->int_rx)
+               retval = musb_interrupt(musb);
+
+       spin_unlock_irqrestore(&musb->Lock, flags);
+
+       /* REVISIT we sometimes get spurious IRQs on g_ep0
+        * not clear why...
+        */
+       if (retval != IRQ_HANDLED)
+               DBG(5, "spurious?\n");
+
+       return IRQ_HANDLED;
+}
+
+#else
+#define generic_interrupt      NULL
+#endif
+
+/*
+ * handle all the irqs defined by the HDRC core. for now we expect:  other
+ * irq sources (phy, dma, etc) will be handled first, musb->int_* values
+ * will be assigned, and the irq will already have been acked.
+ *
+ * called in irq context with spinlock held, irqs blocked
+ */
+irqreturn_t musb_interrupt(struct musb *musb)
+{
+       irqreturn_t     retval = IRQ_NONE;
+       u8              devctl, power;
+       int             ep_num;
+       u32             reg;
+
+       devctl = musb_readb(musb->pRegs, MGC_O_HDRC_DEVCTL);
+       power = musb_readb(musb->pRegs, MGC_O_HDRC_POWER);
+
+       DBG(4, "** IRQ %s usb%04x tx%04x rx%04x\n",
+               (devctl & MGC_M_DEVCTL_HM) ? "host" : "peripheral",
+               musb->int_usb, musb->int_tx, musb->int_rx);
+
+       /* the core can interrupt us for multiple reasons; docs have
+        * a generic interrupt flowchart to follow
+        */
+       if (musb->int_usb & STAGE0_MASK)
+               retval |= musb_stage0_irq(musb, musb->int_usb,
+                               devctl, power);
+
+       /* "stage 1" is handling endpoint irqs */
+
+       /* handle endpoint 0 first */
+       if (musb->int_tx & 1) {
+               if (devctl & MGC_M_DEVCTL_HM)
+                       retval |= musb_h_ep0_irq(musb);
+               else
+                       retval |= musb_g_ep0_irq(musb);
+       }
+
+       /* RX on endpoints 1-15 */
+       reg = musb->int_rx >> 1;
+       ep_num = 1;
+       while (reg) {
+               if (reg & 1) {
+                       // MGC_SelectEnd(musb->pRegs, ep_num);
+                       /* REVISIT just retval = ep->rx_irq(...) */
+                       retval = IRQ_HANDLED;
+                       if (devctl & MGC_M_DEVCTL_HM) {
+                               if (is_host_capable())
+                                       musb_host_rx(musb, ep_num);
+                       } else {
+                               if (is_peripheral_capable())
+                                       musb_g_rx(musb, ep_num);
+                       }
+               }
+
+               reg >>= 1;
+               ep_num++;
+       }
+
+       /* TX on endpoints 1-15 */
+       reg = musb->int_tx >> 1;
+       ep_num = 1;
+       while (reg) {
+               if (reg & 1) {
+                       // MGC_SelectEnd(musb->pRegs, ep_num);
+                       /* REVISIT just retval |= ep->tx_irq(...) */
+                       retval = IRQ_HANDLED;
+                       if (devctl & MGC_M_DEVCTL_HM) {
+                               if (is_host_capable())
+                                       musb_host_tx(musb, ep_num);
+                       } else {
+                               if (is_peripheral_capable())
+                                       musb_g_tx(musb, ep_num);
+                       }
+               }
+               reg >>= 1;
+               ep_num++;
+       }
+
+       /* finish handling "global" interrupts after handling fifos */
+       if (musb->int_usb)
+               retval |= musb_stage2_irq(musb,
+                               musb->int_usb, devctl, power);
+
+       return retval;
+}
+
+
+#ifndef CONFIG_USB_INVENTRA_FIFO
+static int __initdata use_dma = 1;
+
+/* "modprobe ... use_dma=0" etc */
+module_param(use_dma, bool, 0);
+MODULE_PARM_DESC(use_dma, "enable/disable use of DMA");
+
+void musb_dma_completion(struct musb *musb, u8 bLocalEnd, u8 bTransmit)
+{
+       u8      devctl = musb_readb(musb->pRegs, MGC_O_HDRC_DEVCTL);
+
+       /* called with controller lock already held */
+
+       if (!bLocalEnd) {
+#ifndef CONFIG_USB_TUSB_OMAP_DMA
+               if (!is_cppi_enabled()) {
+                       /* endpoint 0 */
+                       if (devctl & MGC_M_DEVCTL_HM)
+                               musb_h_ep0_irq(musb);
+                       else
+                               musb_g_ep0_irq(musb);
+               }
+#endif
+       } else {
+               /* endpoints 1..15 */
+               if (bTransmit) {
+                       if (devctl & MGC_M_DEVCTL_HM) {
+                               if (is_host_capable())
+                                       musb_host_tx(musb, bLocalEnd);
+                       } else {
+                               if (is_peripheral_capable())
+                                       musb_g_tx(musb, bLocalEnd);
+                       }
+               } else {
+                       /* receive */
+                       if (devctl & MGC_M_DEVCTL_HM) {
+                               if (is_host_capable())
+                                       musb_host_rx(musb, bLocalEnd);
+                       } else {
+                               if (is_peripheral_capable())
+                                       musb_g_rx(musb, bLocalEnd);
+                       }
+               }
+       }
+}
+
+#else
+#define use_dma                        0
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_SYSFS
+
+static ssize_t
+musb_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct musb *musb = dev_to_musb(dev);
+       unsigned long flags;
+       int ret = -EINVAL;
+
+       spin_lock_irqsave(&musb->Lock, flags);
+       switch (musb->board_mode) {
+       case MUSB_HOST:
+               ret = sprintf(buf, "host\n");
+               break;
+       case MUSB_PERIPHERAL:
+               ret = sprintf(buf, "peripheral\n");
+               break;
+       case MUSB_OTG:
+               ret = sprintf(buf, "otg\n");
+               break;
+       }
+       spin_unlock_irqrestore(&musb->Lock, flags);
+
+       return ret;
+}
+static DEVICE_ATTR(mode, S_IRUGO, musb_mode_show, NULL);
+
+static ssize_t
+musb_cable_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct musb *musb = dev_to_musb(dev);
+       char *v1= "", *v2 = "?";
+       unsigned long flags;
+       int vbus;
+
+       spin_lock_irqsave(&musb->Lock, flags);
+#if defined(CONFIG_USB_TUSB6010) && !defined(CONFIG_USB_MUSB_OTG)
+       /* REVISIT: connect-A != connect-B ... */
+       vbus = musb_platform_get_vbus_status(musb);
+       if (vbus)
+               v2 = "connected";
+       else
+               v2 = "disconnected";
+#else
+       /* NOTE: board-specific issues, like too-big capacitors keeping
+        * VBUS high for a long time after power has been removed, can
+        * cause temporary false indications of a connection.
+        */
+       vbus = musb_readb(musb->pRegs, MGC_O_HDRC_DEVCTL);
+       if (vbus & 0x10) {
+               /* REVISIT retest on real OTG hardware */
+               switch (musb->board_mode) {
+               case MUSB_HOST:
+                       v2 = "A";
+                       break;
+               case MUSB_PERIPHERAL:
+                       v2 = "B";
+                       break;
+               case MUSB_OTG:
+                       v1 = "Mini-";
+                       v2 = (vbus & MGC_M_DEVCTL_BDEVICE) ? "B" : "A";
+                       break;
+               }
+       } else  /* VBUS level below A-Valid */
+               v2 = "disconnected";
+#endif
+       musb_platform_try_idle(musb);
+       spin_unlock_irqrestore(&musb->Lock, flags);
+
+       return sprintf(buf, "%s%s\n", v1, v2);
+}
+static DEVICE_ATTR(cable, S_IRUGO, musb_cable_show, NULL);
+
+#endif
+
+/* Only used to provide cable state change events */
+static void musb_irq_work(struct work_struct *data)
+{
+       struct musb *musb = container_of(data, struct musb, irq_work);
+
+       sysfs_notify(&musb->controller->kobj, NULL, "cable");
+}
+
+/* --------------------------------------------------------------------------
+ * Init support
+ */
+
+static struct musb *__init
+allocate_instance(struct device *dev, void __iomem *mbase)
+{
+       struct musb             *musb;
+       struct musb_hw_ep       *ep;
+       int                     epnum;
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+       struct usb_hcd  *hcd;
+
+       hcd = usb_create_hcd(&musb_hc_driver, dev, dev->bus_id);
+       if (!hcd)
+               return NULL;
+       /* usbcore sets dev->driver_data to hcd, and sometimes uses that... */
+
+       musb = hcd_to_musb(hcd);
+       INIT_LIST_HEAD(&musb->control);
+       INIT_LIST_HEAD(&musb->in_bulk);
+       INIT_LIST_HEAD(&musb->out_bulk);
+
+       hcd->uses_new_polling = 1;
+
+       musb->vbuserr_retry = VBUSERR_RETRY_COUNT;
+#else
+       musb = kzalloc(sizeof *musb, GFP_KERNEL);
+       if (!musb)
+               return NULL;
+       dev_set_drvdata(dev, musb);
+
+#endif
+
+       musb->pRegs = mbase;
+       musb->ctrl_base = mbase;
+       musb->nIrq = -ENODEV;
+       for (epnum = 0, ep = musb->aLocalEnd;
+                       epnum < MUSB_C_NUM_EPS;
+                       epnum++, ep++) {
+
+               ep->musb = musb;
+               ep->bLocalEnd = epnum;
+       }
+
+       musb->controller = dev;
+       return musb;
+}
+
+static void musb_free(struct musb *musb)
+{
+       /* this has multiple entry modes. it handles fault cleanup after
+        * probe(), where things may be partially set up, as well as rmmod
+        * cleanup after everything's been de-activated.
+        */
+
+#ifdef CONFIG_SYSFS
+       device_remove_file(musb->controller, &dev_attr_mode);
+       device_remove_file(musb->controller, &dev_attr_cable);
+#endif
+
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+       musb_gadget_cleanup(musb);
+#endif
+
+       if (musb->nIrq >= 0) {
+               disable_irq_wake(musb->nIrq);
+               free_irq(musb->nIrq, musb);
+       }
+       if (is_dma_capable() && musb->pDmaController) {
+               struct dma_controller   *c = musb->pDmaController;
+
+               (void) c->stop(c->pPrivateData);
+               dma_controller_destroy(c);
+       }
+
+       musb_writeb(musb->pRegs, MGC_O_HDRC_DEVCTL, 0);
+       musb_platform_exit(musb);
+       musb_writeb(musb->pRegs, MGC_O_HDRC_DEVCTL, 0);
+
+       if (musb->clock) {
+               clk_disable(musb->clock);
+               clk_put(musb->clock);
+       }
+
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+       usb_put_hcd(musb_to_hcd(musb));
+#else
+       kfree(musb);
+#endif
+}
+
+/*
+ * Perform generic per-controller initialization.
+ *
+ * @pDevice: the controller (already clocked, etc)
+ * @nIrq: irq
+ * @pRegs: virtual address of controller registers,
+ *     not yet corrected for platform-specific offsets
+ */
+static int __init
+musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
+{
+       int                     status;
+       struct musb             *pThis;
+       struct musb_hdrc_platform_data *plat = dev->platform_data;
+
+       /* The driver might handle more features than the board; OK.
+        * Fail when the board needs a feature that's not enabled.
+        */
+       if (!plat) {
+               dev_dbg(dev, "no platform_data?\n");
+               return -ENODEV;
+       }
+       switch (plat->mode) {
+       case MUSB_HOST:
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+               break;
+#else
+               goto bad_config;
+#endif
+       case MUSB_PERIPHERAL:
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+               break;
+#else
+               goto bad_config;
+#endif
+       case MUSB_OTG:
+#ifdef CONFIG_USB_MUSB_OTG
+               break;
+#else
+       bad_config:
+#endif
+       default:
+               dev_err(dev, "incompatible Kconfig role setting\n");
+               return -EINVAL;
+       }
+
+       /* allocate */
+       pThis = allocate_instance(dev, ctrl);
+       if (!pThis)
+               return -ENOMEM;
+
+       spin_lock_init(&pThis->Lock);
+       pThis->board_mode = plat->mode;
+       pThis->board_set_power = plat->set_power;
+       pThis->min_power = plat->min_power;
+
+       /* assume vbus is off */
+
+       /* platform adjusts pThis->pRegs and pThis->isr if needed,
+        * and activates clocks
+        */
+       pThis->isr = generic_interrupt;
+       status = musb_platform_init(pThis);
+
+       if (status < 0)
+               goto fail;
+       if (!pThis->isr) {
+               status = -ENODEV;
+               goto fail2;
+       }
+
+#ifndef CONFIG_USB_INVENTRA_FIFO
+       if (use_dma && dev->dma_mask) {
+               struct dma_controller   *c;
+
+               c = dma_controller_create(pThis, pThis->pRegs);
+               pThis->pDmaController = c;
+               if (c)
+                       (void) c->start(c->pPrivateData);
+       }
+#endif
+       /* ideally this would be abstracted in platform setup */
+       if (!is_dma_capable() || !pThis->pDmaController)
+               dev->dma_mask = NULL;
+
+       /* be sure interrupts are disabled before connecting ISR */
+       musb_platform_disable(pThis);
+
+       /* setup musb parts of the core (especially endpoints) */
+       status = musb_core_init(plat->multipoint
+                       ? MUSB_CONTROLLER_MHDRC
+                       : MUSB_CONTROLLER_HDRC, pThis);
+       if (status < 0)
+               goto fail2;
+
+       /* attach to the IRQ */
+       if (request_irq (nIrq, pThis->isr, 0, dev->bus_id, pThis)) {
+               dev_err(dev, "request_irq %d failed!\n", nIrq);
+               status = -ENODEV;
+               goto fail2;
+       }
+       pThis->nIrq = nIrq;
+// FIXME this handles wakeup irqs wrong
+       if (enable_irq_wake(nIrq) == 0)
+               device_init_wakeup(dev, 1);
+
+       pr_info("%s: USB %s mode controller at %p using %s, IRQ %d\n",
+                       musb_driver_name,
+                       ({char *s;
+                       switch (pThis->board_mode) {
+                       case MUSB_HOST:         s = "Host"; break;
+                       case MUSB_PERIPHERAL:   s = "Peripheral"; break;
+                       default:                s = "OTG"; break;
+                       }; s; }),
+                       ctrl,
+                       (is_dma_capable() && pThis->pDmaController)
+                               ? "DMA" : "PIO",
+                       pThis->nIrq);
+
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+       /* host side needs more setup, except for no-host modes */
+       if (pThis->board_mode != MUSB_PERIPHERAL) {
+               struct usb_hcd  *hcd = musb_to_hcd(pThis);
+
+               if (pThis->board_mode == MUSB_OTG)
+                       hcd->self.otg_port = 1;
+               pThis->xceiv.host = &hcd->self;
+               hcd->power_budget = 2 * (plat->power ? : 250);
+       }
+#endif                         /* CONFIG_USB_MUSB_HDRC_HCD */
+
+       /* For the host-only role, we can activate right away.
+        * (We expect the ID pin to be forcibly grounded!!)
+        * Otherwise, wait till the gadget driver hooks up.
+        */
+       if (!is_otg_enabled(pThis) && is_host_enabled(pThis)) {
+               MUSB_HST_MODE(pThis);
+               pThis->xceiv.default_a = 1;
+               pThis->xceiv.state = OTG_STATE_A_IDLE;
+
+               status = usb_add_hcd(musb_to_hcd(pThis), -1, 0);
+
+               DBG(1, "%s mode, status %d, devctl %02x %c\n",
+                       "HOST", status,
+                       musb_readb(pThis->pRegs, MGC_O_HDRC_DEVCTL),
+                       (musb_readb(pThis->pRegs, MGC_O_HDRC_DEVCTL)
+                                       & MGC_M_DEVCTL_BDEVICE
+                               ? 'B' : 'A'));
+
+       } else /* peripheral is enabled */ {
+               MUSB_DEV_MODE(pThis);
+               pThis->xceiv.default_a = 0;
+               pThis->xceiv.state = OTG_STATE_B_IDLE;
+
+               status = musb_gadget_setup(pThis);
+
+               DBG(1, "%s mode, status %d, dev%02x\n",
+                       is_otg_enabled(pThis) ? "OTG" : "PERIPHERAL",
+                       status,
+                       musb_readb(pThis->pRegs, MGC_O_HDRC_DEVCTL));
+
+       }
+
+       if (status == 0)
+               musb_debug_create("driver/musb_hdrc", pThis);
+       else {
+fail:
+               device_init_wakeup(dev, 0);
+               musb_free(pThis);
+               return status;
+       }
+
+       INIT_WORK(&pThis->irq_work, musb_irq_work);
+
+#ifdef CONFIG_SYSFS
+       status = device_create_file(dev, &dev_attr_mode);
+       status = device_create_file(dev, &dev_attr_cable);
+       status = 0;
+#endif
+
+       return status;
+
+fail2:
+       musb_platform_exit(pThis);
+       goto fail;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* all implementations (PCI bridge to FPGA, VLYNQ, etc) should just
+ * bridge to a platform device; this driver then suffices.
+ */
+
+#ifndef CONFIG_USB_INVENTRA_FIFO
+static u64     *orig_dma_mask;
+#endif
+
+static int __init musb_probe(struct platform_device *pdev)
+{
+       struct device   *dev = &pdev->dev;
+       int             irq = platform_get_irq(pdev, 0);
+       struct resource *iomem;
+       void __iomem    *base;
+
+       iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!iomem || irq == 0)
+               return -ENODEV;
+
+       base = ioremap(iomem->start, iomem->end - iomem->start + 1);
+       if (!base) {
+               dev_err(dev, "ioremap failed\n");
+               return -ENOMEM;
+       }
+
+#ifndef CONFIG_USB_INVENTRA_FIFO
+       /* clobbered by use_dma=n */
+       orig_dma_mask = dev->dma_mask;
+#endif
+       return musb_init_controller(dev, irq, base);
+}
+
+static int __devexit musb_remove(struct platform_device *pdev)
+{
+       struct musb     *musb = dev_to_musb(&pdev->dev);
+       void __iomem    *ctrl_base = musb->ctrl_base;
+
+       /* this gets called on rmmod.
+        *  - Host mode: host may still be active
+        *  - Peripheral mode: peripheral is deactivated (or never-activated)
+        *  - OTG mode: both roles are deactivated (or never-activated)
+        */
+       musb_shutdown(pdev);
+       musb_debug_delete("driver/musb_hdrc", musb);
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+       if (musb->board_mode == MUSB_HOST)
+               usb_remove_hcd(musb_to_hcd(musb));
+#endif
+       musb_free(musb);
+       iounmap(ctrl_base);
+       device_init_wakeup(&pdev->dev, 0);
+#ifndef CONFIG_USB_INVENTRA_FIFO
+       pdev->dev.dma_mask = orig_dma_mask;
+#endif
+       return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int musb_suspend(struct platform_device *pdev, pm_message_t message)
+{
+       unsigned long   flags;
+       struct musb     *musb = dev_to_musb(&pdev->dev);
+
+       if (!musb->clock)
+               return 0;
+
+       spin_lock_irqsave(&musb->Lock, flags);
+
+       if (is_peripheral_active(musb)) {
+               /* FIXME force disconnect unless we know USB will wake
+                * the system up quickly enough to respond ...
+                */
+       } else if (is_host_active(musb)) {
+               /* we know all the children are suspended; sometimes
+                * they will even be wakeup-enabled.
+                */
+       }
+
+       clk_disable(musb->clock);
+       spin_unlock_irqrestore(&musb->Lock, flags);
+       return 0;
+}
+
+static int musb_resume(struct platform_device *pdev)
+{
+       unsigned long   flags;
+       struct musb     *musb = dev_to_musb(&pdev->dev);
+
+       if (!musb->clock)
+               return 0;
+
+       spin_lock_irqsave(&musb->Lock, flags);
+       clk_enable(musb->clock);
+       /* for static cmos like DaVinci, register values were preserved
+        * unless for some reason the whole soc powered down and we're
+        * not treating that as a whole-system restart (e.g. swsusp)
+        */
+       spin_unlock_irqrestore(&musb->Lock, flags);
+       return 0;
+}
+
+#else
+#define        musb_suspend    NULL
+#define        musb_resume     NULL
+#endif
+
+static struct platform_driver musb_driver = {
+       .driver = {
+               .name           = (char *)musb_driver_name,
+               .bus            = &platform_bus_type,
+               .owner          = THIS_MODULE,
+       },
+       .remove         = __devexit_p(musb_remove),
+       .shutdown       = musb_shutdown,
+       .suspend        = musb_suspend,
+       .resume         = musb_resume,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int __init musb_init(void)
+{
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+       if (usb_disabled())
+               return 0;
+#endif
+
+       pr_info("%s: version " MUSB_VERSION ", "
+#ifdef CONFIG_USB_INVENTRA_FIFO
+               "pio"
+#elif defined(CONFIG_USB_TI_CPPI_DMA)
+               "cppi-dma"
+#elif defined(CONFIG_USB_INVENTRA_DMA)
+               "musb-dma"
+#elif defined(CONFIG_USB_TUSB_OMAP_DMA)
+               "tusb-omap-dma"
+#else
+               "?dma?"
+#endif
+               ", "
+#ifdef CONFIG_USB_MUSB_OTG
+               "otg (peripheral+host)"
+#elif defined(CONFIG_USB_GADGET_MUSB_HDRC)
+               "peripheral"
+#elif defined(CONFIG_USB_MUSB_HDRC_HCD)
+               "host"
+#endif
+               ", debug=%d\n",
+               musb_driver_name, debug);
+       return platform_driver_probe(&musb_driver, musb_probe);
+}
+
+/* make us init after usbcore and before usb
+ * gadget and host-side drivers start to register
+ */
+subsys_initcall(musb_init);
+
+static void __exit musb_cleanup(void)
+{
+       platform_driver_unregister(&musb_driver);
+}
+module_exit(musb_cleanup);
diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c
new file mode 100644 (file)
index 0000000..1f1e554
--- /dev/null
@@ -0,0 +1,852 @@
+/*
+ * TUSB6010 USB 2.0 OTG Dual Role controller
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Jarkko Nikula <jarkko.nikula@nokia.com>
+ * Tony Lindgren <tony@atomide.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Notes:
+ * - Driver assumes that interface to external host (main CPU) is
+ *   configured for NOR FLASH interface instead of VLYNQ serial
+ *   interface.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/usb.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+
+#include "musbdefs.h"
+
+
+/*
+ * TUSB 6010 may use a parallel bus that doesn't support byte ops;
+ * so both loading and unloading FIFOs need explicit byte counts.
+ */
+
+void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *buf)
+{
+       void __iomem    *ep_conf = hw_ep->conf;
+       void __iomem    *fifo = hw_ep->fifo;
+       u8              epnum = hw_ep->bLocalEnd;
+       u8              *bufp = (u8 *)buf;
+       int             i, remain;
+       u32             val;
+
+       prefetch(bufp);
+
+       DBG(4, "%cX ep%d fifo %p count %d buf %p\n",
+                       'T', epnum, fifo, len, bufp);
+
+       if (epnum)
+               musb_writel(ep_conf, TUSB_EP_TX_OFFSET,
+                       TUSB_EP_CONFIG_XFR_SIZE(len));
+       else
+               musb_writel(ep_conf, 0, TUSB_EP0_CONFIG_DIR_TX |
+                       TUSB_EP0_CONFIG_XFR_SIZE(len));
+
+       /* Write 32-bit blocks from buffer to FIFO
+        * REVISIT: Optimize for burst ... writesl/writesw
+        */
+       if (len >= 4) {
+               if (((unsigned long)bufp & 0x3) == 0) {
+                       for (i = 0; i < (len / 4); i++ ) {
+                               val = *(u32 *)bufp;
+                               bufp += 4;
+                               musb_writel(fifo, 0, val);
+                       }
+               } else if (((unsigned long)bufp & 0x2) == 0x2) {
+                       for (i = 0; i < (len / 4); i++ ) {
+                               val = (u32)(*(u16 *)bufp);
+                               bufp += 2;
+                               val |= (*(u16 *)bufp) << 16;
+                               bufp += 2;
+                               musb_writel(fifo, 0, val);
+                       }
+               } else {
+                       for (i = 0; i < (len / 4); i++ ) {
+                               memcpy(&val, bufp, 4);
+                               bufp += 4;
+                               musb_writel(fifo, 0, val);
+                       }
+               }
+               remain = len - (i * 4);
+       } else
+               remain = len;
+
+       if (remain) {
+               /* Write rest of 1-3 bytes from buffer into FIFO */
+               memcpy(&val, bufp, remain);
+               musb_writel(fifo, 0, val);
+       }
+}
+
+void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *buf)
+{
+       void __iomem    *ep_conf = hw_ep->conf;
+       void __iomem    *fifo = hw_ep->fifo;
+       u8              epnum = hw_ep->bLocalEnd;
+       u8              *bufp = (u8 *)buf;
+       int             i, remain;
+       u32             val;
+
+       DBG(4, "%cX ep%d fifo %p count %d buf %p\n",
+                       'R', epnum, fifo, len, bufp);
+
+       if (epnum)
+               musb_writel(ep_conf, TUSB_EP_RX_OFFSET,
+                       TUSB_EP_CONFIG_XFR_SIZE(len));
+       else
+               musb_writel(ep_conf, 0, TUSB_EP0_CONFIG_XFR_SIZE(len));
+
+       /* Read 32-bit blocks from FIFO to buffer
+        * REVISIT: Optimize for burst ... writesl/writesw
+        */
+       if (len >= 4) {
+               if (((unsigned long)bufp & 0x3) == 0) {
+                       for (i = 0; i < (len / 4); i++) {
+                               val = musb_readl(fifo, 0);
+                               *(u32 *)bufp = val;
+                               bufp += 4;
+                       }
+               } else if (((unsigned long)bufp & 0x2) == 0x2) {
+                       for (i = 0; i < (len / 4); i++) {
+                               val = musb_readl(fifo, 0);
+                               *(u16 *)bufp = (u16)(val & 0xffff);
+                               bufp += 2;
+                               *(u16 *)bufp = (u16)(val >> 16);
+                               bufp += 2;
+                       }
+               } else {
+                       for (i = 0; i < (len / 4); i++) {
+                               val = musb_readl(fifo, 0);
+                               memcpy(bufp, &val, 4);
+                               bufp += 4;
+                       }
+               }
+               remain = len - (i * 4);
+       } else
+               remain = len;
+
+       if (remain) {
+               /* Read rest of 1-3 bytes from FIFO */
+               val = musb_readl(fifo, 0);
+               memcpy(bufp, &val, remain);
+       }
+}
+
+/* This is used by gadget drivers, and OTG transceiver logic, allowing
+ * at most mA current to be drawn from VBUS during a Default-B session
+ * (that is, while VBUS exceeds 4.4V).  In Default-A (including pure host
+ * mode), or low power Default-B sessions, something else supplies power.
+ * Caller must take care of locking.
+ */
+static int tusb_set_power(struct otg_transceiver *x, unsigned mA)
+{
+       struct musb     *musb = container_of(x, struct musb, xceiv);
+       void __iomem    *base = musb->ctrl_base;
+       u32             reg;
+
+       /* tps65030 seems to consume max 100mA, with maybe 60mA available
+        * (measured on one board) for things other than tps and tusb.
+        *
+        * REVISIT we could use VBUS to supply only _one_ of { 1.5V, 3.3V }.
+        * The actual current usage would be very board-specific.  For now,
+        * it's simpler to just use an aggregate (also board-specific).
+        */
+       if (x->default_a || mA < (musb->min_power << 1))
+               mA = 0;
+
+       reg = musb_readl(base, TUSB_PRCM_MNGMT);
+       if (mA)
+               reg |= TUSB_PRCM_MNGMT_15_SW_EN | TUSB_PRCM_MNGMT_33_SW_EN;
+       else
+               reg &= ~(TUSB_PRCM_MNGMT_15_SW_EN | TUSB_PRCM_MNGMT_33_SW_EN);
+       musb_writel(base, TUSB_PRCM_MNGMT, reg);
+
+       DBG(2, "draw max %d mA VBUS\n", mA);
+       return 0;
+}
+
+/* workaround for issue 13:  change clock during chip idle
+ * (to be fixed in rev3 silicon) ... symptoms include disconnect
+ * or looping suspend/resume cycles
+ */
+static void tusb_set_clock_source(struct musb *musb, unsigned mode)
+{
+       void __iomem    *base = musb->ctrl_base;
+       u32             reg;
+
+       reg = musb_readl(base, TUSB_PRCM_CONF);
+       reg &= ~TUSB_PRCM_CONF_SYS_CLKSEL(0x3);
+
+       /* 0 = refclk (clkin, XI)
+        * 1 = PHY 60 MHz (internal PLL)
+        * 2 = not supported
+        * 3 = NOR clock (huh?)
+        */
+       if (mode > 0)
+               reg |= TUSB_PRCM_CONF_SYS_CLKSEL(mode & 0x3);
+
+       musb_writel(base, TUSB_PRCM_CONF, reg);
+
+       // FIXME tusb6010_platform_retime(mode == 0);
+}
+
+/*
+ * Idle TUSB6010 until next wake-up event; NOR access always wakes.
+ * Other code ensures that we idle unless we're connected _and_ the
+ * USB link is not suspended ... and tells us the relevant wakeup
+ * events.  SW_EN for voltage is handled separately.
+ */
+static void tusb_allow_idle(struct musb *musb, u32 wakeup_enables)
+{
+       void __iomem    *base = musb->ctrl_base;
+       u32             reg;
+
+       tusb_set_clock_source(musb, 0);
+
+       wakeup_enables |= TUSB_PRCM_WNORCS;
+       musb_writel(base, TUSB_PRCM_WAKEUP_MASK, ~wakeup_enables);
+
+       /* REVISIT writeup of WID implies that if WID set and ID is grounded,
+        * TUSB_PHY_OTG_CTRL.TUSB_PHY_OTG_CTRL_OTG_ID_PULLUP must be cleared.
+        * Presumably that's mostly to save power, hence WID is immaterial ...
+        */
+
+       reg = musb_readl(base, TUSB_PRCM_MNGMT);
+       /* issue 4: when driving vbus, use hipower (vbus_det) comparator */
+       if (is_host_active(musb)) {
+               reg |= TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN;
+               reg &= ~TUSB_PRCM_MNGMT_OTG_SESS_END_EN;
+       } else {
+               reg |= TUSB_PRCM_MNGMT_OTG_SESS_END_EN;
+               reg &= ~TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN;
+       }
+       reg |= TUSB_PRCM_MNGMT_PM_IDLE | TUSB_PRCM_MNGMT_DEV_IDLE;
+       musb_writel(base, TUSB_PRCM_MNGMT, reg);
+
+       DBG(2, "idle, wake on %02x\n", wakeup_enables);
+}
+
+/*
+ * Updates cable VBUS status. Caller must take care of locking.
+ */
+int musb_platform_get_vbus_status(struct musb *musb)
+{
+       void __iomem    *base = musb->ctrl_base;
+       u32             otg_stat, prcm_mngmt;
+       int             ret = 0;
+
+       otg_stat = musb_readl(base, TUSB_DEV_OTG_STAT);
+       prcm_mngmt = musb_readl(base, TUSB_PRCM_MNGMT);
+
+       /* Temporarily enable VBUS detection if it was disabled for
+        * suspend mode. Unless it's enabled otg_stat and devctl will
+        * not show correct VBUS state.
+        */
+       if (!(prcm_mngmt & TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN)) {
+               u32 tmp = prcm_mngmt;
+               tmp |= TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN;
+               musb_writel(base, TUSB_PRCM_MNGMT, tmp);
+               otg_stat = musb_readl(base, TUSB_DEV_OTG_STAT);
+               musb_writel(base, TUSB_PRCM_MNGMT, prcm_mngmt);
+       }
+
+       if (otg_stat & TUSB_DEV_OTG_STAT_VBUS_SENSE)
+               ret = 1;
+
+       return ret;
+}
+
+static struct timer_list musb_idle_timer;
+
+static void musb_do_idle(unsigned long _musb)
+{
+       struct musb     *musb = (void *)_musb;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&musb->Lock, flags);
+       if (!musb->is_active) {
+               u32     wakeups;
+
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+               /* wait until khubd handles port change status */
+               if (is_host_active(musb) && (musb->port1_status >> 16))
+                       goto done;
+#endif
+
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+               if (is_peripheral_enabled(musb) && !musb->pGadgetDriver)
+                       wakeups = 0;
+               else {
+                       wakeups = TUSB_PRCM_WHOSTDISCON
+                                       | TUSB_PRCM_WBUS
+                                       | TUSB_PRCM_WVBUS;
+                       if (is_otg_enabled(musb))
+                               wakeups |= TUSB_PRCM_WID;
+               }
+#else
+               wakeups = TUSB_PRCM_WHOSTDISCON | TUSB_PRCM_WBUS;
+#endif
+               tusb_allow_idle(musb, wakeups);
+       }
+done:
+       spin_unlock_irqrestore(&musb->Lock, flags);
+}
+
+/*
+ * Maybe put TUSB6010 into idle mode mode depending on USB link status,
+ * like "disconnected" or "suspended".  We'll be woken out of it by
+ * connect, resume, or disconnect.
+ *
+ * Needs to be called as the last function everywhere where there is
+ * register access to TUSB6010 because of NOR flash wake-up.
+ * Caller should own controller spinlock.
+ *
+ * Delay because peripheral enables D+ pullup 3msec after SE0, and
+ * we don't want to treat that full speed J as a wakeup event.
+ * ... peripherals must draw only suspend current after 10 msec.
+ */
+void musb_platform_try_idle(struct musb *musb)
+{
+       if (musb->is_active)
+               del_timer(&musb_idle_timer);
+       else
+               mod_timer(&musb_idle_timer, jiffies + msecs_to_jiffies(3));
+}
+
+/* ticks of 60 MHz clock */
+#define DEVCLOCK               60000000
+#define OTG_TIMER_MS(msecs)    ((msecs) \
+               ? (TUSB_DEV_OTG_TIMER_VAL((DEVCLOCK/1000)*(msecs)) \
+                               | TUSB_DEV_OTG_TIMER_ENABLE) \
+               : 0)
+
+static void tusb_set_vbus(struct musb *musb, int is_on)
+{
+       void __iomem    *base = musb->ctrl_base;
+       u32             conf, prcm, timer;
+       u8              devctl;
+
+       /* HDRC controls CPEN, but beware current surges during device
+        * connect.  They can trigger transient overcurrent conditions
+        * that must be ignored.
+        */
+
+       prcm = musb_readl(base, TUSB_PRCM_MNGMT);
+       conf = musb_readl(base, TUSB_DEV_CONF);
+       devctl = musb_readb(musb->pRegs, MGC_O_HDRC_DEVCTL);
+
+       if (is_on) {
+               musb->is_active = 1;
+               timer = OTG_TIMER_MS(OTG_TIME_A_WAIT_VRISE);
+
+               musb->xceiv.default_a = 1;
+               musb->xceiv.state = OTG_STATE_A_WAIT_VRISE;
+               devctl |= MGC_M_DEVCTL_SESSION;
+
+               conf |= TUSB_DEV_CONF_USB_HOST_MODE;
+               MUSB_HST_MODE(musb);
+       } else {
+               musb->is_active = 0;
+               timer = 0;
+
+               /* NOTE:  we're skipping A_WAIT_VFALL -> A_IDLE and
+                * jumping right to B_IDLE...
+                */
+
+               musb->xceiv.default_a = 0;
+               musb->xceiv.state = OTG_STATE_B_IDLE;
+               devctl &= ~MGC_M_DEVCTL_SESSION;
+
+               conf &= ~TUSB_DEV_CONF_USB_HOST_MODE;
+               MUSB_DEV_MODE(musb);
+       }
+       prcm &= ~(TUSB_PRCM_MNGMT_15_SW_EN | TUSB_PRCM_MNGMT_33_SW_EN);
+
+       musb_writel(base, TUSB_PRCM_MNGMT, prcm);
+       musb_writel(base, TUSB_DEV_OTG_TIMER, timer);
+       musb_writel(base, TUSB_DEV_CONF, conf);
+       musb_writeb(musb->pRegs, MGC_O_HDRC_DEVCTL, devctl);
+
+       DBG(1, "VBUS %s, devctl %02x otg %3x conf %08x prcm %08x\n",
+               otg_state_string(musb),
+               musb_readb(musb->pRegs, MGC_O_HDRC_DEVCTL),
+               musb_readl(base, TUSB_DEV_OTG_STAT),
+               conf, prcm);
+}
+
+static inline void
+tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *base)
+{
+       u32     otg_stat = musb_readl(base, TUSB_DEV_OTG_STAT);
+
+       /* ID pin */
+       if ((int_src & TUSB_INT_SRC_ID_STATUS_CHNG)) {
+               int     default_a;
+
+               if (is_otg_enabled(musb))
+                       default_a = !(otg_stat & TUSB_DEV_OTG_STAT_ID_STATUS);
+               else
+                       default_a = is_host_enabled(musb);
+               DBG(2, "Default-%c\n", default_a ? 'A' : 'B');
+               musb->xceiv.default_a = default_a;
+               tusb_set_vbus(musb, default_a);
+       }
+
+       /* VBUS state change */
+       if (int_src & TUSB_INT_SRC_VBUS_SENSE_CHNG) {
+
+               /* B-dev state machine:  no vbus ~= disconnect */
+               if ((is_otg_enabled(musb) && !musb->xceiv.default_a)
+                               || !is_host_enabled(musb)) {
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+                       // ? musb_root_disconnect(musb);
+                       musb->port1_status &=
+                               ~(USB_PORT_STAT_CONNECTION
+                               | USB_PORT_STAT_ENABLE
+                               | USB_PORT_STAT_LOW_SPEED
+                               | USB_PORT_STAT_HIGH_SPEED
+                               | USB_PORT_STAT_TEST
+                               );
+#endif
+
+                       if (otg_stat & TUSB_DEV_OTG_STAT_SESS_END) {
+                               if (musb->xceiv.state != OTG_STATE_B_IDLE) {
+                                       /* INTR_DISCONNECT can hide... */
+                                       musb->xceiv.state = OTG_STATE_B_IDLE;
+                                       musb->int_usb |= MGC_M_INTR_DISCONNECT;
+                               }
+                               musb->is_active = 0;
+                       }
+                       DBG(2, "vbus change, %s, otg %03x\n",
+                               otg_state_string(musb), otg_stat);
+                       schedule_work(&musb->irq_work);
+
+               } else /* A-dev state machine */ {
+                       DBG(4, "vbus change, %s, otg %03x\n",
+                               otg_state_string(musb), otg_stat);
+
+                       switch (musb->xceiv.state) {
+                       case OTG_STATE_A_WAIT_VRISE:
+                               /* ignore; A-session-valid < VBUS_VALID/2,
+                                * we monitor this with the timer
+                                */
+                               break;
+                       case OTG_STATE_A_WAIT_VFALL:
+                               /* REVISIT this irq triggers during short
+                                * spikes causet by enumeration ...
+                                */
+                               if (musb->vbuserr_retry) {
+                                       musb->vbuserr_retry--;
+                                       tusb_set_vbus(musb, 1);
+                               }
+                               break;
+                       default:
+                               break;
+                       }
+               }
+       }
+
+       /* OTG timer expiration */
+       if (int_src & TUSB_INT_SRC_OTG_TIMEOUT) {
+               u8      devctl;
+
+               DBG(4, "%s timer, %03x\n", otg_state_string(musb), otg_stat);
+
+               switch (musb->xceiv.state) {
+               case OTG_STATE_A_WAIT_VRISE:
+                       /* VBUS has probably been valid for a while now,
+                        * but may well have bounced out of range a bit
+                        */
+                       devctl = musb_readb(musb->pRegs, MGC_O_HDRC_DEVCTL);
+                       if (otg_stat & TUSB_DEV_OTG_STAT_VBUS_VALID) {
+                               u32     timer;
+
+                               if ((devctl & MGC_M_DEVCTL_VBUS)
+                                               != MGC_M_DEVCTL_VBUS) {
+                                       DBG(2, "devctl %02x\n", devctl);
+                                       break;
+                               }
+                               musb->xceiv.state = OTG_STATE_A_WAIT_BCON;
+
+                               /* REVISIT: if nothing is connected yet,
+                                * mark controller as inactive so that
+                                * we can suspend the TUSB chip.
+                                */
+
+                               /* timeout 0 == infinite (like non-OTG hosts) */
+                               timer = OTG_TIMER_MS(OTG_TIME_A_WAIT_BCON);
+                               if (timer)
+                                       musb_writel(base, TUSB_DEV_OTG_TIMER,
+                                                       timer);
+                       } else {
+                               /* REVISIT report overcurrent to hub? */
+                               ERR("vbus too slow, devctl %02x\n", devctl);
+                               tusb_set_vbus(musb, 0);
+                       }
+                       break;
+               case OTG_STATE_A_WAIT_BCON:
+                       if (OTG_TIME_A_WAIT_BCON)
+                               tusb_set_vbus(musb, 0);
+                       break;
+               case OTG_STATE_A_SUSPEND:
+                       break;
+               case OTG_STATE_B_WAIT_ACON:
+                       break;
+               default:
+                       break;
+               }
+       }
+}
+
+static irqreturn_t tusb_interrupt(int irq, void *__hci)
+{
+       struct musb     *musb = __hci;
+       void __iomem    *base = musb->ctrl_base;
+       unsigned long   flags;
+       u32             int_src;
+
+       spin_lock_irqsave(&musb->Lock, flags);
+
+       int_src = musb_readl(base, TUSB_INT_SRC) & ~TUSB_INT_SRC_RESERVED_BITS;
+       DBG(3, "TUSB IRQ %08x\n", int_src);
+
+       musb->int_usb = (u8) int_src;
+
+       /* Acknowledge wake-up source interrupts */
+       if (int_src & TUSB_INT_SRC_DEV_WAKEUP) {
+               u32     reg;
+               u32     i;
+
+               /* there are issues re-locking the PLL on wakeup ... */
+
+               /* work around issue 8 */
+               for (i = 0xf7f7f7; i > 0xf7f7f7 - 1000; i--) {
+                       musb_writel(base, TUSB_SCRATCH_PAD, 0);
+                       musb_writel(base, TUSB_SCRATCH_PAD, i);
+                       reg = musb_readl(base, TUSB_SCRATCH_PAD);
+                       if (reg == i)
+                               break;
+                       DBG(1, "TUSB NOR not ready\n");
+               }
+
+               /* work around issue 13 (2nd half) */
+               tusb_set_clock_source(musb, 1);
+
+               reg = musb_readl(base, TUSB_PRCM_WAKEUP_SOURCE);
+               musb_writel(base, TUSB_PRCM_WAKEUP_CLEAR, reg);
+               if (reg & ~TUSB_PRCM_WNORCS) {
+                       musb->is_active = 1;
+                       schedule_work(&musb->irq_work);
+               }
+               DBG(3, "wake %sactive %02x\n",
+                               musb->is_active ? "" : "in", reg);
+
+               // REVISIT host side TUSB_PRCM_WHOSTDISCON, TUSB_PRCM_WBUS
+       }
+
+       /* OTG state change reports (annoyingly) not issued by Mentor core */
+       if (int_src & (TUSB_INT_SRC_VBUS_SENSE_CHNG
+                               | TUSB_INT_SRC_OTG_TIMEOUT
+                               | TUSB_INT_SRC_ID_STATUS_CHNG))
+               tusb_otg_ints(musb, int_src, base);
+
+       /* TX dma callback must be handled here, RX dma callback is
+        * handled in tusb_omap_dma_cb.
+        */
+       if ((int_src & TUSB_INT_SRC_TXRX_DMA_DONE)) {
+               u32     dma_src = musb_readl(base, TUSB_DMA_INT_SRC);
+               u32     real_dma_src = musb_readl(base, TUSB_DMA_INT_MASK);
+
+               DBG(3, "DMA IRQ %08x\n", dma_src);
+               real_dma_src = ~real_dma_src & dma_src;
+               if (tusb_dma_omap() && real_dma_src) {
+                       int     tx_source = (real_dma_src & 0xffff);
+                       int     i;
+
+                       for (i = 1; i <= 15; i++) {
+                               if (tx_source & (1 << i)) {
+                                       DBG(3, "completing ep%i %s\n", i, "tx");
+                                       musb_dma_completion(musb, i, 1);
+                               }
+                       }
+               }
+               musb_writel(base, TUSB_DMA_INT_CLEAR, dma_src);
+       }
+
+       /* EP interrupts. In OCP mode tusb6010 mirrors the MUSB * interrupts */
+       if (int_src & (TUSB_INT_SRC_USB_IP_TX | TUSB_INT_SRC_USB_IP_RX)) {
+               u32     musb_src = musb_readl(base, TUSB_USBIP_INT_SRC);
+
+               musb_writel(base, TUSB_USBIP_INT_CLEAR, musb_src);
+               musb->int_rx = (((musb_src >> 16) & 0xffff) << 1);
+               musb->int_tx = (musb_src & 0xffff);
+       } else
+               musb->int_rx = musb->int_tx = 0;
+
+       if (int_src & (TUSB_INT_SRC_USB_IP_TX | TUSB_INT_SRC_USB_IP_RX | 0xff))
+               musb_interrupt(musb);
+
+       /* Acknowledge TUSB interrupts. Clear only non-reserved bits */
+       musb_writel(base, TUSB_INT_SRC_CLEAR,
+               int_src & ~TUSB_INT_MASK_RESERVED_BITS);
+
+       musb_platform_try_idle(musb);
+       spin_unlock_irqrestore(&musb->Lock, flags);
+
+       return IRQ_HANDLED;
+}
+
+static int dma_off;
+
+/*
+ * Enables TUSB6010. Caller must take care of locking.
+ * REVISIT:
+ * - Check what is unnecessary in MGC_HdrcStart()
+ */
+void musb_platform_enable(struct musb * musb)
+{
+       void __iomem    *base = musb->ctrl_base;
+
+       /* Setup TUSB6010 main interrupt mask. Enable all interrupts except SOF.
+        * REVISIT: Enable and deal with TUSB_INT_SRC_USB_IP_SOF */
+       musb_writel(base, TUSB_INT_MASK, TUSB_INT_SRC_USB_IP_SOF);
+
+       /* Setup TUSB interrupt, disable DMA and GPIO interrupts */
+       musb_writel(base, TUSB_USBIP_INT_MASK, 0);
+       musb_writel(base, TUSB_DMA_INT_MASK, 0x7fffffff);
+       musb_writel(base, TUSB_GPIO_INT_MASK, 0x1ff);
+
+       /* Clear all subsystem interrups */
+       musb_writel(base, TUSB_USBIP_INT_CLEAR, 0x7fffffff);
+       musb_writel(base, TUSB_DMA_INT_CLEAR, 0x7fffffff);
+       musb_writel(base, TUSB_GPIO_INT_CLEAR, 0x1ff);
+
+       /* Acknowledge pending interrupt(s) */
+       musb_writel(base, TUSB_INT_SRC_CLEAR, ~TUSB_INT_MASK_RESERVED_BITS);
+
+       /* Only 0 clock cycles for minimum interrupt de-assertion time and
+        * interrupt polarity active low seems to work reliably here */
+       musb_writel(base, TUSB_INT_CTRL_CONF,
+                       TUSB_INT_CTRL_CONF_INT_RELCYC(0));
+
+       set_irq_type(musb->nIrq, IRQ_TYPE_LEVEL_LOW);
+
+       /* maybe force into the Default-A OTG state machine */
+       if (!(musb_readl(base, TUSB_DEV_OTG_STAT)
+                       & TUSB_DEV_OTG_STAT_ID_STATUS))
+               musb_writel(base, TUSB_INT_SRC_SET,
+                               TUSB_INT_SRC_ID_STATUS_CHNG);
+
+       if (is_dma_capable() && dma_off)
+               printk(KERN_WARNING "%s %s: dma not reactivated\n",
+                               __FILE__, __FUNCTION__);
+       else
+               dma_off = 1;
+}
+
+/*
+ * Disables TUSB6010. Caller must take care of locking.
+ */
+void musb_platform_disable(struct musb *musb)
+{
+       void __iomem    *base = musb->ctrl_base;
+
+       /* FIXME stop DMA, IRQs, timers, ... */
+
+       /* disable all IRQs */
+       musb_writel(base, TUSB_INT_MASK, ~TUSB_INT_MASK_RESERVED_BITS);
+       musb_writel(base, TUSB_USBIP_INT_MASK, 0);
+       musb_writel(base, TUSB_DMA_INT_MASK, 0x7fffffff);
+       musb_writel(base, TUSB_GPIO_INT_MASK, 0x1ff);
+
+       del_timer(&musb_idle_timer);
+
+       if (is_dma_capable() && !dma_off) {
+               printk(KERN_WARNING "%s %s: dma still active\n",
+                               __FILE__, __FUNCTION__);
+               dma_off = 1;
+       }
+}
+
+/*
+ * Sets up TUSB6010 CPU interface specific signals and registers
+ * Note: Settings optimized for OMAP24xx
+ */
+static void __init tusb_setup_cpu_interface(struct musb *musb)
+{
+       void __iomem    *base = musb->ctrl_base;
+
+       /* Disable GPIO[7:0] pullups (used as output DMA requests) */
+       musb_writel(base, TUSB_PULLUP_1_CTRL, 0x000000FF);
+       /* Disable all pullups on NOR IF, DMAREQ0 and DMAREQ1 */
+       musb_writel(base, TUSB_PULLUP_2_CTRL, 0x01FFFFFF);
+
+       /* Turn GPIO[5:0] to DMAREQ[5:0] signals */
+       musb_writel(base, TUSB_GPIO_CONF, TUSB_GPIO_CONF_DMAREQ(0x3f));
+
+       /* Burst size 16x16 bits, all six DMA requests enabled, DMA request
+        * de-assertion time 2 system clocks p 62 */
+       musb_writel(base, TUSB_DMA_REQ_CONF,
+               TUSB_DMA_REQ_CONF_BURST_SIZE(2) |
+               TUSB_DMA_REQ_CONF_DMA_REQ_EN(0x3f) |
+               TUSB_DMA_REQ_CONF_DMA_REQ_ASSER(2));
+
+       /* Set 0 wait count for synchronous burst access */
+       musb_writel(base, TUSB_WAIT_COUNT, 1);
+}
+
+#define TUSB_REV_MAJOR(reg_val)                ((reg_val >> 4) & 0xf)
+#define TUSB_REV_MINOR(reg_val)                (reg_val & 0xf)
+
+static int __init tusb_print_revision(struct musb *musb)
+{
+       void __iomem    *base = musb->ctrl_base;
+
+       pr_info("tusb: Revisions: %s%i.%i %s%i.%i %s%i.%i %s%i.%i\n",
+               "prcm",
+               TUSB_REV_MAJOR(musb_readl(base, TUSB_PRCM_REV)),
+               TUSB_REV_MINOR(musb_readl(base, TUSB_PRCM_REV)),
+               "int",
+               TUSB_REV_MAJOR(musb_readl(base, TUSB_INT_CTRL_REV)),
+               TUSB_REV_MINOR(musb_readl(base, TUSB_INT_CTRL_REV)),
+               "gpio",
+               TUSB_REV_MAJOR(musb_readl(base, TUSB_GPIO_REV)),
+               TUSB_REV_MINOR(musb_readl(base, TUSB_GPIO_REV)),
+               "dma",
+               TUSB_REV_MAJOR(musb_readl(base, TUSB_DMA_CTRL_REV)),
+               TUSB_REV_MINOR(musb_readl(base, TUSB_DMA_CTRL_REV)));
+
+       return TUSB_REV_MAJOR(musb_readl(base, TUSB_INT_CTRL_REV));
+}
+
+static int __init tusb_start(struct musb *musb)
+{
+       void __iomem    *base = musb->ctrl_base;
+       int             ret = 0;
+       unsigned long   flags;
+       u32             reg;
+
+       if (musb->board_set_power)
+               ret = musb->board_set_power(1);
+       if (ret != 0) {
+               printk(KERN_ERR "tusb: Cannot enable TUSB6010\n");
+               return ret;
+       }
+
+       spin_lock_irqsave(&musb->Lock, flags);
+
+       if (musb_readl(base, TUSB_PROD_TEST_RESET) !=
+               TUSB_PROD_TEST_RESET_VAL) {
+               printk(KERN_ERR "tusb: Unable to detect TUSB6010\n");
+               goto err;
+       }
+
+       ret = tusb_print_revision(musb);
+       if (ret < 2) {
+               printk(KERN_ERR "tusb: Unsupported TUSB6010 revision %i\n",
+                               ret);
+               goto err;
+       }
+
+       /* The uint bit for "USB non-PDR interrupt enable" has to be 1 when
+        * NOR FLASH interface is used */
+       musb_writel(base, TUSB_VLYNQ_CTRL, 8);
+
+       /* Select PHY free running 60MHz as a system clock */
+       tusb_set_clock_source(musb, 1);
+
+       /* VBus valid timer 1us, disable DFT/Debug and VLYNQ clocks for
+        * power saving, enable VBus detect and session end comparators,
+        * enable IDpullup, enable VBus charging */
+       musb_writel(base, TUSB_PRCM_MNGMT,
+               TUSB_PRCM_MNGMT_VBUS_VALID_TIMER(0xa) |
+               TUSB_PRCM_MNGMT_VBUS_VALID_FLT_EN |
+               TUSB_PRCM_MNGMT_OTG_SESS_END_EN |
+               TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN |
+               TUSB_PRCM_MNGMT_OTG_ID_PULLUP);
+       tusb_setup_cpu_interface(musb);
+
+       /* simplify:  always sense/pullup ID pins, as if in OTG mode */
+       reg = musb_readl(base, TUSB_PHY_OTG_CTRL);
+       reg |= TUSB_PHY_OTG_CTRL_WRPROTECT | TUSB_PHY_OTG_CTRL_OTG_ID_PULLUP;
+       musb_writel(base, TUSB_PHY_OTG_CTRL, reg);
+
+       reg = musb_readl(base, TUSB_PHY_OTG_CTRL_ENABLE);
+       reg |= TUSB_PHY_OTG_CTRL_WRPROTECT | TUSB_PHY_OTG_CTRL_OTG_ID_PULLUP;
+       musb_writel(base, TUSB_PHY_OTG_CTRL_ENABLE, reg);
+
+       spin_unlock_irqrestore(&musb->Lock, flags);
+
+       return 0;
+
+err:
+       spin_unlock_irqrestore(&musb->Lock, flags);
+
+       if (musb->board_set_power)
+               musb->board_set_power(0);
+
+       return -ENODEV;
+}
+
+int __init musb_platform_init(struct musb *musb)
+{
+       struct platform_device  *pdev;
+       struct resource         *mem;
+       int                     ret;
+
+       pdev = to_platform_device(musb->controller);
+
+       /* dma address for async dma */
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       musb->async = mem->start;
+
+       /* dma address for sync dma */
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (!mem) {
+               pr_debug("no sync dma resource?\n");
+               return -ENODEV;
+       }
+       musb->sync = mem->start;
+
+       /* Offsets from base: VLYNQ at 0x000, MUSB regs at 0x400,
+        * FIFOs at 0x600, TUSB at 0x800
+        */
+       musb->pRegs += TUSB_BASE_OFFSET;
+
+       ret = tusb_start(musb);
+       if (ret) {
+               printk(KERN_ERR "Could not start tusb6010 (%d)\n",
+                               ret);
+               return -ENODEV;
+       }
+       musb->isr = tusb_interrupt;
+
+       if (is_host_enabled(musb))
+               musb->board_set_vbus = tusb_set_vbus;
+       if (is_peripheral_enabled(musb))
+               musb->xceiv.set_power = tusb_set_power;
+
+       setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
+
+       return ret;
+}
+
+int musb_platform_exit(struct musb *musb)
+{
+       del_timer_sync(&musb_idle_timer);
+
+       if (musb->board_set_power)
+               musb->board_set_power(0);
+
+       return 0;
+}
diff --git a/drivers/usb/musb/tusb6010.h b/drivers/usb/musb/tusb6010.h
new file mode 100644 (file)
index 0000000..df73a29
--- /dev/null
@@ -0,0 +1,388 @@
+/*
+ * Definitions for TUSB6010 USB 2.0 OTG Dual Role controller
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Jarkko Nikula <jarkko.nikula@nokia.com>
+ * Tony Lindgren <tony@atomide.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __TUSB6010_H__
+#define __TUSB6010_H__
+
+#ifdef CONFIG_USB_TUSB6010
+#define musb_in_tusb()                 1
+#else
+#define musb_in_tusb()                 0
+#endif
+
+#ifdef CONFIG_USB_TUSB_OMAP_DMA
+#define tusb_dma_omap()                        1
+#else
+#define tusb_dma_omap()                        0
+#endif
+
+/* VLYNQ control register. 32-bit at offset 0x000 */
+#define TUSB_VLYNQ_CTRL                        0x004
+
+/* Mentor Graphics OTG core registers. 8,- 16- and 32-bit at offset 0x400 */
+#define TUSB_BASE_OFFSET               0x400
+
+/* FIFO registers 32-bit at offset 0x600 */
+#define TUSB_FIFO_BASE                 0x600
+
+/* Device System & Control registers. 32-bit at offset 0x800 */
+#define TUSB_SYS_REG_BASE              0x800
+
+#define TUSB_DEV_CONF                  (TUSB_SYS_REG_BASE + 0x000)
+#define                TUSB_DEV_CONF_USB_HOST_MODE             (1 << 16)
+#define                TUSB_DEV_CONF_PROD_TEST_MODE            (1 << 15)
+#define                TUSB_DEV_CONF_SOFT_ID                   (1 << 1)
+#define                TUSB_DEV_CONF_ID_SEL                    (1 << 0)
+
+#define TUSB_PHY_OTG_CTRL_ENABLE       (TUSB_SYS_REG_BASE + 0x004)
+#define TUSB_PHY_OTG_CTRL              (TUSB_SYS_REG_BASE + 0x008)
+#define                TUSB_PHY_OTG_CTRL_WRPROTECT             (0xa5 << 24)
+#define                TUSB_PHY_OTG_CTRL_OTG_ID_PULLUP         (1 << 23)
+#define                TUSB_PHY_OTG_CTRL_OTG_VBUS_DET_EN       (1 << 19)
+#define                TUSB_PHY_OTG_CTRL_OTG_SESS_END_EN       (1 << 18)
+#define                TUSB_PHY_OTG_CTRL_TESTM2                (1 << 17)
+#define                TUSB_PHY_OTG_CTRL_TESTM1                (1 << 16)
+#define                TUSB_PHY_OTG_CTRL_TESTM0                (1 << 15)
+#define                TUSB_PHY_OTG_CTRL_TX_DATA2              (1 << 14)
+#define                TUSB_PHY_OTG_CTRL_TX_GZ2                (1 << 13)
+#define                TUSB_PHY_OTG_CTRL_TX_ENABLE2            (1 << 12)
+#define                TUSB_PHY_OTG_CTRL_DM_PULLDOWN           (1 << 11)
+#define                TUSB_PHY_OTG_CTRL_DP_PULLDOWN           (1 << 10)
+#define                TUSB_PHY_OTG_CTRL_OSC_EN                (1 << 9)
+#define                TUSB_PHY_OTG_CTRL_PHYREF_CLKSEL(v)      (((v) & 3) << 7)
+#define                TUSB_PHY_OTG_CTRL_PD                    (1 << 6)
+#define                TUSB_PHY_OTG_CTRL_PLL_ON                (1 << 5)
+#define                TUSB_PHY_OTG_CTRL_EXT_RPU               (1 << 4)
+#define                TUSB_PHY_OTG_CTRL_PWR_GOOD              (1 << 3)
+#define                TUSB_PHY_OTG_CTRL_RESET                 (1 << 2)
+#define                TUSB_PHY_OTG_CTRL_SUSPENDM              (1 << 1)
+#define                TUSB_PHY_OTG_CTRL_CLK_MODE              (1 << 0)
+
+/*OTG status register */
+#define TUSB_DEV_OTG_STAT              (TUSB_SYS_REG_BASE + 0x00c)
+#define                TUSB_DEV_OTG_STAT_PWR_CLK_GOOD          (1 << 8)
+#define                TUSB_DEV_OTG_STAT_SESS_END              (1 << 7)
+#define                TUSB_DEV_OTG_STAT_SESS_VALID            (1 << 6)
+#define                TUSB_DEV_OTG_STAT_VBUS_VALID            (1 << 5)
+#define                TUSB_DEV_OTG_STAT_VBUS_SENSE            (1 << 4)
+#define                TUSB_DEV_OTG_STAT_ID_STATUS             (1 << 3)
+#define                TUSB_DEV_OTG_STAT_HOST_DISCON           (1 << 2)
+#define                TUSB_DEV_OTG_STAT_LINE_STATE            (3 << 0)
+#define                TUSB_DEV_OTG_STAT_DP_ENABLE             (1 << 1)
+#define                TUSB_DEV_OTG_STAT_DM_ENABLE             (1 << 0)
+
+#define TUSB_DEV_OTG_TIMER             (TUSB_SYS_REG_BASE + 0x010)
+#      define TUSB_DEV_OTG_TIMER_ENABLE                (1 << 31)
+#      define TUSB_DEV_OTG_TIMER_VAL(v)                ((v) & 0x07ffffff)
+#define TUSB_PRCM_REV                  (TUSB_SYS_REG_BASE + 0x014)
+
+/* PRCM configuration register */
+#define TUSB_PRCM_CONF                 (TUSB_SYS_REG_BASE + 0x018)
+#define                TUSB_PRCM_CONF_SFW_CPEN         (1 << 24)
+#define                TUSB_PRCM_CONF_SYS_CLKSEL(v)    (((v) & 3) << 16)
+
+/* PRCM management register */
+#define TUSB_PRCM_MNGMT                        (TUSB_SYS_REG_BASE + 0x01c)
+#define                TUSB_PRCM_MNGMT_SRP_FIX_TIMER(v)        (((v) & 0xf) << 25)
+#define                TUSB_PRCM_MNGMT_SRP_FIX_EN              (1 << 24)
+#define                TUSB_PRCM_MNGMT_VBUS_VALID_TIMER(v)     (((v) & 0xf) << 20)
+#define                TUSB_PRCM_MNGMT_VBUS_VALID_FLT_EN       (1 << 19)
+#define                TUSB_PRCM_MNGMT_DFT_CLK_DIS             (1 << 18)
+#define                TUSB_PRCM_MNGMT_VLYNQ_CLK_DIS           (1 << 17)
+#define                TUSB_PRCM_MNGMT_OTG_SESS_END_EN         (1 << 10)
+#define                TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN         (1 << 9)
+#define                TUSB_PRCM_MNGMT_OTG_ID_PULLUP           (1 << 8)
+#define                TUSB_PRCM_MNGMT_15_SW_EN                (1 << 4)
+#define                TUSB_PRCM_MNGMT_33_SW_EN                (1 << 3)
+#define                TUSB_PRCM_MNGMT_5V_CPEN                 (1 << 2)
+#define                TUSB_PRCM_MNGMT_PM_IDLE                 (1 << 1)
+#define                TUSB_PRCM_MNGMT_DEV_IDLE                (1 << 0)
+
+/* Wake-up source clear and mask registers */
+#define TUSB_PRCM_WAKEUP_SOURCE                (TUSB_SYS_REG_BASE + 0x020)
+#define TUSB_PRCM_WAKEUP_CLEAR         (TUSB_SYS_REG_BASE + 0x028)
+#define TUSB_PRCM_WAKEUP_MASK          (TUSB_SYS_REG_BASE + 0x02c)
+#define                TUSB_PRCM_WAKEUP_RESERVED_BITS  (0xffffe << 13)
+#define                TUSB_PRCM_WGPIO_7       (1 << 12)
+#define                TUSB_PRCM_WGPIO_6       (1 << 11)
+#define                TUSB_PRCM_WGPIO_5       (1 << 10)
+#define                TUSB_PRCM_WGPIO_4       (1 << 9)
+#define                TUSB_PRCM_WGPIO_3       (1 << 8)
+#define                TUSB_PRCM_WGPIO_2       (1 << 7)
+#define                TUSB_PRCM_WGPIO_1       (1 << 6)
+#define                TUSB_PRCM_WGPIO_0       (1 << 5)
+#define                TUSB_PRCM_WHOSTDISCON   (1 << 4)        /* Host disconnect */
+#define                TUSB_PRCM_WBUS          (1 << 3)        /* USB bus resume */
+#define                TUSB_PRCM_WNORCS        (1 << 2)        /* NOR chip select */
+#define                TUSB_PRCM_WVBUS         (1 << 1)        /* OTG PHY VBUS */
+#define                TUSB_PRCM_WID           (1 << 0)        /* OTG PHY ID detect */
+
+#define TUSB_PULLUP_1_CTRL             (TUSB_SYS_REG_BASE + 0x030)
+#define TUSB_PULLUP_2_CTRL             (TUSB_SYS_REG_BASE + 0x034)
+#define TUSB_INT_CTRL_REV              (TUSB_SYS_REG_BASE + 0x038)
+#define TUSB_INT_CTRL_CONF             (TUSB_SYS_REG_BASE + 0x03c)
+#define TUSB_USBIP_INT_SRC             (TUSB_SYS_REG_BASE + 0x040)
+#define TUSB_USBIP_INT_SET             (TUSB_SYS_REG_BASE + 0x044)
+#define TUSB_USBIP_INT_CLEAR           (TUSB_SYS_REG_BASE + 0x048)
+#define TUSB_USBIP_INT_MASK            (TUSB_SYS_REG_BASE + 0x04c)
+#define TUSB_DMA_INT_SRC               (TUSB_SYS_REG_BASE + 0x050)
+#define TUSB_DMA_INT_SET               (TUSB_SYS_REG_BASE + 0x054)
+#define TUSB_DMA_INT_CLEAR             (TUSB_SYS_REG_BASE + 0x058)
+#define TUSB_DMA_INT_MASK              (TUSB_SYS_REG_BASE + 0x05c)
+#define TUSB_GPIO_INT_SRC              (TUSB_SYS_REG_BASE + 0x060)
+#define TUSB_GPIO_INT_SET              (TUSB_SYS_REG_BASE + 0x064)
+#define TUSB_GPIO_INT_CLEAR            (TUSB_SYS_REG_BASE + 0x068)
+#define TUSB_GPIO_INT_MASK             (TUSB_SYS_REG_BASE + 0x06c)
+
+/* NOR flash interrupt source registers */
+#define TUSB_INT_SRC                   (TUSB_SYS_REG_BASE + 0x070)
+#define TUSB_INT_SRC_SET               (TUSB_SYS_REG_BASE + 0x074)
+#define TUSB_INT_SRC_CLEAR             (TUSB_SYS_REG_BASE + 0x078)
+#define TUSB_INT_MASK                  (TUSB_SYS_REG_BASE + 0x07c)
+#define                TUSB_INT_SRC_TXRX_DMA_DONE              (1 << 24)
+#define                TUSB_INT_SRC_USB_IP_CORE                (1 << 17)
+#define                TUSB_INT_SRC_OTG_TIMEOUT                (1 << 16)
+#define                TUSB_INT_SRC_VBUS_SENSE_CHNG            (1 << 15)
+#define                TUSB_INT_SRC_ID_STATUS_CHNG             (1 << 14)
+#define                TUSB_INT_SRC_DEV_WAKEUP                 (1 << 13)
+#define                TUSB_INT_SRC_DEV_READY                  (1 << 12)
+#define                TUSB_INT_SRC_USB_IP_TX                  (1 << 9)
+#define                TUSB_INT_SRC_USB_IP_RX                  (1 << 8)
+#define                TUSB_INT_SRC_USB_IP_VBUS_ERR            (1 << 7)
+#define                TUSB_INT_SRC_USB_IP_VBUS_REQ            (1 << 6)
+#define                TUSB_INT_SRC_USB_IP_DISCON              (1 << 5)
+#define                TUSB_INT_SRC_USB_IP_CONN                (1 << 4)
+#define                TUSB_INT_SRC_USB_IP_SOF                 (1 << 3)
+#define                TUSB_INT_SRC_USB_IP_RST_BABBLE          (1 << 2)
+#define                TUSB_INT_SRC_USB_IP_RESUME              (1 << 1)
+#define                TUSB_INT_SRC_USB_IP_SUSPEND             (1 << 0)
+
+/* NOR flash interrupt registers reserved bits. Must be written as 0 */
+#define                TUSB_INT_MASK_RESERVED_17               (0x3fff << 17)
+#define                TUSB_INT_MASK_RESERVED_13               (1 << 13)
+#define                TUSB_INT_MASK_RESERVED_8                (0xf << 8)
+#define                TUSB_INT_SRC_RESERVED_26                (0x1f << 26)
+#define                TUSB_INT_SRC_RESERVED_18                (0x3f << 18)
+#define                TUSB_INT_SRC_RESERVED_10                (0x03 << 10)
+
+/* Reserved bits for NOR flash interrupt mask and clear register */
+#define                TUSB_INT_MASK_RESERVED_BITS     (TUSB_INT_MASK_RESERVED_17 | \
+                                               TUSB_INT_MASK_RESERVED_13 | \
+                                               TUSB_INT_MASK_RESERVED_8)
+
+/* Reserved bits for NOR flash interrupt status register */
+#define                TUSB_INT_SRC_RESERVED_BITS      (TUSB_INT_SRC_RESERVED_26 | \
+                                               TUSB_INT_SRC_RESERVED_18 | \
+                                               TUSB_INT_SRC_RESERVED_10)
+
+#define TUSB_GPIO_REV                  (TUSB_SYS_REG_BASE + 0x080)
+#define TUSB_GPIO_CONF                 (TUSB_SYS_REG_BASE + 0x084)
+#define TUSB_DMA_CTRL_REV              (TUSB_SYS_REG_BASE + 0x100)
+#define TUSB_DMA_REQ_CONF              (TUSB_SYS_REG_BASE + 0x104)
+#define TUSB_EP0_CONF                  (TUSB_SYS_REG_BASE + 0x108)
+#define TUSB_DMA_EP_MAP                        (TUSB_SYS_REG_BASE + 0x148)
+
+/* Offsets from each ep base register */
+#define TUSB_EP_TX_OFFSET              0x10c   /* EP_IN in docs */
+#define TUSB_EP_RX_OFFSET              0x14c   /* EP_OUT in docs */
+#define TUSB_EP_MAX_PACKET_SIZE_OFFSET 0x188
+
+#define TUSB_WAIT_COUNT                        (TUSB_SYS_REG_BASE + 0x1c8)
+#define TUSB_SCRATCH_PAD               (TUSB_SYS_REG_BASE + 0x1c4)
+#define TUSB_PROD_TEST_RESET           (TUSB_SYS_REG_BASE + 0x1d8)
+
+/* Device System & Control register bitfields */
+#define TUSB_INT_CTRL_CONF_INT_RELCYC(v)       (((v) & 0x7) << 18)
+#define TUSB_INT_CTRL_CONF_INT_POLARITY                (1 << 17)
+#define TUSB_INT_CTRL_CONF_INT_MODE            (1 << 16)
+#define TUSB_GPIO_CONF_DMAREQ(v)               (((v) & 0x3f) << 24)
+#define TUSB_DMA_REQ_CONF_BURST_SIZE(v)                (((v) & 3) << 26)
+#define TUSB_DMA_REQ_CONF_DMA_REQ_EN(v)                (((v) & 0x3f) << 20)
+#define TUSB_DMA_REQ_CONF_DMA_REQ_ASSER(v)     (((v) & 0xf) << 16)
+#define TUSB_EP0_CONFIG_SW_EN                  (1 << 8)
+#define TUSB_EP0_CONFIG_DIR_TX                 (1 << 7)
+#define TUSB_EP0_CONFIG_XFR_SIZE(v)            ((v) & 0x7f)
+#define TUSB_EP_CONFIG_SW_EN                   (1 << 31)
+#define TUSB_EP_CONFIG_XFR_SIZE(v)             ((v) & 0x7fffffff)
+#define TUSB_PROD_TEST_RESET_VAL               0xa596
+#define TUSB_EP_FIFO(ep)                       (TUSB_FIFO_BASE + (ep) * 0x20)
+
+/*----------------------------------------------------------------------------*/
+
+#ifdef CONFIG_USB_TUSB6010
+
+/* configuration parameters specific to this silicon */
+
+/* Number of Tx endpoints. Legal values are 1 - 16 (this value includes EP0) */
+#define MUSB_C_NUM_EPT 16
+
+/* Number of Rx endpoints. Legal values are 1 - 16 (this value includes EP0) */
+#define MUSB_C_NUM_EPR 16
+
+/* Endpoint 1 to 15 direction types. C_EP1_DEF is defined if either Tx endpoint
+ * 1 or Rx endpoint 1 are used.
+ */
+#define MUSB_C_EP1_DEF
+
+/* C_EP1_TX_DEF is defined if Tx endpoint 1 is used */
+#define MUSB_C_EP1_TX_DEF
+
+/* C_EP1_RX_DEF is defined if Rx endpoint 1 is used */
+#define MUSB_C_EP1_RX_DEF
+
+/* C_EP1_TOR_DEF is defined if Tx endpoint 1 and Rx endpoint 1 share a FIFO */
+/* #define C_EP1_TOR_DEF */
+
+/* C_EP1_TAR_DEF is defined if both Tx endpoint 1 and Rx endpoint 1 are used
+ * and do not share a FIFO.
+ */
+#define MUSB_C_EP1_TAR_DEF
+
+/* Similarly for all other used endpoints */
+#define MUSB_C_EP2_DEF
+#define MUSB_C_EP2_TX_DEF
+#define MUSB_C_EP2_RX_DEF
+#define MUSB_C_EP2_TAR_DEF
+#define MUSB_C_EP3_DEF
+#define MUSB_C_EP3_TX_DEF
+#define MUSB_C_EP3_RX_DEF
+#define MUSB_C_EP3_TAR_DEF
+#define MUSB_C_EP4_DEF
+#define MUSB_C_EP4_TX_DEF
+#define MUSB_C_EP4_RX_DEF
+#define MUSB_C_EP4_TAR_DEF
+
+/* Endpoint 1 to 15 FIFO address bits. Legal values are 3 to 13 - corresponding
+ * to FIFO sizes of 8 to 8192 bytes. If an Tx endpoint shares a FIFO with an Rx
+ * endpoint then the Rx FIFO size must be the same as the Tx FIFO size. All
+ * endpoints 1 to 15 must be defined, unused endpoints should be set to 2.
+ */
+#define MUSB_C_EP1T_BITS 5
+#define MUSB_C_EP1R_BITS 5
+#define MUSB_C_EP2T_BITS 5
+#define MUSB_C_EP2R_BITS 5
+#define MUSB_C_EP3T_BITS 3
+#define MUSB_C_EP3R_BITS 3
+#define MUSB_C_EP4T_BITS 3
+#define MUSB_C_EP4R_BITS 3
+
+#define MUSB_C_EP5T_BITS 2
+#define MUSB_C_EP5R_BITS 2
+#define MUSB_C_EP6T_BITS 2
+#define MUSB_C_EP6R_BITS 2
+#define MUSB_C_EP7T_BITS 2
+#define MUSB_C_EP7R_BITS 2
+#define MUSB_C_EP8T_BITS 2
+#define MUSB_C_EP8R_BITS 2
+#define MUSB_C_EP9T_BITS 2
+#define MUSB_C_EP9R_BITS 2
+#define MUSB_C_EP10T_BITS 2
+#define MUSB_C_EP10R_BITS 2
+#define MUSB_C_EP11T_BITS 2
+#define MUSB_C_EP11R_BITS 2
+#define MUSB_C_EP12T_BITS 2
+#define MUSB_C_EP12R_BITS 2
+#define MUSB_C_EP13T_BITS 2
+#define MUSB_C_EP13R_BITS 2
+#define MUSB_C_EP14T_BITS 2
+#define MUSB_C_EP14R_BITS 2
+#define MUSB_C_EP15T_BITS 2
+#define MUSB_C_EP15R_BITS 2
+
+/* Define the following constant if the USB2.0 Transceiver Macrocell data width
+ * is 16-bits.
+ */
+/* #define C_UTM_16 */
+
+/* Define this constant if the CPU uses big-endian byte ordering. */
+/* #define C_BIGEND */
+
+/* Define the following constant if any Tx endpoint is required to support
+ * multiple bulk packets.
+ */
+/* #define C_MP_TX */
+
+/* Define the following constant if any Rx endpoint is required to support
+ * multiple bulk packets.
+ */
+/* #define C_MP_RX */
+
+/* Define the following constant if any Tx endpoint is required to support high
+ * bandwidth ISO.
+ */
+/* #define C_HB_TX */
+
+/* Define the following constant if any Rx endpoint is required to support high
+ * bandwidth ISO.
+ */
+/* #define C_HB_RX */
+
+/* Define the following constant if software connect/disconnect control is
+ * required.
+ */
+#define MUSB_C_SOFT_CON
+
+/* Define the following constant if Vendor Control Registers are required. */
+/* #define C_VEND_REG */
+
+/* Vendor control register widths. */
+#define MUSB_C_VCTL_BITS 4
+#define MUSB_C_VSTAT_BITS 8
+
+/* Define the following constant to include a DMA controller. */
+/* #define C_DMA */
+
+/* Define the following constant if 2 or more DMA channels are required. */
+/* #define C_DMA2 */
+
+/* Define the following constant if 3 or more DMA channels are required. */
+/* #define C_DMA3 */
+
+/* Define the following constant if 4 or more DMA channels are required. */
+/* #define C_DMA4 */
+
+/* Define the following constant if 5 or more DMA channels are required. */
+/* #define C_DMA5 */
+
+/* Define the following constant if 6 or more DMA channels are required. */
+/* #define C_DMA6 */
+
+/* Define the following constant if 7 or more DMA channels are required. */
+/* #define C_DMA7 */
+
+/* Define the following constant if 8 or more DMA channels are required. */
+/* #define C_DMA8 */
+
+/* Enable Dynamic FIFO Sizing */
+#define MUSB_C_DYNFIFO_DEF
+
+/* Derived constants. The following constants are derived from the previous
+ * configuration constants
+ */
+
+/* Total number of endpoints. Legal values are 2 - 16. This must be equal to
+ * the larger of C_NUM_EPT, C_NUM_EPR
+ */
+/* #define MUSB_C_NUM_EPS 5 */
+
+/* C_EPMAX_BITS is equal to the largest endpoint FIFO word address bits */
+#define MUSB_C_EPMAX_BITS 11
+
+/* C_RAM_BITS is the number of address bits required to address the RAM (32-bit
+ * addresses).  It is defined as log2 of the sum of 2** of all the endpoint FIFO
+ * dword address bits (rounded up).
+ */
+#define MUSB_C_RAM_BITS 12
+
+#endif /* CONFIG_USB_TUSB6010 */
+
+#endif /* __TUSB6010_H__ */
diff --git a/drivers/usb/musb/tusb6010_omap.c b/drivers/usb/musb/tusb6010_omap.c
new file mode 100644 (file)
index 0000000..07f9efe
--- /dev/null
@@ -0,0 +1,684 @@
+/*
+ * TUSB6010 USB 2.0 OTG Dual Role controller OMAP DMA interface
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Tony Lindgren <tony@atomide.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/usb.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <asm/arch/dma.h>
+#include <asm/arch/mux.h>
+
+#include "musbdefs.h"
+
+/*
+ * REVISIT: With TUSB2.0 only one dmareq line can be used at a time.
+ * This should get fixed in hardware at some point.
+ */
+#define BROKEN_DMAREQ
+
+#ifdef BROKEN_DMAREQ
+#define dmareq_works()         0
+#else
+#define dmareq_works()         1
+#endif
+
+#define to_chdat(c)            (struct tusb_omap_dma_ch *)(c)->pPrivateData
+
+#define MAX_DMAREQ             5       /* REVISIT: Really 6, but req5 not OK */
+
+struct tusb_omap_dma_ch {
+       struct musb             *musb;
+       void __iomem            *tusb_base;
+       unsigned long           phys_offset;
+       int                     epnum;
+       u8                      tx;
+       struct musb_hw_ep       *hw_ep;
+
+       int                     ch;
+       s8                      dmareq;
+       s8                      sync_dev;
+
+       struct tusb_omap_dma    *tusb_dma;
+
+       void __iomem            *dma_addr;
+
+       u32                     len;
+       u16                     packet_sz;
+       u16                     transfer_packet_sz;
+       u32                     transfer_len;
+       u32                     completed_len;
+};
+
+struct tusb_omap_dma {
+       struct dma_controller           controller;
+       struct musb                     *musb;
+       void __iomem                    *tusb_base;
+
+       int                             ch;
+       s8                              dmareq;
+       s8                              sync_dev;
+};
+
+static int tusb_omap_dma_start(struct dma_controller *c)
+{
+       struct tusb_omap_dma    *tusb_dma;
+
+       tusb_dma = container_of(c, struct tusb_omap_dma, controller);
+
+       // DBG(3, "ep%i ch: %i\n", chdat->epnum, chdat->ch);
+
+       return 0;
+}
+
+static int tusb_omap_dma_stop(struct dma_controller *c)
+{
+       struct tusb_omap_dma    *tusb_dma;
+
+       tusb_dma = container_of(c, struct tusb_omap_dma, controller);
+
+       // DBG(3, "ep%i ch: %i\n", chdat->epnum, chdat->ch);
+
+       return 0;
+}
+
+#ifdef BROKEN_DMAREQ
+
+/*
+ * Allocate dmareq0 to the current channel unless it's already taken
+ */
+static inline int tusb_omap_use_shared_dmareq(struct tusb_omap_dma_ch *chdat)
+{
+       u32             reg = musb_readl(chdat->tusb_base, TUSB_DMA_EP_MAP);
+
+       if (reg != 0) {
+               DBG(3, "ep%i dmareq0 is busy for ep%i\n",
+                       chdat->epnum, reg & 0xf);
+               return -EAGAIN;
+       }
+
+       if (chdat->tx)
+               reg = (1 << 4) | chdat->epnum;
+       else
+               reg = chdat->epnum;
+
+       musb_writel(chdat->tusb_base, TUSB_DMA_EP_MAP, reg);
+
+       return 0;
+}
+
+static inline void tusb_omap_free_shared_dmareq(struct tusb_omap_dma_ch *chdat)
+{
+       u32             reg = musb_readl(chdat->tusb_base, TUSB_DMA_EP_MAP);
+
+       if ((reg & 0xf) != chdat->epnum) {
+               printk(KERN_ERR "ep%i trying to release dmareq0 for ep%i\n",
+                       chdat->epnum, reg & 0xf);
+               return;
+       }
+       musb_writel(chdat->tusb_base, TUSB_DMA_EP_MAP, 0);
+}
+
+#else
+#define tusb_omap_use_shared_dmareq(x, y)      do {} while (0)
+#define tusb_omap_free_shared_dmareq(x, y)     do {} while (0)
+#endif
+
+/*
+ * See also musb_dma_completion in plat_uds.c and musb_g_[tx|rx]() in
+ * musb_gadget.c.
+ */
+static void tusb_omap_dma_cb(int lch, u16 ch_status, void *data)
+{
+       struct dma_channel      *channel = (struct dma_channel *)data;
+       struct tusb_omap_dma_ch *chdat = to_chdat(channel);
+       struct tusb_omap_dma    *tusb_dma = chdat->tusb_dma;
+       struct musb             *musb = chdat->musb;
+       struct musb_hw_ep       *hw_ep = chdat->hw_ep;
+       void __iomem            *ep_conf = hw_ep->conf;
+       void __iomem            *musb_base = musb->pRegs;
+       unsigned long           remaining, flags;
+       int                     ch;
+
+       spin_lock_irqsave(&musb->Lock, flags);
+
+       if (dmareq_works())
+               ch = chdat->ch;
+       else
+               ch = tusb_dma->ch;
+
+       if (ch_status != OMAP_DMA_BLOCK_IRQ)
+               printk(KERN_ERR "TUSB DMA error status: %i\n", ch_status);
+
+       DBG(2, "ep%i %s dma callback ch: %i status: %x\n",
+               chdat->epnum, chdat->tx ? "tx" : "rx",
+               ch, ch_status);
+
+       if (chdat->tx)
+               remaining = musb_readl(ep_conf, TUSB_EP_TX_OFFSET);
+       else
+               remaining = musb_readl(ep_conf, TUSB_EP_RX_OFFSET);
+
+       remaining = TUSB_EP_CONFIG_XFR_SIZE(remaining);
+       channel->dwActualLength = chdat->transfer_len - remaining;
+
+       DBG(2, "remaining %lu/%u\n", remaining, chdat->transfer_len);
+
+       if (!dmareq_works())
+               tusb_omap_free_shared_dmareq(chdat);
+
+       channel->bStatus = MGC_DMA_STATUS_FREE;
+
+       /* Handle only RX callbacks here. TX callbacks musb be handled based
+        * on the TUSB DMA status interrupt.
+        * REVISIT: Use both TUSB DMA status interrupt and OMAP DMA callback
+        * interrupt for RX and TX.
+        */
+       if (!chdat->tx)
+               musb_dma_completion(musb, chdat->epnum, chdat->tx);
+
+       /* We musb terminate short tx transfers manually by setting TXPKTRDY.
+        * REVISIT: This same problem may occur with other MUSB dma as well.
+        * Easy to test with g_ether by pinging the MUSB board with ping -s54.
+        */
+       if ((chdat->transfer_len < chdat->packet_sz)
+                       || (chdat->transfer_len % chdat->packet_sz != 0)) {
+               u16     csr;
+
+               if (chdat->tx) {
+                       DBG(2, "terminating short tx packet\n");
+                       MGC_SelectEnd(musb_base, chdat->epnum);
+                       csr = musb_readw(hw_ep->regs, MGC_O_HDRC_TXCSR);
+                       csr |= MGC_M_TXCSR_MODE | MGC_M_TXCSR_TXPKTRDY
+                               | MGC_M_TXCSR_P_WZC_BITS;
+                       musb_writew(hw_ep->regs, MGC_O_HDRC_TXCSR, csr);
+               }
+       }
+
+       spin_unlock_irqrestore(&musb->Lock, flags);
+}
+
+static int tusb_omap_dma_program(struct dma_channel *channel, u16 packet_sz,
+                               u8 rndis_mode, dma_addr_t dma_addr, u32 len)
+{
+       struct tusb_omap_dma_ch         *chdat = to_chdat(channel);
+       struct tusb_omap_dma            *tusb_dma = chdat->tusb_dma;
+       struct musb                     *musb = chdat->musb;
+       struct musb_hw_ep               *hw_ep = chdat->hw_ep;
+       void __iomem                    *musb_base = musb->pRegs;
+       void __iomem                    *ep_conf = hw_ep->conf;
+       dma_addr_t                      fifo = hw_ep->fifo_sync;
+       struct omap_dma_channel_params  dma_params;
+       int                             src_burst, dst_burst;
+       u16                             csr;
+       int                             ch;
+       s8                              dmareq;
+       s8                              sync_dev;
+
+       if (unlikely(dma_addr & 0x1))
+               return FALSE;
+       if (len < 32)
+               return FALSE;
+       if ((len % 32 != 0))
+               return FALSE;
+       else
+               chdat->transfer_len = len;
+
+       if (len < packet_sz)
+               chdat->transfer_packet_sz = chdat->transfer_len;
+       else
+               chdat->transfer_packet_sz = packet_sz;
+
+       if (dmareq_works()) {
+               ch = chdat->ch;
+               dmareq = chdat->dmareq;
+               sync_dev = chdat->sync_dev;
+       } else {
+               if (tusb_omap_use_shared_dmareq(chdat) != 0) {
+                       DBG(3, "could not get dma for ep%i\n", chdat->epnum);
+                       return FALSE;
+               }
+               if (tusb_dma->ch < 0) {
+                       /* REVISIT: This should get blocked earlier, happens
+                        * with MSC ErrorRecoveryTest
+                        */
+                       WARN_ON(1);
+                       return FALSE;
+               }
+
+               ch = tusb_dma->ch;
+               dmareq = tusb_dma->dmareq;
+               sync_dev = tusb_dma->sync_dev;
+               omap_set_dma_callback(ch, tusb_omap_dma_cb, channel);
+       }
+
+       chdat->packet_sz = packet_sz;
+       chdat->len = len;
+       channel->dwActualLength = 0;
+       chdat->dma_addr = (void __iomem *)dma_addr;
+       channel->bStatus = MGC_DMA_STATUS_BUSY;
+
+       /* Since we're recycling dma areas, we need to clean or invalidate */
+       if (chdat->tx) {
+               consistent_sync(phys_to_virt(dma_addr), len, DMA_TO_DEVICE);
+       } else
+               consistent_sync(phys_to_virt(dma_addr), len, DMA_FROM_DEVICE);
+
+       /* Use 16-bit transfer if dma_addr is not 32-bit aligned */
+       if ((dma_addr & 0x3) == 0) {
+               dma_params.data_type = OMAP_DMA_DATA_TYPE_S32;
+               dma_params.elem_count = 8;              /* Elements in frame */
+       } else {
+               dma_params.data_type = OMAP_DMA_DATA_TYPE_S16;
+               dma_params.elem_count = 16;             /* Elements in frame */
+               fifo = hw_ep->fifo_async;
+       }
+
+       dma_params.frame_count  = chdat->transfer_len / 32; /* Burst sz frame */
+
+       DBG(2, "ep%i %s dma ch%i dma: %08x len: %u(%u) packet_sz: %i(%i)\n",
+               chdat->epnum, chdat->tx ? "tx" : "rx",
+               ch, dma_addr, chdat->transfer_len, len,
+               chdat->transfer_packet_sz, packet_sz);
+
+       /*
+        * Prepare omap DMA for transfer
+        */
+       if (chdat->tx) {
+               dma_params.src_amode    = OMAP_DMA_AMODE_POST_INC;
+               dma_params.src_start    = (unsigned long)dma_addr;
+               dma_params.src_ei       = 0;
+               dma_params.src_fi       = 0;
+
+               dma_params.dst_amode    = OMAP_DMA_AMODE_DOUBLE_IDX;
+               dma_params.dst_start    = (unsigned long)fifo;
+               dma_params.dst_ei       = 1;
+               dma_params.dst_fi       = -31;          /* Loop 32 byte window */
+
+               dma_params.trigger      = sync_dev;
+               dma_params.sync_mode    = OMAP_DMA_SYNC_FRAME;
+               dma_params.src_or_dst_synch     = 0;    /* Dest sync */
+
+               src_burst = OMAP_DMA_DATA_BURST_16;     /* 16x32 read */
+               dst_burst = OMAP_DMA_DATA_BURST_8;      /* 8x32 write */
+       } else {
+               dma_params.src_amode    = OMAP_DMA_AMODE_DOUBLE_IDX;
+               dma_params.src_start    = (unsigned long)fifo;
+               dma_params.src_ei       = 1;
+               dma_params.src_fi       = -31;          /* Loop 32 byte window */
+
+               dma_params.dst_amode    = OMAP_DMA_AMODE_POST_INC;
+               dma_params.dst_start    = (unsigned long)dma_addr;
+               dma_params.dst_ei       = 0;
+               dma_params.dst_fi       = 0;
+
+               dma_params.trigger      = sync_dev;
+               dma_params.sync_mode    = OMAP_DMA_SYNC_FRAME;
+               dma_params.src_or_dst_synch     = 1;    /* Source sync */
+
+               src_burst = OMAP_DMA_DATA_BURST_8;      /* 8x32 read */
+               dst_burst = OMAP_DMA_DATA_BURST_16;     /* 16x32 write */
+       }
+
+       DBG(2, "ep%i %s using %i-bit %s dma from 0x%08lx to 0x%08lx\n",
+               chdat->epnum, chdat->tx ? "tx" : "rx",
+               (dma_params.data_type == OMAP_DMA_DATA_TYPE_S32) ? 32 : 16,
+               ((dma_addr & 0x3) == 0) ? "sync" : "async",
+               dma_params.src_start, dma_params.dst_start);
+
+       omap_set_dma_params(ch, &dma_params);
+       omap_set_dma_src_burst_mode(ch, src_burst);
+       omap_set_dma_dest_burst_mode(ch, dst_burst);
+       omap_set_dma_write_mode(ch, OMAP_DMA_WRITE_LAST_NON_POSTED);
+
+       /*
+        * Prepare MUSB for DMA transfer
+        */
+       if (chdat->tx) {
+               MGC_SelectEnd(musb_base, chdat->epnum);
+               csr = musb_readw(hw_ep->regs, MGC_O_HDRC_TXCSR);
+               csr |= (MGC_M_TXCSR_AUTOSET | MGC_M_TXCSR_DMAENAB
+                       | MGC_M_TXCSR_DMAMODE | MGC_M_TXCSR_MODE);
+               csr &= ~MGC_M_TXCSR_P_UNDERRUN;
+               musb_writew(hw_ep->regs, MGC_O_HDRC_TXCSR, csr);
+       } else {
+               MGC_SelectEnd(musb_base, chdat->epnum);
+               csr = musb_readw(hw_ep->regs, MGC_O_HDRC_RXCSR);
+               csr |= MGC_M_RXCSR_DMAENAB;
+               csr &= ~(MGC_M_RXCSR_AUTOCLEAR | MGC_M_RXCSR_DMAMODE);
+               musb_writew(hw_ep->regs, MGC_O_HDRC_RXCSR,
+                       csr | MGC_M_RXCSR_P_WZC_BITS);
+       }
+
+       /*
+        * Start DMA transfer
+        */
+       omap_start_dma(ch);
+
+       if (chdat->tx) {
+               /* Send transfer_packet_sz packets at a time */
+               musb_writel(ep_conf, TUSB_EP_MAX_PACKET_SIZE_OFFSET,
+                       chdat->transfer_packet_sz);
+
+               musb_writel(ep_conf, TUSB_EP_TX_OFFSET,
+                       TUSB_EP_CONFIG_XFR_SIZE(chdat->transfer_len));
+       } else {
+               /* Receive transfer_packet_sz packets at a time */
+               musb_writel(ep_conf, TUSB_EP_MAX_PACKET_SIZE_OFFSET,
+                       chdat->transfer_packet_sz << 16);
+
+               musb_writel(ep_conf, TUSB_EP_RX_OFFSET,
+                       TUSB_EP_CONFIG_XFR_SIZE(chdat->transfer_len));
+       }
+
+       return TRUE;
+}
+
+static int tusb_omap_dma_abort(struct dma_channel *channel)
+{
+       struct tusb_omap_dma_ch *chdat = to_chdat(channel);
+       struct tusb_omap_dma    *tusb_dma = chdat->tusb_dma;
+
+       if (!dmareq_works()) {
+               if (tusb_dma->ch >= 0) {
+                       omap_stop_dma(tusb_dma->ch);
+                       omap_free_dma(tusb_dma->ch);
+                       tusb_dma->ch = -1;
+               }
+
+               tusb_dma->dmareq = -1;
+               tusb_dma->sync_dev = -1;
+       }
+
+       channel->bStatus = MGC_DMA_STATUS_FREE;
+
+       return 0;
+}
+
+static inline int tusb_omap_dma_allocate_dmareq(struct tusb_omap_dma_ch *chdat)
+{
+       u32             reg = musb_readl(chdat->tusb_base, TUSB_DMA_EP_MAP);
+       int             i, dmareq_nr = -1;
+
+       const int sync_dev[6] = {
+               OMAP24XX_DMA_EXT_DMAREQ0,
+               OMAP24XX_DMA_EXT_DMAREQ1,
+               OMAP24XX_DMA_EXT_DMAREQ2,
+               OMAP24XX_DMA_EXT_DMAREQ3,
+               OMAP24XX_DMA_EXT_DMAREQ4,
+               OMAP24XX_DMA_EXT_DMAREQ5,
+       };
+
+       for (i = 0; i < MAX_DMAREQ; i++) {
+               int cur = (reg & (0xf << (i * 5))) >> (i * 5);
+               if (cur == 0) {
+                       dmareq_nr = i;
+                       break;
+               }
+       }
+
+       if (dmareq_nr == -1)
+               return -EAGAIN;
+
+       reg |= (chdat->epnum << (dmareq_nr * 5));
+       if (chdat->tx)
+               reg |= ((1 << 4) << (dmareq_nr * 5));
+       musb_writel(chdat->tusb_base, TUSB_DMA_EP_MAP, reg);
+
+       chdat->dmareq = dmareq_nr;
+       chdat->sync_dev = sync_dev[chdat->dmareq];
+
+       return 0;
+}
+
+static inline void tusb_omap_dma_free_dmareq(struct tusb_omap_dma_ch *chdat)
+{
+       u32 reg;
+
+       if (!chdat || chdat->dmareq < 0)
+               return;
+
+       reg = musb_readl(chdat->tusb_base, TUSB_DMA_EP_MAP);
+       reg &= ~(0x1f << (chdat->dmareq * 5));
+       musb_writel(chdat->tusb_base, TUSB_DMA_EP_MAP, reg);
+
+       chdat->dmareq = -1;
+       chdat->sync_dev = -1;
+}
+
+static struct dma_channel *dma_channel_pool[MAX_DMAREQ];
+
+static struct dma_channel *
+tusb_omap_dma_allocate(struct dma_controller *c,
+               struct musb_hw_ep *hw_ep,
+               u8 tx)
+{
+       int ret, i;
+       const char              *dev_name;
+       struct tusb_omap_dma    *tusb_dma;
+       struct musb             *musb;
+       void __iomem            *tusb_base;
+       struct dma_channel      *channel = NULL;
+       struct tusb_omap_dma_ch *chdat = NULL;
+       u32                     reg;
+
+       tusb_dma = container_of(c, struct tusb_omap_dma, controller);
+       musb = tusb_dma->musb;
+       tusb_base = musb->ctrl_base;
+
+       reg = musb_readl(tusb_base, TUSB_DMA_INT_MASK);
+       if (tx)
+               reg &= ~(1 << hw_ep->bLocalEnd);
+       else
+               reg &= ~(1 << (hw_ep->bLocalEnd + 15));
+       musb_writel(tusb_base, TUSB_DMA_INT_MASK, reg);
+
+       /* REVISIT: Why does dmareq5 not work? */
+       if (hw_ep->bLocalEnd == 0) {
+               DBG(3, "Not allowing DMA for ep0 %s\n", tx ? "tx" : "rx");
+               return NULL;
+       }
+
+       for (i = 0; i < MAX_DMAREQ; i++) {
+               struct dma_channel *ch = dma_channel_pool[i];
+               if (ch->bStatus == MGC_DMA_STATUS_UNKNOWN) {
+                       ch->bStatus = MGC_DMA_STATUS_FREE;
+                       channel = ch;
+                       chdat = ch->pPrivateData;
+                       break;
+               }
+       }
+
+       if (!channel)
+               return NULL;
+
+       if (tx) {
+               chdat->tx = 1;
+               dev_name = "TUSB transmit";
+       } else {
+               chdat->tx = 0;
+               dev_name = "TUSB receive";
+       }
+
+       chdat->musb = tusb_dma->musb;
+       chdat->tusb_base = tusb_dma->tusb_base;
+       chdat->hw_ep = hw_ep;
+       chdat->epnum = hw_ep->bLocalEnd;
+       chdat->dmareq = -1;
+       chdat->completed_len = 0;
+       chdat->tusb_dma = tusb_dma;
+
+       channel->dwMaxLength = 0x7fffffff;
+       channel->bDesiredMode = 0;
+       channel->dwActualLength = 0;
+
+       if (dmareq_works()) {
+               ret = tusb_omap_dma_allocate_dmareq(chdat);
+               if (ret != 0)
+                       goto free_dmareq;
+
+               ret = omap_request_dma(chdat->sync_dev, dev_name,
+                               tusb_omap_dma_cb, channel, &chdat->ch);
+               if (ret != 0)
+                       goto free_dmareq;
+       } else if (tusb_dma->ch == -1) {
+               tusb_dma->dmareq = 0;
+               tusb_dma->sync_dev = OMAP24XX_DMA_EXT_DMAREQ0;
+
+               /* Callback data gets set later in the shared dmareq case */
+               ret = omap_request_dma(tusb_dma->sync_dev, "TUSB shared",
+                               tusb_omap_dma_cb, NULL, &tusb_dma->ch);
+               if (ret != 0)
+                       goto free_dmareq;
+
+               chdat->dmareq = -1;
+               chdat->ch = -1;
+       }
+
+       DBG(3, "ep%i %s dma: %s dma%i dmareq%i sync%i\n",
+               chdat->epnum,
+               chdat->tx ? "tx" : "rx",
+               chdat->ch >=0 ? "dedicated" : "shared",
+               chdat->ch >= 0 ? chdat->ch : tusb_dma->ch,
+               chdat->dmareq >= 0 ? chdat->dmareq : tusb_dma->dmareq,
+               chdat->sync_dev >= 0 ? chdat->sync_dev : tusb_dma->sync_dev);
+
+       return channel;
+
+free_dmareq:
+       tusb_omap_dma_free_dmareq(chdat);
+
+       DBG(3, "ep%i: Could not get a DMA channel\n", chdat->epnum);
+       channel->bStatus = MGC_DMA_STATUS_UNKNOWN;
+
+       return NULL;
+}
+
+static void tusb_omap_dma_release(struct dma_channel *channel)
+{
+       struct tusb_omap_dma_ch *chdat = to_chdat(channel);
+       struct musb             *musb = chdat->musb;
+       void __iomem            *tusb_base = musb->ctrl_base;
+       u32                     reg;
+
+       DBG(3, "ep%i ch%i\n", chdat->epnum, chdat->ch);
+
+       reg = musb_readl(tusb_base, TUSB_DMA_INT_MASK);
+       if (chdat->tx)
+               reg |= (1 << chdat->epnum);
+       else
+               reg |= (1 << (chdat->epnum + 15));
+       musb_writel(tusb_base, TUSB_DMA_INT_MASK, reg);
+
+       reg = musb_readl(tusb_base, TUSB_DMA_INT_CLEAR);
+       if (chdat->tx)
+               reg |= (1 << chdat->epnum);
+       else
+               reg |= (1 << (chdat->epnum + 15));
+       musb_writel(tusb_base, TUSB_DMA_INT_CLEAR, reg);
+
+       channel->bStatus = MGC_DMA_STATUS_UNKNOWN;
+
+       if (chdat->ch >= 0) {
+               omap_stop_dma(chdat->ch);
+               omap_free_dma(chdat->ch);
+               chdat->ch = -1;
+       }
+
+       if (chdat->dmareq >= 0)
+               tusb_omap_dma_free_dmareq(chdat);
+
+       channel = NULL;
+}
+
+void dma_controller_destroy(struct dma_controller *c)
+{
+       struct tusb_omap_dma    *tusb_dma;
+       int                     i;
+
+       tusb_dma = container_of(c, struct tusb_omap_dma, controller);
+       for (i = 0; i < MAX_DMAREQ; i++) {
+               struct dma_channel *ch = dma_channel_pool[i];
+               if (ch) {
+                       if (ch->pPrivateData)
+                               kfree(ch->pPrivateData);
+                       kfree(ch);
+               }
+       }
+
+       if (!dmareq_works() && tusb_dma && tusb_dma->ch >= 0)
+               omap_free_dma(tusb_dma->ch);
+
+       kfree(tusb_dma);
+}
+
+struct dma_controller *__init
+dma_controller_create(struct musb *musb, void __iomem *base)
+{
+       void __iomem            *tusb_base = musb->ctrl_base;
+       struct tusb_omap_dma    *tusb_dma;
+       int                     i;
+
+       /* REVISIT: Get dmareq lines used from board-*.c */
+
+       musb_writel(musb->ctrl_base, TUSB_DMA_INT_MASK, 0x7fffffff);
+       musb_writel(musb->ctrl_base, TUSB_DMA_EP_MAP, 0);
+
+       musb_writel(tusb_base, TUSB_DMA_REQ_CONF,
+               TUSB_DMA_REQ_CONF_BURST_SIZE(2)
+               | TUSB_DMA_REQ_CONF_DMA_REQ_EN(0x3f)
+               | TUSB_DMA_REQ_CONF_DMA_REQ_ASSER(2));
+
+       tusb_dma = kzalloc(sizeof(struct tusb_omap_dma), GFP_KERNEL);
+       if (!tusb_dma)
+               goto cleanup;
+
+       tusb_dma->musb = musb;
+       tusb_dma->tusb_base = musb->ctrl_base;
+
+       tusb_dma->ch = -1;
+       tusb_dma->dmareq = -1;
+       tusb_dma->sync_dev = -1;
+
+       tusb_dma->controller.start = tusb_omap_dma_start;
+       tusb_dma->controller.stop = tusb_omap_dma_stop;
+       tusb_dma->controller.channel_alloc = tusb_omap_dma_allocate;
+       tusb_dma->controller.channel_release = tusb_omap_dma_release;
+       tusb_dma->controller.channel_program = tusb_omap_dma_program;
+       tusb_dma->controller.channel_abort = tusb_omap_dma_abort;
+       tusb_dma->controller.pPrivateData = tusb_dma;
+
+       for (i = 0; i < MAX_DMAREQ; i++) {
+               struct dma_channel      *ch;
+               struct tusb_omap_dma_ch *chdat;
+
+               ch = kzalloc(sizeof(struct dma_channel), GFP_KERNEL);
+               if (!ch)
+                       goto cleanup;
+
+               dma_channel_pool[i] = ch;
+
+               chdat = kzalloc(sizeof(struct tusb_omap_dma_ch), GFP_KERNEL);
+               if (!chdat)
+                       goto cleanup;
+
+               ch->bStatus = MGC_DMA_STATUS_UNKNOWN;
+               ch->pPrivateData = chdat;
+       }
+
+       return &tusb_dma->controller;
+
+cleanup:
+       dma_controller_destroy(&tusb_dma->controller);
+
+       return NULL;
+}
diff --git a/drivers/usb/musb/virthub.c b/drivers/usb/musb/virthub.c
new file mode 100644 (file)
index 0000000..41ae741
--- /dev/null
@@ -0,0 +1,384 @@
+/*****************************************************************
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ * Copyright (C) 2006 by Nokia Corporation
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * The Inventra Controller Driver for Linux is free software; you
+ * can redistribute it and/or modify it under the terms of the GNU
+ * General Public License version 2 as published by the Free Software
+ * Foundation.
+ *
+ * The Inventra Controller Driver for Linux is distributed in
+ * the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Inventra Controller Driver for Linux ; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ANY DOWNLOAD, USE, REPRODUCTION, MODIFICATION OR DISTRIBUTION
+ * OF THIS DRIVER INDICATES YOUR COMPLETE AND UNCONDITIONAL ACCEPTANCE
+ * OF THOSE TERMS.THIS DRIVER IS PROVIDED "AS IS" AND MENTOR GRAPHICS
+ * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, RELATED TO THIS DRIVER.
+ * MENTOR GRAPHICS SPECIFICALLY DISCLAIMS ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY; FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT.  MENTOR GRAPHICS DOES NOT PROVIDE SUPPORT
+ * SERVICES OR UPDATES FOR THIS DRIVER, EVEN IF YOU ARE A MENTOR
+ * GRAPHICS SUPPORT CUSTOMER.
+ ******************************************************************/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/timer.h>
+
+#include "musbdefs.h"
+
+
+static void musb_port_suspend(struct musb *musb, u8 bSuspend)
+{
+       u8              power;
+       void __iomem    *pBase = musb->pRegs;
+
+       if (!is_host_active(musb))
+               return;
+
+       /* NOTE:  this doesn't necessarily put PHY into low power mode,
+        * turning off its clock; that's a function of PHY integration and
+        * MGC_M_POWER_ENSUSPEND.  PHY may need a clock (sigh) to detect
+        * SE0 changing to connect (J) or wakeup (K) states.
+        */
+       power = musb_readb(pBase, MGC_O_HDRC_POWER);
+       if (bSuspend) {
+               power &= ~MGC_M_POWER_RESUME;
+               power |= MGC_M_POWER_SUSPENDM;
+               musb_writeb(pBase, MGC_O_HDRC_POWER, power);
+
+               DBG(3, "Root port suspended, power %02x\n", power);
+
+               musb->port1_status |= USB_PORT_STAT_SUSPEND;
+               switch (musb->xceiv.state) {
+               case OTG_STATE_A_HOST:
+                       musb->xceiv.state = OTG_STATE_A_SUSPEND;
+                       musb->is_active = is_otg_enabled(musb)
+                                       && musb->xceiv.host->b_hnp_enable;
+                       musb_platform_try_idle(musb);
+                       break;
+               case OTG_STATE_B_HOST:
+                       musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
+                       MUSB_DEV_MODE(musb);
+                       /* REVISIT restore setting of MGC_M_DEVCTL_HR */
+                       break;
+               default:
+                       DBG(1, "bogus rh suspend? %s\n",
+                               otg_state_string(musb));
+               }
+       } else if (power & MGC_M_POWER_SUSPENDM) {
+               power &= ~MGC_M_POWER_SUSPENDM;
+               power |= MGC_M_POWER_RESUME;
+               musb_writeb(pBase, MGC_O_HDRC_POWER, power);
+
+               DBG(3, "Root port resuming, power %02x\n", power);
+
+               /* later, GetPortStatus will stop RESUME signaling */
+               musb->port1_status |= MUSB_PORT_STAT_RESUME;
+               musb->rh_timer = jiffies + msecs_to_jiffies(20);
+       }
+}
+
+static void musb_port_reset(struct musb *musb, u8 bReset)
+{
+       u8              power;
+       void __iomem    *pBase = musb->pRegs;
+
+#ifdef CONFIG_USB_MUSB_OTG
+       /* REVISIT this looks wrong for HNP */
+       u8 devctl = musb_readb(pBase, MGC_O_HDRC_DEVCTL);
+
+       if (musb->bDelayPortPowerOff || !(devctl & MGC_M_DEVCTL_HM)) {
+               return;
+       }
+#endif
+
+       if (!is_host_active(musb))
+               return;
+
+       /* NOTE:  caller guarantees it will turn off the reset when
+        * the appropriate amount of time has passed
+        */
+       power = musb_readb(pBase, MGC_O_HDRC_POWER);
+       if (bReset) {
+               musb->bIgnoreDisconnect = TRUE;
+               power &= 0xf0;
+               musb_writeb(pBase, MGC_O_HDRC_POWER,
+                               power | MGC_M_POWER_RESET);
+
+               musb->port1_status |= USB_PORT_STAT_RESET;
+               musb->port1_status &= ~USB_PORT_STAT_ENABLE;
+               musb->rh_timer = jiffies + msecs_to_jiffies(50);
+       } else {
+               DBG(4, "root port reset stopped\n");
+               musb_writeb(pBase, MGC_O_HDRC_POWER,
+                               power & ~MGC_M_POWER_RESET);
+
+               musb->bIgnoreDisconnect = FALSE;
+
+               power = musb_readb(pBase, MGC_O_HDRC_POWER);
+               if (power & MGC_M_POWER_HSMODE) {
+                       DBG(4, "high-speed device connected\n");
+                       musb->port1_status |= USB_PORT_STAT_HIGH_SPEED;
+               }
+
+               musb->port1_status &= ~USB_PORT_STAT_RESET;
+               musb->port1_status |= USB_PORT_STAT_ENABLE
+                                       | (USB_PORT_STAT_C_RESET << 16)
+                                       | (USB_PORT_STAT_C_ENABLE << 16);
+               usb_hcd_poll_rh_status(musb_to_hcd(musb));
+
+               musb->vbuserr_retry = VBUSERR_RETRY_COUNT;
+       }
+}
+
+void musb_root_disconnect(struct musb *musb)
+{
+       musb->port1_status = (1 << USB_PORT_FEAT_POWER)
+                       | (1 << USB_PORT_FEAT_C_CONNECTION);
+
+       usb_hcd_poll_rh_status(musb_to_hcd(musb));
+       musb->is_active = 0;
+
+       switch (musb->xceiv.state) {
+       case OTG_STATE_A_HOST:
+       case OTG_STATE_A_SUSPEND:
+               musb->xceiv.state = OTG_STATE_A_WAIT_BCON;
+               break;
+       case OTG_STATE_A_WAIT_VFALL:
+               musb->xceiv.state = OTG_STATE_B_IDLE;
+               break;
+       default:
+               DBG(1, "host disconnect (%s)\n", otg_state_string(musb));
+       }
+}
+
+
+/*---------------------------------------------------------------------*/
+
+int musb_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+       struct musb     *musb = hcd_to_musb(hcd);
+       int             retval = 0;
+
+       /* called in_irq() via usb_hcd_poll_rh_status() */
+       if (musb->port1_status & 0xffff0000) {
+               *buf = 0x02;
+               retval = 1;
+       }
+       return retval;
+}
+
+int musb_hub_control(
+       struct usb_hcd  *hcd,
+       u16             typeReq,
+       u16             wValue,
+       u16             wIndex,
+       char            *buf,
+       u16             wLength)
+{
+       struct musb     *musb = hcd_to_musb(hcd);
+       u32             temp;
+       int             retval = 0;
+       unsigned long   flags;
+
+       if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)))
+               return -ESHUTDOWN;
+
+       /* hub features:  always zero, setting is a NOP
+        * port features: reported, sometimes updated when host is active
+        * no indicators
+        */
+       spin_lock_irqsave(&musb->Lock, flags);
+       switch (typeReq) {
+       case ClearHubFeature:
+       case SetHubFeature:
+               switch (wValue) {
+               case C_HUB_OVER_CURRENT:
+               case C_HUB_LOCAL_POWER:
+                       break;
+               default:
+                       goto error;
+               }
+               break;
+       case ClearPortFeature:
+               if (wIndex != 1)
+                       goto error;
+
+               switch (wValue) {
+               case USB_PORT_FEAT_ENABLE:
+                       break;
+               case USB_PORT_FEAT_SUSPEND:
+                       musb_port_suspend(musb, FALSE);
+                       break;
+               case USB_PORT_FEAT_POWER:
+                       if (!(is_otg_enabled(musb) && hcd->self.is_b_host))
+                               musb_set_vbus(musb, 0);
+                       break;
+               case USB_PORT_FEAT_C_CONNECTION:
+               case USB_PORT_FEAT_C_ENABLE:
+               case USB_PORT_FEAT_C_OVER_CURRENT:
+               case USB_PORT_FEAT_C_RESET:
+               case USB_PORT_FEAT_C_SUSPEND:
+                       break;
+               default:
+                       goto error;
+               }
+               DBG(5, "clear feature %d\n", wValue);
+               musb->port1_status &= ~(1 << wValue);
+               break;
+       case GetHubDescriptor:
+               {
+               struct usb_hub_descriptor *desc = (void *)buf;
+
+               desc->bDescLength = 9;
+               desc->bDescriptorType = 0x29;
+               desc->bNbrPorts = 1;
+               desc->wHubCharacteristics = __constant_cpu_to_le16(
+                                 0x0001        /* per-port power switching */
+                               | 0x0010        /* no overcurrent reporting */
+                               );
+               desc->bPwrOn2PwrGood = 5;       /* msec/2 */
+               desc->bHubContrCurrent = 0;
+
+               /* workaround bogus struct definition */
+               desc->DeviceRemovable[0] = 0x02;        /* port 1 */
+               desc->DeviceRemovable[1] = 0xff;
+               }
+               break;
+       case GetHubStatus:
+               temp = 0;
+               *(__le32 *) buf = cpu_to_le32 (temp);
+               break;
+       case GetPortStatus:
+               if (wIndex != 1)
+                       goto error;
+
+               /* finish RESET signaling? */
+               if ((musb->port1_status & USB_PORT_STAT_RESET)
+                               && time_after(jiffies, musb->rh_timer))
+                       musb_port_reset(musb, FALSE);
+
+               /* finish RESUME signaling? */
+               if ((musb->port1_status & MUSB_PORT_STAT_RESUME)
+                               && time_after(jiffies, musb->rh_timer)) {
+                       u8              power;
+
+                       power = musb_readb(musb->pRegs, MGC_O_HDRC_POWER);
+                       power &= ~MGC_M_POWER_RESUME;
+                       DBG(4, "root port resume stopped, power %02x\n",
+                                       power);
+                       musb_writeb(musb->pRegs, MGC_O_HDRC_POWER, power);
+
+                       /* ISSUE:  DaVinci (RTL 1.300) disconnects after
+                        * resume of high speed peripherals (but not full
+                        * speed ones).
+                        */
+
+                       musb->is_active = 1;
+                       musb->port1_status &= ~(USB_PORT_STAT_SUSPEND
+                                       | MUSB_PORT_STAT_RESUME);
+                       musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16;
+                       usb_hcd_poll_rh_status(musb_to_hcd(musb));
+                       /* NOTE: it might really be A_WAIT_BCON ... */
+                       musb->xceiv.state = OTG_STATE_A_HOST;
+               }
+
+               *(__le32 *) buf = cpu_to_le32(musb->port1_status
+                               & ~MUSB_PORT_STAT_RESUME);
+
+               /* port change status is more interesting */
+               DBG((*(u16*)(buf+2)) ? 2 : 5, "port status %08x\n",
+                               musb->port1_status);
+               break;
+       case SetPortFeature:
+               if ((wIndex & 0xff) != 1)
+                       goto error;
+
+               switch (wValue) {
+               case USB_PORT_FEAT_POWER:
+                       /* NOTE: this controller has a strange state machine
+                        * that involves "requesting sessions" according to
+                        * magic side effects from incompletely-described
+                        * rules about startup...
+                        *
+                        * This call is what really starts the host mode; be
+                        * very careful about side effects if you reorder any
+                        * initialization logic, e.g. for OTG, or change any
+                        * logic relating to VBUS power-up.
+                        */
+                       if (!(is_otg_enabled(musb) && hcd->self.is_b_host))
+                               musb_start(musb);
+                       break;
+               case USB_PORT_FEAT_RESET:
+                       musb_port_reset(musb, TRUE);
+                       break;
+               case USB_PORT_FEAT_SUSPEND:
+                       musb_port_suspend(musb, TRUE);
+                       break;
+               case USB_PORT_FEAT_TEST:
+                       if (unlikely(is_host_active(musb)))
+                               goto error;
+
+                       wIndex >>= 8;
+                       switch (wIndex) {
+                       case 1:
+                               pr_debug("TEST_J\n");
+                               temp = MGC_M_TEST_J;
+                               break;
+                       case 2:
+                               pr_debug("TEST_K\n");
+                               temp = MGC_M_TEST_K;
+                               break;
+                       case 3:
+                               pr_debug("TEST_SE0_NAK\n");
+                               temp = MGC_M_TEST_SE0_NAK;
+                               break;
+                       case 4:
+                               pr_debug("TEST_PACKET\n");
+                               temp = MGC_M_TEST_PACKET;
+                               musb_load_testpacket(musb);
+                               break;
+                       case 5:
+                               pr_debug("TEST_FORCE_ENABLE\n");
+                               temp = MGC_M_TEST_FORCE_HOST
+                                       | MGC_M_TEST_FORCE_HS;
+
+                               /* FIXME and enable a session too */
+                               break;
+                       default:
+                               goto error;
+                       }
+                       musb_writeb(musb->pRegs, MGC_O_HDRC_TESTMODE, temp);
+                       break;
+               default:
+                       goto error;
+               }
+               DBG(5, "set feature %d\n", wValue);
+               musb->port1_status |= 1 << wValue;
+               break;
+
+       default:
+error:
+               /* "protocol stall" on error */
+               retval = -EPIPE;
+       }
+       spin_unlock_irqrestore(&musb->Lock, flags);
+       return retval;
+}
index 4e83f01e894efe30b9cca2da83b6ff35b007e61b..64ad6472db5d201b37725875a6c165c090ddc490 100644 (file)
@@ -1646,6 +1646,9 @@ config FB_VIRTUAL
          the vfb_enable=1 option.
 
          If unsure, say N.
+
+source "drivers/video/omap/Kconfig"
+
 if VT
        source "drivers/video/console/Kconfig"
 endif
index 309a26dd164aede2c8bb57874af4bb60e4cb1c92..f144697b3c21d31f829d7f945e0b86f15773c233 100644 (file)
@@ -106,6 +106,7 @@ obj-$(CONFIG_FB_VESA)             += vesafb.o
 obj-$(CONFIG_FB_IMAC)             += imacfb.o
 obj-$(CONFIG_FB_VGA16)            += vga16fb.o vgastate.o
 obj-$(CONFIG_FB_OF)               += offb.o
+obj-$(CONFIG_FB_OMAP)            += omap/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o
 
 # the test framebuffer is last
 obj-$(CONFIG_FB_VIRTUAL)          += vfb.o
index 02f15297a021b1c7902137ee09bed8355e62f412..915844904104b67f9aa25deea95b1ec14bc0fd5f 100644 (file)
@@ -66,3 +66,11 @@ config BACKLIGHT_HP680
          If you have a HP Jornada 680, say y to enable the
          backlight driver.
 
+config BACKLIGHT_OMAP
+       tristate "OMAP LCD Backlight"
+       depends on BACKLIGHT_DEVICE && (ARCH_OMAP1 || ARCH_OMAP2)
+       default y
+       help
+         This driver controls the LCD backlight level and power
+         for the PWL module of OMAP processors.  Say Y if you plan
+         to use power saving.
index 65e5553fc849fed5bcbadb287640313bdfa09b97..c2e0b879fa5c367d6cd745130c1bf71dba80ca83 100644 (file)
@@ -5,3 +5,4 @@ obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o
 obj-$(CONFIG_BACKLIGHT_CORGI)  += corgi_bl.o
 obj-$(CONFIG_BACKLIGHT_HP680)  += hp680_bl.o
 obj-$(CONFIG_BACKLIGHT_LOCOMO) += locomolcd.o
+obj-$(CONFIG_BACKLIGHT_OMAP)   += omap_bl.o
diff --git a/drivers/video/backlight/omap_bl.c b/drivers/video/backlight/omap_bl.c
new file mode 100644 (file)
index 0000000..3b57b27
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * drivers/video/backlight/omap_bl.c
+ *
+ * Backlight driver for OMAP based boards.
+ *
+ * Copyright (c) 2006 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this package; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/fb.h>
+#include <linux/backlight.h>
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/board.h>
+#include <asm/arch/mux.h>
+
+#define OMAPBL_MAX_INTENSITY           0xff
+
+struct omap_backlight {
+       int powermode;
+       int current_intensity;
+
+       struct device *dev;
+       struct omap_backlight_config *pdata;
+};
+
+static void inline omapbl_send_intensity(int intensity)
+{
+       omap_writeb(intensity, OMAP_PWL_ENABLE);
+}
+
+static void inline omapbl_send_enable(int enable)
+{
+       omap_writeb(enable, OMAP_PWL_CLK_ENABLE);
+}
+
+static void omapbl_blank(struct omap_backlight *bl, int mode)
+{
+       if (bl->pdata->set_power)
+               bl->pdata->set_power(bl->dev, mode);
+
+       switch (mode) {
+       case FB_BLANK_NORMAL:
+       case FB_BLANK_VSYNC_SUSPEND:
+       case FB_BLANK_HSYNC_SUSPEND:
+       case FB_BLANK_POWERDOWN:
+               omapbl_send_intensity(0);
+               omapbl_send_enable(0);
+               break;
+
+       case FB_BLANK_UNBLANK:
+               omapbl_send_intensity(bl->current_intensity);
+               omapbl_send_enable(1);
+               break;
+       }
+}
+
+#ifdef CONFIG_PM
+static int omapbl_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct backlight_device *dev = platform_get_drvdata(pdev);
+       struct omap_backlight *bl = class_get_devdata(&dev->class_dev);
+
+       omapbl_blank(bl, FB_BLANK_POWERDOWN);
+       return 0;
+}
+
+static int omapbl_resume(struct platform_device *pdev)
+{
+       struct backlight_device *dev = platform_get_drvdata(pdev);
+       struct omap_backlight *bl = class_get_devdata(&dev->class_dev);
+
+       omapbl_blank(bl, bl->powermode);
+       return 0;
+}
+#else
+#define omapbl_suspend NULL
+#define omapbl_resume  NULL
+#endif
+
+static int omapbl_set_power(struct backlight_device *dev, int state)
+{
+       struct omap_backlight *bl = class_get_devdata(&dev->class_dev);
+
+       omapbl_blank(bl, state);
+       bl->powermode = state;
+
+       return 0;
+}
+
+static int omapbl_update_status(struct backlight_device *dev)
+{
+       struct omap_backlight *bl = class_get_devdata(&dev->class_dev);
+
+       if (bl->current_intensity != dev->props->brightness) {
+               if (dev->props->brightness < 0)
+                       return -EPERM;  /* Leave current_intensity untouched */
+
+               if (bl->powermode == FB_BLANK_UNBLANK)
+                       omapbl_send_intensity(dev->props->brightness);
+               bl->current_intensity = dev->props->brightness;
+       }
+
+       if (dev->props->fb_blank != bl->powermode)
+               omapbl_set_power(dev, dev->props->fb_blank);
+
+       return 0;
+}
+
+static int omapbl_get_intensity(struct backlight_device *dev)
+{
+       struct omap_backlight *bl = class_get_devdata(&dev->class_dev);
+       return bl->current_intensity;
+}
+
+static struct backlight_properties omapbl_data = {
+       .owner          = THIS_MODULE,
+       .get_brightness = omapbl_get_intensity,
+       .update_status  = omapbl_update_status,
+       .max_brightness = OMAPBL_MAX_INTENSITY,
+};
+
+static int omapbl_probe(struct platform_device *pdev)
+{
+       struct backlight_device *dev;
+       struct omap_backlight *bl;
+       struct omap_backlight_config *pdata = pdev->dev.platform_data;
+
+       if (!pdata)
+               return -ENXIO;
+
+       omapbl_data.check_fb = pdata->check_fb;
+
+       bl = kzalloc(sizeof(struct omap_backlight), GFP_KERNEL);
+       if (unlikely(!bl))
+               return -ENOMEM;
+
+       dev = backlight_device_register("omap-bl", &pdev->dev,
+                       bl, &omapbl_data);
+       if (IS_ERR(dev)) {
+               kfree(bl);
+               return PTR_ERR(dev);
+       }
+
+       bl->powermode = FB_BLANK_POWERDOWN;
+       bl->current_intensity = 0;
+
+       bl->pdata = pdata;
+       bl->dev = &pdev->dev;
+
+       platform_set_drvdata(pdev, dev);
+
+       omap_cfg_reg(PWL);      /* Conflicts with UART3 */
+
+       omapbl_data.fb_blank = FB_BLANK_UNBLANK;
+       omapbl_data.brightness = pdata->default_intensity;
+       omapbl_update_status(dev);
+
+       printk(KERN_INFO "OMAP LCD backlight initialised\n");
+
+       return 0;
+}
+
+static int omapbl_remove(struct platform_device *pdev)
+{
+       struct backlight_device *dev = platform_get_drvdata(pdev);
+       struct omap_backlight *bl = class_get_devdata(&dev->class_dev);
+
+       backlight_device_unregister(dev);
+       kfree(bl);
+
+       return 0;
+}
+
+static struct platform_driver omapbl_driver = {
+       .probe          = omapbl_probe,
+       .remove         = omapbl_remove,
+       .suspend        = omapbl_suspend,
+       .resume         = omapbl_resume,
+       .driver         = {
+               .name   = "omap-bl",
+       },
+};
+
+static int __init omapbl_init(void)
+{
+       return platform_driver_register(&omapbl_driver);
+}
+
+static void __exit omapbl_exit(void)
+{
+       platform_driver_unregister(&omapbl_driver);
+}
+
+module_init(omapbl_init);
+module_exit(omapbl_exit);
+
+MODULE_AUTHOR("Andrzej Zaborowski <balrog@zabor.org>");
+MODULE_DESCRIPTION("OMAP LCD Backlight driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/omap/Kconfig b/drivers/video/omap/Kconfig
new file mode 100644 (file)
index 0000000..81256ae
--- /dev/null
@@ -0,0 +1,68 @@
+config FB_OMAP
+       tristate "OMAP frame buffer support (EXPERIMENTAL)"
+        depends on FB
+        help
+          Frame buffer driver for OMAP based boards.
+
+config FB_OMAP_LCDC_EXTERNAL
+       bool "External LCD controller support"
+       depends on FB_OMAP
+       help
+         Say Y here, if you want to have support for boards with an
+         external LCD controller connected to the SoSSI/RFBI interface. 
+
+config FB_OMAP_LCDC_HWA742
+       bool "Epson HWA742 LCD controller support"
+       depends on FB_OMAP && FB_OMAP_LCDC_EXTERNAL
+       help
+         Say Y here if you want to have support for the external
+         Epson HWA742 LCD controller.
+
+config FB_OMAP_MANUAL_UPDATE
+       bool "Default to manual update mode"
+       depends on FB_OMAP && FB_OMAP_LCDC_EXTERNAL
+       help
+         Say Y here, if your user-space applications are capable of
+         notifying the frame buffer driver when a change has occured in
+          the frame buffer content and thus a reload of the image data to
+         the external frame buffer is required. If unsure, say N.
+
+config FB_OMAP_LCD_MIPID
+       bool "MIPI DBI-C/DCS compatible LCD support"
+       select SPI
+       depends on FB_OMAP
+       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 initializaion"
+       depends on FB_OMAP
+       help
+         Say Y here if you want to enable checking if the bootloader has
+         already initialized the display controller. In this case the
+         driver will skip the initialization.
+
+config FB_OMAP_CONSISTENT_DMA_SIZE
+       int "Consistent DMA memory size (MB)"
+       depends on FB_OMAP
+       range 1 14
+       default 2
+       help
+         Increase the DMA consistent memory size according to your video
+         memory needs, for example if you want to use multiple planes.
+         The size must be 2MB aligned.
+         If unsure say 1.
+
+config FB_OMAP_DMA_TUNE
+        bool "Set DMA SDRAM access priority high"
+        depends on FB_OMAP && ARCH_OMAP1
+        help
+          On systems in which video memory is in system memory
+          (SDRAM) this will speed up graphics DMA operations.
+          If you have such a system and want to use rotation
+          answer yes. Answer no if you have a dedicated video
+          memory, or don't use any of the accelerated features.
+
+
diff --git a/drivers/video/omap/Makefile b/drivers/video/omap/Makefile
new file mode 100644 (file)
index 0000000..f4a1033
--- /dev/null
@@ -0,0 +1,34 @@
+#
+# Makefile for the new OMAP framebuffer device driver
+#
+
+obj-$(CONFIG_FB_OMAP) += omapfb.o
+
+objs-yy := omapfb_main.o
+
+objs-y$(CONFIG_ARCH_OMAP1) += lcdc.o
+objs-y$(CONFIG_ARCH_OMAP2) += dispc.o
+
+objs-$(CONFIG_ARCH_OMAP1)$(CONFIG_FB_OMAP_LCDC_EXTERNAL) += sossi.o
+objs-$(CONFIG_ARCH_OMAP2)$(CONFIG_FB_OMAP_LCDC_EXTERNAL) += rfbi.o
+
+objs-y$(CONFIG_FB_OMAP_LCDC_HWA742) += hwa742.o
+
+objs-y$(CONFIG_MACH_AMS_DELTA) += lcd_ams_delta.o
+objs-y$(CONFIG_MACH_OMAP_H4) += lcd_h4.o
+objs-y$(CONFIG_MACH_OMAP_H3) += lcd_h3.o
+objs-y$(CONFIG_MACH_OMAP_H2) += lcd_h2.o
+objs-y$(CONFIG_MACH_OMAP_PALMTE) += lcd_palmte.o
+objs-y$(CONFIG_MACH_OMAP_PALMZ71) += lcd_palmz71.o
+objs-y$(CONFIG_MACH_OMAP_PALMTT) += lcd_palmtt.o
+objs-$(CONFIG_ARCH_OMAP16XX)$(CONFIG_MACH_OMAP_INNOVATOR) += lcd_inn1610.o
+objs-$(CONFIG_ARCH_OMAP15XX)$(CONFIG_MACH_OMAP_INNOVATOR) += lcd_inn1510.o
+objs-y$(CONFIG_MACH_SX1) += lcd_sx1.o
+objs-y$(CONFIG_MACH_OMAP_OSK) += lcd_osk.o
+objs-y$(CONFIG_MACH_OMAP_PERSEUS2) += lcd_p2.o
+objs-y$(CONFIG_MACH_OMAP_APOLLON) += lcd_apollon.o
+
+objs-y$(CONFIG_FB_OMAP_LCD_MIPID) += lcd_mipid.o
+
+omapfb-objs := $(objs-yy)
+
diff --git a/drivers/video/omap/dispc.c b/drivers/video/omap/dispc.c
new file mode 100644 (file)
index 0000000..1f00c28
--- /dev/null
@@ -0,0 +1,1226 @@
+/*
+ * File: drivers/video/omap/omap2/dispc.c
+ *
+ * OMAP2 display controller support
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ * Author: Imre Deak <imre.deak@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+#include <linux/kernel.h>
+#include <linux/dma-mapping.h>
+#include <linux/vmalloc.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+
+#include <asm/arch/sram.h>
+#include <asm/arch/omapfb.h>
+#include <asm/arch/board.h>
+
+#include "dispc.h"
+
+#define MODULE_NAME                    "dispc"
+
+#define DSS_BASE                       0x48050000
+#define DSS_SYSCONFIG                  0x0010
+
+#define DISPC_BASE                     0x48050400
+
+/* DISPC common */
+#define DISPC_REVISION                 0x0000
+#define DISPC_SYSCONFIG                        0x0010
+#define DISPC_SYSSTATUS                        0x0014
+#define DISPC_IRQSTATUS                        0x0018
+#define DISPC_IRQENABLE                        0x001C
+#define DISPC_CONTROL                  0x0040
+#define DISPC_CONFIG                   0x0044
+#define DISPC_CAPABLE                  0x0048
+#define DISPC_DEFAULT_COLOR0           0x004C
+#define DISPC_DEFAULT_COLOR1           0x0050
+#define DISPC_TRANS_COLOR0             0x0054
+#define DISPC_TRANS_COLOR1             0x0058
+#define DISPC_LINE_STATUS              0x005C
+#define DISPC_LINE_NUMBER              0x0060
+#define DISPC_TIMING_H                 0x0064
+#define DISPC_TIMING_V                 0x0068
+#define DISPC_POL_FREQ                 0x006C
+#define DISPC_DIVISOR                  0x0070
+#define DISPC_SIZE_DIG                 0x0078
+#define DISPC_SIZE_LCD                 0x007C
+
+#define DISPC_DATA_CYCLE1              0x01D4
+#define DISPC_DATA_CYCLE2              0x01D8
+#define DISPC_DATA_CYCLE3              0x01DC
+
+/* DISPC GFX plane */
+#define DISPC_GFX_BA0                  0x0080
+#define DISPC_GFX_BA1                  0x0084
+#define DISPC_GFX_POSITION             0x0088
+#define DISPC_GFX_SIZE                 0x008C
+#define DISPC_GFX_ATTRIBUTES           0x00A0
+#define DISPC_GFX_FIFO_THRESHOLD       0x00A4
+#define DISPC_GFX_FIFO_SIZE_STATUS     0x00A8
+#define DISPC_GFX_ROW_INC              0x00AC
+#define DISPC_GFX_PIXEL_INC            0x00B0
+#define DISPC_GFX_WINDOW_SKIP          0x00B4
+#define DISPC_GFX_TABLE_BA             0x00B8
+
+/* DISPC Video plane 1/2 */
+#define DISPC_VID1_BASE                        0x00BC
+#define DISPC_VID2_BASE                        0x014C
+
+/* Offsets into DISPC_VID1/2_BASE */
+#define DISPC_VID_BA0                  0x0000
+#define DISPC_VID_BA1                  0x0004
+#define DISPC_VID_POSITION             0x0008
+#define DISPC_VID_SIZE                 0x000C
+#define DISPC_VID_ATTRIBUTES           0x0010
+#define DISPC_VID_FIFO_THRESHOLD       0x0014
+#define DISPC_VID_FIFO_SIZE_STATUS     0x0018
+#define DISPC_VID_ROW_INC              0x001C
+#define DISPC_VID_PIXEL_INC            0x0020
+#define DISPC_VID_FIR                  0x0024
+#define DISPC_VID_PICTURE_SIZE         0x0028
+#define DISPC_VID_ACCU0                        0x002C
+#define DISPC_VID_ACCU1                        0x0030
+
+/* 8 elements in 8 byte increments */
+#define DISPC_VID_FIR_COEF_H0          0x0034
+/* 8 elements in 8 byte increments */
+#define DISPC_VID_FIR_COEF_HV0         0x0038
+/* 5 elements in 4 byte increments */
+#define DISPC_VID_CONV_COEF0           0x0074
+
+#define DISPC_IRQ_FRAMEMASK            0x0001
+#define DISPC_IRQ_VSYNC                        0x0002
+#define DISPC_IRQ_EVSYNC_EVEN          0x0004
+#define DISPC_IRQ_EVSYNC_ODD           0x0008
+#define DISPC_IRQ_ACBIAS_COUNT_STAT    0x0010
+#define DISPC_IRQ_PROG_LINE_NUM                0x0020
+#define DISPC_IRQ_GFX_FIFO_UNDERFLOW   0x0040
+#define DISPC_IRQ_GFX_END_WIN          0x0080
+#define DISPC_IRQ_PAL_GAMMA_MASK       0x0100
+#define DISPC_IRQ_OCP_ERR              0x0200
+#define DISPC_IRQ_VID1_FIFO_UNDERFLOW  0x0400
+#define DISPC_IRQ_VID1_END_WIN         0x0800
+#define DISPC_IRQ_VID2_FIFO_UNDERFLOW  0x1000
+#define DISPC_IRQ_VID2_END_WIN         0x2000
+#define DISPC_IRQ_SYNC_LOST            0x4000
+
+#define DISPC_IRQ_MASK_ALL             0x7fff
+
+#define DISPC_IRQ_MASK_ERROR           (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \
+                                            DISPC_IRQ_VID1_FIFO_UNDERFLOW | \
+                                            DISPC_IRQ_VID2_FIFO_UNDERFLOW | \
+                                            DISPC_IRQ_SYNC_LOST)
+
+#define RFBI_CONTROL                   0x48050040
+
+#define MAX_PALETTE_SIZE               (256 * 16)
+
+#define FLD_MASK(pos, len)     (((1 << len) - 1) << pos)
+
+#define MOD_REG_FLD(reg, mask, val) \
+       dispc_write_reg((reg), (dispc_read_reg(reg) & ~(mask)) | (val));
+
+static struct {
+       u32             base;
+
+       struct omapfb_mem_desc  mem_desc;
+
+       dma_addr_t      palette_paddr;
+       void            *palette_vaddr;
+
+       int             ext_mode;
+       int             fbmem_allocated;
+
+       unsigned long   enabled_irqs;
+       void            (*irq_callback)(void *);
+       void            *irq_callback_data;
+       struct completion       frame_done;
+
+       int             fir_hinc[OMAPFB_PLANE_NUM];
+       int             fir_vinc[OMAPFB_PLANE_NUM];
+
+       struct clk      *dss_ick, *dss1_fck;
+       struct clk      *dss_54m_fck;
+
+       enum omapfb_update_mode update_mode;
+       struct omapfb_device    *fbdev;
+
+       struct omapfb_color_key color_key;
+} dispc;
+
+static void enable_lcd_clocks(int enable);
+
+static void inline dispc_write_reg(int idx, u32 val)
+{
+       __raw_writel(val, dispc.base + idx);
+}
+
+static u32 inline dispc_read_reg(int idx)
+{
+       u32 l = __raw_readl(dispc.base + idx);
+       return l;
+}
+
+/* Select RFBI or bypass mode */
+static void enable_rfbi_mode(int enable)
+{
+       u32 l;
+
+       l = dispc_read_reg(DISPC_CONTROL);
+       /* Enable RFBI, GPIO0/1 */
+       l &= ~((1 << 11) | (1 << 15) | (1 << 16));
+       l |= enable ? (1 << 11) : 0;
+       /* RFBI En: GPIO0/1=10  RFBI Dis: GPIO0/1=11 */
+       l |= 1 << 15;
+       l |= enable ? 0 : (1 << 16);
+       dispc_write_reg(DISPC_CONTROL, l);
+
+       /* Set bypass mode in RFBI module */
+       l = __raw_readl(io_p2v(RFBI_CONTROL));
+       l |= enable ? 0 : (1 << 1);
+       __raw_writel(l, io_p2v(RFBI_CONTROL));
+}
+
+static void set_lcd_data_lines(int data_lines)
+{
+       u32 l;
+       int code = 0;
+
+       switch (data_lines) {
+       case 12:
+               code = 0;
+               break;
+       case 16:
+               code = 1;
+               break;
+       case 18:
+               code = 2;
+               break;
+       case 24:
+               code = 3;
+               break;
+       default:
+               BUG();
+       }
+
+       l = dispc_read_reg(DISPC_CONTROL);
+       l &= ~(0x03 << 8);
+       l |= code << 8;
+       dispc_write_reg(DISPC_CONTROL, l);
+}
+
+static void set_load_mode(int mode)
+{
+       BUG_ON(mode & ~(DISPC_LOAD_CLUT_ONLY | DISPC_LOAD_FRAME_ONLY |
+                       DISPC_LOAD_CLUT_ONCE_FRAME));
+       MOD_REG_FLD(DISPC_CONFIG, 0x03 << 1, mode << 1);
+}
+
+void omap_dispc_set_lcd_size(int x, int y)
+{
+       BUG_ON((x > (1 << 11)) || (y > (1 << 11)));
+       enable_lcd_clocks(1);
+       MOD_REG_FLD(DISPC_SIZE_LCD, FLD_MASK(16, 11) | FLD_MASK(0, 11),
+                       ((y - 1) << 16) | (x - 1));
+       enable_lcd_clocks(0);
+}
+EXPORT_SYMBOL(omap_dispc_set_lcd_size);
+
+void omap_dispc_set_digit_size(int x, int y)
+{
+       BUG_ON((x > (1 << 11)) || (y > (1 << 11)));
+       enable_lcd_clocks(1);
+       MOD_REG_FLD(DISPC_SIZE_DIG, FLD_MASK(16, 11) | FLD_MASK(0, 11),
+                       ((y - 1) << 16) | (x - 1));
+       enable_lcd_clocks(0);
+}
+EXPORT_SYMBOL(omap_dispc_set_digit_size);
+
+static void setup_plane_fifo(int plane, int ext_mode)
+{
+       const u32 ftrs_reg[] = { DISPC_GFX_FIFO_THRESHOLD,
+                               DISPC_VID1_BASE + DISPC_VID_FIFO_THRESHOLD,
+                               DISPC_VID2_BASE + DISPC_VID_FIFO_THRESHOLD };
+       const u32 fsz_reg[] = { DISPC_GFX_FIFO_SIZE_STATUS,
+                               DISPC_VID1_BASE + DISPC_VID_FIFO_SIZE_STATUS,
+                               DISPC_VID2_BASE + DISPC_VID_FIFO_SIZE_STATUS };
+       int low, high;
+       u32 l;
+
+       BUG_ON(plane > 2);
+
+       l = dispc_read_reg(fsz_reg[plane]);
+       l &= FLD_MASK(0, 9);
+       if (ext_mode) {
+               low = l * 3 / 4;
+               high = l;
+       } else {
+               low = l / 4;
+               high = l * 3 / 4;
+       }
+       MOD_REG_FLD(ftrs_reg[plane], FLD_MASK(16, 9) | FLD_MASK(0, 9),
+                       (high << 16) | low);
+}
+
+void omap_dispc_enable_lcd_out(int enable)
+{
+       enable_lcd_clocks(1);
+       MOD_REG_FLD(DISPC_CONTROL, 1, enable ? 1 : 0);
+       enable_lcd_clocks(0);
+}
+EXPORT_SYMBOL(omap_dispc_enable_lcd_out);
+
+void omap_dispc_enable_digit_out(int enable)
+{
+       enable_lcd_clocks(1);
+       MOD_REG_FLD(DISPC_CONTROL, 1 << 1, enable ? 1 << 1 : 0);
+       enable_lcd_clocks(0);
+}
+EXPORT_SYMBOL(omap_dispc_enable_digit_out);
+
+static inline int _setup_plane(int plane, int channel_out,
+                                 u32 paddr, int screen_width,
+                                 int pos_x, int pos_y, int width, int height,
+                                 int color_mode)
+{
+       const u32 at_reg[] = { DISPC_GFX_ATTRIBUTES,
+                               DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES,
+                               DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES };
+       const u32 ba_reg[] = { DISPC_GFX_BA0, DISPC_VID1_BASE + DISPC_VID_BA0,
+                               DISPC_VID2_BASE + DISPC_VID_BA0 };
+       const u32 ps_reg[] = { DISPC_GFX_POSITION,
+                               DISPC_VID1_BASE + DISPC_VID_POSITION,
+                               DISPC_VID2_BASE + DISPC_VID_POSITION };
+       const u32 sz_reg[] = { DISPC_GFX_SIZE,
+                               DISPC_VID1_BASE + DISPC_VID_PICTURE_SIZE,
+                               DISPC_VID2_BASE + DISPC_VID_PICTURE_SIZE };
+       const u32 ri_reg[] = { DISPC_GFX_ROW_INC,
+                               DISPC_VID1_BASE + DISPC_VID_ROW_INC,
+                               DISPC_VID2_BASE + DISPC_VID_ROW_INC };
+       const u32 vs_reg[]= { 0, DISPC_VID1_BASE + DISPC_VID_SIZE,
+                               DISPC_VID2_BASE + DISPC_VID_SIZE };
+
+       int chout_shift, burst_shift;
+       int chout_val;
+       int color_code;
+       int bpp;
+       int cconv_en;
+       int set_vsize;
+       u32 l;
+
+#ifdef VERBOSE
+       dev_dbg(dispc.fbdev->dev, "plane %d channel %d paddr %#08x scr_width %d "
+                   "pos_x %d pos_y %d width %d height %d color_mode %d\n",
+                   plane, channel_out, paddr, screen_width, pos_x, pos_y,
+                   width, height, color_mode);
+#endif
+
+       set_vsize = 0;
+       switch (plane) {
+       case OMAPFB_PLANE_GFX:
+               burst_shift = 6;
+               chout_shift = 8;
+               break;
+       case OMAPFB_PLANE_VID1:
+       case OMAPFB_PLANE_VID2:
+               burst_shift = 14;
+               chout_shift = 16;
+               set_vsize = 1;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (channel_out) {
+       case OMAPFB_CHANNEL_OUT_LCD:
+               chout_val = 0;
+               break;
+       case OMAPFB_CHANNEL_OUT_DIGIT:
+               chout_val = 1;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       cconv_en = 0;
+       switch (color_mode) {
+       case OMAPFB_COLOR_RGB565:
+               color_code = DISPC_RGB_16_BPP;
+               bpp = 16;
+               break;
+       case OMAPFB_COLOR_YUV422:
+               if (plane == 0)
+                       return -EINVAL;
+               color_code = DISPC_UYVY_422;
+               cconv_en = 1;
+               bpp = 16;
+               break;
+       case OMAPFB_COLOR_YUY422:
+               if (plane == 0)
+                       return -EINVAL;
+               color_code = DISPC_YUV2_422;
+               cconv_en = 1;
+               bpp = 16;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       l = dispc_read_reg(at_reg[plane]);
+
+       l &= ~(0x0f << 1);
+       l |= color_code << 1;
+       l &= ~(1 << 9);
+       l |= cconv_en << 9;
+
+       l &= ~(0x03 << burst_shift);
+       l |= DISPC_BURST_8x32 << burst_shift;
+
+       l &= ~(1 << chout_shift);
+       l |= chout_val << chout_shift;
+
+       dispc_write_reg(at_reg[plane], l);
+
+       dispc_write_reg(ba_reg[plane], paddr);
+       MOD_REG_FLD(ps_reg[plane],
+                   FLD_MASK(16, 11) | FLD_MASK(0, 11), (pos_y << 16) | pos_x);
+
+       MOD_REG_FLD(sz_reg[plane], FLD_MASK(16, 11) | FLD_MASK(0, 11),
+                       ((height - 1) << 16) | (width - 1));
+
+       if (set_vsize) {
+               /* Set video size if set_scale hasn't set it */
+               if (!dispc.fir_vinc[plane])
+                       MOD_REG_FLD(vs_reg[plane],
+                               FLD_MASK(16, 11), (height - 1) << 16);
+               if (!dispc.fir_hinc[plane])
+                       MOD_REG_FLD(vs_reg[plane],
+                               FLD_MASK(0, 11), width - 1);
+       }
+
+       dispc_write_reg(ri_reg[plane], (screen_width - width) * bpp / 8 + 1);
+
+       return height * screen_width * bpp / 8;
+}
+
+static int omap_dispc_setup_plane(int plane, int channel_out,
+                                 unsigned long offset,
+                                 int screen_width,
+                                 int pos_x, int pos_y, int width, int height,
+                                 int color_mode)
+{
+       u32 paddr;
+       int r;
+
+       if ((unsigned)plane > dispc.mem_desc.region_cnt)
+               return -EINVAL;
+       paddr = dispc.mem_desc.region[plane].paddr + offset;
+       enable_lcd_clocks(1);
+       r = _setup_plane(plane, channel_out, paddr,
+                       screen_width,
+                       pos_x, pos_y, width, height, color_mode);
+       enable_lcd_clocks(0);
+       return r;
+}
+
+static void write_firh_reg(int plane, int reg, u32 value)
+{
+       u32 base;
+
+       if (plane == 1)
+               base = DISPC_VID1_BASE + DISPC_VID_FIR_COEF_H0;
+       else
+               base = DISPC_VID2_BASE + DISPC_VID_FIR_COEF_H0;
+       dispc_write_reg(base + reg * 8, value);
+}
+
+static void write_firhv_reg(int plane, int reg, u32 value)
+{
+       u32 base;
+
+       if (plane == 1)
+               base = DISPC_VID1_BASE + DISPC_VID_FIR_COEF_HV0;
+       else
+               base = DISPC_VID2_BASE + DISPC_VID_FIR_COEF_HV0;
+       dispc_write_reg(base + reg * 8, value);
+}
+
+static void set_upsampling_coef_table(int plane)
+{
+       const u32 coef[][2] = {
+               { 0x00800000, 0x00800000 },
+               { 0x0D7CF800, 0x037B02FF },
+               { 0x1E70F5FF, 0x0C6F05FE },
+               { 0x335FF5FE, 0x205907FB },
+               { 0xF74949F7, 0x00404000 },
+               { 0xF55F33FB, 0x075920FE },
+               { 0xF5701EFE, 0x056F0CFF },
+               { 0xF87C0DFF, 0x027B0300 },
+       };
+       int i;
+
+       for (i = 0; i < 8; i++) {
+               write_firh_reg(plane, i, coef[i][0]);
+               write_firhv_reg(plane, i, coef[i][1]);
+       }
+}
+
+static int omap_dispc_set_scale(int plane,
+                               int orig_width, int orig_height,
+                               int out_width, int out_height)
+{
+       const u32 at_reg[]  = { 0, DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES,
+                                  DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES };
+       const u32 vs_reg[]  = { 0, DISPC_VID1_BASE + DISPC_VID_SIZE,
+                                  DISPC_VID2_BASE + DISPC_VID_SIZE };
+       const u32 fir_reg[] = { 0, DISPC_VID1_BASE + DISPC_VID_FIR,
+                                  DISPC_VID2_BASE + DISPC_VID_FIR };
+
+       u32 l;
+       int fir_hinc;
+       int fir_vinc;
+
+       if ((unsigned)plane > OMAPFB_PLANE_NUM)
+               return -ENODEV;
+
+       if (plane == OMAPFB_PLANE_GFX &&
+           (out_width != orig_width || out_height != orig_height))
+               return -EINVAL;
+
+       enable_lcd_clocks(1);
+       if (orig_width < out_width) {
+               /* Upsampling.
+                * Currently you can only scale both dimensions in one way.
+                */
+               if (orig_height > out_height ||
+                   orig_width * 8 < out_width ||
+                   orig_height * 8 < out_height) {
+                       enable_lcd_clocks(0);
+                       return -EINVAL;
+               }
+               set_upsampling_coef_table(plane);
+       } else if (orig_width > out_width) {
+               /* Downsampling not yet supported
+               */
+
+               enable_lcd_clocks(0);
+               return -EINVAL;
+       }
+       if (!orig_width || orig_width == out_width)
+               fir_hinc = 0;
+       else
+               fir_hinc = 1024 * orig_width / out_width;
+       if (!orig_height || orig_height == out_height)
+               fir_vinc = 0;
+       else
+               fir_vinc = 1024 * orig_height / out_height;
+       dispc.fir_hinc[plane] = fir_hinc;
+       dispc.fir_vinc[plane] = fir_vinc;
+
+       MOD_REG_FLD(fir_reg[plane],
+                   FLD_MASK(16, 12) | FLD_MASK(0, 12),
+                   ((fir_vinc & 4095) << 16) |
+                   (fir_hinc & 4095));
+
+       dev_dbg(dispc.fbdev->dev, "out_width %d out_height %d orig_width %d "
+               "orig_height %d fir_hinc  %d fir_vinc %d\n",
+               out_width, out_height, orig_width, orig_height,
+               fir_hinc, fir_vinc);
+
+       MOD_REG_FLD(vs_reg[plane],
+                   FLD_MASK(16, 11) | FLD_MASK(0, 11),
+                   ((out_height - 1) << 16) | (out_width - 1));
+
+       l = dispc_read_reg(at_reg[plane]);
+       l &= ~(0x03 << 5);
+       l |= fir_hinc ? (1 << 5) : 0;
+       l |= fir_vinc ? (1 << 6) : 0;
+       dispc_write_reg(at_reg[plane], l);
+
+       enable_lcd_clocks(0);
+       return 0;
+}
+
+static int omap_dispc_enable_plane(int plane, int enable)
+{
+       const u32 at_reg[] = { DISPC_GFX_ATTRIBUTES,
+                               DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES,
+                               DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES };
+       if ((unsigned int)plane > dispc.mem_desc.region_cnt)
+               return -EINVAL;
+
+       enable_lcd_clocks(1);
+       MOD_REG_FLD(at_reg[plane], 1, enable ? 1 : 0);
+       enable_lcd_clocks(0);
+
+       return 0;
+}
+
+static int omap_dispc_set_color_key(struct omapfb_color_key *ck)
+{
+       u32 df_reg, tr_reg;
+       int shift, val;
+
+       switch (ck->channel_out) {
+       case OMAPFB_CHANNEL_OUT_LCD:
+               df_reg = DISPC_DEFAULT_COLOR0;
+               tr_reg = DISPC_TRANS_COLOR0;
+               shift = 10;
+               break;
+       case OMAPFB_CHANNEL_OUT_DIGIT:
+               df_reg = DISPC_DEFAULT_COLOR1;
+               tr_reg = DISPC_TRANS_COLOR1;
+               shift = 12;
+               break;
+       default:
+               return -EINVAL;
+       }
+       switch (ck->key_type) {
+       case OMAPFB_COLOR_KEY_DISABLED:
+               val = 0;
+               break;
+       case OMAPFB_COLOR_KEY_GFX_DST:
+               val = 1;
+               break;
+       case OMAPFB_COLOR_KEY_VID_SRC:
+               val = 3;
+               break;
+       default:
+               return -EINVAL;
+       }
+       enable_lcd_clocks(1);
+       MOD_REG_FLD(DISPC_CONFIG, FLD_MASK(shift, 2), val << shift);
+
+       if (val != 0)
+               dispc_write_reg(tr_reg, ck->trans_key);
+       dispc_write_reg(df_reg, ck->background);
+       enable_lcd_clocks(0);
+
+       dispc.color_key = *ck;
+
+       return 0;
+}
+
+static int omap_dispc_get_color_key(struct omapfb_color_key *ck)
+{
+       *ck = dispc.color_key;
+       return 0;
+}
+
+static void load_palette(void)
+{
+}
+
+static int omap_dispc_set_update_mode(enum omapfb_update_mode mode)
+{
+       int r = 0;
+
+       if (mode != dispc.update_mode) {
+               switch (mode) {
+               case OMAPFB_AUTO_UPDATE:
+               case OMAPFB_MANUAL_UPDATE:
+                       enable_lcd_clocks(1);
+                       omap_dispc_enable_lcd_out(1);
+                       dispc.update_mode = mode;
+                       break;
+               case OMAPFB_UPDATE_DISABLED:
+                       init_completion(&dispc.frame_done);
+                       omap_dispc_enable_lcd_out(0);
+                       if (!wait_for_completion_timeout(&dispc.frame_done,
+                                       msecs_to_jiffies(500))) {
+                               dev_err(dispc.fbdev->dev,
+                                        "timeout waiting for FRAME DONE\n");
+                       }
+                       dispc.update_mode = mode;
+                       enable_lcd_clocks(0);
+                       break;
+               default:
+                       r = -EINVAL;
+               }
+       }
+
+       return r;
+}
+
+static unsigned long omap_dispc_get_caps(void)
+{
+       return 0;
+}
+
+static enum omapfb_update_mode omap_dispc_get_update_mode(void)
+{
+       return dispc.update_mode;
+}
+
+static void setup_color_conv_coef(void)
+{
+       u32 mask = FLD_MASK(16, 11) | FLD_MASK(0, 11);
+       int cf1_reg = DISPC_VID1_BASE + DISPC_VID_CONV_COEF0;
+       int cf2_reg = DISPC_VID2_BASE + DISPC_VID_CONV_COEF0;
+       int at1_reg = DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES;
+       int at2_reg = DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES;
+       const struct color_conv_coef {
+               int  ry,  rcr,  rcb,   gy,  gcr,  gcb,   by,  bcr,  bcb;
+               int  full_range;
+       }  ctbl_bt601_5 = {
+                   298,  409,    0,  298, -208, -100,  298,    0,  517, 0,
+       };
+#if 0
+       const struct color_conv_coef ctbl_bt601_5_full = {
+                   256,  351,    0,  256, -179,  -86,  256,    0,  443, 1,
+       }, ctbl_bt709 = {
+                   298,  459,    0,  298, -137,  -55,  298,    0,  541, 0,
+       }, ctbl_bt709_f = {
+                   256,  394,    0,  256, -118,  -47,  256,    0,  465, 1,     },
+#endif
+       const struct color_conv_coef *ct;
+#define CVAL(x, y)     (((x & 2047) << 16) | (y & 2047))
+
+       ct = &ctbl_bt601_5;
+
+       MOD_REG_FLD(cf1_reg,            mask,   CVAL(ct->rcr, ct->ry));
+       MOD_REG_FLD(cf1_reg + 4,        mask,   CVAL(ct->gy,  ct->rcb));
+       MOD_REG_FLD(cf1_reg + 8,        mask,   CVAL(ct->gcb, ct->gcr));
+       MOD_REG_FLD(cf1_reg + 12,       mask,   CVAL(ct->bcr, ct->by));
+       MOD_REG_FLD(cf1_reg + 16,       mask,   CVAL(0,       ct->bcb));
+
+       MOD_REG_FLD(cf2_reg,            mask,   CVAL(ct->rcr, ct->ry));
+       MOD_REG_FLD(cf2_reg + 4,        mask,   CVAL(ct->gy,  ct->rcb));
+       MOD_REG_FLD(cf2_reg + 8,        mask,   CVAL(ct->gcb, ct->gcr));
+       MOD_REG_FLD(cf2_reg + 12,       mask,   CVAL(ct->bcr, ct->by));
+       MOD_REG_FLD(cf2_reg + 16,       mask,   CVAL(0,       ct->bcb));
+#undef CVAL
+
+       MOD_REG_FLD(at1_reg, (1 << 11), ct->full_range);
+       MOD_REG_FLD(at2_reg, (1 << 11), ct->full_range);
+}
+
+static void calc_ck_div(int is_tft, int pck, int *lck_div, int *pck_div)
+{
+       unsigned long fck, lck;
+
+       *lck_div = 1;
+       pck = max(1, pck);
+       fck = clk_get_rate(dispc.dss1_fck);
+       lck = fck;
+       *pck_div = (lck + pck - 1) / pck;
+       if (is_tft)
+               *pck_div = max(2, *pck_div);
+       else
+               *pck_div = max(3, *pck_div);
+       if (*pck_div > 255) {
+               *pck_div = 255;
+               lck = pck * *pck_div;
+               *lck_div = fck / lck;
+               BUG_ON(*lck_div < 1);
+               if (*lck_div > 255) {
+                       *lck_div = 255;
+                       dev_warn(dispc.fbdev->dev, "pixclock %d kHz too low.\n",
+                                pck / 1000);
+               }
+       }
+}
+
+static void set_lcd_tft_mode(int enable)
+{
+       u32 mask;
+
+       mask = 1 << 3;
+       MOD_REG_FLD(DISPC_CONTROL, mask, enable ? mask : 0);
+}
+
+static void set_lcd_timings(void)
+{
+       u32 l;
+       int lck_div, pck_div;
+       struct lcd_panel *panel = dispc.fbdev->panel;
+       int is_tft = panel->config & OMAP_LCDC_PANEL_TFT;
+       unsigned long fck;
+
+       l = dispc_read_reg(DISPC_TIMING_H);
+       l &= ~(FLD_MASK(0, 6) | FLD_MASK(8, 8) | FLD_MASK(20, 8));
+       l |= ( max(1, (min(64,  panel->hsw))) - 1 ) << 0;
+       l |= ( max(1, (min(256, panel->hfp))) - 1 ) << 8;
+       l |= ( max(1, (min(256, panel->hbp))) - 1 ) << 20;
+       dispc_write_reg(DISPC_TIMING_H, l);
+
+       l = dispc_read_reg(DISPC_TIMING_V);
+       l &= ~(FLD_MASK(0, 6) | FLD_MASK(8, 8) | FLD_MASK(20, 8));
+       l |= ( max(1, (min(64,  panel->vsw))) - 1 ) << 0;
+       l |= ( max(0, (min(255, panel->vfp))) - 0 ) << 8;
+       l |= ( max(0, (min(255, panel->vbp))) - 0 ) << 20;
+       dispc_write_reg(DISPC_TIMING_V, l);
+
+       l = dispc_read_reg(DISPC_POL_FREQ);
+       l &= ~FLD_MASK(12, 6);
+       l |= (panel->config & OMAP_LCDC_SIGNAL_MASK) << 12;
+       l |= panel->acb & 0xff;
+       dispc_write_reg(DISPC_POL_FREQ, l);
+
+       calc_ck_div(is_tft, panel->pixel_clock * 1000, &lck_div, &pck_div);
+
+       l = dispc_read_reg(DISPC_DIVISOR);
+       l &= ~(FLD_MASK(16, 8) | FLD_MASK(0, 8));
+       l |= (lck_div << 16) | (pck_div << 0);
+       dispc_write_reg(DISPC_DIVISOR, l);
+
+       /* update panel info with the exact clock */
+       fck = clk_get_rate(dispc.dss1_fck);
+       panel->pixel_clock = fck / lck_div / pck_div / 1000;
+}
+
+int omap_dispc_request_irq(void (*callback)(void *data), void *data)
+{
+       int r = 0;
+
+       BUG_ON(callback == NULL);
+
+       if (dispc.irq_callback)
+               r = -EBUSY;
+       else {
+               dispc.irq_callback = callback;
+               dispc.irq_callback_data = data;
+       }
+
+       return r;
+}
+EXPORT_SYMBOL(omap_dispc_request_irq);
+
+void omap_dispc_enable_irqs(int irq_mask)
+{
+       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)
+{
+       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_disable_irqs);
+
+void omap_dispc_free_irq(void)
+{
+       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);
+}
+EXPORT_SYMBOL(omap_dispc_free_irq);
+
+static irqreturn_t omap_dispc_irq_handler(int irq, void *dev)
+{
+       u32 stat = dispc_read_reg(DISPC_IRQSTATUS);
+       static int jabber;
+
+       if (stat & DISPC_IRQ_FRAMEMASK)
+               complete(&dispc.frame_done);
+
+       if (stat & DISPC_IRQ_MASK_ERROR) {
+               if (jabber++ < 5) {
+                       dev_err(dispc.fbdev->dev, "irq error status %04x\n",
+                               stat & 0x7fff);
+               } else {
+                       dev_err(dispc.fbdev->dev, "disable irq\n");
+                       dispc_write_reg(DISPC_IRQENABLE, 0);
+               }
+       }
+
+       if ((stat & dispc.enabled_irqs) && dispc.irq_callback)
+               dispc.irq_callback(dispc.irq_callback_data);
+
+       dispc_write_reg(DISPC_IRQSTATUS, stat);
+
+       return IRQ_HANDLED;
+}
+
+static int get_dss_clocks(void)
+{
+       if (IS_ERR((dispc.dss_ick = clk_get(dispc.fbdev->dev, "dss_ick")))) {
+               dev_err(dispc.fbdev->dev, "can't get 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");
+               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");
+               clk_put(dispc.dss_ick);
+               clk_put(dispc.dss1_fck);
+               return PTR_ERR(dispc.dss_54m_fck);
+       }
+
+       return 0;
+}
+
+static void put_dss_clocks(void)
+{
+       clk_put(dispc.dss_54m_fck);
+       clk_put(dispc.dss1_fck);
+       clk_put(dispc.dss_ick);
+}
+
+static void enable_lcd_clocks(int enable)
+{
+       if (enable)
+               clk_enable(dispc.dss1_fck);
+       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 (enable)
+               clk_enable(dispc.dss_54m_fck);
+       else
+               clk_disable(dispc.dss_54m_fck);
+}
+
+static void omap_dispc_suspend(void)
+{
+       if (dispc.update_mode == OMAPFB_AUTO_UPDATE) {
+               init_completion(&dispc.frame_done);
+               omap_dispc_enable_lcd_out(0);
+               if (!wait_for_completion_timeout(&dispc.frame_done,
+                               msecs_to_jiffies(500))) {
+                       dev_err(dispc.fbdev->dev,
+                               "timeout waiting for FRAME DONE\n");
+               }
+               enable_lcd_clocks(0);
+       }
+}
+
+static void omap_dispc_resume(void)
+{
+       if (dispc.update_mode == OMAPFB_AUTO_UPDATE) {
+               enable_lcd_clocks(1);
+               if (!dispc.ext_mode) {
+                       set_lcd_timings();
+                       load_palette();
+               }
+               omap_dispc_enable_lcd_out(1);
+       }
+}
+
+
+static int omap_dispc_update_window(struct fb_info *fbi,
+                                struct omapfb_update_window *win,
+                                void (*complete_callback)(void *arg),
+                                void *complete_callback_data)
+{
+       return dispc.update_mode == OMAPFB_UPDATE_DISABLED ? -ENODEV : 0;
+}
+
+static int mmap_kern(struct omapfb_mem_region *region)
+{
+       struct vm_struct        *kvma;
+       struct vm_area_struct   vma;
+       pgprot_t                pgprot;
+       unsigned long           vaddr;
+
+       kvma = get_vm_area(region->size, VM_IOREMAP);
+       if (kvma == NULL) {
+               dev_err(dispc.fbdev->dev, "can't get kernel vm area\n");
+               return -ENOMEM;
+       }
+       vma.vm_mm = &init_mm;
+
+       vaddr = (unsigned long)kvma->addr;
+
+       pgprot = pgprot_writecombine(pgprot_kernel);
+       vma.vm_start = vaddr;
+       vma.vm_end = vaddr + region->size;
+       if (io_remap_pfn_range(&vma, vaddr, region->paddr >> PAGE_SHIFT,
+                          region->size, pgprot) < 0) {
+               dev_err(dispc.fbdev->dev, "kernel mmap for FBMEM failed\n");
+               return -EAGAIN;
+       }
+       region->vaddr = (void *)vaddr;
+
+       return 0;
+}
+
+static void unmap_kern(struct omapfb_mem_region *region)
+{
+       vunmap(region->vaddr);
+}
+
+static int alloc_palette_ram(void)
+{
+       dispc.palette_vaddr = dma_alloc_writecombine(dispc.fbdev->dev,
+               MAX_PALETTE_SIZE, &dispc.palette_paddr, GFP_KERNEL);
+       if (dispc.palette_vaddr == NULL) {
+               dev_err(dispc.fbdev->dev, "failed to alloc palette memory\n");
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static void free_palette_ram(void)
+{
+       dma_free_writecombine(dispc.fbdev->dev, MAX_PALETTE_SIZE,
+                       dispc.palette_vaddr, dispc.palette_paddr);
+}
+
+static int alloc_fbmem(struct omapfb_mem_region *region)
+{
+       region->vaddr = dma_alloc_writecombine(dispc.fbdev->dev,
+                       region->size, &region->paddr, GFP_KERNEL);
+
+       if (region->vaddr == NULL) {
+               dev_err(dispc.fbdev->dev, "unable to allocate FB DMA memory\n");
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static void free_fbmem(struct omapfb_mem_region *region)
+{
+       dma_free_writecombine(dispc.fbdev->dev, region->size,
+                             region->vaddr, region->paddr);
+}
+
+static int setup_fbmem(struct omapfb_mem_desc *req_md)
+{
+       struct omapfb_mem_region        *rg;
+       int i;
+       int r;
+
+       if (!req_md->region_cnt) {
+               dev_err(dispc.fbdev->dev, "no memory regions defined\n");
+               return -ENOENT;
+       }
+
+       rg = &req_md->region[0];
+
+       for (i = 0; i < req_md->region_cnt; i++, rg++) {
+               if (rg->paddr) {
+                       rg->alloc = 0;
+                       if ((r = mmap_kern(rg)) < 0)
+                               return r;
+               } else {
+                       rg->alloc = 1;
+                       if ((r = alloc_fbmem(rg)) < 0)
+                               return r;
+               }
+       }
+
+       dispc.mem_desc = *req_md;
+
+       return 0;
+}
+
+static void cleanup_fbmem(void)
+{
+       int i;
+
+       for (i = 0; i < dispc.mem_desc.region_cnt; i++) {
+               if (dispc.mem_desc.region[i].alloc)
+                       free_fbmem(&dispc.mem_desc.region[i]);
+               else
+                       unmap_kern(&dispc.mem_desc.region[i]);
+       }
+}
+
+static int omap_dispc_init(struct omapfb_device *fbdev, int ext_mode,
+                          struct omapfb_mem_desc *req_vram)
+{
+       int r;
+       u32 l;
+       struct lcd_panel *panel = fbdev->panel;
+       int tmo = 10000;
+       int skip_init = 0;
+       int i;
+
+       memset(&dispc, 0, sizeof(dispc));
+
+       dispc.base = io_p2v(DISPC_BASE);
+       dispc.fbdev = fbdev;
+       dispc.ext_mode = ext_mode;
+
+       init_completion(&dispc.frame_done);
+
+       if ((r = get_dss_clocks()) < 0)
+               return r;
+
+       enable_interface_clocks(1);
+       enable_lcd_clocks(1);
+
+#ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT
+       l = dispc_read_reg(DISPC_CONTROL);
+       /* LCD enabled ? */
+       if (l & 1) {
+               pr_info("omapfb: skipping hardware initialization\n");
+               skip_init = 1;
+       }
+#endif
+
+       if (!skip_init) {
+               /* Reset monitoring works only w/ the 54M clk */
+               enable_digit_clocks(1);
+
+               /* Soft reset */
+               MOD_REG_FLD(DISPC_SYSCONFIG, 1 << 1, 1 << 1);
+
+               while (!(dispc_read_reg(DISPC_SYSSTATUS) & 1)) {
+                       if (!--tmo) {
+                               dev_err(dispc.fbdev->dev, "soft reset failed\n");
+                               r = -ENODEV;
+                               enable_digit_clocks(0);
+                               goto fail1;
+                       }
+               }
+
+               enable_digit_clocks(0);
+       }
+
+       /* Enable smart idle and autoidle */
+       l = dispc_read_reg(DISPC_CONTROL);
+       l &= ~((3 << 12) | (3 << 3));
+       l |= (2 << 12) | (2 << 3) | (1 << 0);
+       dispc_write_reg(DISPC_SYSCONFIG, l);
+       omap_writel(1 << 0, DSS_BASE + DSS_SYSCONFIG);
+
+       /* Set functional clock autogating */
+       l = dispc_read_reg(DISPC_CONFIG);
+       l |= 1 << 9;
+       dispc_write_reg(DISPC_CONFIG, l);
+
+       l = dispc_read_reg(DISPC_IRQSTATUS);
+       dispc_write_reg(l, DISPC_IRQSTATUS);
+
+       /* Enable those that we handle always */
+       omap_dispc_enable_irqs(DISPC_IRQ_FRAMEMASK);
+
+       if ((r = request_irq(INT_24XX_DSS_IRQ, omap_dispc_irq_handler,
+                          0, MODULE_NAME, fbdev)) < 0) {
+               dev_err(dispc.fbdev->dev, "can't get DSS IRQ\n");
+               goto fail1;
+       }
+
+       /* L3 firewall setting: enable access to OCM RAM */
+       __raw_writel(0x402000b0, io_p2v(0x680050a0));
+
+       if ((r = alloc_palette_ram()) < 0)
+               goto fail2;
+
+       if ((r = setup_fbmem(req_vram)) < 0)
+               goto fail3;
+
+       if (!skip_init) {
+               for (i = 0; i < dispc.mem_desc.region_cnt; i++) {
+                       memset(dispc.mem_desc.region[i].vaddr, 0,
+                               dispc.mem_desc.region[i].size);
+               }
+
+               /* Set logic clock to fck, pixel clock to fck/2 for now */
+               MOD_REG_FLD(DISPC_DIVISOR, FLD_MASK(16, 8), 1 << 16);
+               MOD_REG_FLD(DISPC_DIVISOR, FLD_MASK(0, 8), 2 << 0);
+
+               setup_plane_fifo(0, ext_mode);
+               setup_plane_fifo(1, ext_mode);
+               setup_plane_fifo(2, ext_mode);
+
+               setup_color_conv_coef();
+
+               set_lcd_tft_mode(panel->config & OMAP_LCDC_PANEL_TFT);
+               set_load_mode(DISPC_LOAD_FRAME_ONLY);
+
+               if (!ext_mode) {
+                       set_lcd_data_lines(panel->data_lines);
+                       omap_dispc_set_lcd_size(panel->x_res, panel->y_res);
+                       set_lcd_timings();
+               } else
+                       set_lcd_data_lines(panel->bpp);
+               enable_rfbi_mode(ext_mode);
+       }
+
+       l = dispc_read_reg(DISPC_REVISION);
+       pr_info("omapfb: DISPC version %d.%d initialized\n",
+                l >> 4 & 0x0f, l & 0x0f);
+       enable_lcd_clocks(0);
+
+       return 0;
+fail3:
+       free_palette_ram();
+fail2:
+       free_irq(INT_24XX_DSS_IRQ, fbdev);
+fail1:
+       enable_lcd_clocks(0);
+       enable_interface_clocks(0);
+       put_dss_clocks();
+
+       return r;
+}
+
+static void omap_dispc_cleanup(void)
+{
+       int i;
+
+       omap_dispc_set_update_mode(OMAPFB_UPDATE_DISABLED);
+       /* This will also disable clocks that are on */
+       for (i = 0; i < dispc.mem_desc.region_cnt; i++)
+               omap_dispc_enable_plane(i, 0);
+       cleanup_fbmem();
+       free_palette_ram();
+       free_irq(INT_24XX_DSS_IRQ, dispc.fbdev);
+       enable_interface_clocks(0);
+       put_dss_clocks();
+}
+
+const struct lcd_ctrl omap2_int_ctrl = {
+       .name                   = "internal",
+       .init                   = omap_dispc_init,
+       .cleanup                = omap_dispc_cleanup,
+       .get_caps               = omap_dispc_get_caps,
+       .set_update_mode        = omap_dispc_set_update_mode,
+       .get_update_mode        = omap_dispc_get_update_mode,
+       .update_window          = omap_dispc_update_window,
+       .suspend                = omap_dispc_suspend,
+       .resume                 = omap_dispc_resume,
+       .setup_plane            = omap_dispc_setup_plane,
+       .set_scale              = omap_dispc_set_scale,
+       .enable_plane           = omap_dispc_enable_plane,
+       .set_color_key          = omap_dispc_set_color_key,
+       .get_color_key          = omap_dispc_get_color_key,
+};
diff --git a/drivers/video/omap/dispc.h b/drivers/video/omap/dispc.h
new file mode 100644 (file)
index 0000000..eb1512b
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef _DISPC_H
+#define _DISPC_H
+
+#include <linux/interrupt.h>
+
+#define DISPC_PLANE_GFX                        0
+#define DISPC_PLANE_VID1               1
+#define DISPC_PLANE_VID2               2
+
+#define DISPC_RGB_1_BPP                        0x00
+#define DISPC_RGB_2_BPP                        0x01
+#define DISPC_RGB_4_BPP                        0x02
+#define DISPC_RGB_8_BPP                        0x03
+#define DISPC_RGB_12_BPP               0x04
+#define DISPC_RGB_16_BPP               0x06
+#define DISPC_RGB_24_BPP               0x08
+#define DISPC_RGB_24_BPP_UNPACK_32     0x09
+#define DISPC_YUV2_422                 0x0a
+#define DISPC_UYVY_422                 0x0b
+
+#define DISPC_BURST_4x32               0
+#define DISPC_BURST_8x32               1
+#define DISPC_BURST_16x32              2
+
+#define DISPC_LOAD_CLUT_AND_FRAME      0x00
+#define DISPC_LOAD_CLUT_ONLY           0x01
+#define DISPC_LOAD_FRAME_ONLY          0x02
+#define DISPC_LOAD_CLUT_ONCE_FRAME     0x03
+
+#define DISPC_TFT_DATA_LINES_12                0
+#define DISPC_TFT_DATA_LINES_16                1
+#define DISPC_TFT_DATA_LINES_18                2
+#define DISPC_TFT_DATA_LINES_24                3
+
+extern void omap_dispc_set_lcd_size(int width, int height);
+
+extern void omap_dispc_enable_lcd_out(int enable);
+extern void omap_dispc_enable_digit_out(int enable);
+
+extern int  omap_dispc_request_irq(void (*callback)(void *data), void *data);
+extern void omap_dispc_free_irq(void);
+
+#endif
diff --git a/drivers/video/omap/hwa742.c b/drivers/video/omap/hwa742.c
new file mode 100644 (file)
index 0000000..5c96166
--- /dev/null
@@ -0,0 +1,862 @@
+/*
+ * File: drivers/video/omap/hwa742.c
+ *
+ * Epson HWA742 LCD controller driver
+ *
+ * Copyright (C) 2004-2005 Nokia Corporation
+ * Authors:     Juha Yrjölä   <juha.yrjola@nokia.com>
+ *             Imre Deak     <imre.deak@nokia.com>
+ * YUV support: Jussi Laako   <jussi.laako@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+
+#include <asm/arch/dma.h>
+#include <asm/arch/omapfb.h>
+
+#define MODULE_NAME              "hwa742"
+
+#define HWA742_REV_CODE_REG       0x0
+#define HWA742_CONFIG_REG         0x2
+#define HWA742_PLL_DIV_REG        0x4
+#define HWA742_PLL_0_REG          0x6
+#define HWA742_PLL_1_REG          0x8
+#define HWA742_PLL_2_REG          0xa
+#define HWA742_PLL_3_REG          0xc
+#define HWA742_PLL_4_REG          0xe
+#define HWA742_CLK_SRC_REG        0x12
+#define HWA742_PANEL_TYPE_REG     0x14
+#define HWA742_H_DISP_REG         0x16
+#define HWA742_H_NDP_REG          0x18
+#define HWA742_V_DISP_1_REG       0x1a
+#define HWA742_V_DISP_2_REG       0x1c
+#define HWA742_V_NDP_REG          0x1e
+#define HWA742_HS_W_REG           0x20
+#define HWA742_HP_S_REG           0x22
+#define HWA742_VS_W_REG           0x24
+#define HWA742_VP_S_REG           0x26
+#define HWA742_PCLK_POL_REG       0x28
+#define HWA742_INPUT_MODE_REG     0x2a
+#define HWA742_TRANSL_MODE_REG1   0x2e
+#define HWA742_DISP_MODE_REG      0x34
+#define HWA742_WINDOW_TYPE        0x36
+#define HWA742_WINDOW_X_START_0   0x38
+#define HWA742_WINDOW_X_START_1   0x3a
+#define HWA742_WINDOW_Y_START_0   0x3c
+#define HWA742_WINDOW_Y_START_1   0x3e
+#define HWA742_WINDOW_X_END_0     0x40
+#define HWA742_WINDOW_X_END_1     0x42
+#define HWA742_WINDOW_Y_END_0     0x44
+#define HWA742_WINDOW_Y_END_1     0x46
+#define HWA742_MEMORY_WRITE_LSB   0x48
+#define HWA742_MEMORY_WRITE_MSB   0x49
+#define HWA742_MEMORY_READ_0      0x4a
+#define HWA742_MEMORY_READ_1      0x4c
+#define HWA742_MEMORY_READ_2      0x4e
+#define HWA742_POWER_SAVE         0x56
+#define HWA742_NDP_CTRL           0x58
+
+#define HWA742_AUTO_UPDATE_TIME                (HZ / 20)
+
+/* Reserve 4 request slots for requests in irq context */
+#define REQ_POOL_SIZE                  24
+#define IRQ_REQ_POOL_SIZE              4
+
+#define REQ_FROM_IRQ_POOL 0x01
+
+#define REQ_COMPLETE   0
+#define REQ_PENDING    1
+
+struct update_param {
+       int     x, y, width, height;
+       int     color_mode;
+       int     flags;
+};
+
+struct hwa742_request {
+       struct list_head entry;
+       unsigned int     flags;
+
+       int              (*handler)(struct hwa742_request *req);
+       void             (*complete)(void *data);
+       void             *complete_data;
+
+       union {
+               struct update_param     update;
+               struct completion       *sync;
+       } par;
+};
+
+struct {
+       enum omapfb_update_mode update_mode;
+       enum omapfb_update_mode update_mode_before_suspend;
+
+       struct timer_list       auto_update_timer;
+       int                     stop_auto_update;
+       struct omapfb_update_window     auto_update_window;
+
+       struct hwa742_request   req_pool[REQ_POOL_SIZE];
+       struct list_head        pending_req_list;
+       struct list_head        free_req_list;
+       struct semaphore        req_sema;
+       spinlock_t              req_lock;
+
+       struct clk              *sys_ck;
+       struct extif_timings    reg_timings, lut_timings;
+
+       int                     prev_color_mode;
+       int                     prev_flags;
+       int                     window_type;
+
+       u32                     max_transmit_size;
+       u32                     extif_clk_period;
+
+       struct omapfb_device    *fbdev;
+       struct lcd_ctrl_extif   *extif;
+       struct lcd_ctrl         *int_ctrl;
+} hwa742;
+
+struct lcd_ctrl hwa742_ctrl;
+
+static u8 hwa742_read_reg(u8 reg)
+{
+       u8 data;
+
+       hwa742.extif->set_bits_per_cycle(8);
+       hwa742.extif->write_command(&reg, 1);
+       hwa742.extif->read_data(&data, 1);
+
+       return data;
+}
+
+static void hwa742_write_reg(u8 reg, u8 data)
+{
+       hwa742.extif->set_bits_per_cycle(8);
+       hwa742.extif->write_command(&reg, 1);
+       hwa742.extif->write_data(&data, 1);
+}
+
+static void set_window_regs(int x_start, int y_start, int x_end, int y_end)
+{
+       u8 tmp[8];
+       u8 cmd;
+
+       x_end--;
+       y_end--;
+       tmp[0] = x_start;
+       tmp[1] = x_start >> 8;
+       tmp[2] = y_start;
+       tmp[3] = y_start >> 8;
+       tmp[4] = x_end;
+       tmp[5] = x_end >> 8;
+       tmp[6] = y_end;
+       tmp[7] = y_end >> 8;
+
+       hwa742.extif->set_bits_per_cycle(8);
+       cmd = HWA742_WINDOW_X_START_0;
+
+       hwa742.extif->write_command(&cmd, 1);
+
+       hwa742.extif->write_data(tmp, 8);
+}
+
+static void set_format_regs(int conv, int transl, int flags)
+{
+       if (flags & OMAPFB_FORMAT_FLAG_DOUBLE) {
+               hwa742.window_type = ((hwa742.window_type & 0xfc) | 0x01);
+#ifdef VERBOSE
+               dev_dbg(hwa742.fbdev->dev, "hwa742: enabled pixel doubling\n");
+#endif
+       } else {
+               hwa742.window_type = (hwa742.window_type & 0xfc);
+#ifdef VERBOSE
+               dev_dbg(hwa742.fbdev->dev, "hwa742: disabled pixel doubling\n");
+#endif
+       }
+
+       hwa742_write_reg(HWA742_INPUT_MODE_REG, conv);
+       hwa742_write_reg(HWA742_TRANSL_MODE_REG1, transl);
+       hwa742_write_reg(HWA742_WINDOW_TYPE, hwa742.window_type);
+}
+
+static inline struct hwa742_request *alloc_req(void)
+{
+       unsigned long flags;
+       struct hwa742_request *req;
+       int req_flags = 0;
+
+       if (!in_interrupt())
+               down(&hwa742.req_sema);
+       else
+               req_flags = REQ_FROM_IRQ_POOL;
+
+       spin_lock_irqsave(&hwa742.req_lock, flags);
+       BUG_ON(list_empty(&hwa742.free_req_list));
+       req = list_entry(hwa742.free_req_list.next,
+                        struct hwa742_request, entry);
+       list_del(&req->entry);
+       spin_unlock_irqrestore(&hwa742.req_lock, flags);
+
+       INIT_LIST_HEAD(&req->entry);
+       req->flags = req_flags;
+
+       return req;
+}
+
+static inline void free_req(struct hwa742_request *req)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&hwa742.req_lock, flags);
+
+       list_del(&req->entry);
+       list_add(&req->entry, &hwa742.free_req_list);
+       if (!(req->flags & REQ_FROM_IRQ_POOL))
+               up(&hwa742.req_sema);
+
+       spin_unlock_irqrestore(&hwa742.req_lock, flags);
+}
+
+static void process_pending_requests(void)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&hwa742.req_lock, flags);
+
+       while (!list_empty(&hwa742.pending_req_list)) {
+               struct hwa742_request *req;
+               void (*complete)(void *);
+               void *complete_data;
+
+               req = list_entry(hwa742.pending_req_list.next,
+                                struct hwa742_request, entry);
+               spin_unlock_irqrestore(&hwa742.req_lock, flags);
+
+               if (req->handler(req) == REQ_PENDING)
+                       return;
+
+               complete = req->complete;
+               complete_data = req->complete_data;
+               free_req(req);
+
+               if (complete)
+                       complete(complete_data);
+
+               spin_lock_irqsave(&hwa742.req_lock, flags);
+       }
+
+       spin_unlock_irqrestore(&hwa742.req_lock, flags);
+}
+
+static void submit_req_list(struct list_head *head)
+{
+       unsigned long flags;
+       int process = 1;
+
+       spin_lock_irqsave(&hwa742.req_lock, flags);
+       if (likely(!list_empty(&hwa742.pending_req_list)))
+               process = 0;
+       list_splice_init(head, hwa742.pending_req_list.prev);
+       spin_unlock_irqrestore(&hwa742.req_lock, flags);
+
+       if (process)
+               process_pending_requests();
+}
+
+static void request_complete(void *data)
+{
+       struct hwa742_request   *req = (struct hwa742_request *)data;
+       void                    (*complete)(void *);
+       void                    *complete_data;
+
+       complete = req->complete;
+       complete_data = req->complete_data;
+
+       free_req(req);
+
+       if (complete)
+               complete(complete_data);
+
+       process_pending_requests();
+}
+
+static int send_frame_handler(struct hwa742_request *req)
+{
+       struct update_param *par = &req->par.update;
+       int x = par->x;
+       int y = par->y;
+       int w = par->width;
+       int h = par->height;
+       int bpp;
+       int conv, transl;
+       unsigned long offset;
+       int color_mode = par->color_mode;
+       int flags = par->flags;
+       int scr_width = 800;
+
+#ifdef VERBOSE
+       dev_dbg(hwa742.fbdev->dev, "x %d y %d w %d h %d scr_width %d "
+               "color_mode %d flags %d\n",
+               x, y, w, h, scr_width, color_mode, flags);
+#endif
+
+       switch (color_mode) {
+       case OMAPFB_COLOR_YUV422:
+               bpp = 16;
+               conv = 0x08;
+               transl = 0x25;
+               break;
+       case OMAPFB_COLOR_YUV420:
+               bpp = 12;
+               conv = 0x09;
+               transl = 0x25;
+               break;
+       case OMAPFB_COLOR_RGB565:
+               bpp = 16;
+               conv = 0x01;
+               transl = 0x05;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (hwa742.prev_flags != flags ||
+           hwa742.prev_color_mode != color_mode) {
+               set_format_regs(conv, transl, flags);
+               hwa742.prev_color_mode = color_mode;
+               hwa742.prev_flags = flags;
+       }
+
+       set_window_regs(x, y, x + w, y + h);
+
+       offset = (scr_width * y + x) * bpp / 8;
+
+       hwa742.int_ctrl->setup_plane(OMAPFB_PLANE_GFX,
+                       OMAPFB_CHANNEL_OUT_LCD, offset, scr_width, 0, 0, w, h,
+                       color_mode);
+
+       hwa742.extif->set_bits_per_cycle(16);
+
+       hwa742.int_ctrl->enable_plane(OMAPFB_PLANE_GFX, 1);
+       hwa742.extif->transfer_area(w, h, request_complete, req);
+
+       return REQ_PENDING;
+}
+
+static void send_frame_complete(void *data)
+{
+       hwa742.int_ctrl->enable_plane(OMAPFB_PLANE_GFX, 0);
+}
+
+#define ADD_PREQ(_x, _y, _w, _h) do {          \
+       req = alloc_req();                      \
+       req->handler    = send_frame_handler;   \
+       req->complete   = send_frame_complete;  \
+       req->par.update.x = _x;                 \
+       req->par.update.y = _y;                 \
+       req->par.update.width  = _w;            \
+       req->par.update.height = _h;            \
+       req->par.update.color_mode = color_mode;\
+       req->par.update.flags     = flags;      \
+       list_add_tail(&req->entry, req_head);   \
+} while(0)
+
+static void create_req_list(struct omapfb_update_window *win,
+                           struct list_head *req_head)
+{
+       struct hwa742_request *req;
+       int x = win->x;
+       int y = win->y;
+       int width = win->width;
+       int height = win->height;
+       int color_mode;
+       int flags;
+
+       flags = win->format & OMAPFB_FORMAT_FLAG_DOUBLE;
+       color_mode = win->format & OMAPFB_FORMAT_MASK;
+
+       if (x & 1) {
+               ADD_PREQ(x, y, 1, height);
+               width--;
+               x++;
+       }
+       if (width & ~1) {
+               unsigned int xspan = width & ~1;
+               unsigned int ystart = y;
+               unsigned int yspan = height;
+
+               if (xspan * height * 2 > hwa742.max_transmit_size) {
+                       yspan = hwa742.max_transmit_size / (xspan * 2);
+                       ADD_PREQ(x, ystart, xspan, yspan);
+                       ystart += yspan;
+                       yspan = height - yspan;
+               }
+
+               ADD_PREQ(x, ystart, xspan, yspan);
+               x += xspan;
+               width -= xspan;
+       }
+       if (width)
+               ADD_PREQ(x, y, 1, height);
+}
+
+static void auto_update_complete(void *data)
+{
+       if (!hwa742.stop_auto_update)
+               mod_timer(&hwa742.auto_update_timer,
+                         jiffies + HWA742_AUTO_UPDATE_TIME);
+}
+
+static void hwa742_update_window_auto(unsigned long arg)
+{
+       LIST_HEAD(req_list);
+       struct hwa742_request *last;
+
+       create_req_list(&hwa742.auto_update_window, &req_list);
+       last = list_entry(req_list.prev, struct hwa742_request, entry);
+
+       last->complete = auto_update_complete;
+       last->complete_data = NULL;
+
+       submit_req_list(&req_list);
+}
+
+int hwa742_update_window_async(struct fb_info *fbi,
+                                struct omapfb_update_window *win,
+                                void (*complete_callback)(void *arg),
+                                void *complete_callback_data)
+{
+       LIST_HEAD(req_list);
+       struct hwa742_request *last;
+       int r = 0;
+
+       if (hwa742.update_mode != OMAPFB_MANUAL_UPDATE) {
+               dev_dbg(hwa742.fbdev->dev, "invalid update mode\n");
+               r = -EINVAL;
+               goto out;
+       }
+       if (unlikely(win->format & ~(0x03 | OMAPFB_FORMAT_FLAG_DOUBLE))) {
+               dev_dbg(hwa742.fbdev->dev, "invalid window flag");
+               r = -EINVAL;
+               goto out;
+       }
+
+       create_req_list(win, &req_list);
+       last = list_entry(req_list.prev, struct hwa742_request, entry);
+
+       last->complete = complete_callback;
+       last->complete_data = (void *)complete_callback_data;
+
+       submit_req_list(&req_list);
+
+out:
+       return r;
+}
+EXPORT_SYMBOL(hwa742_update_window_async);
+
+static int hwa742_setup_plane(int plane, int channel_out,
+                                 unsigned long offset, int screen_width,
+                                 int pos_x, int pos_y, int width, int height,
+                                 int color_mode)
+{
+       if (plane != OMAPFB_PLANE_GFX ||
+           channel_out != OMAPFB_CHANNEL_OUT_LCD)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int hwa742_enable_plane(int plane, int enable)
+{
+       if (plane != 0)
+               return -EINVAL;
+
+       hwa742.int_ctrl->enable_plane(plane, enable);
+
+       return 0;
+}
+
+static int sync_handler(struct hwa742_request *req)
+{
+       complete(req->par.sync);
+       return REQ_COMPLETE;
+}
+
+static void hwa742_sync(void)
+{
+       LIST_HEAD(req_list);
+       struct hwa742_request *req;
+       struct completion comp;
+
+       req = alloc_req();
+
+       req->handler = sync_handler;
+       req->complete = NULL;
+       init_completion(&comp);
+       req->par.sync = &comp;
+
+       list_add(&req->entry, &req_list);
+       submit_req_list(&req_list);
+
+       wait_for_completion(&comp);
+}
+
+static void hwa742_bind_client(struct omapfb_notifier_block *nb)
+{
+       dev_dbg(hwa742.fbdev->dev, "update_mode %d\n", hwa742.update_mode);
+       if (hwa742.update_mode == OMAPFB_MANUAL_UPDATE) {
+               omapfb_notify_clients(hwa742.fbdev, OMAPFB_EVENT_READY);
+       }
+}
+
+static int hwa742_set_update_mode(enum omapfb_update_mode mode)
+{
+       if (mode != OMAPFB_MANUAL_UPDATE && mode != OMAPFB_AUTO_UPDATE &&
+           mode != OMAPFB_UPDATE_DISABLED)
+               return -EINVAL;
+
+       if (mode == hwa742.update_mode)
+               return 0;
+
+       pr_info("omapfb: hwa742: setting update mode to %s\n",
+                       mode == OMAPFB_UPDATE_DISABLED ? "disabled" :
+                       (mode == OMAPFB_AUTO_UPDATE ? "auto" : "manual"));
+
+       switch (hwa742.update_mode) {
+       case OMAPFB_MANUAL_UPDATE:
+               omapfb_notify_clients(hwa742.fbdev, OMAPFB_EVENT_DISABLED);
+               break;
+       case OMAPFB_AUTO_UPDATE:
+               hwa742.stop_auto_update = 1;
+               del_timer_sync(&hwa742.auto_update_timer);
+               break;
+       case OMAPFB_UPDATE_DISABLED:
+               break;
+       }
+
+       hwa742.update_mode = mode;
+       hwa742_sync();
+       hwa742.stop_auto_update = 0;
+
+       switch (mode) {
+       case OMAPFB_MANUAL_UPDATE:
+               omapfb_notify_clients(hwa742.fbdev, OMAPFB_EVENT_READY);
+               break;
+       case OMAPFB_AUTO_UPDATE:
+               hwa742_update_window_auto(0);
+               break;
+       case OMAPFB_UPDATE_DISABLED:
+               break;
+       }
+
+       return 0;
+}
+
+static enum omapfb_update_mode hwa742_get_update_mode(void)
+{
+       return hwa742.update_mode;
+}
+
+static unsigned long round_to_extif_ticks(unsigned long ps, int div)
+{
+       int bus_tick = hwa742.extif_clk_period * div;
+       return (ps + bus_tick - 1) / bus_tick * bus_tick;
+}
+
+static int calc_reg_timing(unsigned long sysclk, int div)
+{
+       struct extif_timings *t;
+       unsigned long systim;
+
+       /* CSOnTime 0, WEOnTime 2 ns, REOnTime 2 ns,
+        * AccessTime 2 ns + 12.2 ns (regs),
+        * WEOffTime = WEOnTime + 1 ns,
+        * REOffTime = REOnTime + 16 ns (regs),
+        * CSOffTime = REOffTime + 1 ns
+        * ReadCycle = 2ns + 2*SYSCLK  (regs),
+        * WriteCycle = 2*SYSCLK + 2 ns,
+        * CSPulseWidth = 10 ns */
+       systim = 1000000000 / (sysclk / 1000);
+       dev_dbg(hwa742.fbdev->dev, "HWA742 systim %lu ps extif_clk_period %u ps"
+                 "extif_clk_div %d\n", systim, hwa742.extif_clk_period, div);
+
+       t = &hwa742.reg_timings;
+       memset(t, 0, sizeof(*t));
+       t->clk_div = div;
+       t->cs_on_time = 0;
+       t->we_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div);
+       t->re_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div);
+       t->access_time = round_to_extif_ticks(t->re_on_time + 12200, div);
+       t->we_off_time = round_to_extif_ticks(t->we_on_time + 1000, div);
+       t->re_off_time = round_to_extif_ticks(t->re_on_time + 16000, div);
+       t->cs_off_time = round_to_extif_ticks(t->re_off_time + 1000, div);
+       t->we_cycle_time = round_to_extif_ticks(2 * systim + 2000, div);
+       if (t->we_cycle_time < t->we_off_time)
+               t->we_cycle_time = t->we_off_time;
+       t->re_cycle_time = round_to_extif_ticks(2 * systim + 2000, div);
+       if (t->re_cycle_time < t->re_off_time)
+               t->re_cycle_time = t->re_off_time;
+       t->cs_pulse_width = 0;
+
+       dev_dbg(hwa742.fbdev->dev, "[reg]cson %d csoff %d reon %d reoff %d\n",
+                t->cs_on_time, t->cs_off_time, t->re_on_time, t->re_off_time);
+       dev_dbg(hwa742.fbdev->dev, "[reg]weon %d weoff %d recyc %d wecyc %d\n",
+                t->we_on_time, t->we_off_time, t->re_cycle_time,
+                t->we_cycle_time);
+       dev_dbg(hwa742.fbdev->dev, "[reg]rdaccess %d cspulse %d\n",
+                t->access_time, t->cs_pulse_width);
+
+       return hwa742.extif->convert_timings(t);
+}
+
+static int calc_lut_timing(unsigned long sysclk, int div)
+{
+       struct extif_timings *t;
+       unsigned long systim;
+
+       /* CSOnTime 0, WEOnTime 2 ns, REOnTime 2 ns,
+        * AccessTime 2 ns + 4 * SYSCLK + 26 (lut),
+        * WEOffTime = WEOnTime + 1 ns,
+        * REOffTime = REOnTime + 4*SYSCLK + 26 ns (lut),
+        * CSOffTime = REOffTime + 1 ns
+        * ReadCycle = 2ns + 4*SYSCLK + 26 ns (lut),
+        * WriteCycle = 2*SYSCLK + 2 ns,
+        * CSPulseWidth = 10 ns
+        */
+       systim = 1000000000 / (sysclk / 1000);
+       dev_dbg(hwa742.fbdev->dev, "HWA742 systim %lu ps extif_clk_period %u ps"
+                 "extif_clk_div %d\n", systim, hwa742.extif_clk_period, div);
+
+       t = &hwa742.lut_timings;
+       memset(t, 0, sizeof(*t));
+
+       t->clk_div = div;
+
+       t->cs_on_time = 0;
+       t->we_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div);
+       t->re_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div);
+       t->access_time = round_to_extif_ticks(t->re_on_time + 4 * systim +
+                                             26000, div);
+       t->we_off_time = round_to_extif_ticks(t->we_on_time + 1000, div);
+       t->re_off_time = round_to_extif_ticks(t->re_on_time + 4 * systim +
+                                             26000, div);
+       t->cs_off_time = round_to_extif_ticks(t->re_off_time + 1000, div);
+       t->we_cycle_time = round_to_extif_ticks(2 * systim + 2000, div);
+       if (t->we_cycle_time < t->we_off_time)
+               t->we_cycle_time = t->we_off_time;
+       t->re_cycle_time = round_to_extif_ticks(2000 + 4 * systim + 26000, div);
+       if (t->re_cycle_time < t->re_off_time)
+               t->re_cycle_time = t->re_off_time;
+       t->cs_pulse_width = 0;
+
+       dev_dbg(hwa742.fbdev->dev, "[lut]cson %d csoff %d reon %d reoff %d\n",
+                t->cs_on_time, t->cs_off_time, t->re_on_time, t->re_off_time);
+       dev_dbg(hwa742.fbdev->dev, "[lut]weon %d weoff %d recyc %d wecyc %d\n",
+                t->we_on_time, t->we_off_time, t->re_cycle_time,
+                t->we_cycle_time);
+       dev_dbg(hwa742.fbdev->dev, "[lut]rdaccess %d cspulse %d\n",
+                t->access_time, t->cs_pulse_width);
+
+       return hwa742.extif->convert_timings(t);
+}
+
+static int calc_extif_timings(unsigned long sysclk)
+{
+       int max_clk_div;
+       int div;
+
+       hwa742.extif->get_clk_info(&hwa742.extif_clk_period, &max_clk_div);
+       for (div = 1; div < max_clk_div; div++) {
+               if (calc_reg_timing(sysclk, div) == 0)
+                       break;
+       }
+       if (div == max_clk_div)
+               goto err;
+
+       for (div = 1; div < max_clk_div; div++) {
+               if (calc_lut_timing(sysclk, div) == 0)
+                       break;
+       }
+
+       if (div < max_clk_div)
+               return 0;
+
+err:
+       dev_err(hwa742.fbdev->dev, "can't setup timings\n");
+       return -1;
+}
+
+static unsigned long hwa742_get_caps(void)
+{
+       return OMAPFB_CAPS_MANUAL_UPDATE;
+}
+
+static void hwa742_suspend(void)
+{
+       hwa742.update_mode_before_suspend = hwa742.update_mode;
+       hwa742_set_update_mode(OMAPFB_UPDATE_DISABLED);
+       /* Enable sleep mode */
+       hwa742_write_reg(HWA742_POWER_SAVE, 1 << 1);
+       clk_disable(hwa742.sys_ck);
+}
+
+static void hwa742_resume(void)
+{
+       if (clk_enable(hwa742.sys_ck) != 0)
+               dev_err(hwa742.fbdev->dev, "failed to enable SYS clock\n");
+       /* Disable sleep mode */
+       hwa742_write_reg(HWA742_POWER_SAVE, 0);
+       while (1) {
+               /* Loop until PLL output is stabilized */
+               if (hwa742_read_reg(HWA742_PLL_DIV_REG) & (1 << 7))
+                       break;
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule_timeout(msecs_to_jiffies(5));
+       }
+       hwa742_set_update_mode(hwa742.update_mode_before_suspend);
+}
+
+static int hwa742_init(struct omapfb_device *fbdev, int ext_mode,
+                      struct omapfb_mem_desc *req_vram)
+{
+       int r = 0, i;
+       u8 rev, conf;
+       unsigned long sysfreq;
+       int div, nd;
+
+       hwa742.fbdev = fbdev;
+
+       hwa742.sys_ck = clk_get(0, "bclk");
+       if (IS_ERR(hwa742.sys_ck)) {
+               dev_err(fbdev->dev, "can't get SYS clock\n");
+               return PTR_ERR(hwa742.sys_ck);
+       }
+
+       if ((r = clk_enable(hwa742.sys_ck)) != 0) {
+               dev_err(fbdev->dev, "can't enable SYS clock\n");
+               clk_put(hwa742.sys_ck);
+               return r;
+       }
+
+       BUG_ON(!fbdev->ext_if || !fbdev->int_ctrl);
+
+       hwa742.fbdev = fbdev;
+       hwa742.extif = fbdev->ext_if;
+       hwa742.int_ctrl = fbdev->int_ctrl;
+
+       spin_lock_init(&hwa742.req_lock);
+
+       if ((r = hwa742.int_ctrl->init(fbdev, 1, req_vram)) < 0)
+               goto err1;
+
+       if ((r = hwa742.extif->init(fbdev)) < 0)
+               goto err2;
+
+       sysfreq = clk_get_rate(hwa742.sys_ck);
+       if ((r = calc_extif_timings(sysfreq)) < 0)
+               goto err3;
+       hwa742.extif->set_timings(&hwa742.reg_timings);
+
+       div = (hwa742_read_reg(HWA742_PLL_DIV_REG) & 0x3f) + 1;
+
+       nd = (hwa742_read_reg(HWA742_PLL_4_REG) & 0x7f) + 1;
+
+       if ((r = calc_extif_timings(sysfreq / div * nd)) < 0)
+               goto err3;
+       hwa742.extif->set_timings(&hwa742.reg_timings);
+
+       rev = hwa742_read_reg(HWA742_REV_CODE_REG);
+       if ((rev & 0xfc) != 0x80) {
+               dev_err(fbdev->dev, "invalid revision %02x\n", rev);
+               r = -ENODEV;
+               goto err3;
+       }
+
+       if (!(hwa742_read_reg(HWA742_PLL_DIV_REG) & 0x80)) {
+               dev_err(hwa742.fbdev->dev,
+                       "controller not initialized by the bootloader\n");
+               r = -ENODEV;
+               goto err2;
+       }
+
+       hwa742.max_transmit_size = hwa742.extif->max_transmit_size;
+
+       hwa742.update_mode = OMAPFB_UPDATE_DISABLED;
+
+       hwa742.auto_update_window.x = 0;
+       hwa742.auto_update_window.y = 0;
+       hwa742.auto_update_window.width = fbdev->panel->x_res;
+       hwa742.auto_update_window.height = fbdev->panel->y_res;
+       hwa742.auto_update_window.format = 0;
+
+       init_timer(&hwa742.auto_update_timer);
+       hwa742.auto_update_timer.function = hwa742_update_window_auto;
+       hwa742.auto_update_timer.data = 0;
+
+       hwa742.prev_color_mode = -1;
+       hwa742.prev_flags = 0;
+
+       INIT_LIST_HEAD(&hwa742.free_req_list);
+       INIT_LIST_HEAD(&hwa742.pending_req_list);
+       for (i = 0; i < ARRAY_SIZE(hwa742.req_pool); i++)
+               list_add(&hwa742.req_pool[i].entry, &hwa742.free_req_list);
+       BUG_ON(i <= IRQ_REQ_POOL_SIZE);
+       sema_init(&hwa742.req_sema, i - IRQ_REQ_POOL_SIZE);
+
+       conf = hwa742_read_reg(HWA742_CONFIG_REG);
+       pr_info("omapfb: hwa742 LCD controller rev. %d "
+                       "initialized (CNF pins %x)\n", rev & 0x03, conf & 0x07);
+
+       return 0;
+err3:
+       hwa742.extif->cleanup();
+err2:
+       hwa742.int_ctrl->cleanup();
+err1:
+       clk_disable(hwa742.sys_ck);
+       clk_put(hwa742.sys_ck);
+       return r;
+}
+
+static void hwa742_cleanup(void)
+{
+       hwa742_set_update_mode(OMAPFB_UPDATE_DISABLED);
+       hwa742.extif->cleanup();
+       hwa742.int_ctrl->cleanup();
+       clk_disable(hwa742.sys_ck);
+       clk_put(hwa742.sys_ck);
+}
+
+struct lcd_ctrl hwa742_ctrl = {
+       .name                   = "hwa742",
+       .init                   = hwa742_init,
+       .cleanup                = hwa742_cleanup,
+       .bind_client            = hwa742_bind_client,
+       .get_caps               = hwa742_get_caps,
+       .set_update_mode        = hwa742_set_update_mode,
+       .get_update_mode        = hwa742_get_update_mode,
+       .setup_plane            = hwa742_setup_plane,
+       .enable_plane           = hwa742_enable_plane,
+       .update_window          = hwa742_update_window_async,
+       .sync                   = hwa742_sync,
+       .suspend                = hwa742_suspend,
+       .resume                 = hwa742_resume,
+};
+
diff --git a/drivers/video/omap/lcd_ams_delta.c b/drivers/video/omap/lcd_ams_delta.c
new file mode 100644 (file)
index 0000000..3476689
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * File: drivers/video/omap/lcd_ams_delta.c
+ *
+ * Based on drivers/video/omap/lcd_inn1510.c
+ *
+ * LCD panel support for the Amstrad E3 (Delta) videophone.
+ *
+ * Copyright (C) 2006 Jonathan McDowell <noodles@earth.li>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <asm/delay.h>
+#include <asm/io.h>
+
+#include <asm/arch/board-ams-delta.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/omapfb.h>
+
+#define AMS_DELTA_DEFAULT_CONTRAST     112
+
+static int ams_delta_panel_init(struct lcd_panel *panel,
+               struct omapfb_device *fbdev)
+{
+       return 0;
+}
+
+static void ams_delta_panel_cleanup(struct lcd_panel *panel)
+{
+}
+
+static int ams_delta_panel_enable(struct lcd_panel *panel)
+{
+       ams_delta_latch2_write(AMS_DELTA_LATCH2_LCD_NDISP,
+                       AMS_DELTA_LATCH2_LCD_NDISP);
+       ams_delta_latch2_write(AMS_DELTA_LATCH2_LCD_VBLEN,
+                       AMS_DELTA_LATCH2_LCD_VBLEN);
+
+       omap_writeb(1, OMAP_PWL_CLK_ENABLE);
+       omap_writeb(AMS_DELTA_DEFAULT_CONTRAST, OMAP_PWL_ENABLE);
+
+       return 0;
+}
+
+static void ams_delta_panel_disable(struct lcd_panel *panel)
+{
+       ams_delta_latch2_write(AMS_DELTA_LATCH2_LCD_VBLEN, 0);
+       ams_delta_latch2_write(AMS_DELTA_LATCH2_LCD_NDISP, 0);
+}
+
+static unsigned long ams_delta_panel_get_caps(struct lcd_panel *panel)
+{
+       return 0;
+}
+
+static struct lcd_panel ams_delta_panel = {
+       .name           = "ams-delta",
+       .config         = 0,
+
+       .bpp            = 12,
+       .data_lines     = 16,
+       .x_res          = 480,
+       .y_res          = 320,
+       .pixel_clock    = 4687,
+       .hsw            = 3,
+       .hfp            = 1,
+       .hbp            = 1,
+       .vsw            = 1,
+       .vfp            = 0,
+       .vbp            = 0,
+       .pcd            = 0,
+       .acb            = 37,
+
+       .init           = ams_delta_panel_init,
+       .cleanup        = ams_delta_panel_cleanup,
+       .enable         = ams_delta_panel_enable,
+       .disable        = ams_delta_panel_disable,
+       .get_caps       = ams_delta_panel_get_caps,
+};
+
+static int ams_delta_panel_probe(struct platform_device *pdev)
+{
+       omapfb_register_panel(&ams_delta_panel);
+       return 0;
+}
+
+static int ams_delta_panel_remove(struct platform_device *pdev)
+{
+       return 0;
+}
+
+static int ams_delta_panel_suspend(struct platform_device *pdev,
+               pm_message_t mesg)
+{
+       return 0;
+}
+
+static int ams_delta_panel_resume(struct platform_device *pdev)
+{
+       return 0;
+}
+
+struct platform_driver ams_delta_panel_driver = {
+       .probe          = ams_delta_panel_probe,
+       .remove         = ams_delta_panel_remove,
+       .suspend        = ams_delta_panel_suspend,
+       .resume         = ams_delta_panel_resume,
+       .driver         = {
+               .name   = "lcd_ams_delta",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int ams_delta_panel_drv_init(void)
+{
+       return platform_driver_register(&ams_delta_panel_driver);
+}
+
+static void ams_delta_panel_drv_cleanup(void)
+{
+       platform_driver_unregister(&ams_delta_panel_driver);
+}
+
+module_init(ams_delta_panel_drv_init);
+module_exit(ams_delta_panel_drv_cleanup);
diff --git a/drivers/video/omap/lcd_apollon.c b/drivers/video/omap/lcd_apollon.c
new file mode 100644 (file)
index 0000000..4c0f370
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * File: drivers/video/omap/lcd_apollon.c
+ *
+ * LCD panel support for the Samsung OMAP2 Apollon board
+ *
+ * Copyright (C) 2005,2006 Samsung Electronics
+ * Author: Kyungmin Park <kyungmin.park@samsung.com>
+ *
+ * Derived from drivers/video/omap/lcd-h4.c
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/omapfb.h>
+
+/* #define 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);
diff --git a/drivers/video/omap/lcd_h2.c b/drivers/video/omap/lcd_h2.c
new file mode 100644 (file)
index 0000000..b96d81d
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * File: drivers/video/omap/lcd-h2.c
+ *
+ * LCD panel support for the TI OMAP H2 board
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Imre Deak <imre.deak@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <asm/arch/mux.h>
+#include <asm/arch/omapfb.h>
+
+#include "../drivers/ssi/omap-uwire.h"
+
+#define MODULE_NAME            "omapfb-lcd_h2"
+#define TSC2101_UWIRE_CS       1
+
+#define pr_err(fmt, args...) printk(KERN_ERR MODULE_NAME ": " fmt, ## args)
+
+static int tsc2101_write_reg(int page, int reg, u16 data)
+{
+       u16     cmd;
+       int     r;
+
+       cmd = ((page & 3) << 11) | ((reg & 0x3f) << 5);
+       if (omap_uwire_data_transfer(TSC2101_UWIRE_CS, cmd, 16, 0, NULL, 1))
+               r = -1;
+       else
+               r = omap_uwire_data_transfer(TSC2101_UWIRE_CS, data, 16, 0,
+                                            NULL, 0);
+
+       return r;
+}
+
+static int h2_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
+{
+       unsigned long uwire_flags;
+
+        /* Configure N15 pin to be uWire CS1 */
+       omap_cfg_reg(N15_1610_UWIRE_CS1);
+       uwire_flags = UWIRE_READ_RISING_EDGE | UWIRE_WRITE_RISING_EDGE;
+       uwire_flags |= UWIRE_FREQ_DIV_8;
+       omap_uwire_configure_mode(TSC2101_UWIRE_CS, uwire_flags);
+
+       return 0;
+}
+
+static void h2_panel_cleanup(struct lcd_panel *panel)
+{
+}
+
+static int h2_panel_enable(struct lcd_panel *panel)
+{
+       int r;
+
+       /* Assert LCD_EN, BKLIGHT_EN pins on LCD panel
+        * page2, GPIO config reg, GPIO(0,1) to out and asserted
+        */
+       r = tsc2101_write_reg(2, 0x23, 0xCC00) ? -1 : 0;
+
+       return r;
+}
+
+static void h2_panel_disable(struct lcd_panel *panel)
+{
+       /* Deassert LCD_EN and BKLIGHT_EN pins on LCD panel
+        * page2, GPIO config reg, GPIO(0,1) to out and deasserted
+        */
+       if (tsc2101_write_reg(2, 0x23, 0x8800))
+               pr_err("failed to disable LCD panel\n");
+}
+
+static unsigned long h2_panel_get_caps(struct lcd_panel *panel)
+{
+       return 0;
+}
+
+struct lcd_panel h2_panel = {
+       .name           = "h2",
+       .config         = OMAP_LCDC_PANEL_TFT,
+
+       .bpp            = 16,
+       .data_lines     = 16,
+       .x_res          = 240,
+       .y_res          = 320,
+       .pixel_clock    = 5000,
+       .hsw            = 12,
+       .hfp            = 12,
+       .hbp            = 46,
+       .vsw            = 1,
+       .vfp            = 1,
+       .vbp            = 0,
+
+       .init           = h2_panel_init,
+       .cleanup        = h2_panel_cleanup,
+       .enable         = h2_panel_enable,
+       .disable        = h2_panel_disable,
+       .get_caps       = h2_panel_get_caps,
+};
+
+static int h2_panel_probe(struct platform_device *pdev)
+{
+       omapfb_register_panel(&h2_panel);
+       return 0;
+}
+
+static int h2_panel_remove(struct platform_device *pdev)
+{
+       return 0;
+}
+
+static int h2_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+       return 0;
+}
+
+static int h2_panel_resume(struct platform_device *pdev)
+{
+       return 0;
+}
+
+struct platform_driver h2_panel_driver = {
+       .probe          = h2_panel_probe,
+       .remove         = h2_panel_remove,
+       .suspend        = h2_panel_suspend,
+       .resume         = h2_panel_resume,
+       .driver         = {
+               .name   = "lcd_h2",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int h2_panel_drv_init(void)
+{
+       return platform_driver_register(&h2_panel_driver);
+}
+
+static void h2_panel_drv_cleanup(void)
+{
+       platform_driver_unregister(&h2_panel_driver);
+}
+
+module_init(h2_panel_drv_init);
+module_exit(h2_panel_drv_cleanup);
+
diff --git a/drivers/video/omap/lcd_h3.c b/drivers/video/omap/lcd_h3.c
new file mode 100644 (file)
index 0000000..60ad0e0
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * File: drivers/video/omap/lcd-h3.c
+ *
+ * LCD panel support for the TI OMAP H3 board
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Imre Deak <imre.deak@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/tps65010.h>
+#include <asm/arch/omapfb.h>
+
+#define MODULE_NAME    "omapfb-lcd_h3"
+
+#define pr_err(fmt, args...) printk(KERN_ERR MODULE_NAME ": " fmt, ## args)
+
+static int h3_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
+{
+       return 0;
+}
+
+static void h3_panel_cleanup(struct lcd_panel *panel)
+{
+}
+
+static int h3_panel_enable(struct lcd_panel *panel)
+{
+       int r = 0;
+
+       /* GPIO1 and GPIO2 of TPS65010 send LCD_ENBKL and LCD_ENVDD signals */
+       r = tps65010_set_gpio_out_value(GPIO1, HIGH);
+       if (!r)
+               r = tps65010_set_gpio_out_value(GPIO2, HIGH);
+       if (r)
+               pr_err("Unable to turn on LCD panel\n");
+
+       return r;
+}
+
+static void h3_panel_disable(struct lcd_panel *panel)
+{
+       int r = 0;
+
+       /* GPIO1 and GPIO2 of TPS65010 send LCD_ENBKL and LCD_ENVDD signals */
+       r = tps65010_set_gpio_out_value(GPIO1, LOW);
+       if (!r)
+               tps65010_set_gpio_out_value(GPIO2, LOW);
+       if (r)
+               pr_err("Unable to turn off LCD panel\n");
+}
+
+static unsigned long h3_panel_get_caps(struct lcd_panel *panel)
+{
+       return 0;
+}
+
+struct lcd_panel h3_panel = {
+       .name           = "h3",
+       .config         = OMAP_LCDC_PANEL_TFT,
+
+       .data_lines     = 16,
+       .bpp            = 16,
+       .x_res          = 240,
+       .y_res          = 320,
+       .pixel_clock    = 12000,
+       .hsw            = 12,
+       .hfp            = 14,
+       .hbp            = 72 - 12,
+       .vsw            = 1,
+       .vfp            = 1,
+       .vbp            = 0,
+       .pcd            = 0,
+
+       .init           = h3_panel_init,
+       .cleanup        = h3_panel_cleanup,
+       .enable         = h3_panel_enable,
+       .disable        = h3_panel_disable,
+       .get_caps       = h3_panel_get_caps,
+};
+
+static int h3_panel_probe(struct platform_device *pdev)
+{
+       omapfb_register_panel(&h3_panel);
+       return 0;
+}
+
+static int h3_panel_remove(struct platform_device *pdev)
+{
+       return 0;
+}
+
+static int h3_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+       return 0;
+}
+
+static int h3_panel_resume(struct platform_device *pdev)
+{
+       return 0;
+}
+
+struct platform_driver h3_panel_driver = {
+       .probe          = h3_panel_probe,
+       .remove         = h3_panel_remove,
+       .suspend        = h3_panel_suspend,
+       .resume         = h3_panel_resume,
+       .driver         = {
+               .name   = "lcd_h3",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int h3_panel_drv_init(void)
+{
+       return platform_driver_register(&h3_panel_driver);
+}
+
+static void h3_panel_drv_cleanup(void)
+{
+       platform_driver_unregister(&h3_panel_driver);
+}
+
+module_init(h3_panel_drv_init);
+module_exit(h3_panel_drv_cleanup);
+
diff --git a/drivers/video/omap/lcd_h4.c b/drivers/video/omap/lcd_h4.c
new file mode 100644 (file)
index 0000000..dde00d4
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * File: drivers/video/omap/lcd-h4.c
+ *
+ * LCD panel support for the TI OMAP H4 board
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Imre Deak <imre.deak@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <asm/arch/omapfb.h>
+
+static int h4_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
+{
+       return 0;
+}
+
+static void h4_panel_cleanup(struct lcd_panel *panel)
+{
+}
+
+static int h4_panel_enable(struct lcd_panel *panel)
+{
+       return 0;
+}
+
+static void h4_panel_disable(struct lcd_panel *panel)
+{
+}
+
+static unsigned long h4_panel_get_caps(struct lcd_panel *panel)
+{
+       return 0;
+}
+
+struct lcd_panel h4_panel = {
+       .name           = "h4",
+       .config         = OMAP_LCDC_PANEL_TFT,
+
+       .bpp            = 16,
+       .data_lines     = 16,
+       .x_res          = 240,
+       .y_res          = 320,
+       .pixel_clock    = 6250,
+       .hsw            = 15,
+       .hfp            = 15,
+       .hbp            = 60,
+       .vsw            = 1,
+       .vfp            = 1,
+       .vbp            = 1,
+
+       .init           = h4_panel_init,
+       .cleanup        = h4_panel_cleanup,
+       .enable         = h4_panel_enable,
+       .disable        = h4_panel_disable,
+       .get_caps       = h4_panel_get_caps,
+};
+
+static int h4_panel_probe(struct platform_device *pdev)
+{
+       omapfb_register_panel(&h4_panel);
+       return 0;
+}
+
+static int h4_panel_remove(struct platform_device *pdev)
+{
+       return 0;
+}
+
+static int h4_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+       return 0;
+}
+
+static int h4_panel_resume(struct platform_device *pdev)
+{
+       return 0;
+}
+
+struct platform_driver h4_panel_driver = {
+       .probe          = h4_panel_probe,
+       .remove         = h4_panel_remove,
+       .suspend        = h4_panel_suspend,
+       .resume         = h4_panel_resume,
+       .driver         = {
+               .name   = "lcd_h4",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int h4_panel_drv_init(void)
+{
+       return platform_driver_register(&h4_panel_driver);
+}
+
+static void h4_panel_drv_cleanup(void)
+{
+       platform_driver_unregister(&h4_panel_driver);
+}
+
+module_init(h4_panel_drv_init);
+module_exit(h4_panel_drv_cleanup);
+
diff --git a/drivers/video/omap/lcd_inn1510.c b/drivers/video/omap/lcd_inn1510.c
new file mode 100644 (file)
index 0000000..d514b94
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * File: drivers/video/omap/lcd-inn1510.c
+ *
+ * LCD panel support for the TI OMAP1510 Innovator board
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Imre Deak <imre.deak@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <asm/io.h>
+
+#include <asm/arch/fpga.h>
+#include <asm/arch/omapfb.h>
+
+static int innovator1510_panel_init(struct lcd_panel *panel,
+                                   struct omapfb_device *fbdev)
+{
+       return 0;
+}
+
+static void innovator1510_panel_cleanup(struct lcd_panel *panel)
+{
+}
+
+static int innovator1510_panel_enable(struct lcd_panel *panel)
+{
+       fpga_write(0x7, OMAP1510_FPGA_LCD_PANEL_CONTROL);
+       return 0;
+}
+
+static void innovator1510_panel_disable(struct lcd_panel *panel)
+{
+       fpga_write(0x0, OMAP1510_FPGA_LCD_PANEL_CONTROL);
+}
+
+static unsigned long innovator1510_panel_get_caps(struct lcd_panel *panel)
+{
+       return 0;
+}
+
+struct lcd_panel innovator1510_panel = {
+       .name           = "inn1510",
+       .config         = OMAP_LCDC_PANEL_TFT,
+
+       .bpp            = 16,
+       .data_lines     = 16,
+       .x_res          = 240,
+       .y_res          = 320,
+       .pixel_clock    = 12500,
+       .hsw            = 40,
+       .hfp            = 40,
+       .hbp            = 72,
+       .vsw            = 1,
+       .vfp            = 1,
+       .vbp            = 0,
+       .pcd            = 12,
+
+       .init           = innovator1510_panel_init,
+       .cleanup        = innovator1510_panel_cleanup,
+       .enable         = innovator1510_panel_enable,
+       .disable        = innovator1510_panel_disable,
+       .get_caps       = innovator1510_panel_get_caps,
+};
+
+static int innovator1510_panel_probe(struct platform_device *pdev)
+{
+       omapfb_register_panel(&innovator1510_panel);
+       return 0;
+}
+
+static int innovator1510_panel_remove(struct platform_device *pdev)
+{
+       return 0;
+}
+
+static int innovator1510_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+       return 0;
+}
+
+static int innovator1510_panel_resume(struct platform_device *pdev)
+{
+       return 0;
+}
+
+struct platform_driver innovator1510_panel_driver = {
+       .probe          = innovator1510_panel_probe,
+       .remove         = innovator1510_panel_remove,
+       .suspend        = innovator1510_panel_suspend,
+       .resume         = innovator1510_panel_resume,
+       .driver         = {
+               .name   = "lcd_inn1510",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int innovator1510_panel_drv_init(void)
+{
+       return platform_driver_register(&innovator1510_panel_driver);
+}
+
+static void innovator1510_panel_drv_cleanup(void)
+{
+       platform_driver_unregister(&innovator1510_panel_driver);
+}
+
+module_init(innovator1510_panel_drv_init);
+module_exit(innovator1510_panel_drv_cleanup);
+
diff --git a/drivers/video/omap/lcd_inn1610.c b/drivers/video/omap/lcd_inn1610.c
new file mode 100644 (file)
index 0000000..cb1fa5a
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * File: drivers/video/omap/lcd-inn1610.c
+ *
+ * LCD panel support for the TI OMAP1610 Innovator board
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Imre Deak <imre.deak@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/omapfb.h>
+
+#define MODULE_NAME    "omapfb-lcd_h3"
+
+#define pr_err(fmt, args...) printk(KERN_ERR MODULE_NAME ": " fmt, ## args)
+
+static int innovator1610_panel_init(struct lcd_panel *panel,
+                                   struct omapfb_device *fbdev)
+{
+       int r = 0;
+
+       if (omap_request_gpio(14)) {
+               pr_err("can't request GPIO 14\n");
+               r = -1;
+               goto exit;
+       }
+       if (omap_request_gpio(15)) {
+               pr_err("can't request GPIO 15\n");
+               omap_free_gpio(14);
+               r = -1;
+               goto exit;
+       }
+       /* configure GPIO(14, 15) as outputs */
+       omap_set_gpio_direction(14, 0);
+       omap_set_gpio_direction(15, 0);
+exit:
+       return r;
+}
+
+static void innovator1610_panel_cleanup(struct lcd_panel *panel)
+{
+       omap_free_gpio(15);
+       omap_free_gpio(14);
+}
+
+static int innovator1610_panel_enable(struct lcd_panel *panel)
+{
+       /* set GPIO14 and GPIO15 high */
+       omap_set_gpio_dataout(14, 1);
+       omap_set_gpio_dataout(15, 1);
+       return 0;
+}
+
+static void innovator1610_panel_disable(struct lcd_panel *panel)
+{
+       /* set GPIO13, GPIO14 and GPIO15 low */
+       omap_set_gpio_dataout(14, 0);
+       omap_set_gpio_dataout(15, 0);
+}
+
+static unsigned long innovator1610_panel_get_caps(struct lcd_panel *panel)
+{
+       return 0;
+}
+
+struct lcd_panel innovator1610_panel = {
+       .name           = "inn1610",
+       .config         = OMAP_LCDC_PANEL_TFT,
+
+       .bpp            = 16,
+       .data_lines     = 16,
+       .x_res          = 320,
+       .y_res          = 240,
+       .pixel_clock    = 12500,
+       .hsw            = 40,
+       .hfp            = 40,
+       .hbp            = 72,
+       .vsw            = 1,
+       .vfp            = 1,
+       .vbp            = 0,
+       .pcd            = 12,
+
+       .init           = innovator1610_panel_init,
+       .cleanup        = innovator1610_panel_cleanup,
+       .enable         = innovator1610_panel_enable,
+       .disable        = innovator1610_panel_disable,
+       .get_caps       = innovator1610_panel_get_caps,
+};
+
+static int innovator1610_panel_probe(struct platform_device *pdev)
+{
+       omapfb_register_panel(&innovator1610_panel);
+       return 0;
+}
+
+static int innovator1610_panel_remove(struct platform_device *pdev)
+{
+       return 0;
+}
+
+static int innovator1610_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+       return 0;
+}
+
+static int innovator1610_panel_resume(struct platform_device *pdev)
+{
+       return 0;
+}
+
+struct platform_driver innovator1610_panel_driver = {
+       .probe          = innovator1610_panel_probe,
+       .remove         = innovator1610_panel_remove,
+       .suspend        = innovator1610_panel_suspend,
+       .resume         = innovator1610_panel_resume,
+       .driver         = {
+               .name   = "lcd_inn1610",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int innovator1610_panel_drv_init(void)
+{
+       return platform_driver_register(&innovator1610_panel_driver);
+}
+
+static void innovator1610_panel_drv_cleanup(void)
+{
+       platform_driver_unregister(&innovator1610_panel_driver);
+}
+
+module_init(innovator1610_panel_drv_init);
+module_exit(innovator1610_panel_drv_cleanup);
+
diff --git a/drivers/video/omap/lcd_mipid.c b/drivers/video/omap/lcd_mipid.c
new file mode 100644 (file)
index 0000000..acc18ab
--- /dev/null
@@ -0,0 +1,616 @@
+/*
+ * File: drivers/video/omap/lcd_mipid.c
+ *
+ * LCD driver for MIPI DBI-C / DCS compatible LCDs
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Author: Imre Deak <imre.deak@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <linux/spi/spi.h>
+
+#include <asm/arch/omapfb.h>
+#include <asm/arch/lcd_mipid.h>
+
+#include "../../cbus/tahvo.h"
+
+#define MIPID_MODULE_NAME              "lcd_mipid"
+
+#define MIPID_CMD_READ_DISP_ID         0x04
+#define MIPID_CMD_READ_RED             0x06
+#define MIPID_CMD_READ_GREEN           0x07
+#define MIPID_CMD_READ_BLUE            0x08
+#define MIPID_CMD_READ_DISP_STATUS     0x09
+#define MIPID_CMD_RDDSDR               0x0F
+#define MIPID_CMD_SLEEP_IN             0x10
+#define MIPID_CMD_SLEEP_OUT            0x11
+#define MIPID_CMD_DISP_OFF             0x28
+#define MIPID_CMD_DISP_ON              0x29
+
+#define MIPID_VER_LPH8923              3
+#define MIPID_VER_LS041Y3              4
+
+#define MIPID_ESD_CHECK_PERIOD         msecs_to_jiffies(5000)
+
+#define to_mipid_device(p)             container_of(p, struct mipid_device, \
+                                               panel)
+struct mipid_device {
+       int             enabled;
+       int             model;
+       int             revision;
+       u8              display_id[3];
+       unsigned int    saved_bklight_level;
+       unsigned long   hw_guard_end;           /* next value of jiffies
+                                                  when we can issue the
+                                                  next sleep in/out command */
+       unsigned long   hw_guard_wait;          /* max guard time in jiffies */
+
+       struct omapfb_device    *fbdev;
+       struct spi_device       *spi;
+       struct mutex            mutex;
+       struct lcd_panel        panel;
+
+       struct workqueue_struct *esd_wq;
+       struct delayed_work     esd_work;
+       void                    (*esd_check)(struct mipid_device *m);
+};
+
+static void mipid_transfer(struct mipid_device *md, int cmd, const u8 *wbuf,
+                          int wlen, u8 *rbuf, int rlen)
+{
+       struct spi_message      m;
+       struct spi_transfer     *x, xfer[4];
+       u16                     w;
+       int                     r;
+
+       BUG_ON(md->spi == NULL);
+
+       spi_message_init(&m);
+
+       memset(xfer, 0, sizeof(xfer));
+       x = &xfer[0];
+
+       cmd &=  0xff;
+       x->tx_buf       = &cmd;
+       x->bits_per_word= 9;
+       x->len          = 2;
+       spi_message_add_tail(x, &m);
+
+       if (wlen) {
+               x++;
+               x->tx_buf       = wbuf;
+               x->len          = wlen;
+               x->bits_per_word= 9;
+               spi_message_add_tail(x, &m);
+       }
+
+       if (rlen) {
+               x++;
+               x->rx_buf       = &w;
+               x->len          = 1;
+               spi_message_add_tail(x, &m);
+
+               if (rlen > 1) {
+                       /* Arrange for the extra clock before the first
+                        * data bit.
+                        */
+                       x->bits_per_word = 9;
+                       x->len           = 2;
+
+                       x++;
+                       x->rx_buf        = &rbuf[1];
+                       x->len           = rlen - 1;
+                       spi_message_add_tail(x, &m);
+               }
+       }
+
+       r = spi_sync(md->spi, &m);
+       if (r < 0)
+               dev_dbg(&md->spi->dev, "spi_sync %d\n", r);
+
+       if (rlen)
+               rbuf[0] = w & 0xff;
+}
+
+static inline void mipid_cmd(struct mipid_device *md, int cmd)
+{
+       mipid_transfer(md, cmd, NULL, 0, NULL, 0);
+}
+
+static inline void mipid_write(struct mipid_device *md,
+                              int reg, const u8 *buf, int len)
+{
+       mipid_transfer(md, reg, buf, len, NULL, 0);
+}
+
+static inline void mipid_read(struct mipid_device *md,
+                             int reg, u8 *buf, int len)
+{
+       mipid_transfer(md, reg, NULL, 0, buf, len);
+}
+
+static void set_data_lines(struct mipid_device *md, int data_lines)
+{
+       u16 par;
+
+       switch (data_lines) {
+       case 16:
+               par = 0x150;
+               break;
+       case 18:
+               par = 0x160;
+               break;
+       case 24:
+               par = 0x170;
+               break;
+       }
+       mipid_write(md, 0x3a, (u8 *)&par, 2);
+}
+
+static void send_init_string(struct mipid_device *md)
+{
+       u16 initpar[] = { 0x0102, 0x0100, 0x0100 };
+
+       mipid_write(md, 0xc2, (u8 *)initpar, sizeof(initpar));
+       set_data_lines(md, md->panel.data_lines);
+}
+
+static void hw_guard_start(struct mipid_device *md, int guard_msec)
+{
+       md->hw_guard_wait = msecs_to_jiffies(guard_msec);
+       md->hw_guard_end = jiffies + md->hw_guard_wait;
+}
+
+static void hw_guard_wait(struct mipid_device *md)
+{
+       unsigned long wait = md->hw_guard_end - jiffies;
+
+       if ((long)wait > 0 && wait <= md->hw_guard_wait) {
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule_timeout(wait);
+       }
+}
+
+static void set_sleep_mode(struct mipid_device *md, int on)
+{
+       int cmd, sleep_time = 50;
+
+       if (on)
+               cmd = MIPID_CMD_SLEEP_IN;
+       else
+               cmd = MIPID_CMD_SLEEP_OUT;
+       hw_guard_wait(md);
+       mipid_cmd(md, cmd);
+       hw_guard_start(md, 120);
+       /* When we enable the panel, it seems we _have_ to sleep
+        * 120 ms before sending the init string. When disabling the
+        * panel we'll sleep for the duration of 2 frames, so that the
+        * controller can still provide the PCLK,HS,VS signals. */
+       if (!on)
+               sleep_time = 120;
+       msleep(sleep_time);
+}
+
+static void set_display_state(struct mipid_device *md, int enabled)
+{
+       int cmd = enabled ? MIPID_CMD_DISP_ON : MIPID_CMD_DISP_OFF;
+
+       mipid_cmd(md, cmd);
+}
+
+static int mipid_set_bklight_level(struct lcd_panel *panel, unsigned int level)
+{
+       struct mipid_device *md = to_mipid_device(panel);
+
+       if (level > tahvo_get_max_backlight_level())
+               return -EINVAL;
+       if (!md->enabled) {
+               md->saved_bklight_level = level;
+               return 0;
+       }
+       tahvo_set_backlight_level(level);
+
+       return 0;
+}
+
+static unsigned int mipid_get_bklight_level(struct lcd_panel *panel)
+{
+       return tahvo_get_backlight_level();
+}
+
+static unsigned int mipid_get_bklight_max(struct lcd_panel *panel)
+{
+       return tahvo_get_max_backlight_level();
+}
+
+
+static unsigned long mipid_get_caps(struct lcd_panel *panel)
+{
+       return OMAPFB_CAPS_SET_BACKLIGHT;
+}
+
+static u16 read_first_pixel(struct mipid_device *md)
+{
+       u16 pixel;
+       u8 red, green, blue;
+
+       mutex_lock(&md->mutex);
+       mipid_read(md, MIPID_CMD_READ_RED, &red, 1);
+       mipid_read(md, MIPID_CMD_READ_GREEN, &green, 1);
+       mipid_read(md, MIPID_CMD_READ_BLUE, &blue, 1);
+       mutex_unlock(&md->mutex);
+
+       switch (md->panel.data_lines) {
+       case 16:
+               pixel = ((red >> 1) << 11) | (green << 5) | (blue >> 1);
+               break;
+       case 24:
+               /* 24 bit -> 16 bit */
+               pixel = ((red >> 3) << 11) | ((green >> 2) << 5) |
+                       (blue >> 3);
+               break;
+       default:
+               BUG();
+       }
+
+       return pixel;
+}
+
+static int mipid_run_test(struct lcd_panel *panel, int test_num)
+{
+       struct mipid_device *md = to_mipid_device(panel);
+       static const u16 test_values[4] = {
+               0x0000, 0xffff, 0xaaaa, 0x5555,
+       };
+       int i;
+
+       if (test_num != MIPID_TEST_RGB_LINES)
+               return MIPID_TEST_INVALID;
+
+       for (i = 0; i < ARRAY_SIZE(test_values); i++) {
+               int delay;
+               unsigned long tmo;
+
+               omapfb_write_first_pixel(md->fbdev, test_values[i]);
+               tmo = jiffies + msecs_to_jiffies(100);
+               delay = 25;
+               while (1) {
+                       u16 pixel;
+
+                       msleep(delay);
+                       pixel = read_first_pixel(md);
+                       if (pixel == test_values[i])
+                               break;
+                       if (time_after(jiffies, tmo)) {
+                               dev_err(&md->spi->dev,
+                                       "MIPI LCD RGB I/F test failed: "
+                                       "expecting %04x, got %04x\n",
+                                       test_values[i], pixel);
+                               return MIPID_TEST_FAILED;
+                       }
+                       delay = 10;
+               }
+       }
+
+       return 0;
+}
+
+static void ls041y3_esd_recover(struct mipid_device *md)
+{
+       dev_err(&md->spi->dev, "performing LCD ESD recovery\n");
+       set_sleep_mode(md, 1);
+       set_sleep_mode(md, 0);
+}
+
+static void ls041y3_esd_check_mode1(struct mipid_device *md)
+{
+       u8 state1, state2;
+
+       mipid_read(md, MIPID_CMD_RDDSDR, &state1, 1);
+       set_sleep_mode(md, 0);
+       mipid_read(md, MIPID_CMD_RDDSDR, &state2, 1);
+       dev_dbg(&md->spi->dev, "ESD mode 1 state1 %02x state2 %02x\n",
+               state1, state2);
+       /* Each sleep out command will trigger a self diagnostic and flip
+       * Bit6 if the test passes.
+       */
+       if (!((state1 ^ state2) & (1 << 6)))
+               ls041y3_esd_recover(md);
+}
+
+static void ls041y3_esd_check_mode2(struct mipid_device *md)
+{
+       int i;
+       u8 rbuf[2];
+       static const struct {
+               int     cmd;
+               int     wlen;
+               u16     wbuf[3];
+       } *rd, rd_ctrl[7] = {
+               { 0xb0, 4, { 0x0101, 0x01fe, } },
+               { 0xb1, 4, { 0x01de, 0x0121, } },
+               { 0xc2, 4, { 0x0100, 0x0100, } },
+               { 0xbd, 2, { 0x0100, } },
+               { 0xc2, 4, { 0x01fc, 0x0103, } },
+               { 0xb4, 0, },
+               { 0x00, 0, },
+       };
+
+       rd = rd_ctrl;
+       for (i = 0; i < 3; i++, rd++)
+               mipid_write(md, rd->cmd, (u8 *)rd->wbuf, rd->wlen);
+
+       udelay(10);
+       mipid_read(md, rd->cmd, rbuf, 2);
+       rd++;
+
+       for (i = 0; i < 3; i++, rd++) {
+               udelay(10);
+               mipid_write(md, rd->cmd, (u8 *)rd->wbuf, rd->wlen);
+       }
+
+       dev_dbg(&md->spi->dev, "ESD mode 2 state %02x\n", rbuf[1]);
+       if (rbuf[1] == 0x00)
+               ls041y3_esd_recover(md);
+}
+
+static void ls041y3_esd_check(struct mipid_device *md)
+{
+       ls041y3_esd_check_mode1(md);
+       if (md->revision >= 0x88)
+               ls041y3_esd_check_mode2(md);
+}
+
+static void mipid_esd_start_check(struct mipid_device *md)
+{
+       if (md->esd_check != NULL)
+               queue_delayed_work(md->esd_wq, &md->esd_work,
+                                  MIPID_ESD_CHECK_PERIOD);
+}
+
+static void mipid_esd_stop_check(struct mipid_device *md)
+{
+       if (md->esd_check != NULL)
+               cancel_rearming_delayed_workqueue(md->esd_wq, &md->esd_work);
+}
+
+static void mipid_esd_work(struct work_struct *work)
+{
+       struct mipid_device *md = container_of(work, struct mipid_device, esd_work.work);
+
+       mutex_lock(&md->mutex);
+       md->esd_check(md);
+       mutex_unlock(&md->mutex);
+       mipid_esd_start_check(md);
+}
+
+static int mipid_enable(struct lcd_panel *panel)
+{
+       struct mipid_device *md = to_mipid_device(panel);
+
+       mutex_lock(&md->mutex);
+
+       if (md->enabled) {
+               mutex_unlock(&md->mutex);
+               return 0;
+       }
+       set_sleep_mode(md, 0);
+       md->enabled = 1;
+       send_init_string(md);
+       set_display_state(md, 1);
+       mipid_set_bklight_level(panel, md->saved_bklight_level);
+       mipid_esd_start_check(md);
+
+       mutex_unlock(&md->mutex);
+       return 0;
+}
+
+static void mipid_disable(struct lcd_panel *panel)
+{
+       struct mipid_device *md = to_mipid_device(panel);
+
+       /* A final ESD work might be called before returning,
+        * so do this without holding the lock. */
+       mipid_esd_stop_check(md);
+       mutex_lock(&md->mutex);
+
+       if (!md->enabled) {
+               mutex_unlock(&md->mutex);
+               return;
+       }
+       md->saved_bklight_level = mipid_get_bklight_level(panel);
+       mipid_set_bklight_level(panel, 0);
+       set_display_state(md, 0);
+       set_sleep_mode(md, 1);
+       md->enabled = 0;
+
+       mutex_unlock(&md->mutex);
+}
+
+static int panel_enabled(struct mipid_device *md)
+{
+       u32 disp_status;
+       int enabled;
+
+       mipid_read(md, MIPID_CMD_READ_DISP_STATUS, (u8 *)&disp_status, 4);
+       disp_status = __be32_to_cpu(disp_status);
+       enabled = (disp_status & (1 << 17)) && (disp_status & (1 << 10));
+       dev_dbg(&md->spi->dev,
+               "LCD panel %s enabled 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(&md->spi->dev, "out of memory\n");
+               return -ENOMEM;
+       }
+
+       spi->mode = SPI_MODE_1;
+       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");
diff --git a/drivers/video/omap/lcd_osk.c b/drivers/video/omap/lcd_osk.c
new file mode 100644 (file)
index 0000000..cc8bb59
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * File: drivers/video/omap/lcd-osk.c
+ *
+ * LCD panel support for the TI OMAP OSK board
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Imre Deak <imre.deak@nokia.com>
+ * Adapted for OSK by <dirk.behme@de.bosch.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/omapfb.h>
+
+static int osk_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
+{
+       return 0;
+}
+
+static void osk_panel_cleanup(struct lcd_panel *panel)
+{
+}
+
+static int osk_panel_enable(struct lcd_panel *panel)
+{
+       /* configure PWL pin */
+       omap_cfg_reg(PWL);
+
+       /* Enable PWL unit */
+       omap_writeb(0x01, OMAP_PWL_CLK_ENABLE);
+
+       /* Set PWL level */
+       omap_writeb(0xFF, OMAP_PWL_ENABLE);
+
+       /* configure GPIO2 as output */
+       omap_set_gpio_direction(2, 0);
+
+       /* set GPIO2 high */
+       omap_set_gpio_dataout(2, 1);
+
+       return 0;
+}
+
+static void osk_panel_disable(struct lcd_panel *panel)
+{
+       /* Set PWL level to zero */
+       omap_writeb(0x00, OMAP_PWL_ENABLE);
+
+       /* Disable PWL unit */
+       omap_writeb(0x00, OMAP_PWL_CLK_ENABLE);
+
+       /* set GPIO2 low */
+       omap_set_gpio_dataout(2, 0);
+}
+
+static unsigned long osk_panel_get_caps(struct lcd_panel *panel)
+{
+       return 0;
+}
+
+struct lcd_panel osk_panel = {
+       .name           = "osk",
+       .config         = OMAP_LCDC_PANEL_TFT,
+
+       .bpp            = 16,
+       .data_lines     = 16,
+       .x_res          = 240,
+       .y_res          = 320,
+       .pixel_clock    = 12500,
+       .hsw            = 40,
+       .hfp            = 40,
+       .hbp            = 72,
+       .vsw            = 1,
+       .vfp            = 1,
+       .vbp            = 0,
+       .pcd            = 12,
+
+       .init           = osk_panel_init,
+       .cleanup        = osk_panel_cleanup,
+       .enable         = osk_panel_enable,
+       .disable        = osk_panel_disable,
+       .get_caps       = osk_panel_get_caps,
+};
+
+static int osk_panel_probe(struct platform_device *pdev)
+{
+       omapfb_register_panel(&osk_panel);
+       return 0;
+}
+
+static int osk_panel_remove(struct platform_device *pdev)
+{
+       return 0;
+}
+
+static int osk_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+       return 0;
+}
+
+static int osk_panel_resume(struct platform_device *pdev)
+{
+       return 0;
+}
+
+struct platform_driver osk_panel_driver = {
+       .probe          = osk_panel_probe,
+       .remove         = osk_panel_remove,
+       .suspend        = osk_panel_suspend,
+       .resume         = osk_panel_resume,
+       .driver         = {
+               .name   = "lcd_osk",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int osk_panel_drv_init(void)
+{
+       return platform_driver_register(&osk_panel_driver);
+}
+
+static void osk_panel_drv_cleanup(void)
+{
+       platform_driver_unregister(&osk_panel_driver);
+}
+
+module_init(osk_panel_drv_init);
+module_exit(osk_panel_drv_cleanup);
+
diff --git a/drivers/video/omap/lcd_p2.c b/drivers/video/omap/lcd_p2.c
new file mode 100644 (file)
index 0000000..864033d
--- /dev/null
@@ -0,0 +1,344 @@
+/*
+ * File: drivers/video/omap/lcd-p2.c
+ *
+ * LCD panel support for the TI OMAP P2 board
+ *
+ * Authors:
+ *   jekyll <jekyll@mail.jekyll.idv.tw>
+ *   B Jp <lastjp_fr@yahoo.fr>
+ *   Brian Swetland <swetland@android.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+
+#include <asm/arch/mux.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/omapfb.h>
+
+/*
+ * File: epson-md-tft.h
+ *
+ * This file contains definitions for Epsons MD-TF LCD Module
+ *
+ * Copyright (C) 2004 MPC-Data Limited  (http://www.mpc-data.co.uk)
+ * Author: Dave Peverley <dpeverley at mpc-data.co.uk>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  THIS  SOFTWARE  IS  PROVIDED  ``AS  IS''  AND   ANY  EXPRESS  OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Please report all bugs and problems to the author.
+ *
+ */
+
+/* LCD uWire commands & params
+ * All values from Epson
+ */
+#define LCD_DISON 0xAF
+#define LCD_DISOFF 0xAE
+#define LCD_DISNOR 0xA6
+#define LCD_DISINV 0xA7
+#define LCD_DISCTL 0xCA
+#define LCD_GCP64 0xCB
+#define LCD_GCP16 0xCC
+#define LCD_GSSET 0xCD
+#define LCD_SLPIN 0x95
+#define LCD_SLPOUT 0x94
+#define LCD_SD_PSET 0x75
+#define LCD_MD_PSET 0x76
+#define LCD_SD_CSET 0x15
+#define LCD_MD_CSET 0x16
+#define LCD_DATCTL 0xBC
+#define LCD_RAMWR 0x5C
+#define LCD_RAMRD 0x5D
+#define LCD_PTLIN 0xA8
+#define LCD_PTLOUT 0xA9
+#define LCD_ASCSET 0xAA
+#define LCD_SCSTART 0xAB
+#define LCD_VOLCTL 0xC6
+#define LCD_NOP 0x25
+#define LCD_OSCISEL 0x7
+#define LCD_3500KSET 0xD1
+#define LCD_3500KEND 0xD2
+#define LCD_14MSET 0xD3
+#define LCD_14MEND 0xD4
+
+#define INIT_3500KSET 0x45
+#define INIT_14MSET 0x4B
+#define INIT_DATCTL 0x08 /* 6.6.6 bits for D-Sample */
+
+#define INIT_OSCISEL 0x05
+
+#define INIT_VOLCTL 0x77 /* Nominel "volume" */
+
+#define INIT_VOLCTL_Ton 0x98 /* Activate power-IC timer */
+#define INIT_GSSET 0x00
+
+const unsigned short INIT_DISCTL[11] =
+{
+       0xDE, 0x01, 0x64, 0x00, 0x1B, 0xF4, 0x00, 0xDC, 0x00, 0x02, 0x00
+};
+
+const unsigned short INIT_GCP64[126] =
+{
+       0x3B,0x00,0x42,0x00,0x4A,0x00,0x51,0x00,
+       0x58,0x00,0x5F,0x00,0x66,0x00,0x6E,0x00,
+       0x75,0x00,0x7C,0x00,0x83,0x00,0x8A,0x00,
+       0x92,0x00,0x99,0x00,0xA0,0x00,0xA7,0x00,
+       0xAE,0x00,0xB6,0x00,0xBD,0x00,0xC4,0x00,
+       0xCB,0x00,0xD2,0x00,0xDA,0x00,0xE1,0x00,
+       0xE8,0x00,0xEF,0x00,0xF6,0x00,0xFE,0x00,
+       0x05,0x01,0x0C,0x01,0x13,0x01,0x1A,0x01,
+       0x22,0x01,0x29,0x01,0x30,0x01,0x37,0x01,
+       0x3E,0x01,0x46,0x01,0x4D,0x01,0x54,0x01,
+       0x5B,0x01,0x62,0x01,0x6A,0x01,0x71,0x01,
+       0x78,0x01,0x7F,0x01,0x86,0x01,0x8E,0x01,
+       0x95,0x01,0x9C,0x01,0xA3,0x01,0xAA,0x01,
+       0xB2,0x01,0xB9,0x01,0xC0,0x01,0xC7,0x01,
+       0xCE,0x01,0xD6,0x01,0xDD,0x01,0xE4,0x01,
+       0xEB,0x01,0xF2,0x01,0xFA,0x01
+};
+
+const unsigned short INIT_GCP16[15] =
+{
+       0x1A,0x31,0x48,0x54,0x5F,0x67,0x70,0x76,0x7C,0x80,0x83,0x84,0x85,0x87,0x96
+};
+
+const unsigned short INIT_MD_PSET[4] = { 0, 0, 219, 0 };
+const unsigned short INIT_MD_CSET[4] = { 2, 0, 177, 0 };
+
+const unsigned short INIT_SD_PSET[4] = { 0x00, 0x01, 0x00, 0x01 };
+const unsigned short INIT_SD_CSET[4] = { 0x00, 0x02, 0x00, 0x02 };
+
+const unsigned short INIT_ASCSET[7] = { 0x00, 0x00, 0xDB, 0x00, 0xDC, 0x00, 0x01 };
+const unsigned short INIT_SCSTART[2] = { 0x00, 0x00 };
+
+/* ----- end of epson_md_tft.h ----- */
+
+
+#include "../drivers/ssi/omap-uwire.h"
+
+#define LCD_UWIRE_CS 0
+
+static int p2_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
+{
+       return 0;
+}
+
+static void p2_panel_cleanup(struct lcd_panel *panel)
+{
+}
+
+static int p2_panel_enable(struct lcd_panel *panel)
+{
+       int i;
+       unsigned long value;
+
+               /* thwack the reset line */
+       omap_set_gpio_direction(19, 0);
+       omap_set_gpio_dataout(19, 0);
+       mdelay(2);
+       omap_set_gpio_dataout(19, 1);
+
+               /* bits 31:28 -> 0  LCD_PXL_15 .. 12 */
+       value = omap_readl(OMAP730_IO_CONF_3) & 0x0FFFFFFF;
+       omap_writel(value, OMAP730_IO_CONF_3);
+
+               /* bits 19:0 -> 0  LCD_VSYNC, AC, PXL_0, PCLK, HSYNC,
+               **                 PXL_9..1, PXL_10, PXL_11
+               */
+       value = omap_readl(OMAP730_IO_CONF_4) & 0xFFF00000;
+       omap_writel(value, OMAP730_IO_CONF_4);
+
+       omap_uwire_configure_mode(0,16);
+
+       omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_DISOFF, 9, 0,NULL,1);
+       omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_SLPIN, 9, 0,NULL,1);
+       omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_DISNOR, 9, 0,NULL,1);
+       omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_GSSET, 9, 0,NULL,1);
+       omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_GSSET | 0x100), 9, 0,NULL,1);
+
+       /* DISCTL */
+       omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_DISCTL, 9, 0,NULL,1);
+       for (i = 0; i < (sizeof(INIT_DISCTL)/sizeof(unsigned short)); i++)
+               omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_DISCTL[i] | 0x100), 9, 0,NULL,1);
+
+       /* GCP64 */
+       omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_GCP64, 9, 0,NULL,1);
+       for (i = 0; i < (sizeof(INIT_GCP64)/sizeof(unsigned short)); i++)
+               omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_GCP64[i] | 0x100), 9, 0,NULL,1);
+
+       /* GCP16 */
+       omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_GCP16, 9, 0,NULL,1);
+       for (i = 0; i < (sizeof(INIT_GCP16)/sizeof(unsigned short)); i++)
+               omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_GCP16[i] | 0x100), 9, 0,NULL,1);
+
+       /* MD_CSET */
+       omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_MD_CSET, 9, 0,NULL,1);
+       for (i = 0; i < (sizeof(INIT_MD_CSET)/sizeof(unsigned short)); i++)
+               omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_MD_CSET[i] | 0x100), 9, 0,NULL,1);
+
+       /* MD_PSET */
+       omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_MD_PSET, 9, 0,NULL,1);
+       for (i = 0; i < (sizeof(INIT_MD_PSET)/sizeof(unsigned short)); i++)
+               omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_MD_PSET[i] | 0x100), 9, 0,NULL,1);
+
+       /* SD_CSET */
+       omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_SD_CSET, 9, 0,NULL,1);
+       for (i = 0; i < (sizeof(INIT_SD_CSET)/sizeof(unsigned short)); i++)
+               omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_SD_CSET[i] | 0x100), 9, 0,NULL,1);
+
+       /* SD_PSET */
+       omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_SD_PSET, 9, 0,NULL,1);
+       for (i = 0; i < (sizeof(INIT_SD_PSET)/sizeof(unsigned short)); i++)
+               omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_SD_PSET[i] | 0x100), 9, 0,NULL,1);
+
+       /* DATCTL */
+       omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_DATCTL, 9, 0,NULL,1);
+       omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_DATCTL | 0x100), 9, 0,NULL,1);
+
+       /* OSSISEL = d'5 */
+       omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_OSCISEL, 9, 0,NULL,1);
+       omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_OSCISEL | 0x100), 9, 0,NULL,1);
+
+       /* 14MSET = d'74 */
+       omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_14MSET, 9, 0,NULL,1);
+       omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_14MSET | 0x100), 9, 0,NULL,1);
+
+       /* 14MEND */
+       omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_14MEND, 9, 0,NULL,1);
+
+       /* 3500KSET = d'69 */
+       omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_3500KSET, 9, 0,NULL,1);
+       omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_3500KSET | 0x100), 9, 0,NULL,1);
+
+       /* 3500KEND */
+       omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_3500KEND, 9, 0,NULL,1);
+
+       omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_SLPOUT, 9, 0,NULL,1);
+
+       omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_VOLCTL, 9, 0,NULL,1);
+       omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_VOLCTL_Ton | 0x100), 9, 0,NULL,1);
+
+       omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_VOLCTL, 9, 0,NULL,1);
+
+       omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_VOLCTL | 0x100), 9, 0,NULL,1);
+
+       omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_DISON, 9, 0,NULL,1);
+
+       /* enable backlight */
+       omap_set_gpio_direction(134, 0);
+       omap_set_gpio_dataout(134, 1);
+
+       return 0;
+}
+
+static void p2_panel_disable(struct lcd_panel *panel)
+{
+}
+
+static unsigned long p2_panel_get_caps(struct lcd_panel *panel)
+{
+       return 0;
+}
+
+struct lcd_panel p2_panel = {
+       .name           = "p2",
+       .config         = OMAP_LCDC_PANEL_TFT | OMAP_LCDC_INV_PIX_CLOCK,
+
+       .bpp            = 16,
+       .data_lines     = 16,
+       .x_res          = 176,
+       .y_res          = 220,
+       .pixel_clock    = 12500,
+       .hsw            = 5,
+       .hfp            = 1,
+       .hbp            = 1,
+       .vsw            = 2,
+       .vfp            = 12,
+       .vbp            = 1,
+
+       .init           = p2_panel_init,
+       .cleanup        = p2_panel_cleanup,
+       .enable         = p2_panel_enable,
+       .disable        = p2_panel_disable,
+       .get_caps       = p2_panel_get_caps,
+};
+
+static int p2_panel_probe(struct platform_device *pdev)
+{
+       omapfb_register_panel(&p2_panel);
+       return 0;
+}
+
+static int p2_panel_remove(struct platform_device *pdev)
+{
+       return 0;
+}
+
+static int p2_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+       return 0;
+}
+
+static int p2_panel_resume(struct platform_device *pdev)
+{
+       return 0;
+}
+
+struct platform_driver p2_panel_driver = {
+       .probe          = p2_panel_probe,
+       .remove         = p2_panel_remove,
+       .suspend        = p2_panel_suspend,
+       .resume         = p2_panel_resume,
+       .driver         = {
+               .name   = "lcd_p2",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int p2_panel_drv_init(void)
+{
+       return platform_driver_register(&p2_panel_driver);
+}
+
+static void p2_panel_drv_cleanup(void)
+{
+       platform_driver_unregister(&p2_panel_driver);
+}
+
+module_init(p2_panel_drv_init);
+module_exit(p2_panel_drv_cleanup);
+
diff --git a/drivers/video/omap/lcd_palmte.c b/drivers/video/omap/lcd_palmte.c
new file mode 100644 (file)
index 0000000..1d37803
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * File: drivers/video/omap/lcd_palmte.c
+ *
+ * LCD panel support for the Palm Tungsten E
+ *
+ * Original version : Romain Goyet
+ * Current version : Laurent Gonzalez
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <asm/io.h>
+
+#include <asm/arch/fpga.h>
+#include <asm/arch/omapfb.h>
+
+static int palmte_panel_init(struct lcd_panel *panel,
+                               struct omapfb_device *fbdev)
+{
+       return 0;
+}
+
+static void palmte_panel_cleanup(struct lcd_panel *panel)
+{
+}
+
+static int palmte_panel_enable(struct lcd_panel *panel)
+{
+       return 0;
+}
+
+static void palmte_panel_disable(struct lcd_panel *panel)
+{
+}
+
+static unsigned long palmte_panel_get_caps(struct lcd_panel *panel)
+{
+       return 0;
+}
+
+struct lcd_panel palmte_panel = {
+       .name           = "palmte",
+       .config         = OMAP_LCDC_PANEL_TFT | OMAP_LCDC_INV_VSYNC |
+                         OMAP_LCDC_INV_HSYNC | OMAP_LCDC_HSVS_RISING_EDGE |
+                         OMAP_LCDC_HSVS_OPPOSITE,
+
+       .data_lines     = 16,
+       .bpp            = 8,
+       .pixel_clock    = 12000,
+       .x_res          = 320,
+       .y_res          = 320,
+       .hsw            = 4,
+       .hfp            = 8,
+       .hbp            = 28,
+       .vsw            = 1,
+       .vfp            = 8,
+       .vbp            = 7,
+       .pcd            = 0,
+
+       .init           = palmte_panel_init,
+       .cleanup        = palmte_panel_cleanup,
+       .enable         = palmte_panel_enable,
+       .disable        = palmte_panel_disable,
+       .get_caps       = palmte_panel_get_caps,
+};
+
+static int palmte_panel_probe(struct platform_device *pdev)
+{
+       omapfb_register_panel(&palmte_panel);
+       return 0;
+}
+
+static int palmte_panel_remove(struct platform_device *pdev)
+{
+       return 0;
+}
+
+static int palmte_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+       return 0;
+}
+
+static int palmte_panel_resume(struct platform_device *pdev)
+{
+       return 0;
+}
+
+struct platform_driver palmte_panel_driver = {
+       .probe          = palmte_panel_probe,
+       .remove         = palmte_panel_remove,
+       .suspend        = palmte_panel_suspend,
+       .resume         = palmte_panel_resume,
+       .driver         = {
+               .name   = "lcd_palmte",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int palmte_panel_drv_init(void)
+{
+       return platform_driver_register(&palmte_panel_driver);
+}
+
+static void palmte_panel_drv_cleanup(void)
+{
+       platform_driver_unregister(&palmte_panel_driver);
+}
+
+module_init(palmte_panel_drv_init);
+module_exit(palmte_panel_drv_cleanup);
+
diff --git a/drivers/video/omap/lcd_palmtt.c b/drivers/video/omap/lcd_palmtt.c
new file mode 100644 (file)
index 0000000..97d3680
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * File: drivers/video/omap/lcd_palmtt.c
+ *
+ * LCD panel support for Palm Tungsten|T
+ * Current version : Marek Vasut <marek.vasut@gmail.com>
+ *
+ * Modified from lcd_inn1510.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.
+ */
+
+/*
+GPIO11 - backlight
+GPIO12 - screen blanking
+GPIO13 - screen blanking
+*/
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+
+#include <asm/io.h>
+
+#include <asm/arch/gpio.h>
+#include "asm/arch/omapfb.h"
+
+static int palmtt_panel_init(struct lcd_panel *panel,
+       struct omapfb_device *fbdev)
+{
+       return 0;
+}
+
+static void palmtt_panel_cleanup(struct lcd_panel *panel)
+{
+}
+
+static int palmtt_panel_enable(struct lcd_panel *panel)
+{
+       return 0;
+}
+
+static void palmtt_panel_disable(struct lcd_panel *panel)
+{
+}
+
+static unsigned long palmtt_panel_get_caps(struct lcd_panel *panel)
+{
+       return OMAPFB_CAPS_SET_BACKLIGHT;
+}
+
+struct lcd_panel palmtt_panel = {
+       .name           = "palmtt",
+       .config         = OMAP_LCDC_PANEL_TFT | OMAP_LCDC_INV_VSYNC |
+                       OMAP_LCDC_INV_HSYNC | OMAP_LCDC_HSVS_RISING_EDGE |
+                       OMAP_LCDC_HSVS_OPPOSITE,
+       .bpp            = 16,
+       .data_lines     = 16,
+       .x_res          = 320,
+       .y_res          = 320,
+       .pixel_clock    = 10000,
+       .hsw            = 4,
+       .hfp            = 8,
+       .hbp            = 28,
+       .vsw            = 1,
+       .vfp            = 8,
+       .vbp            = 7,
+       .pcd            = 0,
+
+       .init= palmtt_panel_init,
+       .cleanup        = palmtt_panel_cleanup,
+       .enable= palmtt_panel_enable,
+       .disable        = palmtt_panel_disable,
+       .get_caps       = palmtt_panel_get_caps,
+};
+
+static int palmtt_panel_probe(struct platform_device *pdev)
+{
+       omapfb_register_panel(&palmtt_panel);
+       return 0;
+}
+
+static int palmtt_panel_remove(struct platform_device *pdev)
+{
+       return 0;
+}
+
+static int palmtt_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+       return 0;
+}
+
+static int palmtt_panel_resume(struct platform_device *pdev)
+{
+       return 0;
+}
+
+struct platform_driver palmtt_panel_driver = {
+       .probe          = palmtt_panel_probe,
+       .remove         = palmtt_panel_remove,
+       .suspend        = palmtt_panel_suspend,
+       .resume         = palmtt_panel_resume,
+       .driver         = {
+               .name   = "lcd_palmtt",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int palmtt_panel_drv_init(void)
+{
+       return platform_driver_register(&palmtt_panel_driver);
+}
+
+static void palmtt_panel_drv_cleanup(void)
+{
+       platform_driver_unregister(&palmtt_panel_driver);
+}
+
+module_init(palmtt_panel_drv_init);
+module_exit(palmtt_panel_drv_cleanup);
diff --git a/drivers/video/omap/lcd_palmz71.c b/drivers/video/omap/lcd_palmz71.c
new file mode 100644 (file)
index 0000000..892993f
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * File: drivers/video/omap/lcd_palmz71.c
+ *
+ * LCD panel support for the Palm Zire71
+ *
+ * Original version : Romain Goyet
+ * Current version : Laurent Gonzalez
+ * Modified for zire71 : Marek Vasut
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <asm/io.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/omapfb.h>
+
+static int palmz71_panel_init(struct lcd_panel *panel,
+                             struct omapfb_device *fbdev)
+{
+       return 0;
+}
+
+static void palmz71_panel_cleanup(struct lcd_panel *panel)
+{
+
+}
+
+static int palmz71_panel_enable(struct lcd_panel *panel)
+{
+       return 0;
+}
+
+static void palmz71_panel_disable(struct lcd_panel *panel)
+{
+}
+
+static unsigned long palmz71_panel_get_caps(struct lcd_panel *panel)
+{
+       return OMAPFB_CAPS_SET_BACKLIGHT;
+}
+
+struct lcd_panel palmz71_panel = {
+       .name           = "palmz71",
+       .config         = OMAP_LCDC_PANEL_TFT | OMAP_LCDC_INV_VSYNC |
+                         OMAP_LCDC_INV_HSYNC | OMAP_LCDC_HSVS_RISING_EDGE |
+                         OMAP_LCDC_HSVS_OPPOSITE,
+       .data_lines     = 16,
+       .bpp            = 16,
+       .pixel_clock    = 24000,
+       .x_res          = 320,
+       .y_res          = 320,
+       .hsw            = 4,
+       .hfp            = 8,
+       .hbp            = 28,
+       .vsw            = 1,
+       .vfp            = 8,
+       .vbp            = 7,
+       .pcd            = 0,
+
+       .init           = palmz71_panel_init,
+       .cleanup        = palmz71_panel_cleanup,
+       .enable         = palmz71_panel_enable,
+       .disable        = palmz71_panel_disable,
+       .get_caps       = palmz71_panel_get_caps,
+};
+
+static int palmz71_panel_probe(struct platform_device *pdev)
+{
+       omapfb_register_panel(&palmz71_panel);
+       return 0;
+}
+
+static int palmz71_panel_remove(struct platform_device *pdev)
+{
+       return 0;
+}
+
+static int palmz71_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+       return 0;
+}
+
+static int palmz71_panel_resume(struct platform_device *pdev)
+{
+       return 0;
+}
+
+struct platform_driver palmz71_panel_driver = {
+       .probe          = palmz71_panel_probe,
+       .remove         = palmz71_panel_remove,
+       .suspend        = palmz71_panel_suspend,
+       .resume         = palmz71_panel_resume,
+       .driver         = {
+               .name   = "lcd_palmz71",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int palmz71_panel_drv_init(void)
+{
+       return platform_driver_register(&palmz71_panel_driver);
+}
+
+static void palmz71_panel_drv_cleanup(void)
+{
+       platform_driver_unregister(&palmz71_panel_driver);
+}
+
+module_init(palmz71_panel_drv_init);
+module_exit(palmz71_panel_drv_cleanup);
diff --git a/drivers/video/omap/lcd_sx1.c b/drivers/video/omap/lcd_sx1.c
new file mode 100644 (file)
index 0000000..0b927f6
--- /dev/null
@@ -0,0 +1,331 @@
+/*
+ * File: drivers/video/omap/lcd_sx1.c
+ *
+ * LCD panel support for the Siemens SX1 mobile phone
+ *
+ * Current version : Vovan888 at gmail com, great help from FCA00000
+ *
+ * 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 <asm/io.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/omapfb.h>
+#include <asm/arch/mcbsp.h>
+#include <asm/arch/mux.h>
+
+/*
+ * OMAP310 GPIO registers
+ */
+#define GPIO_DATA_INPUT                0xfffce000
+#define GPIO_DATA_OUTPUT       0xfffce004
+#define GPIO_DIR_CONTROL       0xfffce008
+#define GPIO_INT_CONTROL       0xfffce00c
+#define GPIO_INT_MASK          0xfffce010
+#define GPIO_INT_STATUS                0xfffce014
+#define GPIO_PIN_CONTROL       0xfffce018
+
+
+#define A_LCD_SSC_RD   3
+#define A_LCD_SSC_SD   7
+#define _A_LCD_RESET   9
+#define _A_LCD_SSC_CS  12
+#define _A_LCD_SSC_A0  13
+
+#define DSP_REG                0xE1017024
+
+const unsigned char INIT_1[12] = {
+       0x1C, 0x02, 0x88, 0x00, 0x1E, 0xE0, 0x00, 0xDC, 0x00, 0x02, 0x00
+};
+
+const unsigned char INIT_2[127] = {
+       0x15, 0x00, 0x29, 0x00, 0x3E, 0x00, 0x51, 0x00, 0x65, 0x00, 0x7A, 0x00, 0x8D, 0x00, 0xA1, 0x00,
+       0xB6, 0x00, 0xC7, 0x00, 0xD8, 0x00, 0xEB, 0x00, 0xFB, 0x00, 0x0B, 0x01, 0x1B, 0x01, 0x27, 0x01,
+       0x34, 0x01, 0x41, 0x01, 0x4C, 0x01, 0x55, 0x01, 0x5F, 0x01, 0x68, 0x01, 0x70, 0x01, 0x78, 0x01,
+       0x7E, 0x01, 0x86, 0x01, 0x8C, 0x01, 0x94, 0x01, 0x9B, 0x01, 0xA1, 0x01, 0xA4, 0x01, 0xA9, 0x01,
+       0xAD, 0x01, 0xB2, 0x01, 0xB7, 0x01, 0xBC, 0x01, 0xC0, 0x01, 0xC4, 0x01, 0xC8, 0x01, 0xCB, 0x01,
+       0xCF, 0x01, 0xD2, 0x01, 0xD5, 0x01, 0xD8, 0x01, 0xDB, 0x01, 0xE0, 0x01, 0xE3, 0x01, 0xE6, 0x01,
+       0xE8, 0x01, 0xEB, 0x01, 0xEE, 0x01, 0xF1, 0x01, 0xF3, 0x01, 0xF8, 0x01, 0xF9, 0x01, 0xFC, 0x01,
+       0x00, 0x02, 0x03, 0x02, 0x07, 0x02, 0x09, 0x02, 0x0E, 0x02, 0x13, 0x02, 0x1C, 0x02, 0x00
+};
+
+const unsigned char INIT_3[15] = {
+       0x14, 0x26, 0x33, 0x3D, 0x45, 0x4D, 0x53, 0x59,
+       0x5E, 0x63, 0x67, 0x6D, 0x71, 0x78, 0xFF
+};
+
+static void epson_sendbyte(int flag, unsigned char byte)
+{
+       int i, shifter = 0x80;
+
+       if (!flag)
+               omap_set_gpio_dataout(_A_LCD_SSC_A0, 0);
+       mdelay(2);
+       omap_set_gpio_dataout(A_LCD_SSC_RD, 1);
+
+       omap_set_gpio_dataout(A_LCD_SSC_SD, flag);
+
+       OMAP_MCBSP_WRITE(OMAP1510_MCBSP3_BASE, PCR0, 0x2200);
+       OMAP_MCBSP_WRITE(OMAP1510_MCBSP3_BASE, PCR0, 0x2202);
+       for (i = 0; i < 8; i++) {
+               OMAP_MCBSP_WRITE(OMAP1510_MCBSP3_BASE, PCR0, 0x2200);
+               omap_set_gpio_dataout(A_LCD_SSC_SD, shifter & byte);
+               OMAP_MCBSP_WRITE(OMAP1510_MCBSP3_BASE, PCR0, 0x2202);
+               shifter >>= 1;
+       }
+       omap_set_gpio_dataout(_A_LCD_SSC_A0, 1);
+}
+
+static void init_system(void)
+{
+       omap_mcbsp_request(OMAP_MCBSP3);
+       omap_mcbsp_stop(OMAP_MCBSP3);
+}
+
+static void setup_GPIO(void)
+{
+       /* new wave */
+       omap_request_gpio(A_LCD_SSC_RD);
+       omap_request_gpio(A_LCD_SSC_SD);
+       omap_request_gpio(_A_LCD_RESET);
+       omap_request_gpio(_A_LCD_SSC_CS);
+       omap_request_gpio(_A_LCD_SSC_A0);
+
+       /* set all GPIOs to output */
+       omap_set_gpio_direction(A_LCD_SSC_RD, 0);
+       omap_set_gpio_direction(A_LCD_SSC_SD, 0);
+       omap_set_gpio_direction(_A_LCD_RESET, 0);
+       omap_set_gpio_direction(_A_LCD_SSC_CS, 0);
+       omap_set_gpio_direction(_A_LCD_SSC_A0, 0);
+
+       /* set GPIO data */
+       omap_set_gpio_dataout(A_LCD_SSC_RD, 1);
+       omap_set_gpio_dataout(A_LCD_SSC_SD, 0);
+       omap_set_gpio_dataout(_A_LCD_RESET, 0);
+       omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+       omap_set_gpio_dataout(_A_LCD_SSC_A0, 1);
+}
+
+static void display_init(void)
+{
+       int i;
+
+       omap_cfg_reg(MCBSP3_CLKX);
+
+       mdelay(2);
+       setup_GPIO();
+       mdelay(2);
+
+       /* reset LCD */
+       omap_set_gpio_dataout(A_LCD_SSC_SD, 1);
+       epson_sendbyte(0, 0x25);
+
+       omap_set_gpio_dataout(_A_LCD_RESET, 0);
+       mdelay(10);
+       omap_set_gpio_dataout(_A_LCD_RESET, 1);
+
+       omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+       mdelay(2);
+       omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+
+       /* init LCD, phase 1 */
+       epson_sendbyte(0, 0xCA);
+       for (i = 0; i < 10; i++)
+               epson_sendbyte(1, INIT_1[i]);
+       omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+       omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+
+       /* init LCD phase 2 */
+       epson_sendbyte(0, 0xCB);
+       for( i = 0; i < 125; i++)
+               epson_sendbyte(1, INIT_2[i]);
+       omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+       omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+
+       /* init LCD phase 2a */
+       epson_sendbyte(0, 0xCC);
+       for( i = 0; i < 14; i++)
+               epson_sendbyte(1, INIT_3[i]);
+       omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+       omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+
+       /* init LCD phase 3 */
+       epson_sendbyte(0, 0xBC);
+       epson_sendbyte(1, 0x08);
+       omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+       omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+
+       /* init LCD phase 4 */
+       epson_sendbyte(0, 0x07);
+       epson_sendbyte(1, 0x05);
+       omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+       omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+
+       /* init LCD phase 5 */
+       epson_sendbyte(0, 0x94);
+       omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+       omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+
+       /* init LCD phase 6 */
+       epson_sendbyte(0, 0xC6);
+       epson_sendbyte(1, 0x80);
+       omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+       mdelay(100); /* used to be 1000 */
+       omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+
+       /* init LCD phase 7 */
+       epson_sendbyte(0, 0x16);
+       epson_sendbyte(1, 0x02);
+       epson_sendbyte(1, 0x00);
+       epson_sendbyte(1, 0xB1);
+       epson_sendbyte(1, 0x00);
+       omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+       omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+
+       /* init LCD phase 8 */
+       epson_sendbyte(0, 0x76);
+       epson_sendbyte(1, 0x00);
+       epson_sendbyte(1, 0x00);
+       epson_sendbyte(1, 0xDB);
+       epson_sendbyte(1, 0x00);
+       omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+       omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+
+       /* init LCD phase 9 */
+       epson_sendbyte(0, 0xAF);
+       omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+}
+
+static int sx1_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
+{
+       return 0;
+}
+
+static void sx1_panel_cleanup(struct lcd_panel *panel)
+{
+}
+
+static void sx1_panel_disable(struct lcd_panel *panel)
+{
+       printk(KERN_INFO "SX1: LCD panel disable\n");
+       sx1_setmmipower(0);
+       omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+
+       epson_sendbyte(0, 0x25);
+       omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+
+       epson_sendbyte(0, 0xAE);
+       omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+       mdelay(100);
+       omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+
+       epson_sendbyte(0, 0x95);
+       omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+}
+
+static int sx1_panel_enable(struct lcd_panel *panel)
+{
+#if 0
+       sx1_panel_disable(); /* try to disable panel first, if we boot from Symbian */
+#endif
+
+       printk(KERN_INFO "lcd_sx1: LCD panel enable\n");
+       init_system();
+       display_init();
+
+       sx1_setmmipower(1);
+       sx1_setbacklight(0x18);
+       sx1_setkeylight (0x06);
+       return 0;
+}
+
+
+static unsigned long sx1_panel_get_caps(struct lcd_panel *panel)
+{
+       return 0;
+}
+
+struct lcd_panel sx1_panel = {
+       .name           = "sx1",
+       .config         = OMAP_LCDC_PANEL_TFT | OMAP_LCDC_INV_VSYNC |
+                         OMAP_LCDC_INV_HSYNC | OMAP_LCDC_INV_PIX_CLOCK |
+                         OMAP_LCDC_INV_OUTPUT_EN,
+
+       .x_res          = 176,
+       .y_res          = 220,
+       .data_lines     = 16,
+       .bpp            = 16,
+       .hsw            = 5,
+       .hfp            = 5,
+       .hbp            = 5,
+       .vsw            = 2,
+       .vfp            = 1,
+       .vbp            = 1,
+       .pixel_clock    = 1500,
+
+       .init           = sx1_panel_init,
+       .cleanup        = sx1_panel_cleanup,
+       .enable         = sx1_panel_enable,
+       .disable        = sx1_panel_disable,
+       .get_caps       = sx1_panel_get_caps,
+};
+
+static int sx1_panel_probe(struct platform_device *pdev)
+{
+       omapfb_register_panel(&sx1_panel);
+       return 0;
+}
+
+static int sx1_panel_remove(struct platform_device *pdev)
+{
+       return 0;
+}
+
+static int sx1_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+       return 0;
+}
+
+static int sx1_panel_resume(struct platform_device *pdev)
+{
+       return 0;
+}
+
+struct platform_driver sx1_panel_driver = {
+       .probe          = sx1_panel_probe,
+       .remove         = sx1_panel_remove,
+       .suspend        = sx1_panel_suspend,
+       .resume         = sx1_panel_resume,
+       .driver = {
+               .name   = "lcd_sx1",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int sx1_panel_drv_init(void)
+{
+       return platform_driver_register(&sx1_panel_driver);
+}
+
+static void sx1_panel_drv_cleanup(void)
+{
+       platform_driver_unregister(&sx1_panel_driver);
+}
+
+module_init(sx1_panel_drv_init);
+module_exit(sx1_panel_drv_cleanup);
diff --git a/drivers/video/omap/lcdc.c b/drivers/video/omap/lcdc.c
new file mode 100644 (file)
index 0000000..0f86843
--- /dev/null
@@ -0,0 +1,887 @@
+/*
+ * File: drivers/video/omap/omap1/lcdc.c
+ *
+ * OMAP1 internal LCD controller
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Imre Deak <imre.deak@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/err.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+#include <linux/dma-mapping.h>
+#include <linux/vmalloc.h>
+#include <linux/clk.h>
+
+#include <asm/arch/dma.h>
+#include <asm/arch/omapfb.h>
+
+#include <asm/mach-types.h>
+
+#define MODULE_NAME                    "lcdc"
+
+#define OMAP_LCDC_BASE                 0xfffec000
+#define OMAP_LCDC_SIZE                 256
+#define OMAP_LCDC_IRQ                  INT_LCD_CTRL
+
+#define OMAP_LCDC_CONTROL              (OMAP_LCDC_BASE + 0x00)
+#define OMAP_LCDC_TIMING0              (OMAP_LCDC_BASE + 0x04)
+#define OMAP_LCDC_TIMING1              (OMAP_LCDC_BASE + 0x08)
+#define OMAP_LCDC_TIMING2              (OMAP_LCDC_BASE + 0x0c)
+#define OMAP_LCDC_STATUS               (OMAP_LCDC_BASE + 0x10)
+#define OMAP_LCDC_SUBPANEL             (OMAP_LCDC_BASE + 0x14)
+#define OMAP_LCDC_LINE_INT             (OMAP_LCDC_BASE + 0x18)
+#define OMAP_LCDC_DISPLAY_STATUS       (OMAP_LCDC_BASE + 0x1c)
+
+#define OMAP_LCDC_STAT_DONE            (1 << 0)
+#define OMAP_LCDC_STAT_VSYNC           (1 << 1)
+#define OMAP_LCDC_STAT_SYNC_LOST       (1 << 2)
+#define OMAP_LCDC_STAT_ABC             (1 << 3)
+#define OMAP_LCDC_STAT_LINE_INT                (1 << 4)
+#define OMAP_LCDC_STAT_FUF             (1 << 5)
+#define OMAP_LCDC_STAT_LOADED_PALETTE  (1 << 6)
+
+#define OMAP_LCDC_CTRL_LCD_EN          (1 << 0)
+#define OMAP_LCDC_CTRL_LCD_TFT         (1 << 7)
+#define OMAP_LCDC_CTRL_LINE_IRQ_CLR_SEL        (1 << 10)
+
+#define OMAP_LCDC_IRQ_VSYNC            (1 << 2)
+#define OMAP_LCDC_IRQ_DONE             (1 << 3)
+#define OMAP_LCDC_IRQ_LOADED_PALETTE   (1 << 4)
+#define OMAP_LCDC_IRQ_LINE_NIRQ                (1 << 5)
+#define OMAP_LCDC_IRQ_LINE             (1 << 6)
+#define OMAP_LCDC_IRQ_MASK             (((1 << 5) - 1) << 2)
+
+#define MAX_PALETTE_SIZE               PAGE_SIZE
+
+enum lcdc_load_mode {
+       OMAP_LCDC_LOAD_PALETTE,
+       OMAP_LCDC_LOAD_FRAME,
+       OMAP_LCDC_LOAD_PALETTE_AND_FRAME
+};
+
+static struct omap_lcd_controller {
+       enum omapfb_update_mode update_mode;
+       int                     ext_mode;
+
+       unsigned long           frame_offset;
+       int                     screen_width;
+       int                     xres;
+       int                     yres;
+
+       enum omapfb_color_format        color_mode;
+       int                     bpp;
+       void                    *palette_virt;
+       dma_addr_t              palette_phys;
+       int                     palette_code;
+       int                     palette_size;
+
+       unsigned int            irq_mask;
+       struct completion       last_frame_complete;
+       struct completion       palette_load_complete;
+       struct clk              *lcd_ck;
+       struct omapfb_device    *fbdev;
+
+       void                    (*dma_callback)(void *data);
+       void                    *dma_callback_data;
+
+       int                     fbmem_allocated;
+       dma_addr_t              vram_phys;
+       void                    *vram_virt;
+       unsigned long           vram_size;
+} lcdc;
+
+static void inline enable_irqs(int mask)
+{
+       lcdc.irq_mask |= mask;
+}
+
+static void inline disable_irqs(int mask)
+{
+       lcdc.irq_mask &= ~mask;
+}
+
+static void set_load_mode(enum lcdc_load_mode mode)
+{
+       u32 l;
+
+       l = omap_readl(OMAP_LCDC_CONTROL);
+       l &= ~(3 << 20);
+       switch (mode) {
+       case OMAP_LCDC_LOAD_PALETTE:
+               l |= 1 << 20;
+               break;
+       case OMAP_LCDC_LOAD_FRAME:
+               l |= 2 << 20;
+               break;
+       case OMAP_LCDC_LOAD_PALETTE_AND_FRAME:
+               break;
+       default:
+               BUG();
+       }
+       omap_writel(l, OMAP_LCDC_CONTROL);
+}
+
+static void enable_controller(void)
+{
+       u32 l;
+
+       l = omap_readl(OMAP_LCDC_CONTROL);
+       l |= OMAP_LCDC_CTRL_LCD_EN;
+       l &= ~OMAP_LCDC_IRQ_MASK;
+       l |= lcdc.irq_mask | OMAP_LCDC_IRQ_DONE;        /* enabled IRQs */
+       omap_writel(l, OMAP_LCDC_CONTROL);
+}
+
+static void disable_controller_async(void)
+{
+       u32 l;
+       u32 mask;
+
+       l = omap_readl(OMAP_LCDC_CONTROL);
+       mask = OMAP_LCDC_CTRL_LCD_EN | OMAP_LCDC_IRQ_MASK;
+       /* Preserve the DONE mask, since we still want to get the
+        * final DONE irq. It will be disabled in the IRQ handler.
+        */
+       mask &= ~OMAP_LCDC_IRQ_DONE;
+       l &= ~mask;
+       omap_writel(l, OMAP_LCDC_CONTROL);
+}
+
+static void disable_controller(void)
+{
+       init_completion(&lcdc.last_frame_complete);
+       disable_controller_async();
+       if (!wait_for_completion_timeout(&lcdc.last_frame_complete,
+                               msecs_to_jiffies(500)))
+               dev_err(lcdc.fbdev->dev, "timeout waiting for FRAME DONE\n");
+}
+
+static void reset_controller(u32 status)
+{
+       static unsigned long reset_count = 0;
+       static unsigned long last_jiffies = 0;
+
+       disable_controller_async();
+       reset_count++;
+       if (reset_count == 1 || time_after(jiffies, last_jiffies + HZ)) {
+               dev_err(lcdc.fbdev->dev,
+                         "resetting (status %#010x,reset count %lu)\n",
+                         status, reset_count);
+               last_jiffies = jiffies;
+       }
+       if (reset_count < 100) {
+               enable_controller();
+       } else {
+               reset_count = 0;
+               dev_err(lcdc.fbdev->dev,
+                       "too many reset attempts, giving up.\n");
+       }
+}
+
+/* Configure the LCD DMA according to the current mode specified by parameters
+ * in lcdc.fbdev and fbdev->var.
+ */
+static void setup_lcd_dma(void)
+{
+       static const int dma_elem_type[] = {
+               0,
+               OMAP_DMA_DATA_TYPE_S8,
+               OMAP_DMA_DATA_TYPE_S16,
+               0,
+               OMAP_DMA_DATA_TYPE_S32,
+       };
+       struct omapfb_plane_struct *plane = lcdc.fbdev->fb_info[0]->par;
+       struct fb_var_screeninfo *var = &lcdc.fbdev->fb_info[0]->var;
+       unsigned long   src;
+       int             esize, xelem, yelem;
+
+       src = lcdc.vram_phys + lcdc.frame_offset;
+
+       switch (var->rotate) {
+       case 0:
+               if (plane->info.mirror || (src & 3) ||
+                   lcdc.color_mode == OMAPFB_COLOR_YUV420 ||
+                   (lcdc.xres & 1))
+                       esize = 2;
+               else
+                       esize = 4;
+               xelem = lcdc.xres * lcdc.bpp / 8 / esize;
+               yelem = lcdc.yres;
+               break;
+       case 90:
+       case 180:
+       case 270:
+               if (cpu_is_omap15xx()) {
+                       BUG();
+               }
+               esize = 2;
+               xelem = lcdc.yres * lcdc.bpp / 16;
+               yelem = lcdc.xres;
+               break;
+       default:
+               BUG();
+               return;
+       }
+#ifdef VERBOSE
+       dev_dbg(lcdc.fbdev->dev,
+                "setup_dma: src %#010lx esize %d xelem %d yelem %d\n",
+                src, esize, xelem, yelem);
+#endif
+       omap_set_lcd_dma_b1(src, xelem, yelem, dma_elem_type[esize]);
+       if (!cpu_is_omap15xx()) {
+               int bpp = lcdc.bpp;
+
+               /* YUV support is only for external mode when we have the
+                * YUV window embedded in a 16bpp frame buffer.
+                */
+               if (lcdc.color_mode == OMAPFB_COLOR_YUV420)
+                       bpp = 16;
+               /* Set virtual xres elem size */
+               omap_set_lcd_dma_b1_vxres(
+                       lcdc.screen_width * bpp / 8 / esize);
+               /* Setup transformations */
+               omap_set_lcd_dma_b1_rotation(var->rotate);
+               omap_set_lcd_dma_b1_mirror(plane->info.mirror);
+       }
+       omap_setup_lcd_dma();
+}
+
+static irqreturn_t lcdc_irq_handler(int irq, void *dev_id)
+{
+       u32 status;
+
+       status = omap_readl(OMAP_LCDC_STATUS);
+
+       if (status & (OMAP_LCDC_STAT_FUF | OMAP_LCDC_STAT_SYNC_LOST))
+               reset_controller(status);
+       else {
+               if (status & OMAP_LCDC_STAT_DONE) {
+                       u32 l;
+
+                       /* Disable IRQ_DONE. The status bit will be cleared
+                        * only when the controller is reenabled and we don't
+                        * want to get more interrupts.
+                        */
+                       l = omap_readl(OMAP_LCDC_CONTROL);
+                       l &= ~OMAP_LCDC_IRQ_DONE;
+                       omap_writel(l, OMAP_LCDC_CONTROL);
+                       complete(&lcdc.last_frame_complete);
+               }
+               if (status & OMAP_LCDC_STAT_LOADED_PALETTE) {
+                       disable_controller_async();
+                       complete(&lcdc.palette_load_complete);
+               }
+       }
+
+       /* Clear these interrupt status bits.
+        * Sync_lost, FUF bits were cleared by disabling the LCD controller
+        * LOADED_PALETTE can be cleared this way only in palette only
+        * load mode. In other load modes it's cleared by disabling the
+        * controller.
+        */
+       status &= ~(OMAP_LCDC_STAT_VSYNC |
+                   OMAP_LCDC_STAT_LOADED_PALETTE |
+                   OMAP_LCDC_STAT_ABC |
+                   OMAP_LCDC_STAT_LINE_INT);
+       omap_writel(status, OMAP_LCDC_STATUS);
+       return IRQ_HANDLED;
+}
+
+/* Change to a new video mode. We defer this to a later time to avoid any
+ * flicker and not to mess up the current LCD DMA context. For this we disable
+ * the LCD controler, which will generate a DONE irq after the last frame has
+ * been transferred. Then it'll be safe to reconfigure both the LCD controller
+ * as well as the LCD DMA.
+ */
+static int omap_lcdc_setup_plane(int plane, int channel_out,
+                                unsigned long offset, int screen_width,
+                                int pos_x, int pos_y, int width, int height,
+                                int color_mode)
+{
+       struct fb_var_screeninfo *var = &lcdc.fbdev->fb_info[0]->var;
+       struct lcd_panel *panel = lcdc.fbdev->panel;
+       int rot_x, rot_y;
+
+       if (var->rotate == 0) {
+               rot_x = panel->x_res;
+               rot_y = panel->y_res;
+       } else {
+               rot_x = panel->y_res;
+               rot_y = panel->x_res;
+       }
+       if (plane != 0 || channel_out != 0 || pos_x != 0 || pos_y != 0 ||
+           width > rot_x || height > rot_y) {
+#ifdef VERBOSE
+               dev_dbg(lcdc.fbdev->dev,
+                       "invalid plane params plane %d pos_x %d pos_y %d "
+                       "w %d h %d\n", plane, pos_x, pos_y, width, height);
+#endif
+               return -EINVAL;
+       }
+
+       lcdc.frame_offset = offset;
+       lcdc.xres = width;
+       lcdc.yres = height;
+       lcdc.screen_width = screen_width;
+       lcdc.color_mode = color_mode;
+
+       switch (color_mode) {
+       case OMAPFB_COLOR_CLUT_8BPP:
+               lcdc.bpp = 8;
+               lcdc.palette_code = 0x3000;
+               lcdc.palette_size = 512;
+               break;
+       case OMAPFB_COLOR_RGB565:
+               lcdc.bpp = 16;
+               lcdc.palette_code = 0x4000;
+               lcdc.palette_size = 32;
+               break;
+       case OMAPFB_COLOR_RGB444:
+               lcdc.bpp = 16;
+               lcdc.palette_code = 0x4000;
+               lcdc.palette_size = 32;
+               break;
+       case OMAPFB_COLOR_YUV420:
+               if (lcdc.ext_mode) {
+                       lcdc.bpp = 12;
+                       break;
+               }
+               /* fallthrough */
+       case OMAPFB_COLOR_YUV422:
+               if (lcdc.ext_mode) {
+                       lcdc.bpp = 16;
+                       break;
+               }
+               /* fallthrough */
+       default:
+               /* FIXME: other BPPs.
+                * bpp1: code  0,     size 256
+                * bpp2: code  0x1000 size 256
+                * bpp4: code  0x2000 size 256
+                * bpp12: code 0x4000 size 32
+                */
+               dev_dbg(lcdc.fbdev->dev, "invalid color mode %d\n", color_mode);
+               BUG();
+               return -1;
+       }
+
+       if (lcdc.ext_mode) {
+               setup_lcd_dma();
+               return 0;
+       }
+
+       if (lcdc.update_mode == OMAPFB_AUTO_UPDATE) {
+               disable_controller();
+               omap_stop_lcd_dma();
+               setup_lcd_dma();
+               enable_controller();
+       }
+
+       return 0;
+}
+
+static int omap_lcdc_enable_plane(int plane, int enable)
+{
+       dev_dbg(lcdc.fbdev->dev,
+               "plane %d enable %d update_mode %d ext_mode %d\n",
+               plane, enable, lcdc.update_mode, lcdc.ext_mode);
+       if (plane != OMAPFB_PLANE_GFX)
+               return -EINVAL;
+
+       return 0;
+}
+
+/* Configure the LCD DMA for a palette load operation and do the palette
+ * downloading synchronously. We don't use the frame+palette load mode of
+ * the controller, since the palette can always be downloaded seperately.
+ */
+static void load_palette(void)
+{
+       u16     *palette;
+
+       palette = (u16 *)lcdc.palette_virt;
+
+       *(u16 *)palette &= 0x0fff;
+       *(u16 *)palette |= lcdc.palette_code;
+
+       omap_set_lcd_dma_b1(lcdc.palette_phys,
+               lcdc.palette_size / 4 + 1, 1, OMAP_DMA_DATA_TYPE_S32);
+
+       omap_set_lcd_dma_single_transfer(1);
+       omap_setup_lcd_dma();
+
+       init_completion(&lcdc.palette_load_complete);
+       enable_irqs(OMAP_LCDC_IRQ_LOADED_PALETTE);
+       set_load_mode(OMAP_LCDC_LOAD_PALETTE);
+       enable_controller();
+       if (!wait_for_completion_timeout(&lcdc.palette_load_complete,
+                               msecs_to_jiffies(500)))
+               dev_err(lcdc.fbdev->dev, "timeout waiting for FRAME DONE\n");
+       /* The controller gets disabled in the irq handler */
+       disable_irqs(OMAP_LCDC_IRQ_LOADED_PALETTE);
+       omap_stop_lcd_dma();
+
+       omap_set_lcd_dma_single_transfer(lcdc.ext_mode);
+}
+
+/* Used only in internal controller mode */
+static int omap_lcdc_setcolreg(u_int regno, u16 red, u16 green, u16 blue,
+                              u16 transp, int update_hw_pal)
+{
+       u16 *palette;
+
+       if (lcdc.color_mode != OMAPFB_COLOR_CLUT_8BPP || regno > 255)
+               return -EINVAL;
+
+       palette = (u16 *)lcdc.palette_virt;
+
+       palette[regno] &= ~0x0fff;
+       palette[regno] |= ((red >> 12) << 8) | ((green >> 12) << 4 ) |
+                          (blue >> 12);
+
+       if (update_hw_pal) {
+               disable_controller();
+               omap_stop_lcd_dma();
+               load_palette();
+               setup_lcd_dma();
+               set_load_mode(OMAP_LCDC_LOAD_FRAME);
+               enable_controller();
+       }
+
+       return 0;
+}
+
+static void calc_ck_div(int is_tft, int pck, int *pck_div)
+{
+       unsigned long lck;
+
+       pck = max(1, pck);
+       lck = clk_get_rate(lcdc.lcd_ck);
+       *pck_div = (lck + pck - 1) / pck;
+       if (is_tft)
+               *pck_div = max(2, *pck_div);
+       else
+               *pck_div = max(3, *pck_div);
+       if (*pck_div > 255) {
+               /* FIXME: try to adjust logic clock divider as well */
+               *pck_div = 255;
+               dev_warn(lcdc.fbdev->dev, "pixclock %d kHz too low.\n",
+                        pck / 1000);
+       }
+}
+
+static void inline setup_regs(void)
+{
+       u32 l;
+       struct lcd_panel *panel = lcdc.fbdev->panel;
+       int is_tft = panel->config & OMAP_LCDC_PANEL_TFT;
+       unsigned long lck;
+       int pcd;
+
+       l = omap_readl(OMAP_LCDC_CONTROL);
+       l &= ~OMAP_LCDC_CTRL_LCD_TFT;
+       l |= is_tft ? OMAP_LCDC_CTRL_LCD_TFT : 0;
+#ifdef CONFIG_MACH_OMAP_PALMTE
+/* FIXME:if (machine_is_omap_palmte()) { */
+               /* PalmTE uses alternate TFT setting in 8BPP mode */
+               l |= (is_tft && panel->bpp == 8) ? 0x810000 : 0;
+/*     } */
+#endif
+       omap_writel(l, OMAP_LCDC_CONTROL);
+
+       l = omap_readl(OMAP_LCDC_TIMING2);
+       l &= ~(((1 << 6) - 1) << 20);
+       l |= (panel->config & OMAP_LCDC_SIGNAL_MASK) << 20;
+       omap_writel(l, OMAP_LCDC_TIMING2);
+
+       l = panel->x_res - 1;
+       l |= (panel->hsw - 1) << 10;
+       l |= (panel->hfp - 1) << 16;
+       l |= (panel->hbp - 1) << 24;
+       omap_writel(l, OMAP_LCDC_TIMING0);
+
+       l = panel->y_res - 1;
+       l |= (panel->vsw - 1) << 10;
+       l |= panel->vfp << 16;
+       l |= panel->vbp << 24;
+       omap_writel(l, OMAP_LCDC_TIMING1);
+
+       l = omap_readl(OMAP_LCDC_TIMING2);
+       l &= ~0xff;
+
+       lck = clk_get_rate(lcdc.lcd_ck);
+
+       if (!panel->pcd)
+               calc_ck_div(is_tft, panel->pixel_clock * 1000, &pcd);
+       else {
+               dev_warn(lcdc.fbdev->dev,
+                   "Pixel clock divider value is obsolete.\n"
+                   "Try to set pixel_clock to %lu and pcd to 0 "
+                   "in drivers/video/omap/lcd_%s.c and submit a patch.\n",
+                       lck / panel->pcd / 1000, panel->name);
+
+               pcd = panel->pcd;
+       }
+       l |= pcd & 0xff;
+       l |= panel->acb << 8;
+       omap_writel(l, OMAP_LCDC_TIMING2);
+
+       /* update panel info with the exact clock */
+       panel->pixel_clock = lck / pcd / 1000;
+}
+
+/* Configure the LCD controller, download the color palette and start a looped
+ * DMA transfer of the frame image data. Called only in internal
+ * controller mode.
+ */
+static int omap_lcdc_set_update_mode(enum omapfb_update_mode mode)
+{
+       int r = 0;
+
+       if (mode != lcdc.update_mode) {
+               switch (mode) {
+               case OMAPFB_AUTO_UPDATE:
+                       setup_regs();
+                       load_palette();
+
+                       /* Setup and start LCD DMA */
+                       setup_lcd_dma();
+
+                       set_load_mode(OMAP_LCDC_LOAD_FRAME);
+                       enable_irqs(OMAP_LCDC_IRQ_DONE);
+                       /* This will start the actual DMA transfer */
+                       enable_controller();
+                       lcdc.update_mode = mode;
+                       break;
+               case OMAPFB_UPDATE_DISABLED:
+                       disable_controller();
+                       omap_stop_lcd_dma();
+                       lcdc.update_mode = mode;
+                       break;
+               default:
+                       r = -EINVAL;
+               }
+       }
+
+       return r;
+}
+
+static enum omapfb_update_mode omap_lcdc_get_update_mode(void)
+{
+       return lcdc.update_mode;
+}
+
+/* PM code called only in internal controller mode */
+static void omap_lcdc_suspend(void)
+{
+       if (lcdc.update_mode == OMAPFB_AUTO_UPDATE) {
+               disable_controller();
+               omap_stop_lcd_dma();
+       }
+}
+
+static void omap_lcdc_resume(void)
+{
+       if (lcdc.update_mode == OMAPFB_AUTO_UPDATE) {
+               setup_regs();
+               load_palette();
+               setup_lcd_dma();
+               set_load_mode(OMAP_LCDC_LOAD_FRAME);
+               enable_irqs(OMAP_LCDC_IRQ_DONE);
+               enable_controller();
+       }
+}
+
+static unsigned long omap_lcdc_get_caps(void)
+{
+       return 0;
+}
+
+int omap_lcdc_set_dma_callback(void (*callback)(void *data), void *data)
+{
+       BUG_ON(callback == NULL);
+
+       if (lcdc.dma_callback)
+               return -EBUSY;
+       else {
+               lcdc.dma_callback = callback;
+               lcdc.dma_callback_data = data;
+       }
+       return 0;
+}
+EXPORT_SYMBOL(omap_lcdc_set_dma_callback);
+
+void omap_lcdc_free_dma_callback(void)
+{
+       lcdc.dma_callback = NULL;
+}
+EXPORT_SYMBOL(omap_lcdc_free_dma_callback);
+
+static void lcdc_dma_handler(u16 status, void *data)
+{
+       if (lcdc.dma_callback)
+               lcdc.dma_callback(lcdc.dma_callback_data);
+}
+
+static int mmap_kern(void)
+{
+       struct vm_struct        *kvma;
+       struct vm_area_struct   vma;
+       pgprot_t                pgprot;
+       unsigned long           vaddr;
+
+       kvma = get_vm_area(lcdc.vram_size, VM_IOREMAP);
+       if (kvma == NULL) {
+               dev_err(lcdc.fbdev->dev, "can't get kernel vm area\n");
+               return -ENOMEM;
+       }
+       vma.vm_mm = &init_mm;
+
+       vaddr = (unsigned long)kvma->addr;
+       vma.vm_start = vaddr;
+       vma.vm_end = vaddr + lcdc.vram_size;
+
+       pgprot = pgprot_writecombine(pgprot_kernel);
+       if (io_remap_pfn_range(&vma, vaddr,
+                          lcdc.vram_phys >> PAGE_SHIFT,
+                          lcdc.vram_size, pgprot) < 0) {
+               dev_err(lcdc.fbdev->dev, "kernel mmap for FB memory failed\n");
+               return -EAGAIN;
+       }
+
+       lcdc.vram_virt = (void *)vaddr;
+
+       return 0;
+}
+
+static void unmap_kern(void)
+{
+       vunmap(lcdc.vram_virt);
+}
+
+static int alloc_palette_ram(void)
+{
+       lcdc.palette_virt = dma_alloc_writecombine(lcdc.fbdev->dev,
+               MAX_PALETTE_SIZE, &lcdc.palette_phys, GFP_KERNEL);
+       if (lcdc.palette_virt == NULL) {
+               dev_err(lcdc.fbdev->dev, "failed to alloc palette memory\n");
+               return -ENOMEM;
+       }
+       memset(lcdc.palette_virt, 0, MAX_PALETTE_SIZE);
+
+       return 0;
+}
+
+static void free_palette_ram(void)
+{
+       dma_free_writecombine(lcdc.fbdev->dev, MAX_PALETTE_SIZE,
+                       lcdc.palette_virt, lcdc.palette_phys);
+}
+
+static int alloc_fbmem(struct omapfb_mem_region *region)
+{
+       int bpp;
+       int frame_size;
+       struct lcd_panel *panel = lcdc.fbdev->panel;
+
+       bpp = panel->bpp;
+       if (bpp == 12)
+               bpp = 16;
+       frame_size = PAGE_ALIGN(panel->x_res * bpp / 8 * panel->y_res);
+       if (region->size > frame_size)
+               frame_size = region->size;
+       lcdc.vram_size = frame_size;
+       lcdc.vram_virt = dma_alloc_writecombine(lcdc.fbdev->dev,
+                       lcdc.vram_size, &lcdc.vram_phys, GFP_KERNEL);
+       if (lcdc.vram_virt == NULL) {
+               dev_err(lcdc.fbdev->dev, "unable to allocate FB DMA memory\n");
+               return -ENOMEM;
+       }
+       region->size = frame_size;
+       region->paddr = lcdc.vram_phys;
+       region->vaddr = lcdc.vram_virt;
+       region->alloc = 1;
+
+       memset(lcdc.vram_virt, 0, lcdc.vram_size);
+
+       return 0;
+}
+
+static void free_fbmem(void)
+{
+       dma_free_writecombine(lcdc.fbdev->dev, lcdc.vram_size,
+                             lcdc.vram_virt, lcdc.vram_phys);
+}
+
+static int setup_fbmem(struct omapfb_mem_desc *req_md)
+{
+       int r;
+
+       if (!req_md->region_cnt) {
+               dev_err(lcdc.fbdev->dev, "no memory regions defined\n");
+               return -EINVAL;
+       }
+
+       if (req_md->region_cnt > 1) {
+               dev_err(lcdc.fbdev->dev, "only one plane is supported\n");
+               req_md->region_cnt = 1;
+       }
+
+       if (req_md->region[0].paddr == 0) {
+               lcdc.fbmem_allocated = 1;
+               if ((r = alloc_fbmem(&req_md->region[0])) < 0)
+                       return r;
+               return 0;
+       }
+
+       lcdc.vram_phys = req_md->region[0].paddr;
+       lcdc.vram_size = req_md->region[0].size;
+
+       if ((r = mmap_kern()) < 0)
+               return r;
+
+       dev_dbg(lcdc.fbdev->dev, "vram at %08x size %08lx mapped to 0x%p\n",
+                lcdc.vram_phys, lcdc.vram_size, lcdc.vram_virt);
+
+       return 0;
+}
+
+static void cleanup_fbmem(void)
+{
+       if (lcdc.fbmem_allocated)
+               free_fbmem();
+       else
+               unmap_kern();
+}
+
+static int omap_lcdc_init(struct omapfb_device *fbdev, int ext_mode,
+                         struct omapfb_mem_desc *req_vram)
+{
+       int r;
+       u32 l;
+       int rate;
+       struct clk *tc_ck;
+
+       lcdc.irq_mask = 0;
+
+       lcdc.fbdev = fbdev;
+       lcdc.ext_mode = ext_mode;
+
+       l = 0;
+       omap_writel(l, OMAP_LCDC_CONTROL);
+
+       /* FIXME:
+        * According to errata some platforms have a clock rate limitiation
+        */
+       lcdc.lcd_ck = clk_get(NULL, "lcd_ck");
+       if (IS_ERR(lcdc.lcd_ck)) {
+               dev_err(fbdev->dev, "unable to access LCD clock\n");
+               r = PTR_ERR(lcdc.lcd_ck);
+               goto fail0;
+       }
+
+       tc_ck = clk_get(NULL, "tc_ck");
+       if (IS_ERR(tc_ck)) {
+               dev_err(fbdev->dev, "unable to access TC clock\n");
+               r = PTR_ERR(tc_ck);
+               goto fail1;
+       }
+
+       rate = clk_get_rate(tc_ck);
+       clk_put(tc_ck);
+
+       if (machine_is_ams_delta())
+               rate /= 4;
+       if (machine_is_omap_h3())
+               rate /= 3;
+       r = clk_set_rate(lcdc.lcd_ck, rate);
+       if (r) {
+               dev_err(fbdev->dev, "failed to adjust LCD rate\n");
+               goto fail1;
+       }
+       clk_enable(lcdc.lcd_ck);
+
+       r = request_irq(OMAP_LCDC_IRQ, lcdc_irq_handler, 0, MODULE_NAME, fbdev);
+       if (r) {
+               dev_err(fbdev->dev, "unable to get IRQ\n");
+               goto fail2;
+       }
+
+       r = omap_request_lcd_dma(lcdc_dma_handler, NULL);
+       if (r) {
+               dev_err(fbdev->dev, "unable to get LCD DMA\n");
+               goto fail3;
+       }
+
+       omap_set_lcd_dma_single_transfer(ext_mode);
+       omap_set_lcd_dma_ext_controller(ext_mode);
+
+       if (!ext_mode)
+               if ((r = alloc_palette_ram()) < 0)
+                       goto fail4;
+
+       if ((r = setup_fbmem(req_vram)) < 0)
+               goto fail5;
+
+       pr_info("omapfb: LCDC initialized\n");
+
+       return 0;
+fail5:
+       if (!ext_mode)
+               free_palette_ram();
+fail4:
+       omap_free_lcd_dma();
+fail3:
+       free_irq(OMAP_LCDC_IRQ, lcdc.fbdev);
+fail2:
+       clk_disable(lcdc.lcd_ck);
+fail1:
+       clk_put(lcdc.lcd_ck);
+fail0:
+        return r;
+}
+
+static void omap_lcdc_cleanup(void)
+{
+       if (!lcdc.ext_mode)
+               free_palette_ram();
+       cleanup_fbmem();
+       omap_free_lcd_dma();
+       free_irq(OMAP_LCDC_IRQ, lcdc.fbdev);
+       clk_disable(lcdc.lcd_ck);
+       clk_put(lcdc.lcd_ck);
+}
+
+const struct lcd_ctrl omap1_int_ctrl = {
+       .name                   = "internal",
+       .init                   = omap_lcdc_init,
+       .cleanup                = omap_lcdc_cleanup,
+       .get_caps               = omap_lcdc_get_caps,
+       .set_update_mode        = omap_lcdc_set_update_mode,
+       .get_update_mode        = omap_lcdc_get_update_mode,
+       .update_window          = NULL,
+       .suspend                = omap_lcdc_suspend,
+       .resume                 = omap_lcdc_resume,
+       .setup_plane            = omap_lcdc_setup_plane,
+       .enable_plane           = omap_lcdc_enable_plane,
+       .setcolreg              = omap_lcdc_setcolreg,
+};
diff --git a/drivers/video/omap/lcdc.h b/drivers/video/omap/lcdc.h
new file mode 100644 (file)
index 0000000..adb731e
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef LCDC_H
+#define LCDC_H
+
+int omap_lcdc_set_dma_callback(void (*callback)(void *data), void *data);
+void omap_lcdc_free_dma_callback(void);
+
+#endif
diff --git a/drivers/video/omap/omapfb_main.c b/drivers/video/omap/omapfb_main.c
new file mode 100644 (file)
index 0000000..a7cf760
--- /dev/null
@@ -0,0 +1,1673 @@
+/*
+ * File: drivers/video/omap/omapfb_main.c
+ *
+ * Framebuffer driver for TI OMAP boards
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Imre Deak <imre.deak@nokia.com>
+ *
+ * Acknowledgements:
+ *   Alex McMains <aam@ridgerun.com>       - Original driver
+ *   Juha Yrjola <juha.yrjola@nokia.com>   - Original driver and improvements
+ *   Dirk Behme <dirk.behme@de.bosch.com>  - changes for 2.6 kernel API
+ *   Texas Instruments                     - H3 support
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+#include <linux/platform_device.h>
+
+#include <asm/uaccess.h>
+#include <asm/mach-types.h>
+#include <asm/arch/dma.h>
+#include <asm/arch/omapfb.h>
+
+#define MODULE_NAME    "omapfb"
+
+static unsigned int    def_accel;
+static unsigned long   def_vram[OMAPFB_PLANE_NUM];
+static int             def_vram_cnt;
+static unsigned long   def_vxres;
+static unsigned long   def_vyres;
+static unsigned int    def_rotate;
+static unsigned int    def_mirror;
+
+#ifdef CONFIG_FB_OMAP_MANUAL_UPDATE
+static int             manual_update = 1;
+#else
+static int             manual_update;
+#endif
+
+static struct platform_device  *fbdev_pdev;
+static struct lcd_panel                *fbdev_panel;
+static struct omapfb_device    *omapfb_dev;
+
+static struct caps_table_struct {
+        unsigned long flag;
+        const char *name;
+} omapfb_caps_table[] = {
+       { OMAPFB_CAPS_MANUAL_UPDATE, "manual update" },
+       { OMAPFB_CAPS_SET_BACKLIGHT, "backlight setting" },
+};
+
+/*
+ * ---------------------------------------------------------------------------
+ * LCD panel
+ * ---------------------------------------------------------------------------
+ */
+extern struct lcd_ctrl omap1_int_ctrl;
+extern struct lcd_ctrl omap2_int_ctrl;
+extern struct lcd_ctrl hwa742_ctrl;
+
+static struct lcd_ctrl *ctrls[] = {
+#ifdef CONFIG_ARCH_OMAP1
+       &omap1_int_ctrl,
+#else
+       &omap2_int_ctrl,
+#endif
+
+#ifdef CONFIG_FB_OMAP_LCDC_HWA742
+       &hwa742_ctrl,
+#endif
+};
+
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+#ifdef CONFIG_ARCH_OMAP1
+extern struct lcd_ctrl_extif omap1_ext_if;
+#else
+extern struct lcd_ctrl_extif omap2_ext_if;
+#endif
+#endif
+
+static void omapfb_rqueue_lock(struct omapfb_device *fbdev)
+{
+       mutex_lock(&fbdev->rqueue_mutex);
+}
+
+static void omapfb_rqueue_unlock(struct omapfb_device *fbdev)
+{
+       mutex_unlock(&fbdev->rqueue_mutex);
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ * LCD controller and LCD DMA
+ * ---------------------------------------------------------------------------
+ */
+/* Lookup table to map elem size to elem type. */
+static const int dma_elem_type[] = {
+       0,
+       OMAP_DMA_DATA_TYPE_S8,
+       OMAP_DMA_DATA_TYPE_S16,
+       0,
+       OMAP_DMA_DATA_TYPE_S32,
+};
+
+/* Allocate resources needed for LCD controller and LCD DMA operations. Video
+ * memory is allocated from system memory according to the virtual display
+ * size, except if a bigger memory size is specified explicitly as a kernel
+ * parameter.
+ */
+static int ctrl_init(struct omapfb_device *fbdev)
+{
+       int r;
+       int i;
+
+       /* kernel/module vram parameters override boot tags/board config */
+       if (def_vram_cnt) {
+               for (i = 0; i < def_vram_cnt; i++)
+                       fbdev->mem_desc.region[i].size = def_vram[i];
+               fbdev->mem_desc.region_cnt = i;
+       } else {
+               struct omapfb_platform_data *conf;
+
+               conf = fbdev->dev->platform_data;
+               fbdev->mem_desc = conf->mem_desc;
+       }
+
+       if (!fbdev->mem_desc.region_cnt) {
+               struct lcd_panel *panel = fbdev->panel;
+               int def_size;
+               int bpp = panel->bpp;
+
+               /* 12 bpp is packed in 16 bits */
+               if (bpp == 12)
+                       bpp = 16;
+               def_size = def_vxres * def_vyres * bpp / 8;
+               fbdev->mem_desc.region_cnt = 1;
+               fbdev->mem_desc.region[0].size = def_size;
+       }
+       r = fbdev->ctrl->init(fbdev, 0, &fbdev->mem_desc);
+       if (r < 0) {
+               dev_err(fbdev->dev, "controller initialization failed (%d)\n", r);
+               return r;
+       }
+
+#ifdef DEBUG
+       for (i = 0; i < fbdev->mem_desc.region_cnt; i++) {
+               dev_dbg(fbdev->dev, "region%d phys %08x virt %p size=%lu\n",
+                        i,
+                        fbdev->mem_desc.region[i].paddr,
+                        fbdev->mem_desc.region[i].vaddr,
+                        fbdev->mem_desc.region[i].size);
+       }
+#endif
+       return 0;
+}
+
+static void ctrl_cleanup(struct omapfb_device *fbdev)
+{
+       fbdev->ctrl->cleanup();
+}
+
+static int ctrl_change_mode(struct fb_info *fbi)
+{
+       int r;
+       unsigned long offset;
+       struct omapfb_plane_struct *plane = fbi->par;
+       struct omapfb_device *fbdev = plane->fbdev;
+       struct fb_var_screeninfo *var = &fbi->var;
+
+       offset = var->yoffset * fbi->fix.line_length +
+                var->xoffset * var->bits_per_pixel / 8;
+
+       omapfb_rqueue_lock(fbdev);
+       r = fbdev->ctrl->setup_plane(plane->idx, plane->info.channel_out,
+                                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)
+               r = fbdev->ctrl->set_scale(plane->idx,
+                                  var->xres, var->yres,
+                                  plane->info.out_width,
+                                  plane->info.out_height);
+       omapfb_rqueue_unlock(fbdev);
+
+       return r;
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ * fbdev framework callbacks and the ioctl interface
+ * ---------------------------------------------------------------------------
+ */
+/* Called each time the omapfb device is opened */
+static int omapfb_open(struct fb_info *info, int user)
+{
+       return 0;
+}
+
+static void omapfb_sync(struct fb_info *info);
+
+/* Called when the omapfb device is closed. We make sure that any pending
+ * gfx DMA operations are ended, before we return. */
+static int omapfb_release(struct fb_info *info, int user)
+{
+       omapfb_sync(info);
+       return 0;
+}
+
+/* Store a single color palette entry into a pseudo palette or the hardware
+ * palette if one is available. For now we support only 16bpp and thus store
+ * the entry only to the pseudo palette.
+ */
+static int _setcolreg(struct fb_info *info, u_int regno, u_int red, u_int green,
+                       u_int blue, u_int transp, int update_hw_pal)
+{
+       struct omapfb_plane_struct *plane = info->par;
+       struct omapfb_device *fbdev = plane->fbdev;
+       struct fb_var_screeninfo *var = &info->var;
+       int r = 0;
+
+       switch (plane->color_mode) {
+       case OMAPFB_COLOR_YUV422:
+       case OMAPFB_COLOR_YUV420:
+       case OMAPFB_COLOR_YUY422:
+               r = -EINVAL;
+               break;
+       case OMAPFB_COLOR_CLUT_8BPP:
+       case OMAPFB_COLOR_CLUT_4BPP:
+       case OMAPFB_COLOR_CLUT_2BPP:
+       case OMAPFB_COLOR_CLUT_1BPP:
+               if (fbdev->ctrl->setcolreg)
+                       r = fbdev->ctrl->setcolreg(regno, red, green, blue,
+                                                       transp, update_hw_pal);
+               /* Fallthrough */
+       case OMAPFB_COLOR_RGB565:
+       case OMAPFB_COLOR_RGB444:
+               if (r != 0)
+                       break;
+
+               if (regno < 0) {
+                       r = -EINVAL;
+                       break;
+               }
+
+               if (regno < 16) {
+                       u16 pal;
+                       pal = ((red >> (16 - var->red.length)) <<
+                                       var->red.offset) |
+                             ((green >> (16 - var->green.length)) <<
+                                       var->green.offset) |
+                             (blue >> (16 - var->blue.length));
+                       ((u32 *)(info->pseudo_palette))[regno] = pal;
+               }
+               break;
+       default:
+               BUG();
+       }
+       return r;
+}
+
+static int omapfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+                           u_int transp, struct fb_info *info)
+{
+       return _setcolreg(info, regno, red, green, blue, transp, 1);
+}
+
+static int omapfb_setcmap(struct fb_cmap *cmap, struct fb_info *info)
+{
+       int count, index, r;
+       u16 *red, *green, *blue, *transp;
+       u16 trans = 0xffff;
+
+       red     = cmap->red;
+       green   = cmap->green;
+       blue    = cmap->blue;
+       transp  = cmap->transp;
+       index   = cmap->start;
+
+       for (count = 0; count < cmap->len; count++) {
+               if (transp)
+                       trans = *transp++;
+               r = _setcolreg(info, index++, *red++, *green++, *blue++, trans,
+                               count == cmap->len - 1);
+               if (r != 0)
+                       return r;
+       }
+
+       return 0;
+}
+
+static int omapfb_update_full_screen(struct fb_info *fbi);
+
+static int omapfb_blank(int blank, struct fb_info *fbi)
+{
+       struct omapfb_plane_struct *plane = fbi->par;
+       struct omapfb_device *fbdev = plane->fbdev;
+       int do_update = 0;
+       int r = 0;
+
+       omapfb_rqueue_lock(fbdev);
+       switch (blank) {
+       case VESA_NO_BLANKING:
+               if (fbdev->state == OMAPFB_SUSPENDED) {
+                       if (fbdev->ctrl->resume)
+                               fbdev->ctrl->resume();
+                       fbdev->panel->enable(fbdev->panel);
+                       fbdev->state = OMAPFB_ACTIVE;
+                       if (fbdev->ctrl->get_update_mode() ==
+                                       OMAPFB_MANUAL_UPDATE)
+                               do_update = 1;
+               }
+               break;
+       case VESA_POWERDOWN:
+               if (fbdev->state == OMAPFB_ACTIVE) {
+                       fbdev->panel->disable(fbdev->panel);
+                       if (fbdev->ctrl->suspend)
+                               fbdev->ctrl->suspend();
+                       fbdev->state = OMAPFB_SUSPENDED;
+               }
+               break;
+       default:
+               r = -EINVAL;
+       }
+       omapfb_rqueue_unlock(fbdev);
+
+       if (r == 0 && do_update)
+               r = omapfb_update_full_screen(fbi);
+
+       return r;
+}
+
+static void omapfb_sync(struct fb_info *fbi)
+{
+       struct omapfb_plane_struct *plane = fbi->par;
+       struct omapfb_device *fbdev = plane->fbdev;
+
+       omapfb_rqueue_lock(fbdev);
+       if (fbdev->ctrl->sync)
+               fbdev->ctrl->sync();
+       omapfb_rqueue_unlock(fbdev);
+}
+
+/* Set fb_info.fix fields and also updates fbdev.
+ * When calling this fb_info.var must be set up already.
+ */
+static void set_fb_fix(struct fb_info *fbi)
+{
+       struct fb_fix_screeninfo *fix = &fbi->fix;
+       struct fb_var_screeninfo *var = &fbi->var;
+       int bpp;
+
+       fix->type = FB_TYPE_PACKED_PIXELS;
+       bpp = var->bits_per_pixel;
+       if (var->nonstd)
+               fix->visual = FB_VISUAL_PSEUDOCOLOR;
+       else switch (var->bits_per_pixel) {
+       case 16:
+       case 12:
+               fix->visual = FB_VISUAL_TRUECOLOR;
+               /* 12bpp is stored in 16 bits */
+               bpp = 16;
+               break;
+       case 1:
+       case 2:
+       case 4:
+       case 8:
+               fix->visual = FB_VISUAL_PSEUDOCOLOR;
+               break;
+       }
+       fix->accel              = FB_ACCEL_OMAP1610;
+       fix->line_length        = var->xres_virtual * bpp / 8;
+}
+
+static int set_color_mode(struct omapfb_plane_struct *plane,
+                         struct fb_var_screeninfo *var)
+{
+       switch (var->nonstd) {
+       case 0:
+               break;
+       case OMAPFB_COLOR_YUV422:
+               var->bits_per_pixel = 16;
+               plane->color_mode = var->nonstd;
+               return 0;
+       case OMAPFB_COLOR_YUV420:
+               var->bits_per_pixel = 12;
+               plane->color_mode = var->nonstd;
+               return 0;
+       case OMAPFB_COLOR_YUY422:
+               var->bits_per_pixel = 16;
+               plane->color_mode = var->nonstd;
+               return 0;
+       default:
+               return -EINVAL;
+       }
+
+       switch (var->bits_per_pixel) {
+       case 1:
+               plane->color_mode = OMAPFB_COLOR_CLUT_1BPP;
+               return 0;
+       case 2:
+               plane->color_mode = OMAPFB_COLOR_CLUT_2BPP;
+               return 0;
+       case 4:
+               plane->color_mode = OMAPFB_COLOR_CLUT_4BPP;
+               return 0;
+       case 8:
+               plane->color_mode = OMAPFB_COLOR_CLUT_8BPP;
+               return 0;
+       case 12:
+               var->bits_per_pixel = 16;
+               plane->color_mode = OMAPFB_COLOR_RGB444;
+               return 0;
+       case 16:
+               plane->color_mode = OMAPFB_COLOR_RGB565;
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+/* Check the values in var against our capabilities and in case of out of
+ * bound values try to adjust them.
+ */
+static int set_fb_var(struct fb_info *fbi,
+                     struct fb_var_screeninfo *var)
+{
+       int             bpp;
+       unsigned long   max_frame_size;
+       unsigned long   line_size;
+       int             xres_min, xres_max;
+       int             yres_min, yres_max;
+       struct omapfb_plane_struct *plane = fbi->par;
+       struct omapfb_device *fbdev = plane->fbdev;
+       struct lcd_panel *panel = fbdev->panel;
+
+       if (set_color_mode(plane, var) < 0)
+               return -EINVAL;
+
+       bpp = var->bits_per_pixel;
+       if (plane->color_mode == OMAPFB_COLOR_RGB444)
+               bpp = 16;
+
+       switch (var->rotate) {
+       case 0:
+       case 180:
+               xres_min = OMAPFB_PLANE_XRES_MIN;
+               xres_max = panel->x_res;
+               yres_min = OMAPFB_PLANE_YRES_MIN;
+               yres_max = panel->y_res;
+               if (cpu_is_omap15xx()) {
+                       var->xres = panel->x_res;
+                       var->yres = panel->y_res;
+               }
+               break;
+       case 90:
+       case 270:
+               xres_min = OMAPFB_PLANE_YRES_MIN;
+               xres_max = panel->y_res;
+               yres_min = OMAPFB_PLANE_XRES_MIN;
+               yres_max = panel->x_res;
+               if (cpu_is_omap15xx()) {
+                       var->xres = panel->y_res;
+                       var->yres = panel->x_res;
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (var->xres < xres_min)
+               var->xres = xres_min;
+       if (var->yres < yres_min)
+               var->yres = yres_min;
+       if (var->xres > xres_max)
+               var->xres = xres_max;
+       if (var->yres > yres_max)
+               var->yres = yres_max;
+
+       if (var->xres_virtual < var->xres)
+               var->xres_virtual = var->xres;
+       if (var->yres_virtual < var->yres)
+               var->yres_virtual = var->yres;
+       max_frame_size = fbdev->mem_desc.region[plane->idx].size;
+       line_size = var->xres_virtual * bpp / 8;
+       if (line_size * var->yres_virtual > max_frame_size) {
+               /* Try to keep yres_virtual first */
+               line_size = max_frame_size / var->yres_virtual;
+               var->xres_virtual = line_size * 8 / bpp;
+               if (var->xres_virtual < var->xres) {
+                       /* Still doesn't fit. Shrink yres_virtual too */
+                       var->xres_virtual = var->xres;
+                       line_size = var->xres * bpp / 8;
+                       var->yres_virtual = max_frame_size / line_size;
+               }
+       }
+       if (var->xres + var->xoffset > var->xres_virtual)
+               var->xoffset = var->xres_virtual - var->xres;
+       if (var->yres + var->yoffset > var->yres_virtual)
+               var->yoffset = var->yres_virtual - var->yres;
+       line_size = var->xres * bpp / 8;
+
+       if (plane->color_mode == OMAPFB_COLOR_RGB444) {
+               var->red.offset   = 8; var->red.length   = 4;
+                                               var->red.msb_right   = 0;
+               var->green.offset = 4; var->green.length = 4;
+                                               var->green.msb_right = 0;
+               var->blue.offset  = 0; var->blue.length  = 4;
+                                               var->blue.msb_right  = 0;
+       } else {
+               var->red.offset  = 11; var->red.length   = 5;
+                                               var->red.msb_right   = 0;
+               var->green.offset= 5;  var->green.length = 6;
+                                               var->green.msb_right = 0;
+               var->blue.offset = 0;  var->blue.length  = 5;
+                                               var->blue.msb_right  = 0;
+       }
+
+       var->height             = -1;
+       var->width              = -1;
+       var->grayscale          = 0;
+
+       /* pixclock in ps, the rest in pixclock */
+       var->pixclock           = 10000000 / (panel->pixel_clock / 100);
+       var->left_margin        = panel->hfp;
+       var->right_margin       = panel->hbp;
+       var->upper_margin       = panel->vfp;
+       var->lower_margin       = panel->vbp;
+       var->hsync_len          = panel->hsw;
+       var->vsync_len          = panel->vsw;
+
+       /* TODO: get these from panel->config */
+       var->vmode              = FB_VMODE_NONINTERLACED;
+       var->sync               = 0;
+
+       return 0;
+}
+
+static struct fb_var_screeninfo new_var;
+
+/* Set rotation (0, 90, 180, 270 degree), and switch to the new mode. */
+static void omapfb_rotate(struct fb_info *fbi, int rotate)
+{
+       if (cpu_is_omap15xx() && rotate != fbi->var.rotate) {
+               memcpy(&new_var, &fbi->var, sizeof(new_var));
+               new_var.rotate = rotate;
+               if (set_fb_var(fbi, &new_var) == 0 &&
+                   memcmp(&new_var, &fbi->var, sizeof(new_var))) {
+                       memcpy(&fbi->var, &new_var, sizeof(new_var));
+                       ctrl_change_mode(fbi);
+               }
+       }
+}
+
+/* Set new x,y offsets in the virtual display for the visible area and switch
+ * to the new mode.
+ */
+static int omapfb_pan_display(struct fb_var_screeninfo *var,
+                              struct fb_info *fbi)
+{
+       int r = 0;
+
+       if (var->xoffset != fbi->var.xoffset ||
+           var->yoffset != fbi->var.yoffset) {
+               memcpy(&new_var, &fbi->var, sizeof(new_var));
+               new_var.xoffset = var->xoffset;
+               new_var.yoffset = var->yoffset;
+               if (set_fb_var(fbi, &new_var))
+                       r = -EINVAL;
+               else {
+                       memcpy(&fbi->var, &new_var, sizeof(new_var));
+                       ctrl_change_mode(fbi);
+               }
+       }
+
+       return r;
+}
+
+/* Set mirror to vertical axis and switch to the new mode. */
+static int omapfb_mirror(struct fb_info *fbi, int mirror)
+{
+       struct omapfb_plane_struct *plane = fbi->par;
+       int r = 0;
+
+       mirror = mirror ? 1 : 0;
+       if (cpu_is_omap15xx())
+               r = -EINVAL;
+       else if (mirror != plane->info.mirror) {
+               plane->info.mirror = mirror;
+               r = ctrl_change_mode(fbi);
+       }
+
+       return r;
+}
+
+/* Check values in var, try to adjust them in case of out of bound values if
+ * possible, or return error.
+ */
+static int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi)
+{
+       return set_fb_var(fbi, var);
+}
+
+/* Switch to a new mode. The parameters for it has been check already by
+ * omapfb_check_var.
+ */
+static int omapfb_set_par(struct fb_info *fbi)
+{
+       set_fb_fix(fbi);
+       return ctrl_change_mode(fbi);
+}
+
+int omapfb_update_window_async(struct fb_info *fbi,
+                               struct omapfb_update_window *win,
+                               void (*callback)(void *),
+                               void *callback_data)
+{
+       struct omapfb_plane_struct *plane;
+       struct omapfb_device *fbdev;
+       struct fb_var_screeninfo *var;
+
+       if (!fbi)
+               return -EINVAL;
+
+       plane = fbi->par;
+       fbdev = plane->fbdev;
+       var = &fbi->var;
+
+       if (win->x >= var->xres || win->y >= var->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;
+       if (!win->width || !win->height)
+               return 0;
+
+       return fbdev->ctrl->update_window(fbi, win, callback, callback_data);
+}
+EXPORT_SYMBOL(omapfb_update_window_async);
+
+static int omapfb_update_win(struct fb_info *fbi,
+                               struct omapfb_update_window *win)
+{
+       struct omapfb_plane_struct *plane = fbi->par;
+       int ret;
+
+       omapfb_rqueue_lock(plane->fbdev);
+       ret = omapfb_update_window_async(fbi, win, NULL, 0);
+       omapfb_rqueue_unlock(plane->fbdev);
+
+       return ret;
+}
+
+static int omapfb_update_full_screen(struct fb_info *fbi)
+{
+       struct omapfb_plane_struct *plane = fbi->par;
+       struct omapfb_device *fbdev = plane->fbdev;
+       struct omapfb_update_window win;
+       int r;
+
+       if (!fbdev->ctrl->update_window ||
+           fbdev->ctrl->get_update_mode() != OMAPFB_MANUAL_UPDATE)
+               return -ENODEV;
+
+       win.x = 0;
+       win.y = 0;
+       win.width = fbi->var.xres;
+       win.height = fbi->var.yres;
+       win.format = 0;
+
+       omapfb_rqueue_lock(fbdev);
+       r = fbdev->ctrl->update_window(fbi, &win, NULL, 0);
+       omapfb_rqueue_unlock(fbdev);
+
+       return r;
+}
+
+static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
+{
+       struct omapfb_plane_struct *plane = fbi->par;
+       struct omapfb_device *fbdev = plane->fbdev;
+       struct lcd_panel *panel = fbdev->panel;
+       int r;
+
+       if (pi->pos_x + pi->out_width > panel->x_res ||
+           pi->pos_y + pi->out_height > panel->y_res)
+               return -EINVAL;
+
+       plane->info = *pi;
+       r = ctrl_change_mode(fbi);
+       if (r < 0)
+               return r;
+       return fbdev->ctrl->enable_plane(plane->idx, pi->enabled);
+}
+
+static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
+{
+       struct omapfb_plane_struct *plane = fbi->par;
+
+       *pi = plane->info;
+       return 0;
+}
+
+static int omapfb_set_color_key(struct omapfb_device *fbdev,
+                               struct omapfb_color_key *ck)
+{
+       int r;
+
+       if (!fbdev->ctrl->set_color_key)
+               return -ENODEV;
+
+       omapfb_rqueue_lock(fbdev);
+       r = fbdev->ctrl->set_color_key(ck);
+       omapfb_rqueue_unlock(fbdev);
+
+       return r;
+}
+
+static int omapfb_get_color_key(struct omapfb_device *fbdev,
+                               struct omapfb_color_key *ck)
+{
+       int r;
+
+       if (!fbdev->ctrl->get_color_key)
+               return -ENODEV;
+
+       omapfb_rqueue_lock(fbdev);
+       r = fbdev->ctrl->get_color_key(ck);
+       omapfb_rqueue_unlock(fbdev);
+
+       return r;
+}
+
+static struct blocking_notifier_head omapfb_client_list[OMAPFB_PLANE_NUM];
+static int notifier_inited;
+
+static void omapfb_init_notifier(void)
+{
+       int i;
+
+       for (i = 0; i < OMAPFB_PLANE_NUM; i++)
+               BLOCKING_INIT_NOTIFIER_HEAD(&omapfb_client_list[i]);
+}
+
+int omapfb_register_client(struct omapfb_notifier_block *omapfb_nb,
+                           omapfb_notifier_callback_t callback,
+                           void *callback_data)
+{
+       int r;
+
+       if ((unsigned)omapfb_nb->plane_idx > OMAPFB_PLANE_NUM)
+               return -EINVAL;
+
+       if (!notifier_inited) {
+               omapfb_init_notifier();
+               notifier_inited = 1;
+       }
+
+       omapfb_nb->nb.notifier_call = (int (*)(struct notifier_block *,
+                                       unsigned long, void *))callback;
+       omapfb_nb->data = callback_data;
+       r = blocking_notifier_chain_register(
+                               &omapfb_client_list[omapfb_nb->plane_idx],
+                               &omapfb_nb->nb);
+       if (r)
+               return r;
+       if (omapfb_dev != NULL &&
+           omapfb_dev->ctrl && omapfb_dev->ctrl->bind_client) {
+               omapfb_dev->ctrl->bind_client(omapfb_nb);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(omapfb_register_client);
+
+int omapfb_unregister_client(struct omapfb_notifier_block *omapfb_nb)
+{
+       return blocking_notifier_chain_unregister(
+               &omapfb_client_list[omapfb_nb->plane_idx], &omapfb_nb->nb);
+}
+EXPORT_SYMBOL(omapfb_unregister_client);
+
+void omapfb_notify_clients(struct omapfb_device *fbdev, unsigned long event)
+{
+       int i;
+
+       if (!notifier_inited)
+               /* no client registered yet */
+               return;
+
+       for (i = 0; i < OMAPFB_PLANE_NUM; i++)
+               blocking_notifier_call_chain(&omapfb_client_list[i], event,
+                                   fbdev->fb_info[i]);
+}
+EXPORT_SYMBOL(omapfb_notify_clients);
+
+static int omapfb_set_update_mode(struct omapfb_device *fbdev,
+                                  enum omapfb_update_mode mode)
+{
+       int r;
+
+       omapfb_rqueue_lock(fbdev);
+       r = fbdev->ctrl->set_update_mode(mode);
+       omapfb_rqueue_unlock(fbdev);
+
+       return r;
+}
+
+static enum omapfb_update_mode omapfb_get_update_mode(struct omapfb_device *fbdev)
+{
+       int r;
+
+       omapfb_rqueue_lock(fbdev);
+       r = fbdev->ctrl->get_update_mode();
+       omapfb_rqueue_unlock(fbdev);
+
+       return r;
+}
+
+static unsigned long omapfb_get_caps(struct omapfb_device *fbdev)
+{
+       unsigned long caps;
+
+       caps = 0;
+       caps |= fbdev->panel->get_caps(fbdev->panel);
+       caps |= fbdev->ctrl->get_caps();
+       return caps;
+}
+
+/* For lcd testing */
+void omapfb_write_first_pixel(struct omapfb_device *fbdev, u16 pixval)
+{
+       omapfb_rqueue_lock(fbdev);
+       *(u16 *)fbdev->mem_desc.region[0].vaddr = pixval;
+       if (fbdev->ctrl->get_update_mode() == OMAPFB_MANUAL_UPDATE) {
+               struct omapfb_update_window win;
+
+               win.x = 0;
+               win.y = 0;
+               win.width = 1;
+               win.height = 1;
+               win.format = 0;
+               fbdev->ctrl->update_window(fbdev->fb_info[0], &win, NULL, 0);
+       }
+       omapfb_rqueue_unlock(fbdev);
+}
+EXPORT_SYMBOL(omapfb_write_first_pixel);
+
+/* Ioctl interface. Part of the kernel mode frame buffer API is duplicated
+ * here to be accessible by user mode code.
+ */
+static int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd,
+                       unsigned long arg)
+{
+       struct omapfb_plane_struct *plane = fbi->par;
+       struct omapfb_device    *fbdev = plane->fbdev;
+       struct fb_ops           *ops = fbi->fbops;
+       union {
+               struct omapfb_update_window     update_window;
+               struct omapfb_plane_info        plane_info;
+               struct omapfb_color_key         color_key;
+               enum omapfb_update_mode         update_mode;
+               unsigned long           caps;
+               unsigned int            mirror;
+               int                     plane_out;
+               int                     enable_plane;
+       } p;
+       int r = 0;
+
+       BUG_ON(!ops);
+       switch (cmd)
+       {
+       case OMAPFB_MIRROR:
+               if (get_user(p.mirror, (int __user *)arg))
+                       r = -EFAULT;
+               else
+                       omapfb_mirror(fbi, p.mirror);
+               break;
+       case OMAPFB_SYNC_GFX:
+               omapfb_sync(fbi);
+               break;
+       case OMAPFB_VSYNC:
+               break;
+       case OMAPFB_SET_UPDATE_MODE:
+               if (get_user(p.update_mode, (int __user *)arg))
+                       r = -EFAULT;
+               else
+                       r = omapfb_set_update_mode(fbdev, p.update_mode);
+               break;
+       case OMAPFB_GET_UPDATE_MODE:
+               p.update_mode = omapfb_get_update_mode(fbdev);
+               if (put_user(p.update_mode,
+                                       (enum omapfb_update_mode __user *)arg))
+                       r = -EFAULT;
+               break;
+       case OMAPFB_UPDATE_WINDOW_OLD:
+               if (copy_from_user(&p.update_window, (void __user *)arg,
+                                  sizeof(struct omapfb_update_window_old)))
+                       r = -EFAULT;
+               else {
+                       p.update_window.format = 0;
+                       r = omapfb_update_win(fbi, &p.update_window);
+               }
+               break;
+       case OMAPFB_UPDATE_WINDOW:
+               if (copy_from_user(&p.update_window, (void __user *)arg,
+                                  sizeof(p.update_window)))
+                       r = -EFAULT;
+               else
+                       r = omapfb_update_win(fbi, &p.update_window);
+               break;
+       case OMAPFB_SETUP_PLANE:
+               if (copy_from_user(&p.plane_info, (void __user *)arg,
+                                  sizeof(p.plane_info)))
+                       r = -EFAULT;
+               else
+                       r = omapfb_setup_plane(fbi, &p.plane_info);
+               break;
+       case OMAPFB_QUERY_PLANE:
+               if ((r = omapfb_query_plane(fbi, &p.plane_info)) < 0)
+                       break;
+               if (copy_to_user((void __user *)arg, &p.plane_info,
+                                  sizeof(p.plane_info)))
+                       r = -EFAULT;
+               break;
+       case OMAPFB_SET_COLOR_KEY:
+               if (copy_from_user(&p.color_key, (void __user *)arg,
+                                  sizeof(p.color_key)))
+                       r = -EFAULT;
+               else
+                       r = omapfb_set_color_key(fbdev, &p.color_key);
+               break;
+       case OMAPFB_GET_COLOR_KEY:
+               if ((r = omapfb_get_color_key(fbdev, &p.color_key)) < 0)
+                       break;
+               if (copy_to_user((void __user *)arg, &p.color_key,
+                                sizeof(p.color_key)))
+                       r = -EFAULT;
+               break;
+       case OMAPFB_LCD_TEST:
+               {
+                       int test_num;
+
+                       if (get_user(test_num, (int __user *)arg)) {
+                               r = -EFAULT;
+                               break;
+                       }
+                       if (!fbdev->panel->run_test) {
+                               r = -EINVAL;
+                               break;
+                       }
+                       r = fbdev->panel->run_test(fbdev->panel, test_num);
+                       break;
+               }
+       case OMAPFB_CTRL_TEST:
+               {
+                       int test_num;
+
+                       if (get_user(test_num, (int __user *)arg)) {
+                               r = -EFAULT;
+                               break;
+                       }
+                       if (!fbdev->ctrl->run_test) {
+                               r = -EINVAL;
+                               break;
+                       }
+                       r = fbdev->ctrl->run_test(test_num);
+                       break;
+               }
+       default:
+               r = -EINVAL;
+       }
+
+       return r;
+}
+
+/* Callback table for the frame buffer framework. Some of these pointers
+ * will be changed according to the current setting of fb_info->accel_flags.
+ */
+static struct fb_ops omapfb_ops = {
+       .owner          = THIS_MODULE,
+       .fb_open        = omapfb_open,
+       .fb_release     = omapfb_release,
+       .fb_setcolreg   = omapfb_setcolreg,
+       .fb_setcmap     = omapfb_setcmap,
+       .fb_fillrect    = cfb_fillrect,
+       .fb_copyarea    = cfb_copyarea,
+       .fb_imageblit   = cfb_imageblit,
+       .fb_blank       = omapfb_blank,
+       .fb_ioctl       = omapfb_ioctl,
+       .fb_check_var   = omapfb_check_var,
+       .fb_set_par     = omapfb_set_par,
+       .fb_rotate      = omapfb_rotate,
+       .fb_pan_display = omapfb_pan_display,
+};
+
+/*
+ * ---------------------------------------------------------------------------
+ * Sysfs interface
+ * ---------------------------------------------------------------------------
+ */
+/* omapfbX sysfs entries */
+static ssize_t omapfb_show_caps_num(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
+
+       return snprintf(buf, PAGE_SIZE, "%#010lx\n", omapfb_get_caps(fbdev));
+}
+
+static ssize_t omapfb_show_caps_text(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
+       int pos = 0;
+       int i;
+       unsigned long caps;
+
+       caps = omapfb_get_caps(fbdev);
+       for (i = 0; i < ARRAY_SIZE(omapfb_caps_table) && pos < PAGE_SIZE; i++) {
+               if (omapfb_caps_table[i].flag & caps) {
+                       pos += snprintf(&buf[pos], PAGE_SIZE - pos, "%s\n",
+                                       omapfb_caps_table[i].name);
+               }
+       }
+       return min((int)PAGE_SIZE, pos);
+}
+
+static DEVICE_ATTR(caps_num, 0444, omapfb_show_caps_num, NULL);
+static DEVICE_ATTR(caps_text, 0444, omapfb_show_caps_text, NULL);
+
+/* panel sysfs entries */
+static ssize_t omapfb_show_panel_name(struct device *dev,
+                                     struct device_attribute *attr, char *buf)
+{
+       struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
+
+       return snprintf(buf, PAGE_SIZE, "%s\n", fbdev->panel->name);
+}
+
+static ssize_t omapfb_show_bklight_level(struct device *dev,
+                                        struct device_attribute *attr,
+                                        char *buf)
+{
+       struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
+       int r;
+
+       if (fbdev->panel->get_bklight_level) {
+               r = snprintf(buf, PAGE_SIZE, "%d\n",
+                            fbdev->panel->get_bklight_level(fbdev->panel));
+       } else
+               r = -ENODEV;
+       return r;
+}
+
+static ssize_t omapfb_store_bklight_level(struct device *dev,
+                                         struct device_attribute *attr,
+                                         const char *buf, size_t size)
+{
+       struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
+       int r;
+
+       if (fbdev->panel->set_bklight_level) {
+               unsigned int level;
+
+               if (sscanf(buf, "%10d", &level) == 1) {
+                       r = fbdev->panel->set_bklight_level(fbdev->panel, level);
+               } else
+                       r = -EINVAL;
+       } else
+               r = -ENODEV;
+       return r ? r : size;
+}
+
+static ssize_t omapfb_show_bklight_max(struct device *dev,
+                                      struct device_attribute *attr, char *buf)
+{
+       struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
+       int r;
+
+       if (fbdev->panel->get_bklight_level) {
+               r = snprintf(buf, PAGE_SIZE, "%d\n",
+                            fbdev->panel->get_bklight_max(fbdev->panel));
+       } else
+               r = -ENODEV;
+       return r;
+}
+
+static struct device_attribute dev_attr_panel_name =
+       __ATTR(name, 0444, omapfb_show_panel_name, NULL);
+static DEVICE_ATTR(backlight_level, 0664,
+                  omapfb_show_bklight_level, omapfb_store_bklight_level);
+static DEVICE_ATTR(backlight_max, 0444, omapfb_show_bklight_max, NULL);
+
+static struct attribute *panel_attrs[] = {
+       &dev_attr_panel_name.attr,
+       &dev_attr_backlight_level.attr,
+       &dev_attr_backlight_max.attr,
+       NULL,
+};
+
+static struct attribute_group panel_attr_grp = {
+       .name  = "panel",
+       .attrs = panel_attrs,
+};
+
+/* ctrl sysfs entries */
+static ssize_t omapfb_show_ctrl_name(struct device *dev,
+                                    struct device_attribute *attr, char *buf)
+{
+       struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
+
+       return snprintf(buf, PAGE_SIZE, "%s\n", fbdev->ctrl->name);
+}
+
+static struct device_attribute dev_attr_ctrl_name =
+       __ATTR(name, 0444, omapfb_show_ctrl_name, NULL);
+
+static struct attribute *ctrl_attrs[] = {
+       &dev_attr_ctrl_name.attr,
+       NULL,
+};
+
+static struct attribute_group ctrl_attr_grp = {
+       .name  = "ctrl",
+       .attrs = ctrl_attrs,
+};
+
+static int omapfb_register_sysfs(struct omapfb_device *fbdev)
+{
+       int r;
+
+       if ((r = device_create_file(fbdev->dev, &dev_attr_caps_num)))
+               goto fail0;
+
+       if ((r = device_create_file(fbdev->dev, &dev_attr_caps_text)))
+               goto fail1;
+
+       if ((r = sysfs_create_group(&fbdev->dev->kobj, &panel_attr_grp)))
+               goto fail2;
+
+       if ((r = sysfs_create_group(&fbdev->dev->kobj, &ctrl_attr_grp)))
+               goto fail3;
+
+       return 0;
+fail3:
+       sysfs_remove_group(&fbdev->dev->kobj, &panel_attr_grp);
+fail2:
+       device_remove_file(fbdev->dev, &dev_attr_caps_text);
+fail1:
+       device_remove_file(fbdev->dev, &dev_attr_caps_num);
+fail0:
+       dev_err(fbdev->dev, "unable to register sysfs interface\n");
+       return r;
+}
+
+static void omapfb_unregister_sysfs(struct omapfb_device *fbdev)
+{
+       sysfs_remove_group(&fbdev->dev->kobj, &ctrl_attr_grp);
+       sysfs_remove_group(&fbdev->dev->kobj, &panel_attr_grp);
+       device_remove_file(fbdev->dev, &dev_attr_caps_num);
+       device_remove_file(fbdev->dev, &dev_attr_caps_text);
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ * LDM callbacks
+ * ---------------------------------------------------------------------------
+ */
+/* Initialize system fb_info object and set the default video mode.
+ * The frame buffer memory already allocated by lcddma_init
+ */
+static int fbinfo_init(struct omapfb_device *fbdev, struct fb_info *info,
+                       struct omapfb_mem_region *region)
+{
+       struct fb_var_screeninfo        *var = &info->var;
+       struct fb_fix_screeninfo        *fix = &info->fix;
+       int                             r = 0;
+
+       info->fbops = &omapfb_ops;
+       info->flags = FBINFO_FLAG_DEFAULT;
+
+       strncpy(fix->id, MODULE_NAME, sizeof(fix->id));
+
+       info->screen_base       = (char __iomem *)region->vaddr;
+       fix->smem_start         = region->paddr;
+       fix->smem_len           = region->size;
+
+       info->pseudo_palette = fbdev->pseudo_palette;
+
+       var->accel_flags  = def_accel ? FB_ACCELF_TEXT : 0;
+       var->xres = def_vxres;
+       var->yres = def_vyres;
+       var->xres_virtual = def_vxres;
+       var->yres_virtual = def_vyres;
+       var->rotate       = def_rotate;
+       var->bits_per_pixel = fbdev->panel->bpp;
+
+       set_fb_var(info, var);
+       set_fb_fix(info);
+
+       r = fb_alloc_cmap(&info->cmap, 16, 0);
+       if (r != 0)
+               dev_err(fbdev->dev, "unable to allocate color map memory\n");
+
+       return r;
+}
+
+/* Release the fb_info object */
+static void fbinfo_cleanup(struct omapfb_device *fbdev, struct fb_info *fbi)
+{
+       fb_dealloc_cmap(&fbi->cmap);
+}
+
+static void planes_cleanup(struct omapfb_device *fbdev)
+{
+       int i;
+
+       for (i = 0; i < fbdev->mem_desc.region_cnt; i++) {
+               if (fbdev->fb_info[i] == NULL)
+                       break;
+               fbinfo_cleanup(fbdev, fbdev->fb_info[i]);
+               framebuffer_release(fbdev->fb_info[i]);
+       }
+}
+
+static int planes_init(struct omapfb_device *fbdev)
+{
+       struct fb_info *fbi;
+       int i;
+       int r;
+
+       for (i = 0; i < fbdev->mem_desc.region_cnt; i++) {
+               struct omapfb_plane_struct *plane;
+               fbi = framebuffer_alloc(sizeof(struct omapfb_plane_struct),
+                                       fbdev->dev);
+               if (fbi == NULL) {
+                       dev_err(fbdev->dev,
+                               "unable to allocate memory for plane info\n");
+                       planes_cleanup(fbdev);
+                       return -ENOMEM;
+               }
+               plane = fbi->par;
+               plane->idx = i;
+               plane->fbdev = fbdev;
+               plane->info.mirror = def_mirror;
+               fbdev->fb_info[i] = fbi;
+
+               if ((r = fbinfo_init(fbdev, fbi,
+                                       &fbdev->mem_desc.region[i])) < 0) {
+                       framebuffer_release(fbi);
+                       planes_cleanup(fbdev);
+                       return r;
+               }
+               plane->info.out_width = fbi->var.xres;
+               plane->info.out_height = fbi->var.yres;
+       }
+       return 0;
+}
+
+/* Free driver resources. Can be called to rollback an aborted initialization
+ * sequence.
+ */
+static void omapfb_free_resources(struct omapfb_device *fbdev, int state)
+{
+       int i;
+
+       switch (state) {
+       case OMAPFB_ACTIVE:
+               for (i = 0; i < fbdev->mem_desc.region_cnt; i++)
+                       unregister_framebuffer(fbdev->fb_info[i]);
+       case 7:
+               omapfb_unregister_sysfs(fbdev);
+       case 6:
+               fbdev->panel->disable(fbdev->panel);
+       case 5:
+               omapfb_set_update_mode(fbdev, OMAPFB_UPDATE_DISABLED);
+       case 4:
+               planes_cleanup(fbdev);
+       case 3:
+               ctrl_cleanup(fbdev);
+       case 2:
+               fbdev->panel->cleanup(fbdev->panel);
+       case 1:
+               dev_set_drvdata(fbdev->dev, NULL);
+               kfree(fbdev);
+       case 0:
+               /* nothing to free */
+               break;
+       default:
+               BUG();
+       }
+}
+
+static int omapfb_find_ctrl(struct omapfb_device *fbdev)
+{
+       struct omapfb_platform_data *conf;
+       char name[17];
+       int i;
+
+       conf = fbdev->dev->platform_data;
+
+       fbdev->ctrl = NULL;
+
+       strncpy(name, conf->lcd.ctrl_name, sizeof(name) - 1);
+       name[sizeof(name) - 1] = '\0';
+
+       if (strcmp(name, "internal") == 0) {
+               fbdev->ctrl = fbdev->int_ctrl;
+               return 0;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(ctrls); i++) {
+               dev_dbg(fbdev->dev, "ctrl %s\n", ctrls[i]->name);
+               if (strcmp(ctrls[i]->name, name) == 0) {
+                       fbdev->ctrl = ctrls[i];
+                       break;
+               }
+       }
+
+       if (fbdev->ctrl == NULL) {
+               dev_dbg(fbdev->dev, "ctrl %s not supported\n", name);
+               return -1;
+       }
+
+       return 0;
+}
+
+static void check_required_callbacks(struct omapfb_device *fbdev)
+{
+#define _C(x) (fbdev->ctrl->x != NULL)
+#define _P(x) (fbdev->panel->x != NULL)
+       BUG_ON(fbdev->ctrl == NULL || fbdev->panel == NULL);
+       BUG_ON(!(_C(init) && _C(cleanup) && _C(get_caps) &&
+                _C(set_update_mode) && _C(setup_plane) && _C(enable_plane) &&
+                _P(init) && _P(cleanup) && _P(enable) && _P(disable) &&
+                _P(get_caps)));
+#undef _P
+#undef _C
+}
+
+/* Called by LDM binding to probe and attach a new device.
+ * Initialization sequence:
+ *   1. allocate system omapfb_device structure
+ *   2. select controller type according to platform configuration
+ *      init LCD panel
+ *   3. init LCD controller and LCD DMA
+ *   4. init system fb_info structure for all planes
+ *   5. setup video mode for first plane and enable it
+ *   6. enable LCD panel
+ *   7. register sysfs attributes
+ *   OMAPFB_ACTIVE: register system fb_info structure for all planes
+ */
+static int omapfb_do_probe(struct platform_device *pdev, struct lcd_panel *panel)
+{
+       struct omapfb_device    *fbdev = NULL;
+       int                     init_state;
+       unsigned long           phz, hhz, vhz;
+       unsigned long           vram;
+       int                     i;
+       int                     r = 0;
+
+       init_state = 0;
+
+       if (pdev->num_resources != 0) {
+               dev_err(&pdev->dev, "probed for an unknown device\n");
+               r = -ENODEV;
+               goto cleanup;
+       }
+
+       if (pdev->dev.platform_data == NULL) {
+               dev_err(&pdev->dev, "missing platform data\n");
+               r = -ENOENT;
+               goto cleanup;
+       }
+
+       fbdev = kzalloc(sizeof(struct omapfb_device), GFP_KERNEL);
+       if (fbdev == NULL) {
+               dev_err(&pdev->dev,
+                       "unable to allocate memory for device info\n");
+               r = -ENOMEM;
+               goto cleanup;
+       }
+       init_state++;
+
+       fbdev->dev = &pdev->dev;
+       fbdev->panel = panel;
+       platform_set_drvdata(pdev, fbdev);
+
+       mutex_init(&fbdev->rqueue_mutex);
+
+#ifdef CONFIG_ARCH_OMAP1
+       fbdev->int_ctrl = &omap1_int_ctrl;
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+       fbdev->ext_if = &omap1_ext_if;
+#endif
+#else  /* OMAP2 */
+       fbdev->int_ctrl = &omap2_int_ctrl;
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+       fbdev->ext_if = &omap2_ext_if;
+#endif
+#endif
+       if (omapfb_find_ctrl(fbdev) < 0) {
+               dev_err(fbdev->dev,
+                       "LCD controller not found, board not supported\n");
+               r = -ENODEV;
+               goto cleanup;
+       }
+
+       r = fbdev->panel->init(fbdev->panel, fbdev);
+       if (r)
+               goto cleanup;
+
+       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;
+
+       init_state++;
+
+       r = ctrl_init(fbdev);
+       if (r)
+               goto cleanup;
+       init_state++;
+
+       check_required_callbacks(fbdev);
+
+       r = planes_init(fbdev);
+       if (r)
+               goto cleanup;
+       init_state++;
+
+#ifdef CONFIG_FB_OMAP_DMA_TUNE
+       /* Set DMA priority for EMIFF access to highest */
+       if (cpu_class_is_omap1())
+               omap_set_dma_priority(0, OMAP_DMA_PORT_EMIFF, 15);
+#endif
+
+       r = ctrl_change_mode(fbdev->fb_info[0]);
+       if (r) {
+               dev_err(fbdev->dev, "mode setting failed\n");
+               goto cleanup;
+       }
+
+       /* GFX plane is enabled by default */
+       r = fbdev->ctrl->enable_plane(OMAPFB_PLANE_GFX, 1);
+       if (r)
+               goto cleanup;
+
+       omapfb_set_update_mode(fbdev, manual_update ?
+                                  OMAPFB_MANUAL_UPDATE : OMAPFB_AUTO_UPDATE);
+       init_state++;
+
+       r = fbdev->panel->enable(fbdev->panel);
+       if (r)
+               goto cleanup;
+       init_state++;
+
+       r = omapfb_register_sysfs(fbdev);
+       if (r)
+               goto cleanup;
+       init_state++;
+
+       vram = 0;
+       for (i = 0; i < fbdev->mem_desc.region_cnt; i++) {
+               r = register_framebuffer(fbdev->fb_info[i]);
+               if (r != 0) {
+                       dev_err(fbdev->dev,
+                               "registering framebuffer %d failed\n", i);
+                       goto cleanup;
+               }
+               vram += fbdev->mem_desc.region[i].size;
+       }
+
+       fbdev->state = OMAPFB_ACTIVE;
+
+       panel = fbdev->panel;
+       phz = panel->pixel_clock * 1000;
+       hhz = phz * 10 / (panel->hfp + panel->x_res + panel->hbp + panel->hsw);
+       vhz = hhz / (panel->vfp + panel->y_res + panel->vbp + panel->vsw);
+
+       omapfb_dev = fbdev;
+
+       pr_info("omapfb: Framebuffer initialized. Total vram %lu planes %d\n",
+                       vram, fbdev->mem_desc.region_cnt);
+       pr_info("omapfb: Pixclock %lu kHz hfreq %lu.%lu kHz "
+                       "vfreq %lu.%lu Hz\n",
+                       phz / 1000, hhz / 10000, hhz % 10, vhz / 10, vhz % 10);
+
+       return 0;
+
+cleanup:
+       omapfb_free_resources(fbdev, init_state);
+
+       return r;
+}
+
+static int omapfb_probe(struct platform_device *pdev)
+{
+       BUG_ON(fbdev_pdev != NULL);
+
+       /* Delay actual initialization until the LCD is registered */
+       fbdev_pdev = pdev;
+       if (fbdev_panel != NULL)
+               omapfb_do_probe(fbdev_pdev, fbdev_panel);
+       return 0;
+}
+
+void omapfb_register_panel(struct lcd_panel *panel)
+{
+       BUG_ON(fbdev_panel != NULL);
+
+       fbdev_panel = panel;
+       if (fbdev_pdev != NULL)
+               omapfb_do_probe(fbdev_pdev, fbdev_panel);
+}
+
+/* Called when the device is being detached from the driver */
+static int omapfb_remove(struct platform_device *pdev)
+{
+       struct omapfb_device *fbdev = platform_get_drvdata(pdev);
+       enum omapfb_state saved_state = fbdev->state;
+
+       /* FIXME: wait till completion of pending events */
+
+       fbdev->state = OMAPFB_DISABLED;
+       omapfb_free_resources(fbdev, saved_state);
+
+       return 0;
+}
+
+/* PM suspend */
+static int omapfb_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+       struct omapfb_device *fbdev = platform_get_drvdata(pdev);
+
+       omapfb_blank(VESA_POWERDOWN, fbdev->fb_info[0]);
+
+       return 0;
+}
+
+/* PM resume */
+static int omapfb_resume(struct platform_device *pdev)
+{
+       struct omapfb_device *fbdev = platform_get_drvdata(pdev);
+
+       omapfb_blank(VESA_NO_BLANKING, fbdev->fb_info[0]);
+       return 0;
+}
+
+static struct platform_driver omapfb_driver = {
+       .probe          = omapfb_probe,
+       .remove         = omapfb_remove,
+       .suspend        = omapfb_suspend,
+       .resume         = omapfb_resume,
+       .driver         = {
+               .name   = MODULE_NAME,
+               .owner  = THIS_MODULE,
+       },
+};
+
+#ifndef MODULE
+
+/* Process kernel command line parameters */
+static int __init omapfb_setup(char *options)
+{
+       char *this_opt = NULL;
+       int r = 0;
+
+       pr_debug("omapfb: options %s\n", options);
+
+       if (!options || !*options)
+               return 0;
+
+       while (!r && (this_opt = strsep(&options, ",")) != NULL) {
+               if (!strncmp(this_opt, "accel", 5))
+                       def_accel = 1;
+               else if (!strncmp(this_opt, "vram:", 5)) {
+                       char *suffix;
+                       unsigned long vram;
+                       vram = (simple_strtoul(this_opt + 5, &suffix, 0));
+                       switch (suffix[0]) {
+                       case '\0':
+                               break;
+                       case 'm':
+                       case 'M':
+                               vram *= 1024;
+                               /* Fall through */
+                       case 'k':
+                       case 'K':
+                               vram *= 1024;
+                               break;
+                       default:
+                               pr_debug("omapfb: invalid vram suffix %c\n",
+                                        suffix[0]);
+                               r = -1;
+                       }
+                       def_vram[def_vram_cnt++] = vram;
+               }
+               else if (!strncmp(this_opt, "vxres:", 6))
+                       def_vxres = simple_strtoul(this_opt + 6, NULL, 0);
+               else if (!strncmp(this_opt, "vyres:", 6))
+                       def_vyres = simple_strtoul(this_opt + 6, NULL, 0);
+               else if (!strncmp(this_opt, "rotate:", 7))
+                       def_rotate = (simple_strtoul(this_opt + 7, NULL, 0));
+               else if (!strncmp(this_opt, "mirror:", 7))
+                       def_mirror = (simple_strtoul(this_opt + 7, NULL, 0));
+               else if (!strncmp(this_opt, "manual_update", 13))
+                       manual_update = 1;
+               else {
+                       pr_debug("omapfb: invalid option\n");
+                       r = -1;
+               }
+       }
+
+       return r;
+}
+
+#endif
+
+/* Register both the driver and the device */
+static int __init omapfb_init(void)
+{
+#ifndef MODULE
+       char *option;
+
+       if (fb_get_options("omapfb", &option))
+               return -ENODEV;
+       omapfb_setup(option);
+#endif
+       /* Register the driver with LDM */
+       if (platform_driver_register(&omapfb_driver)) {
+               pr_debug("failed to register omapfb driver\n");
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static void __exit omapfb_cleanup(void)
+{
+       platform_driver_unregister(&omapfb_driver);
+}
+
+module_param_named(accel, def_accel, uint, 0664);
+module_param_array_named(vram, def_vram, ulong, &def_vram_cnt, 0664);
+module_param_named(vxres, def_vxres, long, 0664);
+module_param_named(vyres, def_vyres, long, 0664);
+module_param_named(rotate, def_rotate, uint, 0664);
+module_param_named(mirror, def_mirror, uint, 0664);
+module_param_named(manual_update, manual_update, bool, 0664);
+
+module_init(omapfb_init);
+module_exit(omapfb_cleanup);
+
+MODULE_DESCRIPTION("TI OMAP framebuffer driver");
+MODULE_AUTHOR("Imre Deak <imre.deak@nokia.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/omap/rfbi.c b/drivers/video/omap/rfbi.c
new file mode 100644 (file)
index 0000000..ebb3176
--- /dev/null
@@ -0,0 +1,456 @@
+/*
+ * File: drivers/video/omap/omap2/rfbi.c
+ *
+ * OMAP2 Remote Frame Buffer Interface support
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ * Author: Juha Yrjölä <juha.yrjola@nokia.com>
+ *        Imre Deak <imre.deak@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+
+#include <asm/arch/omapfb.h>
+
+#include "dispc.h"
+
+#define RFBI_BASE              0x48050800
+#define RFBI_REVISION          0x0000
+#define RFBI_SYSCONFIG         0x0010
+#define RFBI_SYSSTATUS         0x0014
+#define RFBI_CONTROL           0x0040
+#define RFBI_PIXEL_CNT         0x0044
+#define RFBI_LINE_NUMBER       0x0048
+#define RFBI_CMD               0x004c
+#define RFBI_PARAM             0x0050
+#define RFBI_DATA              0x0054
+#define RFBI_READ              0x0058
+#define RFBI_STATUS            0x005c
+#define RFBI_CONFIG0           0x0060
+#define RFBI_ONOFF_TIME0       0x0064
+#define RFBI_CYCLE_TIME0       0x0068
+#define RFBI_DATA_CYCLE1_0     0x006c
+#define RFBI_DATA_CYCLE2_0     0x0070
+#define RFBI_DATA_CYCLE3_0     0x0074
+#define RFBI_VSYNC_WIDTH       0x0090
+#define RFBI_HSYNC_WIDTH       0x0094
+
+#define DISPC_BASE             0x48050400
+#define DISPC_CONTROL          0x0040
+
+static struct {
+       u32             base;
+       void            (*lcdc_callback)(void *data);
+       void            *lcdc_callback_data;
+       unsigned long   l4_khz;
+       int             bits_per_cycle;
+       struct omapfb_device *fbdev;
+       struct clk      *dss_ick;
+       struct clk      *dss1_fck;
+} rfbi;
+
+static inline void rfbi_write_reg(int idx, u32 val)
+{
+       __raw_writel(val, rfbi.base + idx);
+}
+
+static inline u32 rfbi_read_reg(int idx)
+{
+       return __raw_readl(rfbi.base + idx);
+}
+
+static int rfbi_get_clocks(void)
+{
+       if (IS_ERR((rfbi.dss_ick = clk_get(rfbi.fbdev->dev, "dss_ick")))) {
+               dev_err(rfbi.fbdev->dev, "can't get dss_ick");
+               return PTR_ERR(rfbi.dss_ick);
+       }
+
+       if (IS_ERR((rfbi.dss1_fck = clk_get(rfbi.fbdev->dev, "dss1_fck")))) {
+               dev_err(rfbi.fbdev->dev, "can't get dss1_fck");
+               clk_put(rfbi.dss_ick);
+               return PTR_ERR(rfbi.dss1_fck);
+       }
+
+       return 0;
+}
+
+static void rfbi_put_clocks(void)
+{
+       clk_put(rfbi.dss1_fck);
+       clk_put(rfbi.dss_ick);
+}
+
+static void rfbi_enable_clocks(int enable)
+{
+       if (enable) {
+               clk_enable(rfbi.dss_ick);
+               clk_enable(rfbi.dss1_fck);
+       } else {
+               clk_disable(rfbi.dss1_fck);
+               clk_disable(rfbi.dss_ick);
+       }
+}
+
+
+#ifdef VERBOSE
+static void rfbi_print_timings(void)
+{
+       u32 l;
+       u32 time;
+
+       l = rfbi_read_reg(RFBI_CONFIG0);
+       time = 1000000000 / rfbi.l4_khz;
+       if (l & (1 << 4))
+               time *= 2;
+
+       dev_dbg(rfbi.fbdev->dev, "Tick time %u ps\n", time);
+       l = rfbi_read_reg(RFBI_ONOFF_TIME0);
+       dev_dbg(rfbi.fbdev->dev,
+               "CSONTIME %d, CSOFFTIME %d, WEONTIME %d, WEOFFTIME %d, "
+               "REONTIME %d, REOFFTIME %d\n",
+               l & 0x0f, (l >> 4) & 0x3f, (l >> 10) & 0x0f, (l >> 14) & 0x3f,
+               (l >> 20) & 0x0f, (l >> 24) & 0x3f);
+
+       l = rfbi_read_reg(RFBI_CYCLE_TIME0);
+       dev_dbg(rfbi.fbdev->dev,
+               "WECYCLETIME %d, RECYCLETIME %d, CSPULSEWIDTH %d, "
+               "ACCESSTIME %d\n",
+               (l & 0x3f), (l >> 6) & 0x3f, (l >> 12) & 0x3f,
+               (l >> 22) & 0x3f);
+}
+#else
+static void rfbi_print_timings(void) {}
+#endif
+
+static void rfbi_set_timings(const struct extif_timings *t)
+{
+       u32 l;
+
+       BUG_ON(!t->converted);
+
+       rfbi_enable_clocks(1);
+       rfbi_write_reg(RFBI_ONOFF_TIME0, t->tim[0]);
+       rfbi_write_reg(RFBI_CYCLE_TIME0, t->tim[1]);
+
+       l = rfbi_read_reg(RFBI_CONFIG0);
+       l &= ~(1 << 4);
+       l |= (t->tim[2] ? 1 : 0) << 4;
+       rfbi_write_reg(RFBI_CONFIG0, l);
+
+       rfbi_print_timings();
+       rfbi_enable_clocks(0);
+}
+
+static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div)
+{
+       *clk_period = 1000000000 / rfbi.l4_khz;
+       *max_clk_div = 2;
+}
+
+static int ps_to_rfbi_ticks(int time, int div)
+{
+       unsigned long tick_ps;
+       int ret;
+
+       /* Calculate in picosecs to yield more exact results */
+       tick_ps = 1000000000 / (rfbi.l4_khz) * div;
+
+       ret = (time + tick_ps - 1) / tick_ps;
+
+       return ret;
+}
+
+static int rfbi_convert_timings(struct extif_timings *t)
+{
+       u32 l;
+       int reon, reoff, weon, weoff, cson, csoff, cs_pulse;
+       int actim, recyc, wecyc;
+       int div = t->clk_div;
+
+       if (div <= 0 || div > 2)
+               return -1;
+
+       /* Make sure that after conversion it still holds that:
+        * weoff > weon, reoff > reon, recyc >= reoff, wecyc >= weoff,
+        * csoff > cson, csoff >= max(weoff, reoff), actim > reon
+        */
+       weon = ps_to_rfbi_ticks(t->we_on_time, div);
+       weoff = ps_to_rfbi_ticks(t->we_off_time, div);
+       if (weoff <= weon)
+               weoff = weon + 1;
+       if (weon > 0x0f)
+               return -1;
+       if (weoff > 0x3f)
+               return -1;
+
+       reon = ps_to_rfbi_ticks(t->re_on_time, div);
+       reoff = ps_to_rfbi_ticks(t->re_off_time, div);
+       if (reoff <= reon)
+               reoff = reon + 1;
+       if (reon > 0x0f)
+               return -1;
+       if (reoff > 0x3f)
+               return -1;
+
+       cson = ps_to_rfbi_ticks(t->cs_on_time, div);
+       csoff = ps_to_rfbi_ticks(t->cs_off_time, div);
+       if (csoff <= cson)
+               csoff = cson + 1;
+       if (csoff < max(weoff, reoff))
+               csoff = max(weoff, reoff);
+       if (cson > 0x0f)
+               return -1;
+       if (csoff > 0x3f)
+               return -1;
+
+       l =  cson;
+       l |= csoff << 4;
+       l |= weon  << 10;
+       l |= weoff << 14;
+       l |= reon  << 20;
+       l |= reoff << 24;
+
+       t->tim[0] = l;
+
+       actim = ps_to_rfbi_ticks(t->access_time, div);
+       if (actim <= reon)
+               actim = reon + 1;
+       if (actim > 0x3f)
+               return -1;
+
+       wecyc = ps_to_rfbi_ticks(t->we_cycle_time, div);
+       if (wecyc < weoff)
+               wecyc = weoff;
+       if (wecyc > 0x3f)
+               return -1;
+
+       recyc = ps_to_rfbi_ticks(t->re_cycle_time, div);
+       if (recyc < reoff)
+               recyc = reoff;
+       if (recyc > 0x3f)
+               return -1;
+
+       cs_pulse = ps_to_rfbi_ticks(t->cs_pulse_width, div);
+       if (cs_pulse > 0x3f)
+               return -1;
+
+       l =  wecyc;
+       l |= recyc    << 6;
+       l |= cs_pulse << 12;
+       l |= actim    << 22;
+
+       t->tim[1] = l;
+
+       t->tim[2] = div - 1;
+
+       t->converted = 1;
+
+       return 0;
+}
+
+static void rfbi_write_command(const void *buf, unsigned int len)
+{
+       rfbi_enable_clocks(1);
+       if (rfbi.bits_per_cycle == 16) {
+               const u16 *w = buf;
+               BUG_ON(len & 1);
+               for (; len; len -= 2)
+                       rfbi_write_reg(RFBI_CMD, *w++);
+       } else {
+               const u8 *b = buf;
+               BUG_ON(rfbi.bits_per_cycle != 8);
+               for (; len; len--)
+                       rfbi_write_reg(RFBI_CMD, *b++);
+       }
+       rfbi_enable_clocks(0);
+}
+
+static void rfbi_read_data(void *buf, unsigned int len)
+{
+       rfbi_enable_clocks(1);
+       if (rfbi.bits_per_cycle == 16) {
+               u16 *w = buf;
+               BUG_ON(len & ~1);
+               for (; len; len -= 2) {
+                       rfbi_write_reg(RFBI_READ, 0);
+                       *w++ = rfbi_read_reg(RFBI_READ);
+               }
+       } else {
+               u8 *b = buf;
+               BUG_ON(rfbi.bits_per_cycle != 8);
+               for (; len; len--) {
+                       rfbi_write_reg(RFBI_READ, 0);
+                       *b++ = rfbi_read_reg(RFBI_READ);
+               }
+       }
+       rfbi_enable_clocks(0);
+}
+
+static void rfbi_write_data(const void *buf, unsigned int len)
+{
+       rfbi_enable_clocks(1);
+       if (rfbi.bits_per_cycle == 16) {
+               const u16 *w = buf;
+               BUG_ON(len & 1);
+               for (; len; len -= 2)
+                       rfbi_write_reg(RFBI_PARAM, *w++);
+       } else {
+               const u8 *b = buf;
+               BUG_ON(rfbi.bits_per_cycle != 8);
+               for (; len; len--)
+                       rfbi_write_reg(RFBI_PARAM, *b++);
+       }
+       rfbi_enable_clocks(0);
+}
+
+static void rfbi_transfer_area(int width, int height,
+                               void (callback)(void * data), void *data)
+{
+       u32 w;
+
+       BUG_ON(callback == NULL);
+
+       rfbi_enable_clocks(1);
+       omap_dispc_set_lcd_size(width, height);
+
+       rfbi.lcdc_callback = callback;
+       rfbi.lcdc_callback_data = data;
+
+       rfbi_write_reg(RFBI_PIXEL_CNT, width * height);
+
+       w = rfbi_read_reg(RFBI_CONTROL);
+       /* Enable, Internal trigger */
+       rfbi_write_reg(RFBI_CONTROL, w | (1 << 0) | (1 << 4));
+
+       omap_dispc_enable_lcd_out(1);
+}
+
+static inline void _stop_transfer(void)
+{
+       u32 w;
+
+       w = rfbi_read_reg(RFBI_CONTROL);
+       rfbi_write_reg(RFBI_CONTROL, w & ~(1 << 0));
+       rfbi_enable_clocks(0);
+}
+
+static void rfbi_dma_callback(void *data)
+{
+       _stop_transfer();
+       rfbi.lcdc_callback(rfbi.lcdc_callback_data);
+}
+
+static void rfbi_set_bits_per_cycle(int bpc)
+{
+       u32 l;
+
+       rfbi_enable_clocks(1);
+       l = rfbi_read_reg(RFBI_CONFIG0);
+       l &= ~(0x03 << 0);
+       switch (bpc)
+       {
+       case 8:
+               break;
+       case 16:
+               l |= 3;
+               break;
+       default:
+               BUG();
+       }
+       rfbi_write_reg(RFBI_CONFIG0, l);
+       rfbi.bits_per_cycle = bpc;
+       rfbi_enable_clocks(0);
+}
+
+static int rfbi_init(struct omapfb_device *fbdev)
+{
+       u32 l;
+       int r;
+
+       rfbi.fbdev = fbdev;
+       rfbi.base = io_p2v(RFBI_BASE);
+
+       if ((r = rfbi_get_clocks()) < 0)
+               return r;
+       rfbi_enable_clocks(1);
+
+       rfbi.l4_khz = clk_get_rate(rfbi.dss_ick) / 1000;
+
+       /* Reset */
+       rfbi_write_reg(RFBI_SYSCONFIG, 1 << 1);
+       while (!(rfbi_read_reg(RFBI_SYSSTATUS) & (1 << 0)));
+
+       l = rfbi_read_reg(RFBI_SYSCONFIG);
+       /* Enable autoidle and smart-idle */
+       l |= (1 << 0) | (2 << 3);
+       rfbi_write_reg(RFBI_SYSCONFIG, l);
+
+       /* 16-bit interface, ITE trigger mode, 16-bit data */
+       l = (0x03 << 0) | (0x00 << 2) | (0x01 << 5) | (0x02 << 7);
+       l |= (0 << 9) | (1 << 20) | (1 << 21);
+       rfbi_write_reg(RFBI_CONFIG0, l);
+
+       rfbi_write_reg(RFBI_DATA_CYCLE1_0, 0x00000010);
+
+       l = rfbi_read_reg(RFBI_CONTROL);
+       /* Select CS0, clear bypass mode */
+       l = (0x01 << 2);
+       rfbi_write_reg(RFBI_CONTROL, l);
+
+       if ((r = omap_dispc_request_irq(rfbi_dma_callback, NULL)) < 0) {
+               dev_err(fbdev->dev, "can't get DISPC irq\n");
+               rfbi_enable_clocks(0);
+               return r;
+       }
+
+       l = rfbi_read_reg(RFBI_REVISION);
+       pr_info("omapfb: RFBI version %d.%d initialized\n",
+               (l >> 4) & 0x0f, l & 0x0f);
+
+       rfbi_enable_clocks(0);
+
+       return 0;
+}
+
+static void rfbi_cleanup(void)
+{
+       omap_dispc_free_irq();
+       rfbi_put_clocks();
+}
+
+const struct lcd_ctrl_extif omap2_ext_if = {
+       .init                   = rfbi_init,
+       .cleanup                = rfbi_cleanup,
+       .get_clk_info           = rfbi_get_clk_info,
+       .set_bits_per_cycle     = rfbi_set_bits_per_cycle,
+       .convert_timings        = rfbi_convert_timings,
+       .set_timings            = rfbi_set_timings,
+       .write_command          = rfbi_write_command,
+       .read_data              = rfbi_read_data,
+       .write_data             = rfbi_write_data,
+       .transfer_area          = rfbi_transfer_area,
+
+       .max_transmit_size      = (u32)~0,
+};
+
diff --git a/drivers/video/omap/sossi.c b/drivers/video/omap/sossi.c
new file mode 100644 (file)
index 0000000..8149de0
--- /dev/null
@@ -0,0 +1,530 @@
+/*
+ * File: drivers/video/omap/omap1/sossi.c
+ *
+ * OMAP1 Special OptimiSed Screen Interface support
+ *
+ * Copyright (C) 2004-2005 Nokia Corporation
+ * Author: Juha Yrjölä <juha.yrjola@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+
+#include <asm/arch/dma.h>
+#include <asm/arch/omapfb.h>
+
+#include "lcdc.h"
+
+#define MODULE_NAME            "omapfb-sossi"
+
+#define OMAP_SOSSI_BASE         0xfffbac00
+#define SOSSI_ID_REG           0x00
+#define SOSSI_INIT1_REG                0x04
+#define SOSSI_INIT2_REG                0x08
+#define SOSSI_INIT3_REG                0x0c
+#define SOSSI_FIFO_REG         0x10
+#define SOSSI_REOTABLE_REG     0x14
+#define SOSSI_TEARING_REG      0x18
+#define SOSSI_INIT1B_REG       0x1c
+#define SOSSI_FIFOB_REG                0x20
+
+#define DMA_GSCR          0xfffedc04
+#define DMA_LCD_CCR       0xfffee3c2
+#define DMA_LCD_CTRL      0xfffee3c4
+#define DMA_LCD_LCH_CTRL  0xfffee3ea
+
+#define RD_ACCESS              0
+#define WR_ACCESS              1
+
+#define SOSSI_MAX_XMIT_BYTES   (512 * 1024)
+
+static struct {
+       void __iomem    *base;
+       unsigned long   dpll_khz;
+       int             bus_pick_width;
+       void            (*lcdc_callback)(void *data);
+       void            *lcdc_callback_data;
+       /* timing for read and write access */
+       int             clk_div;
+       u8              clk_tw0[2];
+       u8              clk_tw1[2];
+       /* if last_access is the same as current we don't have to change
+        * the timings
+        */
+       int             last_access;
+
+       struct omapfb_device    *fbdev;
+       struct lcd_ctrl_extif   *extif;
+} sossi;
+
+static inline u32 sossi_read_reg(int reg)
+{
+        return readl(sossi.base + reg);
+}
+
+static inline u16 sossi_read_reg16(int reg)
+{
+        return readw(sossi.base + reg);
+}
+
+static inline u8 sossi_read_reg8(int reg)
+{
+        return readb(sossi.base + reg);
+}
+
+static inline void sossi_write_reg(int reg, u32 value)
+{
+        writel(value, sossi.base + reg);
+}
+
+static inline void sossi_write_reg16(int reg, u16 value)
+{
+        writew(value, sossi.base + reg);
+}
+
+static inline void sossi_write_reg8(int reg, u8 value)
+{
+        writeb(value, sossi.base + reg);
+}
+
+static void sossi_set_bits(int reg, u32 bits)
+{
+        sossi_write_reg(reg, sossi_read_reg(reg) | bits);
+}
+
+static void sossi_clear_bits(int reg, u32 bits)
+{
+        sossi_write_reg(reg, sossi_read_reg(reg) & ~bits);
+}
+
+#define MOD_CONF_CTRL_1   0xfffe1110
+#define CONF_SOSSI_RESET_R      (1 << 23)
+#define CONF_MOD_SOSSI_CLK_EN_R (1 << 16)
+
+static void sossi_dma_callback(void *data);
+
+#define KHZ_TO_PS(x)   (1000000000 / (x))
+
+static u32 ps_to_sossi_ticks(u32 ps, int div)
+{
+       u32 clk_period = KHZ_TO_PS(sossi.dpll_khz) * div;
+       return (clk_period + ps - 1) / clk_period;
+}
+
+static int calc_rd_timings(struct extif_timings *t)
+{
+       u32 tw0, tw1;
+       int reon, reoff, recyc, actim;
+       int div = t->clk_div;
+
+       /* Make sure that after conversion it still holds that:
+        * reoff > reon, recyc >= reoff, actim > reon
+        */
+       reon = ps_to_sossi_ticks(t->re_on_time, div);
+       /* reon will be exactly one sossi tick */
+       if (reon > 1)
+               return -1;
+
+       reoff = ps_to_sossi_ticks(t->re_off_time, div);
+
+       if (reoff <= reon)
+               reoff = reon + 1;
+
+       tw0 = reoff - reon;
+       if (tw0 > 0x10)
+               return -1;
+
+       recyc = ps_to_sossi_ticks(t->re_cycle_time, div);
+       if (recyc <= reoff)
+               recyc = reoff + 1;
+
+       tw1 = recyc - tw0;
+       /* values less then 3 result in the SOSSI block resetting itself */
+       if (tw1 < 3)
+               tw1 = 3;
+       if (tw1 > 0x40)
+               return -1;
+
+       actim = ps_to_sossi_ticks(t->access_time, div);
+       if (actim < reoff)
+               actim++;
+       /* access time (data hold time) will be exactly one sossi
+        * tick
+        */
+       if (actim - reoff > 1)
+               return -1;
+
+       t->tim[0] = tw0 - 1;
+       t->tim[1] = tw1 - 1;
+
+       return 0;
+}
+
+static int calc_wr_timings(struct extif_timings *t)
+{
+       u32 tw0, tw1;
+       int weon, weoff, wecyc;
+       int div = t->clk_div;
+
+       /* Make sure that after conversion it still holds that:
+        * weoff > weon, wecyc >= weoff
+        */
+       weon = ps_to_sossi_ticks(t->we_on_time, div);
+       /* weon will be exactly one sossi tick */
+       if (weon > 1)
+               return -1;
+
+       weoff = ps_to_sossi_ticks(t->we_off_time, div);
+       if (weoff <= weon)
+               weoff = weon + 1;
+       tw0 = weoff - weon;
+       if (tw0 > 0x10)
+               return -1;
+
+       wecyc = ps_to_sossi_ticks(t->we_cycle_time, div);
+       if (wecyc <= weoff)
+               wecyc = weoff + 1;
+
+       tw1 = wecyc - tw0;
+       /* values less then 3 result in the SOSSI block resetting itself */
+       if (tw1 < 3)
+               tw1 = 3;
+       if (tw1 > 0x40)
+               return -1;
+
+       t->tim[2] = tw0 - 1;
+       t->tim[3] = tw1 - 1;
+
+       return 0;
+}
+
+static void _set_timing(int div, int tw0, int tw1)
+{
+       u32 l;
+
+#ifdef VERBOSE
+       dev_dbg(sossi.fbdev->dev, "Using TW0 = %d, TW1 = %d, div = %d\n",
+                tw0 + 1, tw1 + 1, div + 1);
+#endif
+
+       l = omap_readl(MOD_CONF_CTRL_1);
+       l &= ~(7 << 17);
+       l |= div << 17;
+       omap_writel(l, MOD_CONF_CTRL_1);
+
+       l = sossi_read_reg(SOSSI_INIT1_REG);
+       l &= ~((0x0f << 20) | (0x3f << 24));
+       l |= (tw0 << 20) | (tw1 << 24);
+       sossi_write_reg(SOSSI_INIT1_REG, l);
+}
+
+static inline void set_timing(int access)
+{
+       if (access != sossi.last_access) {
+               sossi.last_access = access;
+               _set_timing(sossi.clk_div,
+                           sossi.clk_tw0[access], sossi.clk_tw1[access]);
+       }
+}
+
+static void sossi_start_transfer(void)
+{
+       /* WE */
+       sossi_clear_bits(SOSSI_INIT2_REG, 1 << 4);
+       /* CS active low */
+       sossi_clear_bits(SOSSI_INIT1_REG, 1 << 30);
+       /* FIXME: locking? */
+}
+
+static void sossi_stop_transfer(void)
+{
+       /* WE */
+       sossi_set_bits(SOSSI_INIT2_REG, 1 << 4);
+       /* CS active low */
+       sossi_set_bits(SOSSI_INIT1_REG, 1 << 30);
+       /* FIXME: locking? */
+}
+
+static void wait_end_of_write(void)
+{
+       /* Before reading we must check if some writings are going on */
+       while (!(sossi_read_reg(SOSSI_INIT2_REG) & (1 << 3)));
+}
+
+static void send_data(const void *data, unsigned int len)
+{
+       while (len >= 4) {
+               sossi_write_reg(SOSSI_FIFO_REG, *(const u32 *) data);
+               len -= 4;
+               data += 4;
+       }
+       while (len >= 2) {
+               sossi_write_reg16(SOSSI_FIFO_REG, *(const u16 *) data);
+               len -= 2;
+               data += 2;
+       }
+       while (len) {
+               sossi_write_reg8(SOSSI_FIFO_REG, *(const u8 *) data);
+               len--;
+               data++;
+       }
+}
+
+static void set_cycles(unsigned int len)
+{
+       unsigned long nr_cycles = len / (sossi.bus_pick_width / 8);
+
+       BUG_ON((nr_cycles - 1) & ~0x3ffff);
+
+       sossi_clear_bits(SOSSI_INIT1_REG, 0x3ffff);
+       sossi_set_bits(SOSSI_INIT1_REG, (nr_cycles - 1) & 0x3ffff);
+}
+
+static int sossi_convert_timings(struct extif_timings *t)
+{
+       int r = 0;
+       int div = t->clk_div;
+
+       t->converted = 0;
+
+       if (div <= 0 || div > 8)
+               return -1;
+
+       /* no CS on SOSSI, so ignore cson, csoff, cs_pulsewidth */
+       if ((r = calc_rd_timings(t)) < 0)
+               return r;
+
+       if ((r = calc_wr_timings(t)) < 0)
+               return r;
+
+       t->tim[4] = div - 1;
+
+       t->converted = 1;
+
+       return 0;
+}
+
+static void sossi_set_timings(const struct extif_timings *t)
+{
+       BUG_ON(!t->converted);
+
+       sossi.clk_tw0[RD_ACCESS] = t->tim[0];
+       sossi.clk_tw1[RD_ACCESS] = t->tim[1];
+
+       sossi.clk_tw0[WR_ACCESS] = t->tim[2];
+       sossi.clk_tw1[WR_ACCESS] = t->tim[3];
+
+       sossi.clk_div = t->tim[4];
+}
+
+static void sossi_get_clk_info(u32 *clk_period, u32 *max_clk_div)
+{
+       *clk_period = KHZ_TO_PS(sossi.dpll_khz);
+       *max_clk_div = 8;
+}
+
+static void sossi_set_bits_per_cycle(int bpc)
+{
+       u32 l;
+       int bus_pick_count, bus_pick_width;
+
+       /* We set explicitly the the bus_pick_count as well, although
+        * with remapping/reordering disabled it will be calculated by HW
+        * as (32 / bus_pick_width).
+        */
+       switch (bpc) {
+       case 8:
+               bus_pick_count = 4;
+               bus_pick_width = 8;
+               break;
+       case 16:
+               bus_pick_count = 2;
+               bus_pick_width = 16;
+               break;
+       default:
+               BUG();
+               return;
+       }
+       l = sossi_read_reg(SOSSI_INIT3_REG);
+       sossi.bus_pick_width = bus_pick_width;
+       l &= ~0x3ff;
+       l |= ((bus_pick_count - 1) << 5) | ((bus_pick_width - 1) & 0x1f);
+       sossi_write_reg(SOSSI_INIT3_REG, l);
+}
+
+static void sossi_write_command(const void *data, unsigned int len)
+{
+       set_timing(WR_ACCESS);
+       /* CMD#/DATA */
+       sossi_clear_bits(SOSSI_INIT1_REG, 1 << 18);
+       set_cycles(len);
+       sossi_start_transfer();
+       send_data(data, len);
+       sossi_stop_transfer();
+       wait_end_of_write();
+}
+
+static void sossi_write_data(const void *data, unsigned int len)
+{
+       set_timing(WR_ACCESS);
+       /* CMD#/DATA */
+       sossi_set_bits(SOSSI_INIT1_REG, 1 << 18);
+       set_cycles(len);
+       sossi_start_transfer();
+       send_data(data, len);
+       sossi_stop_transfer();
+       wait_end_of_write();
+}
+
+static void sossi_transfer_area(int width, int height,
+                               void (callback)(void *data), void *data)
+{
+       BUG_ON(callback == NULL);
+
+       sossi.lcdc_callback = callback;
+       sossi.lcdc_callback_data = data;
+
+       set_timing(WR_ACCESS);
+       /* CMD#/DATA */
+       sossi_set_bits(SOSSI_INIT1_REG, 1 << 18);
+       set_cycles(width * height * sossi.bus_pick_width / 8);
+
+       sossi_start_transfer();
+       omap_enable_lcd_dma();
+}
+
+static void sossi_dma_callback(void *data)
+{
+       omap_stop_lcd_dma();
+       sossi_stop_transfer();
+       sossi.lcdc_callback(sossi.lcdc_callback_data);
+}
+
+static void sossi_read_data(void *data, unsigned int len)
+{
+       set_timing(RD_ACCESS);
+       /* CMD#/DATA */
+       sossi_set_bits(SOSSI_INIT1_REG, 1 << 18);
+       set_cycles(len);
+       sossi_start_transfer();
+       while (len >= 4) {
+               *(u32 *) data = sossi_read_reg(SOSSI_FIFO_REG);
+               len -= 4;
+               data += 4;
+       }
+       while (len >= 2) {
+               *(u16 *) data = sossi_read_reg16(SOSSI_FIFO_REG);
+               len -= 2;
+               data += 2;
+       }
+       while (len) {
+               *(u8 *) data = sossi_read_reg8(SOSSI_FIFO_REG);
+               len--;
+               data++;
+       }
+       sossi_stop_transfer();
+}
+
+static int sossi_init(struct omapfb_device *fbdev)
+{
+       u32 l, k;
+       struct clk *dpll_clk;
+       int r;
+
+       sossi.fbdev = fbdev;
+
+       sossi.base = (void __iomem *)IO_ADDRESS(OMAP_SOSSI_BASE);
+       dpll_clk = clk_get(fbdev->dev, "ck_dpll1");
+       if (IS_ERR(dpll_clk)) {
+               dev_err(fbdev->dev, "can't get dpll1 clock\n");
+               return PTR_ERR(dpll_clk);
+       }
+
+       sossi.dpll_khz = clk_get_rate(dpll_clk) / 1000;
+       clk_put(dpll_clk);
+
+       /* Reset and enable the SoSSI module */
+       l = omap_readl(MOD_CONF_CTRL_1);
+       l |= CONF_SOSSI_RESET_R;
+       omap_writel(l, MOD_CONF_CTRL_1);
+       l &= ~CONF_SOSSI_RESET_R;
+       omap_writel(l, MOD_CONF_CTRL_1);
+
+       l |= CONF_MOD_SOSSI_CLK_EN_R;
+       omap_writel(l, MOD_CONF_CTRL_1);
+
+       omap_writel(omap_readl(ARM_IDLECT2) | (1 << 11), ARM_IDLECT2);
+       omap_writel(omap_readl(ARM_IDLECT1) | (1 << 6), ARM_IDLECT1);
+
+       l = sossi_read_reg(SOSSI_INIT2_REG);
+       /* Enable and reset the SoSSI block */
+       l |= (1 << 0) | (1 << 1);
+       sossi_write_reg(SOSSI_INIT2_REG, l);
+       /* Take SoSSI out of reset */
+       l &= ~(1 << 1);
+       sossi_write_reg(SOSSI_INIT2_REG, l);
+
+       sossi_write_reg(SOSSI_ID_REG, 0);
+       l = sossi_read_reg(SOSSI_ID_REG);
+       k = sossi_read_reg(SOSSI_ID_REG);
+
+       if (l != 0x55555555 || k != 0xaaaaaaaa) {
+               dev_err(fbdev->dev,
+                       "invalid SoSSI sync pattern: %08x, %08x\n", l, k);
+               return -ENODEV;
+       }
+
+       if ((r = omap_lcdc_set_dma_callback(sossi_dma_callback, NULL)) < 0) {
+               dev_err(fbdev->dev, "can't get LCDC IRQ\n");
+               return r;
+       }
+
+       l = sossi_read_reg(SOSSI_ID_REG); /* Component code */
+       l = sossi_read_reg(SOSSI_ID_REG);
+       pr_info("omapfb: SoSSI version %d.%d initialized\n",
+               l >> 16, l & 0xffff);
+
+       l = sossi_read_reg(SOSSI_INIT1_REG);
+       l |= (1 << 19); /* DMA_MODE */
+       l &= ~(1 << 31); /* REORDERING */
+       sossi_write_reg(SOSSI_INIT1_REG, l);
+
+       return 0;
+}
+
+static void sossi_cleanup(void)
+{
+       omap_lcdc_free_dma_callback();
+}
+
+const struct lcd_ctrl_extif omap1_ext_if = {
+       .init                   = sossi_init,
+       .cleanup                = sossi_cleanup,
+       .get_clk_info           = sossi_get_clk_info,
+       .convert_timings        = sossi_convert_timings,
+       .set_timings            = sossi_set_timings,
+       .set_bits_per_cycle     = sossi_set_bits_per_cycle,
+       .write_command          = sossi_write_command,
+       .read_data              = sossi_read_data,
+       .write_data             = sossi_write_data,
+       .transfer_area          = sossi_transfer_area,
+
+       .max_transmit_size      = SOSSI_MAX_XMIT_BYTES,
+};
+
diff --git a/include/asm-arm/.gitignore b/include/asm-arm/.gitignore
new file mode 100644 (file)
index 0000000..e1bf470
--- /dev/null
@@ -0,0 +1,3 @@
+arch
+asm-offsets.h
+mach-types.h
index 6513065941d0872753ba5ded51dec517f82393de..aec2d65636229a5a49b05e970481eaf2386986db 100644 (file)
 #define TLV320AIC23ID1                  (0x1a) // cs low
 #define TLV320AIC23ID2                  (0x1b) // cs high
 
-void tlv320aic23_power_up(void);
-void tlv320aic23_power_down(void);
+void aic23_power_up(void);
+void aic23_power_down(void);
 
 #endif /* __ASM_ARCH_AIC23_H */
diff --git a/include/asm-arm/arch-omap/blizzard.h b/include/asm-arm/arch-omap/blizzard.h
new file mode 100644 (file)
index 0000000..8d160f1
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef _BLIZZARD_H
+#define _BLIZZARD_H
+
+struct blizzard_platform_data {
+       void            (*power_up)(struct device *dev);
+       void            (*power_down)(struct device *dev);
+       unsigned long   (*get_clock_rate)(struct device *dev);
+
+       unsigned        te_connected : 1;
+};
+
+#endif
diff --git a/include/asm-arm/arch-omap/board-2430sdp.h b/include/asm-arm/arch-omap/board-2430sdp.h
new file mode 100644 (file)
index 0000000..e9c65ce
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * linux/include/asm-arm/arch-omap/board-2430sdp.h
+ *
+ * Hardware definitions for TI OMAP2430 SDP board.
+ *
+ * Based on board-h4.h by Dirk Behme <dirk.behme@de.bosch.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __ASM_ARCH_OMAP_2430SDP_H
+#define __ASM_ARCH_OMAP_2430SDP_H
+
+/* Placeholder for 2430SDP specific defines */
+#define OMAP24XX_ETHR_START             0x08000300
+#define OMAP24XX_ETHR_GPIO_IRQ         149
+#define SDP2430_CS0_BASE               0x04000000
+
+#define TWL4030_IRQNUM                 INT_24XX_SYS_NIRQ
+
+/* TWL4030 Primary Interrupt Handler (PIH) interrupts */
+#define IH_TWL4030_BASE                        IH_BOARD_BASE
+#define IH_TWL4030_END                 (IH_TWL4030_BASE+8)
+#define NR_IRQS                                (IH_TWL4030_END)
+
+#endif /* __ASM_ARCH_OMAP_2430SDP_H */
index de0c5b792c5852aa2190f2cc099e51a8410cc64c..dcb587b311f18fa038b21c38ff0044861a6a9bab 100644 (file)
 #define __ASM_ARCH_OMAP_APOLLON_H
 
 /* Placeholder for APOLLON specific defines */
-/* GPMC CS0 */
-#define APOLLON_CS0_BASE               0x00000000
-/* GPMC CS1 */
-#define APOLLON_CS1_BASE               0x08000000
-#define APOLLON_ETHR_START             (APOLLON_CS1_BASE + 0x300)
 #define APOLLON_ETHR_GPIO_IRQ          74
-/* GPMC CS2 - reserved for OneNAND */
-#define APOLLON_CS2_BASE               0x10000000
-/* GPMC CS3 - reserved for NOR or NAND */
-#define APOLLON_CS3_BASE               0x18000000
 
 #endif /*  __ASM_ARCH_OMAP_APOLLON_H */
 
index 7ef664bc9e330c4b284cdd81042ca38bb670066a..23b5ac6e2822689ff148c4cf722a72475908999c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * linux/include/asm-arm/arch-omap/board-h4.h
  *
- * Hardware definitions for TI OMAP1610 H4 board.
+ * Hardware definitions for TI OMAP2420 H4 board.
  *
  * Initial creation by Dirk Behme <dirk.behme@de.bosch.com>
  *
@@ -30,9 +30,6 @@
 #define __ASM_ARCH_OMAP_H4_H
 
 /* Placeholder for H4 specific defines */
-/* GPMC CS1 */
-#define OMAP24XX_ETHR_START             0x08000300
 #define OMAP24XX_ETHR_GPIO_IRQ         92
-#define H4_CS0_BASE                    0x04000000
 #endif /*  __ASM_ARCH_OMAP_H4_H */
 
diff --git a/include/asm-arm/arch-omap/board-palmte.h b/include/asm-arm/arch-omap/board-palmte.h
new file mode 100644 (file)
index 0000000..cd22035
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * linux/include/asm-arm/arch-omap/board-palmte.h
+ *
+ * Hardware definitions for the Palm Tungsten E device.
+ *
+ * Maintainters :      http://palmtelinux.sf.net
+ *                     palmtelinux-developpers@lists.sf.net
+ *
+ * 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 __OMAP_BOARD_PALMTE_H
+#define __OMAP_BOARD_PALMTE_H
+
+#include <asm/arch/gpio.h>
+
+#define PALMTE_USBDETECT_GPIO  0
+#define PALMTE_USB_OR_DC_GPIO  1
+#define PALMTE_TSC_GPIO                4
+#define PALMTE_PINTDAV_GPIO    6
+#define PALMTE_MMC_WP_GPIO     8
+#define PALMTE_MMC_POWER_GPIO  9
+#define PALMTE_HDQ_GPIO                11
+#define PALMTE_HEADPHONES_GPIO 14
+#define PALMTE_SPEAKER_GPIO    15
+#define PALMTE_DC_GPIO         OMAP_MPUIO(2)
+#define PALMTE_MMC_SWITCH_GPIO OMAP_MPUIO(4)
+#define PALMTE_MMC1_GPIO       OMAP_MPUIO(6)
+#define PALMTE_MMC2_GPIO       OMAP_MPUIO(7)
+#define PALMTE_MMC3_GPIO       OMAP_MPUIO(11)
+
+#endif /* __OMAP_BOARD_PALMTE_H */
diff --git a/include/asm-arm/arch-omap/board-palmtt.h b/include/asm-arm/arch-omap/board-palmtt.h
new file mode 100644 (file)
index 0000000..d9590b0
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * linux/include/asm-arm/arch-omap/board-palmte.h
+ *
+ * Hardware definitions for the Palm Tungsten|T device.
+ *
+ * Maintainters :      Marek Vasut <marek.vasut@gmail.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 __OMAP_BOARD_PALMTT_H
+#define __OMAP_BOARD_PALMTT_H
+
+#define PALMTT_USBDETECT_GPIO  0
+#define PALMTT_CABLE_GPIO      1
+#define PALMTT_LED_GPIO                3
+#define PALMTT_PENIRQ_GPIO     6
+#define PALMTT_MMC_WP_GPIO     8
+#define PALMTT_HDQ_GPIO                11
+
+#endif /* __OMAP_BOARD_PALMTT_H */
diff --git a/include/asm-arm/arch-omap/board-palmz71.h b/include/asm-arm/arch-omap/board-palmz71.h
new file mode 100644 (file)
index 0000000..1252a85
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * linux/include/asm-arm/arch-omap/board-palmz71.h
+ *
+ * Hardware definitions for the Palm Zire71 device.
+ *
+ * Maintainters :      Marek Vasut <marek.vasut@gmail.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 __OMAP_BOARD_PALMZ71_H
+#define __OMAP_BOARD_PALMZ71_H
+
+#define PALMZ71_USBDETECT_GPIO 0
+#define PALMZ71_PENIRQ_GPIO    6
+#define PALMZ71_MMC_WP_GPIO    8
+#define PALMZ71_HDQ_GPIO       11
+
+#define PALMZ71_HOTSYNC_GPIO   OMAP_MPUIO(1)
+#define PALMZ71_CABLE_GPIO     OMAP_MPUIO(2)
+#define PALMZ71_SLIDER_GPIO    OMAP_MPUIO(3)
+#define PALMZ71_MMC_IN_GPIO    OMAP_MPUIO(4)
+
+#endif /* __OMAP_BOARD_PALMZ71_H */
diff --git a/include/asm-arm/arch-omap/board-sx1.h b/include/asm-arm/arch-omap/board-sx1.h
new file mode 100644 (file)
index 0000000..2bb8dd6
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Siemens SX1 board definitions
+ *
+ * Copyright: Vovan888 at gmail com
+ *
+ * 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_SX1_I2C_CHIPS_H
+#define __ASM_ARCH_SX1_I2C_CHIPS_H
+
+#define SOFIA_MAX_LIGHT_VAL    0x2B
+
+#define SOFIA_I2C_ADDR         0x32
+/* Sofia reg 3 bits masks */
+#define SOFIA_POWER1_REG       0x03
+
+#define        SOFIA_USB_POWER         0x01
+#define        SOFIA_MMC_POWER         0x04
+#define        SOFIA_BLUETOOTH_POWER   0x08
+#define        SOFIA_MMILIGHT_POWER    0x20
+
+#define SOFIA_POWER2_REG       0x04
+#define SOFIA_BACKLIGHT_REG    0x06
+#define SOFIA_KEYLIGHT_REG     0x07
+#define SOFIA_DIMMING_REG      0x09
+
+
+/* Function Prototypes for SX1 devices control on I2C bus */
+
+int sx1_setbacklight(u8 backlight);
+int sx1_getbacklight(u8 *backlight);
+int sx1_setkeylight(u8 keylight);
+int sx1_getkeylight(u8 *keylight);
+
+int sx1_setmmipower(u8 onoff);
+int sx1_setusbpower(u8 onoff);
+int sx1_setmmcpower(u8 onoff);
+
+#endif /* __ASM_ARCH_SX1_I2C_CHIPS_H */
index edf1dc6ad919b45ec807807762c1cdcd37c487e8..bbadf08a4d2fb10a5e9281d5961af3997f01daa1 100644 (file)
@@ -12,6 +12,8 @@
 
 #include <linux/types.h>
 
+#include <asm/arch/gpio-switch.h>
+
 /* Different peripheral ids */
 #define OMAP_TAG_CLOCK         0x4f01
 #define OMAP_TAG_MMC           0x4f02
 #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 {
@@ -99,26 +104,31 @@ struct omap_usb_config {
 struct omap_lcd_config {
        char panel_name[16];
        char ctrl_name[16];
+       s16  nreset_gpio;
+       u8   data_lines;
+};
+
+struct device;
+struct fb_info;
+struct omap_backlight_config {
+       int default_intensity;
+       int (*set_power)(struct device *dev, int state);
+       int (*check_fb)(struct fb_info *fb);
 };
 
 struct omap_fbmem_config {
-       u32 fb_sram_start;
-       u32 fb_sram_size;
-       u32 fb_sdram_start;
-       u32 fb_sdram_size;
-};
-
-/* Cover:
- *      high -> closed
- *      low  -> open
- * Connection:
- *      high -> connected
- *      low  -> disconnected
- */
-#define OMAP_GPIO_SWITCH_TYPE_COVER            0x0000
-#define OMAP_GPIO_SWITCH_TYPE_CONNECTION       0x0001
-#define OMAP_GPIO_SWITCH_FLAG_INVERTED         0x0001
-#define OMAP_GPIO_SWITCH_FLAG_OUTPUT           0x0002
+       u32 start;
+       u32 size;
+};
+
+struct omap_pwm_led_platform_data {
+       const char *name;
+       int intensity_timer;
+       int blink_timer;
+       void (*set_power)(struct omap_pwm_led_platform_data *self, int on_off);
+};
+
+/* See include/asm-arm/arch-omap/gpio-switch.h for definitions */
 struct omap_gpio_switch_config {
        char name[12];
        u16 gpio;
@@ -132,8 +142,25 @@ 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];
 };
 
@@ -172,4 +199,8 @@ extern const void *omap_get_var_config(u16 tag, size_t *len);
 extern struct omap_board_config_kernel *omap_board_config;
 extern int omap_board_config_size;
 
+
+/* for TI reference platforms sharing the same debug card */
+extern int debug_card_init(u32 addr, unsigned gpio);
+
 #endif
diff --git a/include/asm-arm/arch-omap/dsp.h b/include/asm-arm/arch-omap/dsp.h
deleted file mode 100644 (file)
index 06dad83..0000000
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * linux/include/asm-arm/arch-omap/dsp.h
- *
- * Header for OMAP DSP driver
- *
- * Copyright (C) 2002-2005 Nokia Corporation
- *
- * Written by Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * 2005/06/01:  DSP Gateway version 3.3
- */
-
-#ifndef ASM_ARCH_DSP_H
-#define ASM_ARCH_DSP_H
-
-
-/*
- * for /dev/dspctl/ctl
- */
-#define OMAP_DSP_IOCTL_RESET                   1
-#define OMAP_DSP_IOCTL_RUN                     2
-#define OMAP_DSP_IOCTL_SETRSTVECT              3
-#define OMAP_DSP_IOCTL_CPU_IDLE                        4
-#define OMAP_DSP_IOCTL_MPUI_WORDSWAP_ON                5
-#define OMAP_DSP_IOCTL_MPUI_WORDSWAP_OFF       6
-#define OMAP_DSP_IOCTL_MPUI_BYTESWAP_ON                7
-#define OMAP_DSP_IOCTL_MPUI_BYTESWAP_OFF       8
-#define OMAP_DSP_IOCTL_GBL_IDLE                        9
-#define OMAP_DSP_IOCTL_DSPCFG                  10
-#define OMAP_DSP_IOCTL_DSPUNCFG                        11
-#define OMAP_DSP_IOCTL_TASKCNT                 12
-#define OMAP_DSP_IOCTL_POLL                    13
-#define OMAP_DSP_IOCTL_REGMEMR                 40
-#define OMAP_DSP_IOCTL_REGMEMW                 41
-#define OMAP_DSP_IOCTL_REGIOR                  42
-#define OMAP_DSP_IOCTL_REGIOW                  43
-#define OMAP_DSP_IOCTL_GETVAR                  44
-#define OMAP_DSP_IOCTL_SETVAR                  45
-#define OMAP_DSP_IOCTL_RUNLEVEL                        50
-#define OMAP_DSP_IOCTL_SUSPEND                 51
-#define OMAP_DSP_IOCTL_RESUME                  52
-#define OMAP_DSP_IOCTL_FBEN                    53
-#define OMAP_DSP_IOCTL_FBDIS                   54
-#define OMAP_DSP_IOCTL_MBSEND                  99
-
-/*
- * for taskdev
- * (ioctls below should be >= 0x10000)
- */
-#define OMAP_DSP_TASK_IOCTL_BFLSH      0x10000
-#define OMAP_DSP_TASK_IOCTL_SETBSZ     0x10001
-#define OMAP_DSP_TASK_IOCTL_LOCK       0x10002
-#define OMAP_DSP_TASK_IOCTL_UNLOCK     0x10003
-#define OMAP_DSP_TASK_IOCTL_GETNAME    0x10004
-
-/*
- * for /dev/dspctl/mem
- */
-#define OMAP_DSP_MEM_IOCTL_EXMAP       1
-#define OMAP_DSP_MEM_IOCTL_EXUNMAP     2
-#define OMAP_DSP_MEM_IOCTL_EXMAP_FLUSH 3
-#define OMAP_DSP_MEM_IOCTL_FBEXPORT    5
-#define OMAP_DSP_MEM_IOCTL_MMUITACK    7
-#define OMAP_DSP_MEM_IOCTL_MMUINIT     9
-#define OMAP_DSP_MEM_IOCTL_KMEM_RESERVE        11
-#define OMAP_DSP_MEM_IOCTL_KMEM_RELEASE        12
-
-struct omap_dsp_mapinfo {
-       unsigned long dspadr;
-       unsigned long size;
-};
-
-/*
- * for /dev/dspctl/twch
- */
-#define OMAP_DSP_TWCH_IOCTL_MKDEV      1
-#define OMAP_DSP_TWCH_IOCTL_RMDEV      2
-#define OMAP_DSP_TWCH_IOCTL_TADD       11
-#define OMAP_DSP_TWCH_IOCTL_TDEL       12
-#define OMAP_DSP_TWCH_IOCTL_TKILL      13
-
-#define OMAP_DSP_DEVSTATE_NOTASK       0x00000001
-#define OMAP_DSP_DEVSTATE_ATTACHED     0x00000002
-#define OMAP_DSP_DEVSTATE_GARBAGE      0x00000004
-#define OMAP_DSP_DEVSTATE_INVALID      0x00000008
-#define OMAP_DSP_DEVSTATE_ADDREQ       0x00000100
-#define OMAP_DSP_DEVSTATE_DELREQ       0x00000200
-#define OMAP_DSP_DEVSTATE_ADDFAIL      0x00001000
-#define OMAP_DSP_DEVSTATE_ADDING       0x00010000
-#define OMAP_DSP_DEVSTATE_DELING       0x00020000
-#define OMAP_DSP_DEVSTATE_KILLING      0x00040000
-#define OMAP_DSP_DEVSTATE_STATE_MASK   0x7fffffff
-#define OMAP_DSP_DEVSTATE_STALE                0x80000000
-
-struct omap_dsp_taddinfo {
-       unsigned char minor;
-       unsigned long taskadr;
-};
-#define OMAP_DSP_TADD_ABORTADR 0xffffffff
-
-
-/*
- * error cause definition (for error detection device)
- */
-#define OMAP_DSP_ERRDT_WDT     0x00000001
-#define OMAP_DSP_ERRDT_MMU     0x00000002
-
-
-/*
- * mailbox protocol definitions
- */
-
-struct omap_dsp_mailbox_cmd {
-       unsigned short cmd;
-       unsigned short data;
-};
-
-struct omap_dsp_reginfo {
-       unsigned short adr;
-       unsigned short val;
-};
-
-struct omap_dsp_varinfo {
-       unsigned char varid;
-       unsigned short val[0];
-};
-
-#define OMAP_DSP_MBPROT_REVISION       0x0019
-
-#define OMAP_DSP_MBCMD_WDSND   0x10
-#define OMAP_DSP_MBCMD_WDREQ   0x11
-#define OMAP_DSP_MBCMD_BKSND   0x20
-#define OMAP_DSP_MBCMD_BKREQ   0x21
-#define OMAP_DSP_MBCMD_BKYLD   0x23
-#define OMAP_DSP_MBCMD_BKSNDP  0x24
-#define OMAP_DSP_MBCMD_BKREQP  0x25
-#define OMAP_DSP_MBCMD_TCTL    0x30
-#define OMAP_DSP_MBCMD_TCTLDATA        0x31
-#define OMAP_DSP_MBCMD_POLL    0x32
-#define OMAP_DSP_MBCMD_WDT     0x50    /* v3.3: obsolete */
-#define OMAP_DSP_MBCMD_RUNLEVEL        0x51
-#define OMAP_DSP_MBCMD_PM      0x52
-#define OMAP_DSP_MBCMD_SUSPEND 0x53
-#define OMAP_DSP_MBCMD_KFUNC   0x54
-#define OMAP_DSP_MBCMD_TCFG    0x60
-#define OMAP_DSP_MBCMD_TADD    0x62
-#define OMAP_DSP_MBCMD_TDEL    0x63
-#define OMAP_DSP_MBCMD_TSTOP   0x65
-#define OMAP_DSP_MBCMD_DSPCFG  0x70
-#define OMAP_DSP_MBCMD_REGRW   0x72
-#define OMAP_DSP_MBCMD_GETVAR  0x74
-#define OMAP_DSP_MBCMD_SETVAR  0x75
-#define OMAP_DSP_MBCMD_ERR     0x78
-#define OMAP_DSP_MBCMD_DBG     0x79
-
-#define OMAP_DSP_MBCMD_TCTL_TINIT      0x0000
-#define OMAP_DSP_MBCMD_TCTL_TEN                0x0001
-#define OMAP_DSP_MBCMD_TCTL_TDIS       0x0002
-#define OMAP_DSP_MBCMD_TCTL_TCLR       0x0003
-#define OMAP_DSP_MBCMD_TCTL_TCLR_FORCE 0x0004
-
-#define OMAP_DSP_MBCMD_RUNLEVEL_USER           0x01
-#define OMAP_DSP_MBCMD_RUNLEVEL_SUPER          0x0e
-#define OMAP_DSP_MBCMD_RUNLEVEL_RECOVERY       0x10
-
-#define OMAP_DSP_MBCMD_PM_DISABLE      0x00
-#define OMAP_DSP_MBCMD_PM_ENABLE       0x01
-
-#define OMAP_DSP_MBCMD_KFUNC_FBCTL     0x00
-#define OMAP_DSP_MBCMD_KFUNC_AUDIO_PWR 0x01
-
-#define OMAP_DSP_MBCMD_FBCTL_UPD       0x0000
-#define OMAP_DSP_MBCMD_FBCTL_ENABLE    0x0002
-#define OMAP_DSP_MBCMD_FBCTL_DISABLE   0x0003
-
-#define OMAP_DSP_MBCMD_AUDIO_PWR_UP    0x0000
-#define OMAP_DSP_MBCMD_AUDIO_PWR_DOWN1 0x0001
-#define OMAP_DSP_MBCMD_AUDIO_PWR_DOWN2 0x0002
-
-#define OMAP_DSP_MBCMD_TDEL_SAFE       0x0000
-#define OMAP_DSP_MBCMD_TDEL_KILL       0x0001
-
-#define OMAP_DSP_MBCMD_DSPCFG_REQ      0x00
-#define OMAP_DSP_MBCMD_DSPCFG_SYSADRH  0x28
-#define OMAP_DSP_MBCMD_DSPCFG_SYSADRL  0x29
-#define OMAP_DSP_MBCMD_DSPCFG_PROTREV  0x70
-#define OMAP_DSP_MBCMD_DSPCFG_ABORT    0x78
-#define OMAP_DSP_MBCMD_DSPCFG_LAST     0x80
-
-#define OMAP_DSP_MBCMD_REGRW_MEMR      0x00
-#define OMAP_DSP_MBCMD_REGRW_MEMW      0x01
-#define OMAP_DSP_MBCMD_REGRW_IOR       0x02
-#define OMAP_DSP_MBCMD_REGRW_IOW       0x03
-#define OMAP_DSP_MBCMD_REGRW_DATA      0x04
-
-#define OMAP_DSP_MBCMD_VARID_ICRMASK   0x00
-#define OMAP_DSP_MBCMD_VARID_LOADINFO  0x01
-
-#define OMAP_DSP_TTYP_ARCV     0x0001
-#define OMAP_DSP_TTYP_ASND     0x0002
-#define OMAP_DSP_TTYP_BKMD     0x0004
-#define OMAP_DSP_TTYP_BKDM     0x0008
-#define OMAP_DSP_TTYP_PVMD     0x0010
-#define OMAP_DSP_TTYP_PVDM     0x0020
-
-#define OMAP_DSP_EID_BADTID    0x10
-#define OMAP_DSP_EID_BADTCN    0x11
-#define OMAP_DSP_EID_BADBID    0x20
-#define OMAP_DSP_EID_BADCNT    0x21
-#define OMAP_DSP_EID_NOTLOCKED 0x22
-#define OMAP_DSP_EID_STVBUF    0x23
-#define OMAP_DSP_EID_BADADR    0x24
-#define OMAP_DSP_EID_BADTCTL   0x30
-#define OMAP_DSP_EID_BADPARAM  0x50
-#define OMAP_DSP_EID_FATAL     0x58
-#define OMAP_DSP_EID_NOMEM     0xc0
-#define OMAP_DSP_EID_NORES     0xc1
-#define OMAP_DSP_EID_IPBFULL   0xc2
-#define OMAP_DSP_EID_WDT       0xd0
-#define OMAP_DSP_EID_TASKNOTRDY        0xe0
-#define OMAP_DSP_EID_TASKBSY   0xe1
-#define OMAP_DSP_EID_TASKERR   0xef
-#define OMAP_DSP_EID_BADCFGTYP 0xf0
-#define OMAP_DSP_EID_DEBUG     0xf8
-#define OMAP_DSP_EID_BADSEQ    0xfe
-#define OMAP_DSP_EID_BADCMD    0xff
-
-#define OMAP_DSP_TNM_LEN       16
-
-#define OMAP_DSP_TID_FREE      0xff
-#define OMAP_DSP_TID_ANON      0xfe
-
-#define OMAP_DSP_BID_NULL      0xffff
-#define OMAP_DSP_BID_PVT       0xfffe
-
-#endif /* ASM_ARCH_DSP_H */
index 16a459dfa714ab770da53bff8680d90a36a70d6c..c61f868f24ee8de1590c0cb0743f7a0ce8452475 100644 (file)
@@ -1,38 +1,34 @@
 /*
- * linux/include/asm-arm/arch-omap/dsp_common.h
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
  *
- * Header for OMAP DSP subsystem control
+ * Copyright (C) 2004-2006 Nokia Corporation. All rights reserved.
  *
- * Copyright (C) 2004,2005 Nokia Corporation
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
  *
- * Written by Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
  *
- * 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.
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
  *
  * You 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
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
  *
- * 2005/06/03:  DSP Gateway version 3.3
  */
 
 #ifndef ASM_ARCH_DSP_COMMON_H
 #define ASM_ARCH_DSP_COMMON_H
 
+#ifdef CONFIG_ARCH_OMAP1
 extern void omap_dsp_request_mpui(void);
 extern void omap_dsp_release_mpui(void);
 extern int omap_dsp_request_mem(void);
 extern int omap_dsp_release_mem(void);
-
-extern void (*omap_dsp_audio_pwr_up_request)(int stage);
-extern void (*omap_dsp_audio_pwr_down_request)(int stage);
+#endif
 
 #endif /* ASM_ARCH_DSP_COMMON_H */
diff --git a/include/asm-arm/arch-omap/eac.h b/include/asm-arm/arch-omap/eac.h
new file mode 100644 (file)
index 0000000..5a4c831
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * linux/include/asm-arm/arch-omap2/eac.h
+ *
+ * Defines for Enhanced Audio Controller
+ *
+ * Contact: Jarkko Nikula <jarkko.nikula@nokia.com>
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __ASM_ARM_ARCH_OMAP2_EAC_H
+#define __ASM_ARM_ARCH_OMAP2_EAC_H
+
+#include <asm/arch/io.h>
+#include <asm/arch/hardware.h>
+#include <asm/irq.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+
+/* master codec clock source */
+#define EAC_MCLK_EXT_MASK      0x100
+enum eac_mclk_src {
+       EAC_MCLK_INT_11290000, /* internal 96 MHz / 8.5 = 11.29 Mhz */
+       EAC_MCLK_EXT_11289600 = EAC_MCLK_EXT_MASK,
+       EAC_MCLK_EXT_12288000,
+       EAC_MCLK_EXT_2x11289600,
+       EAC_MCLK_EXT_2x12288000,
+};
+
+/* codec port interface mode */
+enum eac_codec_mode {
+       EAC_CODEC_PCM,
+       EAC_CODEC_AC97,
+       EAC_CODEC_I2S,
+};
+
+/* configuration structure for I2S mode */
+struct eac_i2s_conf {
+       /* it seems according to TRM that the polarity-changed I2S mode is not
+        * only that frame sync polarity (EAC.AC_FS) is changed but also direction
+        * of it and interface serial clock (EAC.AC_SCLK) */
+       unsigned        polarity_changed_mode:1;
+       /* if enabled, then serial data starts one clock cycle after the
+        * of EAC.AC_FS for first audio slot */
+       unsigned        sync_delay_enable:1;
+};
+
+/* configuration structure for EAC codec port */
+struct eac_codec {
+       enum eac_mclk_src       mclk_src;
+
+       enum eac_codec_mode     codec_mode;
+       union {
+               struct eac_i2s_conf     i2s;
+       } codec_conf;
+
+       int             default_rate; /* audio sampling rate */
+
+       int             (* set_power)(void *private_data, int dac, int adc);
+       int             (* register_controls)(void *private_data,
+                                             struct snd_card *card);
+       const char      *short_name;
+
+       void            *private_data;
+};
+
+/* structure for passing platform dependent data to the EAC driver */
+struct eac_platform_data {
+        int    (* init)(struct device *eac_dev);
+       void    (* cleanup)(struct device *eac_dev);
+       /* these callbacks are used to configure & control external MCLK
+        * source. NULL if not used */
+       int     (* enable_ext_clocks)(struct device *eac_dev);
+       void    (* disable_ext_clocks)(struct device *eac_dev);
+};
+
+extern void omap_init_eac(struct eac_platform_data *pdata);
+
+extern int eac_register_codec(struct device *eac_dev, struct eac_codec *codec);
+extern void eac_unregister_codec(struct device *eac_dev);
+
+extern int eac_set_mode(struct device *eac_dev, int play, int rec);
+
+#endif /* __ASM_ARM_ARCH_OMAP2_EAC_H */
diff --git a/include/asm-arm/arch-omap/gpio-switch.h b/include/asm-arm/arch-omap/gpio-switch.h
new file mode 100644 (file)
index 0000000..10da0e0
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * GPIO switch definitions
+ *
+ * Copyright (C) 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_ARCH_OMAP_GPIO_SWITCH_H
+#define __ASM_ARCH_OMAP_GPIO_SWITCH_H
+
+#include <linux/types.h>
+
+/* Cover:
+ *     high -> closed
+ *     low  -> open
+ * Connection:
+ *     high -> connected
+ *     low  -> disconnected
+ * Activity:
+ *     high -> active
+ *     low  -> inactive
+ *
+ */
+#define OMAP_GPIO_SWITCH_TYPE_COVER            0x0000
+#define OMAP_GPIO_SWITCH_TYPE_CONNECTION       0x0001
+#define OMAP_GPIO_SWITCH_TYPE_ACTIVITY         0x0002
+#define OMAP_GPIO_SWITCH_FLAG_INVERTED         0x0001
+#define OMAP_GPIO_SWITCH_FLAG_OUTPUT           0x0002
+
+struct omap_gpio_switch {
+       const char *name;
+       s16 gpio;
+       unsigned flags:4;
+       unsigned type:4;
+
+       /* Time in ms to debounce when transitioning from
+        * inactive state to active state. */
+       u16 debounce_rising;
+       /* Same for transition from active to inactive state. */
+       u16 debounce_falling;
+
+       /* notify board-specific code about state changes */
+       void (* notify)(void *data, int state);
+       void *notify_data;
+};
+
+/* Call at init time only */
+extern void omap_register_gpio_switches(const struct omap_gpio_switch *tbl,
+                                       int count);
+
+#endif
index 7c03ef6c14c4f6e7d4391bb5275ef9be61045aec..0fe920ac901723b64c647082888e5564a3731486 100644 (file)
 #define GPMC_CS_NAND_DATA      0x24
 
 #define GPMC_CONFIG1_WRAPBURST_SUPP     (1 << 31)
-#define GPMC_CONFIG1_READMULTIPLE_SUPP  (1 << 20)
+#define GPMC_CONFIG1_READMULTIPLE_SUPP  (1 << 30)
 #define GPMC_CONFIG1_READTYPE_ASYNC     (0 << 29)
 #define GPMC_CONFIG1_READTYPE_SYNC      (1 << 29)
+#define GPMC_CONFIG1_WRITEMULTIPLE_SUPP (1 << 28)
 #define GPMC_CONFIG1_WRITETYPE_ASYNC    (0 << 27)
 #define GPMC_CONFIG1_WRITETYPE_SYNC     (1 << 27)
 #define GPMC_CONFIG1_CLKACTIVATIONTIME(val) ((val & 3) << 25)
@@ -80,6 +81,7 @@ struct gpmc_timings {
 };
 
 extern unsigned int gpmc_ns_to_ticks(unsigned int time_ns);
+extern unsigned int gpmc_round_ns_to_ticks(unsigned int time_ns);
 
 extern void gpmc_cs_write_reg(int cs, int idx, u32 val);
 extern u32 gpmc_cs_read_reg(int cs, int idx);
@@ -87,5 +89,7 @@ extern int gpmc_cs_calc_divider(int cs, unsigned int sync_clk);
 extern int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t);
 extern int gpmc_cs_request(int cs, unsigned long size, unsigned long *base);
 extern void gpmc_cs_free(int cs);
+extern int gpmc_cs_set_reserved(int cs, int reserved);
+extern int gpmc_cs_reserved(int cs);
 
 #endif
index 481048d65214815d85b22568b742995f3ea3269d..da572092e255aa390bd68ec69cdb84d0a0e91acd 100644 (file)
 #define OMAP_LPG2_LCR                  (OMAP_LPG2_BASE + 0x00)
 #define OMAP_LPG2_PMR                  (OMAP_LPG2_BASE + 0x04)
 
+/*
+ * ----------------------------------------------------------------------------
+ * Pulse-Width Light
+ * ----------------------------------------------------------------------------
+ */
+#define OMAP_PWL_BASE                  0xfffb5800
+#define OMAP_PWL_ENABLE                        (OMAP_PWL_BASE + 0x00)
+#define OMAP_PWL_CLK_ENABLE            (OMAP_PWL_BASE + 0x04)
+
 /*
  * ---------------------------------------------------------------------------
  * Processor specific defines
 #include "board-h4.h"
 #endif
 
+#ifdef CONFIG_MACH_OMAP_2430SDP
+#include "board-2430sdp.h"
+#endif
+
 #ifdef CONFIG_MACH_OMAP_APOLLON
 #include "board-apollon.h"
 #endif
 #include "board-voiceblue.h"
 #endif
 
+#ifdef CONFIG_MACH_OMAP_PALMTE
+#include "board-palmte.h"
+#endif
+
+#ifdef CONFIG_MACH_OMAP_PALMZ71
+#include "board-palmz71.h"
+#endif
+
+#ifdef CONFIG_MACH_OMAP_PALMTT
+#include "board-palmtt.h"
+#endif
+
+#ifdef CONFIG_MACH_SX1
+#include "board-sx1.h"
+#endif
+
 #endif /* !__ASSEMBLER__ */
 
 #endif /* __ASM_ARCH_OMAP_HARDWARE_H */
index 78f68e6a4f0c59a24407cd7fbe8c905dea0b97ec..289082d07f14ec284e7cf7d54cf61b229074acf8 100644 (file)
 #define L4_24XX_PHYS   L4_24XX_BASE    /* 0x48000000 */
 #define L4_24XX_VIRT   0xd8000000
 #define L4_24XX_SIZE   SZ_1M           /* 1MB of 128MB used, want 1MB sect */
+
+#ifdef CONFIG_ARCH_OMAP2430
+#define L4_WK_243X_PHYS                L4_WK_243X_BASE         /* 0x49000000 */
+#define L4_WK_243X_VIRT                0xd9000000
+#define L4_WK_243X_SIZE                SZ_1M
+#define OMAP243X_GPMC_PHYS     OMAP243X_GPMC_BASE      /* 0x49000000 */
+#define OMAP243X_GPMC_VIRT     0xFE000000
+#define OMAP243X_GPMC_SIZE     SZ_1M
+#endif
+
 #define IO_OFFSET      0x90000000
 #define IO_ADDRESS(pa) ((pa) + IO_OFFSET)      /* Works for L3 and L4 */
 #define io_p2v(pa)     ((pa) + IO_OFFSET)      /* Works for L3 and L4 */
 #define io_v2p(va)     ((va) - IO_OFFSET)      /* Works for L3 and L4 */
 
+/* DSP */
+#define DSP_MEM_24XX_PHYS      OMAP24XX_DSP_MEM_BASE   /* 0x58000000 */
+#define DSP_MEM_24XX_VIRT      0xe0000000
+#define DSP_MEM_24XX_SIZE      0x28000
+#define DSP_IPI_24XX_PHYS      OMAP24XX_DSP_IPI_BASE   /* 0x59000000 */
+#define DSP_IPI_24XX_VIRT      0xe1000000
+#define DSP_IPI_24XX_SIZE      SZ_4K
+#define DSP_MMU_24XX_PHYS      OMAP24XX_DSP_MMU_BASE   /* 0x5a000000 */
+#define DSP_MMU_24XX_VIRT      0xe2000000
+#define DSP_MMU_24XX_SIZE      SZ_4K
+
 #endif
 
 #ifndef __ASSEMBLER__
index 345a649ec8389fbaf303bfab8297ddfa6a1676ac..96bb12fab4383582fbd11d5c979d0112fbd85180 100644 (file)
@@ -31,6 +31,7 @@ struct omap_irda_config {
        unsigned long src_start;
        int tx_trigger;
        int rx_trigger;
+       int mode;
 };
 
 #endif
index c5bb05a69b81ec815c405d79b8b3bd553e29abc3..3ede58b51db28f36688e451d173b51b1fffc12ab 100644 (file)
@@ -37,8 +37,6 @@
 #define INT_DSP_MMU_ABORT      7
 #define INT_HOST               8
 #define INT_ABORT              9
-#define INT_DSP_MAILBOX1       10
-#define INT_DSP_MAILBOX2       11
 #define INT_BRIDGE_PRIV                13
 #define INT_GPIO_BANK1         14
 #define INT_UART3              15
@@ -63,6 +61,8 @@
 #define INT_1510_RES2          2
 #define INT_1510_SPI_TX                4
 #define INT_1510_SPI_RX                5
+#define INT_1510_DSP_MAILBOX1  10
+#define INT_1510_DSP_MAILBOX2  11
 #define INT_1510_RES12         12
 #define INT_1510_LB_MMU                17
 #define INT_1510_RES18         18
@@ -75,6 +75,8 @@
 #define INT_1610_IH2_FIQ       2
 #define INT_1610_McBSP2_TX     4
 #define INT_1610_McBSP2_RX     5
+#define INT_1610_DSP_MAILBOX1  10
+#define INT_1610_DSP_MAILBOX2  11
 #define INT_1610_LCD_LINE      12
 #define INT_1610_GPTIMER1      17
 #define INT_1610_GPTIMER2      18
 #define INT_RTC_TIMER          (25 + IH2_BASE)
 #define INT_RTC_ALARM          (26 + IH2_BASE)
 #define INT_MEM_STICK          (27 + IH2_BASE)
-#define INT_DSP_MMU            (28 + IH2_BASE)
 
 /*
  * OMAP-1510 specific IRQ numbers for interrupt handler 2
  */
+#define INT_1510_DSP_MMU       (28 + IH2_BASE)
 #define INT_1510_COM_SPI_RO    (31 + IH2_BASE)
 
 /*
 #define INT_1610_USB_OTG       (8 + IH2_BASE)
 #define INT_1610_SoSSI         (9 + IH2_BASE)
 #define INT_1610_SoSSI_MATCH   (19 + IH2_BASE)
+#define INT_1610_DSP_MMU       (28 + IH2_BASE)
 #define INT_1610_McBSP2RX_OF   (31 + IH2_BASE)
 #define INT_1610_STI           (32 + IH2_BASE)
 #define INT_1610_STI_WAKEUP    (33 + IH2_BASE)
 #define INT_24XX_SDMA_IRQ3     15
 #define INT_24XX_CAM_IRQ       24
 #define INT_24XX_DSS_IRQ       25
+#define INT_24XX_MAIL_U0_MPU   26
+#define INT_24XX_DSP_UMA       27
+#define INT_24XX_DSP_MMU       28
 #define INT_24XX_GPIO_BANK1    29
 #define INT_24XX_GPIO_BANK2    30
 #define INT_24XX_GPIO_BANK3    31
 #define INT_24XX_GPIO_BANK4    32
+#define INT_24XX_GPIO_BANK5    33
+#define INT_24XX_MAIL_U3_MPU   34
 #define INT_24XX_GPTIMER1      37
 #define INT_24XX_GPTIMER2      38
 #define INT_24XX_GPTIMER3      39
 #define INT_24XX_UART1_IRQ     72
 #define INT_24XX_UART2_IRQ     73
 #define INT_24XX_UART3_IRQ     74
+#define INT_24XX_USB_IRQ_GEN   75
+#define INT_24XX_USB_IRQ_NISO  76
+#define INT_24XX_USB_IRQ_ISO   77
+#define INT_24XX_USB_IRQ_HGEN  78
+#define INT_24XX_USB_IRQ_HSOF  79
+#define INT_24XX_USB_IRQ_OTG   80
 #define INT_24XX_MMC_IRQ       83
 
 /* Max. 128 level 2 IRQs (OMAP1610), 192 GPIOs (OMAP730) and
diff --git a/include/asm-arm/arch-omap/lcd_lph8923.h b/include/asm-arm/arch-omap/lcd_lph8923.h
deleted file mode 100644 (file)
index 004e67e..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef __LCD_LPH8923_H
-#define __LCD_LPH8923_H
-
-enum lcd_lph8923_test_num {
-       LCD_LPH8923_TEST_RGB_LINES,
-};
-
-enum lcd_lph8923_test_result {
-       LCD_LPH8923_TEST_SUCCESS,
-       LCD_LPH8923_TEST_INVALID,
-       LCD_LPH8923_TEST_FAILED,
-};
-
-#endif
diff --git a/include/asm-arm/arch-omap/lcd_mipid.h b/include/asm-arm/arch-omap/lcd_mipid.h
new file mode 100644 (file)
index 0000000..f8fbc48
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef __LCD_MIPID_H
+#define __LCD_MIPID_H
+
+enum mipid_test_num {
+       MIPID_TEST_RGB_LINES,
+};
+
+enum mipid_test_result {
+       MIPID_TEST_SUCCESS,
+       MIPID_TEST_INVALID,
+       MIPID_TEST_FAILED,
+};
+
+#ifdef __KERNEL__
+
+struct mipid_platform_data {
+       int     nreset_gpio;
+       int     data_lines;
+       void    (*shutdown)(struct mipid_platform_data *pdata);
+};
+
+#endif
+
+#endif
diff --git a/include/asm-arm/arch-omap/led.h b/include/asm-arm/arch-omap/led.h
new file mode 100644 (file)
index 0000000..f3acae2
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ *  linux/include/asm-arm/arch-omap/led.h
+ *
+ *  Copyright (C) 2006 Samsung Electronics
+ *  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.
+ */
+#ifndef ASMARM_ARCH_LED_H
+#define ASMARM_ARCH_LED_H
+
+struct omap_led_config {
+       struct led_classdev     cdev;
+       s16                     gpio;
+};
+
+struct omap_led_platform_data {
+       s16                     nr_leds;
+       struct omap_led_config  *leds;
+};
+
+#endif
diff --git a/include/asm-arm/arch-omap/mailbox.h b/include/asm-arm/arch-omap/mailbox.h
new file mode 100644 (file)
index 0000000..66669f0
--- /dev/null
@@ -0,0 +1,68 @@
+/* mailbox.h */
+
+#ifndef MAILBOX_H
+#define MAILBOX_H
+
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+
+typedef u32 mbox_msg_t;
+typedef void (mbox_receiver_t)(mbox_msg_t msg);
+struct omap_mbox;
+struct omap_mbq;
+
+typedef int __bitwise omap_mbox_irq_t;
+#define IRQ_TX ((__force omap_mbox_irq_t) 1)
+#define IRQ_RX ((__force omap_mbox_irq_t) 2)
+
+typedef int __bitwise omap_mbox_type_t;
+#define OMAP_MBOX_TYPE1 ((__force omap_mbox_type_t) 1)
+#define OMAP_MBOX_TYPE2 ((__force omap_mbox_type_t) 2)
+
+struct omap_mbox_ops {
+       omap_mbox_type_t        type;
+       int (*startup)(struct omap_mbox *mbox);
+       void (*shutdown)(struct omap_mbox *mbox);
+       /* fifo */
+       mbox_msg_t (*fifo_read)(struct omap_mbox *mbox);
+       void (*fifo_write)(struct omap_mbox *mbox, mbox_msg_t msg);
+       int (*fifo_empty)(struct omap_mbox *mbox);
+       int (*fifo_full)(struct omap_mbox *mbox);
+       /* irq */
+       void (*enable_irq)(struct omap_mbox *mbox, omap_mbox_irq_t irq);
+       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);
+};
+
+struct omap_mbox {
+       char *name;
+       spinlock_t lock;
+       unsigned int irq;
+       struct omap_mbox_ops *ops;
+
+       wait_queue_head_t tx_waitq;
+
+       struct work_struct msg_receive;
+       void (*msg_receive_cb)(mbox_msg_t);
+       struct omap_mbq *mbq;
+
+       int (*msg_sender_cb)(void*);
+
+       mbox_msg_t seq_snd, seq_rcv;
+
+       struct class_device class_dev;
+
+       void *priv;
+
+       struct omap_mbox *next;
+};
+
+int omap_mbox_msg_send(struct omap_mbox *mbox_h, mbox_msg_t msg, void* arg);
+void omap_mbox_init_seq(struct omap_mbox *mbox);
+
+struct omap_mbox *omap_mbox_get(const char *name);
+int omap_mbox_register(struct omap_mbox *mbox);
+int omap_mbox_unregister(struct omap_mbox *mbox);
+
+#endif /* MAILBOX_H */
index 9e7f40a88e1b2be0d2d8cabe4fe98a89ddd101e3..1254e4945b6f85d9ede13b23a0df4b99be6e9118 100644 (file)
@@ -2,7 +2,6 @@
 #define _OMAP2_MCSPI_H
 
 struct omap2_mcspi_platform_config {
-       unsigned long   base;
        unsigned short  num_cs;
 };
 
index df50dd53e1dde37f3733887e09e231173394eac0..14cba97c18ad061973876d1763aed27c7d8647ba 100644 (file)
@@ -70,7 +70,7 @@
 
 #define virt_to_lbus(x)                ((x) - PAGE_OFFSET + OMAP1510_LB_OFFSET)
 #define lbus_to_virt(x)                ((x) - OMAP1510_LB_OFFSET + PAGE_OFFSET)
-#define is_lbus_device(dev)    (cpu_is_omap1510() && dev && (strncmp(dev->bus_id, "ohci", 4) == 0))
+#define is_lbus_device(dev)    (cpu_is_omap15xx() && dev && (strncmp(dev->bus_id, "ohci", 4) == 0))
 
 #define __arch_page_to_dma(dev, page)  ({is_lbus_device(dev) ? \
                                        (dma_addr_t)virt_to_lbus(page_address(page)) : \
 
 #endif /* CONFIG_ARCH_OMAP15XX */
 
+/* Override the ARM default */
+#ifdef CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE
+
+#if (CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE == 0)
+#undef CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE
+#define CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE 2
+#endif
+
+#define CONSISTENT_DMA_SIZE \
+       (((CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE + 1) & ~1) * 1024 * 1024)
+
+#endif
+
 #endif
 
index 88cd4c87f0decd72f22a5ba1d5f012911ff59933..0c401c4eb7f2c015d8e09aa8b62dff0c4a5bdf9b 100644 (file)
@@ -7,10 +7,41 @@
 #ifndef __ASM_ARCH_MENELAUS_H
 #define __ASM_ARCH_MENELAUS_H
 
-extern void menelaus_mmc_register(void (*callback)(unsigned long data, u8 card_mask),
-                                 unsigned long data);
-extern void menelaus_mmc_remove(void);
-extern void menelaus_mmc_opendrain(int enable);
+struct device;
+
+struct menelaus_platform_data {
+       int (* late_init)(struct device *dev);
+};
+
+/* Call only at init time. */
+extern void menelaus_set_platform_data(struct menelaus_platform_data *pdata);
+
+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_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
@@ -19,4 +50,3 @@ extern void menelaus_mmc_opendrain(int enable);
 #endif
 
 #endif
-
diff --git a/include/asm-arm/arch-omap/mmc.h b/include/asm-arm/arch-omap/mmc.h
new file mode 100644 (file)
index 0000000..1b0e539
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * MMC definitions for OMAP2
+ *
+ * Copyright (C) 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __OMAP2_MMC_H
+#define __OMAP2_MMC_H
+
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/mmc/protocol.h>
+#include <linux/mmc/host.h>
+
+#define OMAP_MMC_MAX_SLOTS     2
+
+struct omap_mmc_platform_data {
+       unsigned enabled:1;
+       /* number of slots on board */
+       unsigned nr_slots:2;
+       /* nomux means "standard" muxing is wrong on this board, and that
+        * board-specific code handled it before common init logic.
+        */
+       unsigned nomux:1;
+       /* 4 wire signaling is optional, and is only used for SD/SDIO and
+        * MMCv4 */
+       unsigned wire4:1;
+       /* set if your board has components or wiring that limits the
+        * maximum frequency on the MMC bus */
+       unsigned int max_freq;
+
+       /* switch the bus to a new slot */
+       int (* switch_slot)(struct device *dev, int slot);
+       /* initialize board-specific MMC functionality, can be NULL if
+        * not supported */
+       int (* init)(struct device *dev);
+       void (* cleanup)(struct device *dev);
+
+       struct omap_mmc_slot_data {
+               int (* set_bus_mode)(struct device *dev, int slot, int bus_mode);
+               int (* set_power)(struct device *dev, int slot, int power_on, int vdd);
+               int (* get_ro)(struct device *dev, int slot);
+
+               /* return MMC cover switch state, can be NULL if not supported.
+                *
+                * possible return values:
+                *   0 - open
+                *   1 - closed
+                */
+               int (* get_cover_state)(struct device *dev, int slot);
+
+               const char *name;
+               u32 ocr_mask;
+       } slots[OMAP_MMC_MAX_SLOTS];
+};
+
+extern void omap_set_mmc_info(int host, const struct omap_mmc_platform_data *info);
+
+/* called from board-specific card detection service routine */
+extern void omap_mmc_notify_card_detect(struct device *dev, int slot, int detected);
+extern void omap_mmc_notify_cover_event(struct device *dev, int slot, int is_closed);
+
+#endif
index 828cc5c114e18e66e4e0c7a797b4df3d928dc281..b8fff50e6a87acd6399eb4f24249fbbbf01f6fb2 100644 (file)
@@ -406,6 +406,29 @@ enum omap1xxx_index {
        V10_1610_CF_IREQ,
        W10_1610_CF_RESET,
        W11_1610_CF_CD1,
+
+       /* parallel camera */
+       J15_1610_CAM_LCLK,
+       J18_1610_CAM_D7,
+       J19_1610_CAM_D6,
+       J14_1610_CAM_D5,
+       K18_1610_CAM_D4,
+       K19_1610_CAM_D3,
+       K15_1610_CAM_D2,
+       K14_1610_CAM_D1,
+       L19_1610_CAM_D0,
+       L18_1610_CAM_VS,
+       L15_1610_CAM_HS,
+       M19_1610_CAM_RSTZ,
+       Y15_1610_CAM_OUTCLK,
+
+       /* serial camera */
+       H19_1610_CAM_EXCLK,
+       Y12_1610_CCP_CLKP,
+       W13_1610_CCP_CLKM,
+       W14_1610_CCP_DATAP,
+       Y14_1610_CCP_DATAM,
+
 };
 
 enum omap24xx_index {
@@ -421,7 +444,9 @@ enum omap24xx_index {
        /* 24xx clock */
        W14_24XX_SYS_CLKOUT,
 
-       /* 24xx GPMC wait pin monitoring */
+       /* 24xx GPMC chipselects, wait pin monitoring */
+       E2_GPMC_NCS2,
+       L2_GPMC_NCS7,
        L3_GPMC_WAIT0,
        N7_GPMC_WAIT1,
        M1_GPMC_WAIT2,
@@ -435,6 +460,7 @@ enum omap24xx_index {
 
        /* 24xx GPIO */
        M21_242X_GPIO11,
+       P21_242X_GPIO12,
        AA10_242X_GPIO13,
        AA6_242X_GPIO14,
        AA4_242X_GPIO15,
@@ -444,7 +470,9 @@ enum omap24xx_index {
        Y20_24XX_GPIO60,
        W4__24XX_GPIO74,
        M15_24XX_GPIO92,
+       J15_24XX_GPIO99,
        V14_24XX_GPIO117,
+       P14_24XX_GPIO125,
 
        /* 242x DBG GPIO */
        V4_242X_GPIO49,
@@ -486,6 +514,30 @@ enum omap24xx_index {
        G18_24XX_MMC_CMD_DIR,
        H15_24XX_MMC_CLKI,
 
+       /* Full speed USB */
+       J20_24XX_USB0_PUEN,
+       J19_24XX_USB0_VP,
+       K20_24XX_USB0_VM,
+       J18_24XX_USB0_RCV,
+       K19_24XX_USB0_TXEN,
+       J14_24XX_USB0_SE0,
+       K18_24XX_USB0_DAT,
+
+       N14_24XX_USB1_SE0,
+       W12_24XX_USB1_SE0,
+       P15_24XX_USB1_DAT,
+       R13_24XX_USB1_DAT,
+       W20_24XX_USB1_TXEN,
+       P13_24XX_USB1_TXEN,
+       V19_24XX_USB1_RCV,
+       V12_24XX_USB1_RCV,
+
+       AA10_24XX_USB2_SE0,
+       Y11_24XX_USB2_DAT,
+       AA12_24XX_USB2_TXEN,
+       AA6_24XX_USB2_RCV,
+       AA4_24XX_USB2_TLLSE0,
+
        /* Keypad GPIO*/
        T19_24XX_KBR0,
        R19_24XX_KBR1,
index df4695474e3d89606d0c0542d2c178466ea92bd8..e655d35720068c2e87fec4987e2e4a8b5b9a69eb 100644 (file)
 #include <sound/pcm.h>
 #include <asm/arch/mcbsp.h>
 #include <linux/platform_device.h>
+/*
+ * Debug functions
+ */
+#undef DEBUG
+//#define DEBUG
+
+#define ERR(ARGS...) printk(KERN_ERR "{%s}-ERROR: ", __FUNCTION__);printk(ARGS);
+
+#ifdef DEBUG
+#define DPRINTK(ARGS...)  printk(KERN_INFO "<%s>: ",__FUNCTION__);printk(ARGS)
+#define ADEBUG() printk("XXX Alsa debug f:%s, l:%d\n", __FUNCTION__, __LINE__)
+#define FN_IN printk(KERN_INFO "[%s]: start\n", __FUNCTION__)
+#define FN_OUT(n) printk(KERN_INFO "[%s]: end(%u)\n",__FUNCTION__, n)
+#else
+#define DPRINTK(ARGS...)       /* nop */
+#define ADEBUG()               /* nop */
+#define FN_IN                  /* nop */
+#define FN_OUT(n)              /* nop */
+#endif
 
 #define DMA_BUF_SIZE   (1024 * 8)
 
index f0c7f0fb4dc032e2a8c2303714b49504c3b7235b..f7f5cdfdccce4f40a4a6a2c9e54240f76864ae49 100644 (file)
 #define UART3_OSC_12M_SEL       (OMAP_UART3_BASE + 0x4C)
 #define UART3_MVR               (OMAP_UART3_BASE + 0x50)
 
-/*
- * ----------------------------------------------------------------------------
- * Pulse-Width Light
- * ----------------------------------------------------------------------------
- */
-#define OMAP16XX_PWL_BASE      (0xfffb5800)
-#define OMAP16XX_PWL_ENABLE    (OMAP16XX_PWL_BASE + 0x00)
-#define OMAP16XX_PWL_CLK_ENABLE        (OMAP16XX_PWL_BASE + 0x04)
-
 /*
  * ---------------------------------------------------------------------------
  * Watchdog timer
 #define WSPR_DISABLE_0         (0x0000aaaa)
 #define WSPR_DISABLE_1         (0x00005555)
 
+/* Mailbox */
+#define OMAP16XX_MAILBOX_BASE  (0xfffcf000)
+
 #endif /*  __ASM_ARCH_OMAP16XX_H */
 
index 6e59805fa6545b8c3edeef8be3e2378b8fb0cf19..14c0f94965795d4019adc8d4fe2b1654cdaf71b5 100644 (file)
@@ -8,6 +8,7 @@
  */
 
 #define L4_24XX_BASE           0x48000000
+#define L4_WK_243X_BASE                0x49000000
 #define L3_24XX_BASE           0x68000000
 
 /* interrupt controller */
 #define OMAP24XX_IVA_INTC_BASE 0x40000000
 #define IRQ_SIR_IRQ            0x0040
 
+#ifdef CONFIG_ARCH_OMAP2420
 #define OMAP24XX_32KSYNCT_BASE (L4_24XX_BASE + 0x4000)
 #define OMAP24XX_PRCM_BASE     (L4_24XX_BASE + 0x8000)
 #define OMAP24XX_SDRC_BASE     (L3_24XX_BASE + 0x9000)
+#define OMAP242X_CONTROL_STATUS        (L4_24XX_BASE + 0x2f8)
+#endif
+
+#ifdef CONFIG_ARCH_OMAP2430
+#define OMAP24XX_32KSYNCT_BASE (L4_WK_243X_BASE + 0x20000)
+#define OMAP24XX_PRCM_BASE     (L4_WK_243X_BASE + 0x6000)
+#define OMAP24XX_SDRC_BASE     (0x6D000000)
+#define OMAP242X_CONTROL_STATUS        (L4_24XX_BASE + 0x2f8)
+#define OMAP243X_GPMC_BASE     0x6E000000
+#endif
+
+/* DSP SS */
+#define OMAP24XX_DSP_BASE      0x58000000
+#define OMAP24XX_DSP_MEM_BASE  (OMAP24XX_DSP_BASE + 0x0)
+#define OMAP24XX_DSP_IPI_BASE  (OMAP24XX_DSP_BASE + 0x1000000)
+#define OMAP24XX_DSP_MMU_BASE  (OMAP24XX_DSP_BASE + 0x2000000)
+
+/* Mailbox */
+#define OMAP24XX_MAILBOX_BASE  (L4_24XX_BASE + 0x94000)
 
 #endif /* __ASM_ARCH_OMAP24XX_H */
 
index fccdb3db025ff0dc79fd08dc4c5d7a0a27f0d1d3..adf1d81f22d1509fd5a4069e9d741d5a07eea0fe 100644 (file)
@@ -24,6 +24,9 @@
 #ifndef __OMAPFB_H
 #define __OMAPFB_H
 
+#include <asm/ioctl.h>
+#include <asm/types.h>
+
 /* IOCTL commands. */
 
 #define OMAP_IOW(num, dtype)   _IOW('O', num, dtype)
 #define OMAPFB_VSYNC           OMAP_IO(38)
 #define OMAPFB_SET_UPDATE_MODE OMAP_IOW(40, int)
 #define OMAPFB_UPDATE_WINDOW_OLD OMAP_IOW(41, struct omapfb_update_window_old)
-#define OMAPFB_GET_CAPS                OMAP_IOR(42, unsigned long)
 #define OMAPFB_GET_UPDATE_MODE OMAP_IOW(43, int)
 #define OMAPFB_LCD_TEST                OMAP_IOW(45, int)
 #define OMAPFB_CTRL_TEST       OMAP_IOW(46, int)
 #define OMAPFB_UPDATE_WINDOW   OMAP_IOW(47, struct omapfb_update_window)
-#define OMAPFB_SETUP_PLANE     OMAP_IOW(48, struct omapfb_setup_plane)
-#define OMAPFB_ENABLE_PLANE    OMAP_IOW(49, struct omapfb_enable_plane)
 #define OMAPFB_SET_COLOR_KEY   OMAP_IOW(50, struct omapfb_color_key)
+#define OMAPFB_GET_COLOR_KEY   OMAP_IOW(51, struct omapfb_color_key)
+#define OMAPFB_SETUP_PLANE     OMAP_IOW(52, struct omapfb_plane_info)
+#define OMAPFB_QUERY_PLANE     OMAP_IOW(53, struct omapfb_plane_info)
 
 #define OMAPFB_CAPS_GENERIC_MASK       0x00000fff
 #define OMAPFB_CAPS_LCDC_MASK          0x00fff000
@@ -56,6 +59,9 @@
 #define OMAPFB_FORMAT_MASK         0x00ff
 #define OMAPFB_FORMAT_FLAG_DOUBLE  0x0100
 
+#define OMAPFB_EVENT_READY     1
+#define OMAPFB_EVENT_DISABLED  2
+
 enum omapfb_color_format {
        OMAPFB_COLOR_RGB565 = 0,
        OMAPFB_COLOR_YUV422,
@@ -64,6 +70,8 @@ enum omapfb_color_format {
        OMAPFB_COLOR_CLUT_4BPP,
        OMAPFB_COLOR_CLUT_2BPP,
        OMAPFB_COLOR_CLUT_1BPP,
+       OMAPFB_COLOR_RGB444,
+       OMAPFB_COLOR_YUY422,
 };
 
 struct omapfb_update_window {
@@ -88,18 +96,16 @@ enum omapfb_channel_out {
        OMAPFB_CHANNEL_OUT_DIGIT,
 };
 
-struct omapfb_setup_plane {
-       __u8  plane;
+struct omapfb_plane_info {
+       __u32 pos_x;
+       __u32 pos_y;
+       __u8  enabled;
        __u8  channel_out;
-       __u32 offset;
-       __u32 pos_x, pos_y;
-       __u32 width, height;
-       __u32 color_mode;
-};
-
-struct omapfb_enable_plane {
-       __u8  plane;
-       __u8  enable;
+       __u8  mirror;
+       __u8  reserved1;
+       __u32 out_width;
+       __u32 out_height;
+       __u32 reserved2[12];
 };
 
 enum omapfb_color_key_type {
@@ -141,6 +147,9 @@ enum omapfb_update_mode {
 
 #define OMAP_LCDC_PANEL_TFT            0x0100
 
+#define OMAPFB_PLANE_XRES_MIN          8
+#define OMAPFB_PLANE_YRES_MIN          8
+
 #ifdef CONFIG_ARCH_OMAP1
 #define OMAPFB_PLANE_NUM               1
 #else
@@ -169,15 +178,17 @@ struct lcd_panel {
        int             pcd;            /* pixel clock divider.
                                           Obsolete use pixel_clock instead */
 
-       int             (*init)         (struct omapfb_device *fbdev);
-       void            (*cleanup)      (void);
-       int             (*enable)       (void);
-       void            (*disable)      (void);
-       unsigned long   (*get_caps)     (void);
-       int             (*set_bklight_level)(unsigned int level);
-       unsigned int    (*get_bklight_level)(void);
-       unsigned int    (*get_bklight_max)  (void);
-       int             (*run_test)     (int test_num);
+       int             (*init)         (struct lcd_panel *panel,
+                                        struct omapfb_device *fbdev);
+       void            (*cleanup)      (struct lcd_panel *panel);
+       int             (*enable)       (struct lcd_panel *panel);
+       void            (*disable)      (struct lcd_panel *panel);
+       unsigned long   (*get_caps)     (struct lcd_panel *panel);
+       int             (*set_bklight_level)(struct lcd_panel *panel,
+                                            unsigned int level);
+       unsigned int    (*get_bklight_level)(struct lcd_panel *panel);
+       unsigned int    (*get_bklight_max)  (struct lcd_panel *panel);
+       int             (*run_test)     (struct lcd_panel *panel, int test_num);
 };
 
 struct omapfb_device;
@@ -202,7 +213,7 @@ struct extif_timings {
 };
 
 struct lcd_ctrl_extif {
-       int  (*init)            (void);
+       int  (*init)            (struct omapfb_device *fbdev);
        void (*cleanup)         (void);
        void (*get_clk_info)    (u32 *clk_period, u32 *max_clk_div);
        int  (*convert_timings) (struct extif_timings *timings);
@@ -213,30 +224,41 @@ struct lcd_ctrl_extif {
        void (*write_data)      (const void *buf, unsigned int len);
        void (*transfer_area)   (int width, int height,
                                 void (callback)(void * data), void *data);
+
        unsigned long           max_transmit_size;
 };
 
 struct omapfb_notifier_block {
        struct notifier_block   nb;
        void                    *data;
+       int                     plane_idx;
 };
 
-typedef int (*omapfb_notifier_callback_t)(struct omapfb_notifier_block *,
-                                          unsigned long event,
-                                          struct omapfb_device *fbdev);
+typedef int (*omapfb_notifier_callback_t)(struct notifier_block *,
+                                         unsigned long event,
+                                         void *fbi);
+
+struct omapfb_mem_region {
+       dma_addr_t      paddr;
+       void            *vaddr;
+       unsigned long   size;
+       int             alloc:1;
+};
+
+struct omapfb_mem_desc {
+       int                             region_cnt;
+       struct omapfb_mem_region        region[OMAPFB_PLANE_NUM];
+};
 
 struct lcd_ctrl {
        const char      *name;
        void            *data;
 
        int             (*init)           (struct omapfb_device *fbdev,
-                                          int ext_mode, int req_vram_size);
+                                          int ext_mode,
+                                          struct omapfb_mem_desc *req_md);
        void            (*cleanup)        (void);
        void            (*bind_client)    (struct omapfb_notifier_block *nb);
-       void            (*get_vram_layout)(unsigned long *size,
-                                          void **virt_base,
-                                          dma_addr_t *phys_base);
-       int             (*mmap)           (struct vm_area_struct *vma);
        unsigned long   (*get_caps)       (void);
        int             (*set_update_mode)(enum omapfb_update_mode mode);
        enum omapfb_update_mode (*get_update_mode)(void);
@@ -245,8 +267,12 @@ struct lcd_ctrl {
                                           int screen_width,
                                           int pos_x, int pos_y, int width,
                                           int height, int color_mode);
+       int             (*set_scale)      (int plane,
+                                          int orig_width, int orig_height,
+                                          int out_width, int out_height);
        int             (*enable_plane)   (int plane, int enable);
-       int             (*update_window)  (struct omapfb_update_window *win,
+       int             (*update_window)  (struct fb_info *fbi,
+                                          struct omapfb_update_window *win,
                                           void (*callback)(void *),
                                           void *callback_data);
        void            (*sync)           (void);
@@ -257,6 +283,7 @@ struct lcd_ctrl {
                                           u16 blue, u16 transp,
                                           int update_hw_mem);
        int             (*set_color_key)  (struct omapfb_color_key *ck);
+       int             (*get_color_key)  (struct omapfb_color_key *ck);
 
 };
 
@@ -266,19 +293,20 @@ enum omapfb_state {
        OMAPFB_ACTIVE   = 100
 };
 
+struct omapfb_plane_struct {
+       int                             idx;
+       struct omapfb_plane_info        info;
+       enum omapfb_color_format        color_mode;
+       struct omapfb_device            *fbdev;
+};
+
 struct omapfb_device {
        int                     state;
        int                     ext_lcdc;               /* Using external
                                                            LCD controller */
        struct mutex            rqueue_mutex;
 
-       void                    *vram_virt_base;
-       dma_addr_t              vram_phys_base;
-       unsigned long           vram_size;
-
-       int                     color_mode;
        int                     palette_size;
-       int                     mirror;
        u32                     pseudo_palette[17];
 
        struct lcd_panel        *panel;                 /* LCD panel */
@@ -286,19 +314,18 @@ struct omapfb_device {
        struct lcd_ctrl         *int_ctrl;              /* internal LCD ctrl */
        struct lcd_ctrl_extif   *ext_if;                /* LCD ctrl external
                                                           interface */
-       struct fb_info          *fb_info;
-
        struct device           *dev;
+
+       struct omapfb_mem_desc          mem_desc;
+       struct fb_info                  *fb_info[OMAPFB_PLANE_NUM];
 };
 
 struct omapfb_platform_data {
-       struct omap_lcd_config   lcd;
-       struct omap_fbmem_config fbmem;
+       struct omap_lcd_config          lcd;
+       struct omapfb_mem_desc          mem_desc;
+       void                            *ctrl_platform_data;
 };
 
-#define OMAPFB_EVENT_READY     1
-#define OMAPFB_EVENT_DISABLED  2
-
 #ifdef CONFIG_ARCH_OMAP1
 extern struct lcd_ctrl omap1_lcd_ctrl;
 #else
@@ -310,15 +337,17 @@ extern void omapfb_write_first_pixel(struct omapfb_device *fbdev, u16 pixval);
 extern void omapfb_notify_clients(struct omapfb_device *fbdev,
                                  unsigned long event);
 extern int  omapfb_register_client(struct omapfb_notifier_block *nb,
-                                   omapfb_notifier_callback_t callback,
-                                   void *callback_data);
+                                  omapfb_notifier_callback_t callback,
+                                  void *callback_data);
 extern int  omapfb_unregister_client(struct omapfb_notifier_block *nb);
-extern int  omapfb_update_window_async(struct omapfb_update_window *win,
-                                       void (*callback)(void *),
-                                       void *callback_data);
+extern int  omapfb_update_window_async(struct fb_info *fbi,
+                                      struct omapfb_update_window *win,
+                                      void (*callback)(void *),
+                                      void *callback_data);
 
-/* in arch/arm/plat-omap/devices.c */
+/* in arch/arm/plat-omap/fb.c */
 extern void omapfb_reserve_mem(void);
+extern void omapfb_set_ctrl_platform_data(void *pdata);
 
 #endif /* __KERNEL__ */
 
diff --git a/include/asm-arm/arch-omap/onenand.h b/include/asm-arm/arch-omap/onenand.h
new file mode 100644 (file)
index 0000000..b8a19be
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * include/asm-arm/arch-omap/onenand.h
+ *
+ * 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/mtd/partitions.h>
+
+struct omap_onenand_platform_data {
+       int                     cs;
+       int                     gpio_irq;
+       struct mtd_partition    *parts;
+       int                     nr_parts;
+};
index 14588059981f99cf8f8f299d5f79292c1b8e9fb0..0b75e3389e520b79f12ea847d6d55cef722335ec 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/include/asm-arm/arch-omap/pm.h
+ * linux/include/asm/arch-omap/pm.h
  *
  * Header file for OMAP Power Management Routines
  *
@@ -132,6 +132,8 @@ void clk_deny_idle(struct clk *clk);
 
 extern void omap_pm_idle(void);
 extern void omap_pm_suspend(void);
+extern void omap2_block_sleep(void);
+extern void omap2_allow_sleep(void);
 extern void omap730_cpu_suspend(unsigned short, unsigned short);
 extern void omap1510_cpu_suspend(unsigned short, unsigned short);
 extern void omap1610_cpu_suspend(unsigned short, unsigned short);
@@ -181,10 +183,6 @@ 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
@@ -294,63 +292,5 @@ enum mpui1610_save_state {
 #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 */
index 6fc0dd57b7c383ae69c6aea14679e4f6c5bc1115..cc6161d639881c5d311a0036c15b9176bfe6306e 100644 (file)
@@ -20,8 +20,8 @@ extern void omap2_sram_reprogram_sdrc(u32 perf_level, u32 dll_val,
                                      u32 mem_type);
 extern u32 omap2_set_prcm(u32 dpll_ctrl_val, u32 sdrc_rfr_val, int bypass);
 
-extern unsigned long omap_fb_sram_start;
-extern unsigned long omap_fb_sram_size;
+extern int omap_fb_sram_plane;
+extern int omap_fb_sram_valid;
 
 /* Do not use these */
 extern void sram_reprogram_clock(u32 ckctl, u32 dpllctl);
diff --git a/include/asm-arm/arch-omap/sti.h b/include/asm-arm/arch-omap/sti.h
new file mode 100644 (file)
index 0000000..e5a383d
--- /dev/null
@@ -0,0 +1,161 @@
+#ifndef __ASM_ARCH_OMAP_STI_H
+#define __ASM_ARCH_OMAP_STI_H
+
+#include <asm/io.h>
+
+/*
+ * STI/XTI
+ */
+#define STI_REVISION           0x00
+#define STI_SYSCONFIG          0x10
+#define STI_SYSSTATUS          0x14
+#define STI_IRQSTATUS          0x18
+#define STI_IRQSETEN           0x1c
+
+#if defined(CONFIG_ARCH_OMAP1)
+#define STI_IRQCLREN           0x20
+#define STI_ER                 0x24
+#define STI_DR                 0x28
+#define STI_RX_DR              0x2c
+#define STI_RX_STATUS          0x30
+#define STI_CLK_CTRL           0x34
+#define STI_IOBOTT0            0x4c
+#define STI_IOTOP0             0x50
+#define STI_IOBOTT1            0x54
+#define STI_IOTOP1             0x58
+#define STI_SERIAL_CFG         0x60
+
+#define STI_OCPT2_MATCH_INT    0
+#define STI_OCPT1_MATCH_INT    1
+#define STI_EMIFS_MATCH_INT    2
+#define STI_EMIFF_MATCH_INT    3
+#define STI_IO_MATCH_INT       4
+#define STI_RX_INT             5
+#define STI_DUMP_REQUEST_INT   6
+#define STI_DUMP_UNDERRUN_INT  7
+#define STI_WAKEUP_INT         9
+
+#define STI_NR_IRQS    10
+
+#define STI_IRQSTATUS_MASK     0x2ff
+#define STI_PERCHANNEL_SIZE    4
+
+#define STI_RXFIFO_EMPTY       (1 << 0)
+
+/*
+ * We use the following enums to retain consistency with the STI "functional"
+ * specification.
+ */
+
+/* STI_ER */
+enum {
+       UnlockStatMatch = (1 <<  2), /* Unlock status match event regs */
+       IOMPUStr1En1    = (1 <<  3), /* MPU IO match, strobe 1, window 1 */
+       IOMPUStr0En1    = (1 <<  4), /* MPU IO match, strobe 0, window 1 */
+       IOMPUStr1En0    = (1 <<  5), /* MPU IO match, strobe 1, window 0 */
+       IOMPUStr0En0    = (1 <<  6), /* MPU IO match, strobe 0, window 0 */
+       IODSPStr1En1    = (1 <<  7), /* DSP IO match, strobe 1, window 1 */
+       IODSPStr0En1    = (1 <<  8), /* DSP IO match, strobe 0, window 1 */
+       IODSPStr1En0    = (1 <<  9), /* DSP IO match, strobe 1, window 0 */
+       IODSPStr0En0    = (1 << 10), /* DSP IO match, strobe 0, window 0 */
+       MemMatchEn      = (1 << 11), /* Memory matched event */
+       DSPCmdEn        = (1 << 12), /* DSP command write */
+       MPUCmdEn        = (1 << 13), /* MPU command write */
+       MemDumpEn       = (1 << 14), /* System memory dump */
+       STIEn           = (1 << 15), /* Global trace enable */
+};
+#elif defined(CONFIG_ARCH_OMAP2)
+
+/* XTI interrupt bits */
+enum {
+       STI_WAKEUP_INT  = 0,
+       STI_ETB_THRESHOLD_INT,
+       STI_RX_INT,
+       STI_DUMP_REQUEST_INT,
+       STI_NR_IRQS,
+};
+
+/* XTI_TRACESELECT */
+enum {
+       CmdTimeStampEn  = (1 << 0),     /* Command write timestamps */
+       WinTimeStampEn  = (1 << 1),     /* Window match timestamps */
+       WinMatchEn      = (1 << 2),     /* Window match trace */
+       DSPCmdEn        = (1 << 3),     /* DSP command write */
+       MPUCmdEn        = (1 << 4),     /* MPU command write */
+       MemDumpEn0      = (1 << 5),     /* System memory dump */
+       MemDumpEn1      = (1 << 6),
+       MemDumpEn2      = (1 << 7),
+       ExtTriggerEn    = (1 << 8),     /* External trace trigger */
+       STIEn           = (1 << 9),     /* System trace enable */
+};
+
+#define STI_IRQSTATUS_MASK     0x0f
+#define STI_PERCHANNEL_SIZE    64
+
+/* XTI registers */
+#define XTI_SYSSTATUS          0x14
+#define XTI_TRACESELECT                0x24
+#define XTI_RXDATA             0x28
+#define XTI_SCLKCRTL           0x2c
+#define XTI_SCONFIG            0x30
+
+/* STI Compatability */
+#define STI_RX_STATUS          XTI_SYSSTATUS
+#define STI_IRQCLREN           STI_IRQSETEN
+#define STI_ER                 XTI_TRACESELECT
+#define STI_DR                 XTI_TRACESELECT
+#define STI_RX_DR              XTI_RXDATA
+#define STI_CLK_CTRL           XTI_SCLKCRTL
+#define STI_SERIAL_CFG         XTI_SCONFIG
+
+#define STI_RXFIFO_EMPTY       (1 << 8)
+
+#endif
+
+/* arch/arm/plat-omap/sti/sti.c */
+extern unsigned long sti_base, sti_channel_base;
+
+int sti_request_irq(unsigned int irq, void *handler, unsigned long arg);
+void sti_free_irq(unsigned int irq);
+void sti_enable_irq(unsigned int irq);
+void sti_disable_irq(unsigned int irq);
+void sti_ack_irq(unsigned int irq);
+
+int sti_trace_enable(int event);
+void sti_trace_disable(int event);
+
+void sti_channel_write_trace(int len, int id, void *data, unsigned int channel);
+
+/* arch/arm/plat-omap/sti/sti-fifo.c */
+int sti_read_packet(unsigned char *buf, int maxsize);
+
+static inline unsigned long sti_readl(unsigned long reg)
+{
+       return __raw_readl(sti_base + reg);
+}
+
+static inline void sti_writel(unsigned long data, unsigned long reg)
+{
+       __raw_writel(data, sti_base + reg);
+}
+
+#define to_channel_address(channel) \
+       (sti_channel_base + STI_PERCHANNEL_SIZE * (channel))
+
+static inline void sti_channel_writeb(unsigned char data, unsigned int channel)
+{
+       __raw_writeb(data, to_channel_address(channel));
+}
+
+static inline void sti_channel_writel(unsigned long data, unsigned int channel)
+{
+       __raw_writel(data, to_channel_address(channel));
+}
+
+#define STI_TRACE_CONTROL_CHANNEL      253
+
+static inline void sti_channel_flush(unsigned int channel)
+{
+       sti_channel_writeb(channel, STI_TRACE_CONTROL_CHANNEL);
+}
+#endif /* __ASM_ARCH_OMAP_STI_H */
diff --git a/include/asm-arm/arch-omap/twl4030.h b/include/asm-arm/arch-omap/twl4030.h
new file mode 100644 (file)
index 0000000..a603c10
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * twl4030.h - header for TWL4030 PM and audio CODEC device
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * Based on tlv320aic23.c:
+ * Copyright (c) by Kai Svahn <kai.svahn@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#ifndef __TWL4030_H_
+#define __TWL4030_H_
+
+/* USB ID */
+#define TWL4030_MODULE_USB             0x00
+/* AUD ID */
+#define TWL4030_MODULE_AUDIO_VOICE     0x01
+#define TWL4030_MODULE_GPIO            0x02
+#define TWL4030_MODULE_INTBR           0x03
+#define TWL4030_MODULE_PIH             0x04
+#define TWL4030_MODULE_TEST            0x05
+/* AUX ID */
+#define TWL4030_MODULE_KEYPAD          0x06
+#define TWL4030_MODULE_MADC            0x07
+#define TWL4030_MODULE_INTERRUPTS      0x08
+#define TWL4030_MODULE_LED             0x09
+#define TWL4030_MODULE_MAIN_CHARGE     0x0A
+#define TWL4030_MODULE_PRECHARGE       0x0B
+#define TWL4030_MODULE_PWM0            0x0C
+#define TWL4030_MODULE_PWM1            0x0D
+#define TWL4030_MODULE_PWMA            0x0E
+#define TWL4030_MODULE_PWMB            0x0F
+/* POWER ID */
+#define TWL4030_MODULE_BACKUP          0x10
+#define TWL4030_MODULE_INT             0x11
+#define TWL4030_MODULE_PM_MASTER       0x12
+#define TWL4030_MODULE_PM_RECIEVER     0x13
+#define TWL4030_MODULE_RTC             0x14
+#define TWL4030_MODULE_SECURED_REG     0x15
+
+/* IRQ information-need base */
+#include <asm/arch/irqs.h>
+/* TWL4030 interrupts */
+
+#define TWL4030_MODIRQ_GPIO            (IH_TWL4030_BASE + 0)
+#define TWL4030_MODIRQ_KEYPAD          (IH_TWL4030_BASE + 1)
+#define TWL4030_MODIRQ_BCI             (IH_TWL4030_BASE + 2)
+#define TWL4030_MODIRQ_MADC            (IH_TWL4030_BASE + 3)
+#define TWL4030_MODIRQ_USB             (IH_TWL4030_BASE + 4)
+#define TWL4030_MODIRQ_PWR             (IH_TWL4030_BASE + 5)
+/* Rest are unsued currently*/
+
+/* Offsets to Power Registers */
+#define TWL4030_VDAC_DEV_GRP           0x3B
+#define TWL4030_VDAC_DEDICATED         0x3E
+#define TWL4030_VAUX2_DEV_GRP          0x1B
+#define TWL4030_VAUX2_DEDICATED                0x1E
+#define TWL4030_VAUX3_DEV_GRP          0x1F
+#define TWL4030_VAUX3_DEDICATED                0x22
+
+/* Functions to read and write from TWL4030 */
+
+/*
+ * IMP NOTE:
+ * The base address of the module will be added by the triton driver
+ * It is the caller's responsibility to ensure sane values
+ */
+int twl4030_i2c_write_u8(u8 mod_no, u8 val, u8 reg);
+int twl4030_i2c_read_u8(u8 mod_no, u8* val, u8 reg);
+
+ /*
+  * i2c_write: IMPORTANT - Allocate value num_bytes+1 and valid data starts at
+  *            Offset 1.
+  */
+int twl4030_i2c_write(u8 mod_no, u8 * value, u8 reg, u8 num_bytes);
+int twl4030_i2c_read(u8 mod_no, u8 * value, u8 reg, u8 num_bytes);
+
+#endif /* End of __TWL4030_H */
index 054fb9a8e0c684052ec4046be5c887c61538582b..99ae9eabaf71bb3740aabe11cc6b2667065d91f5 100644 (file)
@@ -7,9 +7,27 @@
 
 /*-------------------------------------------------------------------------*/
 
-#define OTG_BASE                       0xfffb0400
-#define UDC_BASE                       0xfffb4000
-#define OMAP_OHCI_BASE                 0xfffba000
+#define OMAP1_OTG_BASE                 0xfffb0400
+#define OMAP1_UDC_BASE                 0xfffb4000
+#define OMAP1_OHCI_BASE                        0xfffba000
+
+#define OMAP2_OHCI_BASE                        0x4805e000
+#define OMAP2_UDC_BASE                 0x4805e200
+#define OMAP2_OTG_BASE                 0x4805e300
+
+#ifdef CONFIG_ARCH_OMAP1
+
+#define OTG_BASE                       OMAP1_OTG_BASE
+#define UDC_BASE                       OMAP1_UDC_BASE
+#define OMAP_OHCI_BASE                 OMAP1_OHCI_BASE
+
+#else
+
+#define OTG_BASE                       OMAP2_OTG_BASE
+#define UDC_BASE                       OMAP2_UDC_BASE
+#define OMAP_OHCI_BASE                 OMAP2_OHCI_BASE
+
+#endif
 
 /*-------------------------------------------------------------------------*/
 
@@ -28,6 +46,7 @@
 #      define   HST_IDLE_EN            (1 << 14)
 #      define   DEV_IDLE_EN            (1 << 13)
 #      define   OTG_RESET_DONE         (1 << 2)
+#      define   OTG_SOFT_RESET         (1 << 1)
 #define OTG_SYSCON_2_REG               OTG_REG32(0x08)
 #      define   OTG_EN                 (1 << 31)
 #      define   USBX_SYNCHRO           (1 << 30)
 
 /*-------------------------------------------------------------------------*/
 
+/* OMAP1 */
 #define        USB_TRANSCEIVER_CTRL_REG        __REG32(0xfffe1000 + 0x0064)
 #      define  CONF_USB2_UNI_R         (1 << 8)
 #      define  CONF_USB1_UNI_R         (1 << 7)
 #      define  CONF_USB_PWRDN_DM_R     (1 << 2)
 #      define  CONF_USB_PWRDN_DP_R     (1 << 1)
 
-
-
+/* OMAP2 */
+#define        CONTROL_DEVCONF_REG             __REG32(L4_24XX_BASE + 0x0274)
+#      define  USB_UNIDIR                      0x0
+#      define  USB_UNIDIR_TLL                  0x1
+#      define  USB_BIDIR                       0x2
+#      define  USB_BIDIR_TLL                   0x3
+#      define  USBT0WRMODEI(x)         ((x) << 22)
+#      define  USBT1WRMODEI(x)         ((x) << 20)
+#      define  USBT2WRMODEI(x)         ((x) << 18)
+#      define  USBT2TLL5PI             (1 << 17)
+#      define  USB0PUENACTLOI          (1 << 16)
+#      define  USBSTANDBYCTRL          (1 << 15)
 
 #endif /* __ASM_ARCH_OMAP_USB_H */
diff --git a/include/asm-arm/hardware/tsc2101.h b/include/asm-arm/hardware/tsc2101.h
new file mode 100644 (file)
index 0000000..4490458
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ *
+ * 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 */
index 05b029ef6371c6203b1471897490bebce8920815..664b708d2576689a80a6bb5199cb247cebfb6ffd 100644 (file)
@@ -36,4 +36,18 @@ struct flash_platform_data {
        unsigned int    nr_parts;
 };
 
+/**
+ * struct nand_platform_data - platform data describing NAND flash banks
+ * @dev_ready: tests if the NAND flash is ready (READY signal is high)
+ * @options:   bitmask for nand_chip.options
+ * @parts:     optional array of mtd_partitions for static partitioning
+ * @nr_parts:  number of mtd_partitions for static partitoning
+ */
+struct nand_platform_data {
+       int             (*dev_ready)(struct nand_platform_data *data);
+       unsigned int    options;
+       struct mtd_partition *parts;
+       unsigned int    nr_parts;
+};
+
 #endif
index e5407392afcad0413c0df46030f51e2c93c4fd5b..42f00678b362f2b684b5ec610f41d7ed8ce7d999 100644 (file)
@@ -136,6 +136,13 @@ struct tag_acorn {
        __u8 adfsdrives;
 };
 
+/* TI OMAP specific information */
+#define ATAG_BOARD       0x414f4d50
+
+struct tag_omap {
+       u8 data[0];
+};
+
 /* footbridge memory clock, see arch/arm/mach-footbridge/arch.c */
 #define ATAG_MEMCLK    0x41000402
 
@@ -161,6 +168,11 @@ struct tag {
                 */
                struct tag_acorn        acorn;
 
+               /*
+                * OMAP specific
+                 */
+                struct tag_omap         omap;
+
                /*
                 * DC21285 specific
                 */
index 10eb56b2940ad8c8b7f6775de247d552a99cc6fe..6905ec573921e27a9fbf702e54f169bd862a609b 100644 (file)
 #define CN_VAL_CIFS                     0x1
 #define CN_W1_IDX                      0x3     /* w1 communication */
 #define CN_W1_VAL                      0x1
+#define CN_IDX_SX1SND                  0x4
+#define CN_VAL_SX1SND                  0x1
+#define CN_IDX_SX1PM                   0x5
+#define CN_VAL_SX1PM                   0x1
 
 
-#define CN_NETLINK_USERS               4
+#define CN_NETLINK_USERS               6
 
 /*
  * Maximum connector's message size.
index 64177ec9a01910e71adee4d777ddb1ad49e29e6d..b700c9cb9d7f554e253886bc766b0a3e665a4bf3 100644 (file)
 #define FB_ACCEL_NV_40          46      /* nVidia Arch 40               */
 #define FB_ACCEL_XGI_VOLARI_V  47      /* XGI Volari V3XT, V5, V8      */
 #define FB_ACCEL_XGI_VOLARI_Z  48      /* XGI Volari Z7                */
+#define FB_ACCEL_OMAP1610       49     /* TI OMAP16xx                  */
 #define FB_ACCEL_NEOMAGIC_NM2070 90    /* NeoMagic NM2070              */
 #define FB_ACCEL_NEOMAGIC_NM2090 91    /* NeoMagic NM2090              */
 #define FB_ACCEL_NEOMAGIC_NM2093 92    /* NeoMagic NM2093              */
index d38778f2fbecec8ef06fca43f06b3ecc86fa5e89..8c8a9ed92f247c7c9e9cc9435246e757c3f7640a 100644 (file)
 #define I2C_DRIVERID_TLV320AIC23B 87   /* TI TLV320AIC23B audio codec  */
 #define I2C_DRIVERID_ISL1208   88      /* Intersil ISL1208 RTC         */
 
+#define I2C_DRIVERID_MISC      99      /* Whatever until sorted out    */
+
 #define I2C_DRIVERID_I2CDEV    900
 #define I2C_DRIVERID_ARP        902    /* SMBus ARP Client              */
 #define I2C_DRIVERID_ALERT      903    /* SMBus Alert Responder Client  */
index bde65c8a351939ce5aa19fc7e85c511be1037e99..8467e40de769c64304b667c20bdfe4a8e1f5c6d5 100644 (file)
@@ -336,10 +336,22 @@ struct input_absinfo {
 #define KEY_BRIGHTNESSUP       225
 #define KEY_MEDIA              226
 
-#define KEY_SWITCHVIDEOMODE    227
-#define KEY_KBDILLUMTOGGLE     228
-#define KEY_KBDILLUMDOWN       229
-#define KEY_KBDILLUMUP         230
+
+/*Zeus: these keys are defined for OMAP730 Perseus2*/
+#define KEY_STAR               227
+#define KEY_SHARP              228
+#define KEY_SOFT1              229
+#define KEY_SOFT2              230
+#define KEY_SEND               231
+#define KEY_CENTER             232
+#define KEY_HEADSETHOOK                233
+#define KEY_0_5                        234
+#define KEY_2_5                        235
+
+#define KEY_SWITCHVIDEOMODE    236
+#define KEY_KBDILLUMTOGGLE     237
+#define KEY_KBDILLUMDOWN       238
+#define KEY_KBDILLUMUP         239
 
 #define KEY_SEND               231
 #define KEY_REPLY              232
diff --git a/include/linux/netfilter_ipv4/ipt_IDLETIMER.h b/include/linux/netfilter_ipv4/ipt_IDLETIMER.h
new file mode 100644 (file)
index 0000000..89993e2
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * 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
index adb3dafd33e96a6d12c122fc62101b6c7a5c0947..c371475829b3e673b07c8a319a14b7ebfa492698 100644 (file)
@@ -5,9 +5,17 @@
  *
  * It's OK if the min/max values are zero.
  */
+enum ads7846_filter {
+       ADS7846_FILTER_OK,
+       ADS7846_FILTER_REPEAT,
+       ADS7846_FILTER_IGNORE,
+};
+
 struct ads7846_platform_data {
        u16     model;                  /* 7843, 7845, 7846. */
        u16     vref_delay_usecs;       /* 0 for external vref; etc */
+       int     keep_vref_on : 1;       /* set to keep vref on for differential
+                                        * measurements as well */
        u16     x_plate_ohms;
        u16     y_plate_ohms;
 
@@ -21,5 +29,9 @@ struct ads7846_platform_data {
        u16     debounce_rep;           /* additional consecutive good readings
                                         * required after the first two */
        int     (*get_pendown_state)(void);
+       int     (*filter_init)  (struct ads7846_platform_data *pdata,
+                                void **filter_data);
+       int     (*filter)       (void *filter_data, int data_idx, int *val);
+       void    (*filter_cleanup)(void *filter_data);
 };
 
diff --git a/include/linux/spi/tsc2102.h b/include/linux/spi/tsc2102.h
new file mode 100644 (file)
index 0000000..b779fb1
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * include/linux/spi/tsc2102.h
+ *
+ * TI TSC2102 Touchscreen, Audio and Battery control register definitions 
+ *
+ * Copyright (c) 2005 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this package; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __LINUX_SPI_TSC2102_H
+#define __LINUX_SPI_TSC2102_H
+
+struct apm_power_info;
+struct tsc2102_config {
+       int use_internal;       /* Use internal reference voltage */
+       uint32_t monitor;       /* What inputs are relevant */
+       int temp_at25c[2];      /* Thermometer calibration data */
+       void (*apm_report)(struct apm_power_info *info, int *battery);
+                               /* Report status to APM based on battery[] */
+       void *alsa_config;      /* .platform_data for the ALSA device */
+};
+
+#define TSC_BAT1       (1 << 0)
+#define TSC_BAT2       (1 << 1)
+#define TSC_AUX                (1 << 2)
+#define TSC_TEMP       (1 << 4)
+
+extern u16 tsc2102_read_sync(int page, u8 address);
+extern void tsc2102_reads_sync(int page, u8 startaddress, u16 *data,
+               int numregs);
+extern void tsc2102_write_sync(int page, u8 address, u16 data);
+
+typedef void (*tsc2102_touch_t)(int touching);
+typedef void (*tsc2102_coords_t)(int x, int y, int z1, int z2);
+typedef void (*tsc2102_ports_t)(int bat1, int bat2, int aux);
+typedef void (*tsc2102_temp_t)(int temp);
+extern int tsc2102_touch_cb(tsc2102_touch_t handler);
+extern int tsc2102_coords_cb(tsc2102_coords_t handler);
+extern int tsc2102_ports_cb(tsc2102_ports_t handler);
+extern int tsc2102_temp1_cb(tsc2102_temp_t handler);
+extern int tsc2102_temp2_cb(tsc2102_temp_t handler);
+
+#ifdef CONFIG_SOUND
+extern void tsc2102_set_volume(uint8_t left_ch, uint8_t right_ch);
+extern void tsc2102_set_mute(int left_ch, int right_ch);
+extern void tsc2102_get_mute(int *left_ch, int *right_ch);
+extern void tsc2102_dac_power(int state);
+extern int tsc2102_set_rate(int rate);
+extern void tsc2102_set_i2s_master(int state);
+extern void tsc2102_set_deemphasis(int enable);
+extern void tsc2102_set_bassboost(int enable);
+#endif
+
+extern void tsc2102_keyclick(int amplitude, int freq, int length);
+
+#define TSC2102_REG(pg, addr)          pg, addr
+
+/* Page 0, Touch Screen & Keypad Data registers */
+#define TSC2102_TS_X                   TSC2102_REG(0, 0x00)
+#define TSC2102_TS_Y                   TSC2102_REG(0, 0x01)
+#define TSC2102_TS_Z1                  TSC2102_REG(0, 0x02)
+#define TSC2102_TS_Z2                  TSC2102_REG(0, 0x03)
+#define TSC2102_TS_BAT1                        TSC2102_REG(0, 0x05)
+#define TSC2102_TS_BAT2                        TSC2102_REG(0, 0x06)
+#define TSC2102_TS_AUX                 TSC2102_REG(0, 0x07)
+#define TSC2102_TS_TEMP1               TSC2102_REG(0, 0x09)
+#define TSC2102_TS_TEMP2               TSC2102_REG(0, 0x0a)
+
+/* Page 1, Touch Screen & Keypad Control registers */
+#define TSC2102_TS_ADC_CTRL            TSC2102_REG(1, 0x00)
+#define TSC2102_TS_STATUS_CTRL         TSC2102_REG(1, 0x01)
+#define TSC2102_TS_REF_CTRL            TSC2102_REG(1, 0x03)
+#define TSC2102_TS_RESET_CTRL          TSC2102_REG(1, 0x04)
+#define TSC2102_TS_CONFIG_CTRL         TSC2102_REG(1, 0x05)
+
+/* Page 2, Audio Control registers */
+#define TSC2102_AUDIO1_CTRL            TSC2102_REG(2, 0x00)
+#define TSC2102_DAC_GAIN_CTRL          TSC2102_REG(2, 0x02)
+#define TSC2102_AUDIO2_CTRL            TSC2102_REG(2, 0x04)
+#define TSC2102_DAC_POWER_CTRL         TSC2102_REG(2, 0x05)
+#define TSC2102_AUDIO3_CTRL            TSC2102_REG(2, 0x06)
+#define TSC2102_LCH_BASS_BOOST_N0      TSC2102_REG(2, 0x07)
+#define TSC2102_LCH_BASS_BOOST_N1      TSC2102_REG(2, 0x08)
+#define TSC2102_LCH_BASS_BOOST_N2      TSC2102_REG(2, 0x09)
+#define TSC2102_LCH_BASS_BOOST_N3      TSC2102_REG(2, 0x0a)
+#define TSC2102_LCH_BASS_BOOST_N4      TSC2102_REG(2, 0x0b)
+#define TSC2102_LCH_BASS_BOOST_N5      TSC2102_REG(2, 0x0c)
+#define TSC2102_LCH_BASS_BOOST_D1      TSC2102_REG(2, 0x0d)
+#define TSC2102_LCH_BASS_BOOST_D2      TSC2102_REG(2, 0x0e)
+#define TSC2102_LCH_BASS_BOOST_D4      TSC2102_REG(2, 0x0f)
+#define TSC2102_LCH_BASS_BOOST_D5      TSC2102_REG(2, 0x10)
+#define TSC2102_RCH_BASS_BOOST_N0      TSC2102_REG(2, 0x11)
+#define TSC2102_RCH_BASS_BOOST_N1      TSC2102_REG(2, 0x12)
+#define TSC2102_RCH_BASS_BOOST_N2      TSC2102_REG(2, 0x13)
+#define TSC2102_RCH_BASS_BOOST_N3      TSC2102_REG(2, 0x14)
+#define TSC2102_RCH_BASS_BOOST_N4      TSC2102_REG(2, 0x15)
+#define TSC2102_RCH_BASS_BOOST_N5      TSC2102_REG(2, 0x16)
+#define TSC2102_RCH_BASS_BOOST_D1      TSC2102_REG(2, 0x17)
+#define TSC2102_RCH_BASS_BOOST_D2      TSC2102_REG(2, 0x18)
+#define TSC2102_RCH_BASS_BOOST_D4      TSC2102_REG(2, 0x19)
+#define TSC2102_RCH_BASS_BOOST_D5      TSC2102_REG(2, 0x1a)
+#define TSC2102_PLL1_CTRL              TSC2102_REG(2, 0x1b)
+#define TSC2102_PLL2_CTRL              TSC2102_REG(2, 0x1c)
+#define TSC2102_AUDIO4_CTRL            TSC2102_REG(2, 0x1d)
+
+/* Field masks for Audio Control 1 */
+#define AC1_WLEN(ARG)                  (((ARG) & 0x03) << 10)
+#define AC1_DATFM(ARG)                 (((ARG) & 0x03) << 8)
+#define AC1_DACFS(ARG)                 ((ARG) & 0x3f)
+
+/* Field masks for TSC2102_DAC_GAIN_CTRL */
+#define DGC_DALMU                      (1 << 15)
+#define DGC_DALVL(ARG)                 (((ARG) & 0x7f) << 8)
+#define DGC_DARMU                      (1 << 7)
+#define DGC_DARVL(ARG)                 (((ARG) & 0x7f))
+
+/* Field formats for TSC2102_AUDIO2_CTRL */
+#define AC2_KCLEN                      (1 << 15)
+#define AC2_KCLAC(ARG)                 (((ARG) & 0x07) << 12)
+#define AC2_KCLFRQ(ARG)                        (((ARG) & 0x07) << 8)
+#define AC2_KCLLN(ARG)                 (((ARG) & 0x0f) << 4)
+#define AC2_DLGAF                      (1 << 3)
+#define AC2_DRGAF                      (1 << 2)
+#define AC2_DASTC                      (1 << 1)
+
+/* Field masks for TSC2102_DAC_POWER_CTRL */
+#define CPC_PWDNC                      (1 << 15)
+#define CPC_DAODRC                     (1 << 12)
+#define CPC_DAPWDN                     (1 << 10)
+#define CPC_VGPWDN                     (1 << 8)
+#define CPC_DAPWDF                     (1 << 6)
+#define CPC_BASSBC                     (1 << 1)
+#define CPC_DEEMPF                     (0x01)
+
+/* Field masks for TSC2101_AUDIO_CTRL_3 */
+#define AC3_DMSVOL(ARG)                        (((ARG) & 0x03) << 14)
+#define AC3_REFFS                      (1 << 13)
+#define AC3_DAXFM                      (1 << 12)
+#define AC3_SLVMS                      (1 << 11)
+#define AC3_DALOVF                     (1 << 7)
+#define AC3_DAROVF                     (1 << 6)
+#define AC3_REVID(ARG)                 (((ARG) & 0x07))
+
+/* Field masks for TSC2102_PLL1_CTRL */
+#define PLL1_PLLEN                     (1 << 15)
+#define PLL1_Q_VAL(ARG)                        (((ARG) & 0x0f) << 11)
+#define PLL1_P_VAL(ARG)                        (((ARG) & 0x07) << 8)
+#define PLL1_I_VAL(ARG)                        (((ARG) & 0x3f) << 2)
+
+/* Field masks for TSC2102_PLL2_CTRL */
+#define PLL2_D_VAL(ARG)                        (((ARG) & 0x3fff) << 2)
+
+/* Field masks for TSC2101_AUDIO_CTRL_4 */
+#define AC4_DASTPD                     (1 << 14)
+
+struct tsc2102_rate_info_s {
+       u16 sample_rate;
+       u8 divisor;
+       u8 fs_44k;      /* 44.1 kHz Fsref if 1, 48 kHz if 0 */
+};
+
+#endif /* __LINUX_SPI_TSC2102_H */
diff --git a/include/linux/spi/tsc2301.h b/include/linux/spi/tsc2301.h
new file mode 100644 (file)
index 0000000..6621042
--- /dev/null
@@ -0,0 +1,207 @@
+#ifndef _LINUX_SPI_TSC2301_H
+#define _LINUX_SPI_TSC2301_H
+
+#include <linux/types.h>
+#include <linux/timer.h>
+
+struct tsc2301_platform_data {
+       /*
+        * Keypad
+        */
+       s16     reset_gpio;
+       s16     keyb_int;
+       s16     keymap[16];     /* Set a key to a negative value if not used */
+       unsigned kp_rep:1;      /* Enable keypad repeating */
+
+       /*
+        * Touchscreen
+        */
+       s16     dav_gpio;
+       s16     pen_int_gpio;
+       u16     ts_x_plate_ohm;
+       u32     ts_stab_time;   /* voltage settling time */
+       u8      ts_hw_avg;      /* HW assiseted averaging. Can be
+                                  0, 4, 8, 16 samples per reading */
+       u32     ts_max_pressure;/* Samples with bigger pressure value will
+                                  be ignored, since the corresponding X, Y
+                                  values are unreliable */
+       u32     ts_touch_pressure;      /* Pressure limit until we report a
+                                          touch event. After that we switch
+                                          to ts_max_pressure. */
+       unsigned ts_ignore_last : 1;
+
+       /*
+        * Audio
+        */
+       unsigned        pll_pdc:4;
+       unsigned        pll_a:4;
+       unsigned        pll_n:4;
+       unsigned        pll_output:1; /* Output PLL on GPIO_0 */
+
+       unsigned        mclk_ratio:2;
+       unsigned        i2s_sample_rate:4;
+       unsigned        i2s_format:2;
+       /* Mask for audio blocks to be powered down */
+       u16             power_down_blocks;
+
+       /* Called after codec has been initialized, can be NULL */
+       int (* codec_init)(struct device *tsc2301_dev);
+       /* Called when codec is being removed, can be NULL */
+       void (* codec_cleanup)(struct device *tsc2301_dev);
+       int     (*enable_clock)(struct device *dev);
+       void    (*disable_clock)(struct device *dev);
+       int     (*get_keyb_irq_state)(struct device *dev);
+
+       const struct tsc2301_mixer_gpio {
+               const char      *name;
+               unsigned        gpio:4;
+               unsigned        inverted:1;
+               unsigned        def_enable:1; /* enable by default */
+               unsigned        deactivate_on_pd:1; /* power-down flag */
+       } *mixer_gpios;
+       int     n_mixer_gpios;
+};
+
+struct tsc2301_kp;
+struct tsc2301_ts;
+struct tsc2301_mixer;
+
+struct tsc2301 {
+       struct spi_device       *spi;
+
+       s16                     reset_gpio;
+       u16                     config2_shadow;
+
+        struct tsc2301_kp      *kp;
+       struct tsc2301_ts       *ts;
+       struct tsc2301_mixer    *mixer;
+
+       int                     (*enable_clock)(struct device *dev);
+       void                    (*disable_clock)(struct device *dev);
+};
+
+
+#define TSC2301_HZ     33000000
+
+#define TSC2301_REG(page, addr)  (((page) << 11) | ((addr) << 5))
+#define TSC2301_REG_TO_PAGE(reg) (((reg) >> 11) & 0x03)
+#define TSC2301_REG_TO_ADDR(reg) (((reg) >> 5)  & 0x1f)
+
+#define TSC2301_REG_X          TSC2301_REG(0, 0)
+#define TSC2301_REG_Y          TSC2301_REG(0, 1)
+#define TSC2301_REG_Z1         TSC2301_REG(0, 2)
+#define TSC2301_REG_Z2         TSC2301_REG(0, 3)
+#define TSC2301_REG_KPDATA     TSC2301_REG(0, 4)
+#define TSC2301_REG_ADC                TSC2301_REG(1, 0)
+#define TSC2301_REG_KEY                TSC2301_REG(1, 1)
+#define TSC2301_REG_DAC                TSC2301_REG(1, 2)
+#define TSC2301_REG_REF                TSC2301_REG(1, 3)
+#define TSC2301_REG_CONFIG     TSC2301_REG(1, 5)
+#define TSC2301_REG_CONFIG2    TSC2301_REG(1, 6)
+#define TSC2301_REG_KPMASK     TSC2301_REG(1, 16)
+#define TSC2301_REG_AUDCNTL    TSC2301_REG(2, 0)
+#define TSC2301_REG_ADCVOL     TSC2301_REG(2, 1)
+#define TSC2301_REG_DACVOL     TSC2301_REG(2, 2)
+#define TSC2301_REG_BPVOL      TSC2301_REG(2, 3)
+#define TSC2301_REG_KEYCTL     TSC2301_REG(2, 4)
+#define TSC2301_REG_PD_MISC    TSC2301_REG(2, 5)
+#define TSC2301_REG_GPIO       TSC2301_REG(2, 6)
+#define TSC2301_REG_ADCLKCFG   TSC2301_REG(2, 27)
+
+#define TSC2301_REG_PD_MISC_APD                (1 << 15)
+#define TSC2301_REG_PD_MISC_AVPD       (1 << 14)
+#define TSC2301_REG_PD_MISC_ABPD       (1 << 13)
+#define TSC2301_REG_PD_MISC_HAPD       (1 << 12)
+#define TSC2301_REG_PD_MISC_MOPD       (1 << 11)
+#define TSC2301_REG_PD_MISC_DAPD       (1 << 10)
+#define TSC2301_REG_PD_MISC_ADPDL      (1 << 9)
+#define TSC2301_REG_PD_MISC_ADPDR      (1 << 8)
+#define TSC2301_REG_PD_MISC_PDSTS      (1 << 7)
+#define TSC2301_REG_PD_MISC_MIBPD      (1 << 6)
+
+/* I2S sample rate */
+#define TSC2301_I2S_SR_48000   0x00
+#define TSC2301_I2S_SR_44100   0x01
+#define TSC2301_I2S_SR_32000   0x02
+#define TSC2301_I2S_SR_24000   0x03
+#define TSC2301_I2S_SR_22050   0x04
+#define TSC2301_I2S_SR_16000   0x05
+#define TSC2301_I2S_SR_12000   0x06
+#define TSC2301_I2S_SR_11050   0x07
+#define TSC2301_I2S_SR_8000    0x08
+
+/* 16-bit, MSB-first. DAC Right-Justified, ADC Left-Justified */
+#define TSC2301_I2S_FORMAT0    0x00
+/* 20-bit, MSB-first. DAC Right-Justified, ADC Left-Justified */
+#define TSC2301_I2S_FORMAT1    0x01
+/* 20-bit, MSB-first. DAC Left-Justified, ADC Left-Justified */
+#define TSC2301_I2S_FORMAT2    0x02
+/* 20-bit, MSB-first */
+#define TSC2301_I2S_FORMAT3    0x03
+
+/* Master Clock Ratio */
+#define TSC2301_MCLK_256xFS    0x00 /* default */
+#define TSC2301_MCLK_384xFS    0x01
+#define TSC2301_MCLK_512xFS    0x02
+
+
+extern u16 tsc2301_read_reg(struct tsc2301 *tsc, int reg);
+extern void tsc2301_write_reg(struct tsc2301 *tsc, int reg, u16 val);
+extern void tsc2301_write_kbc(struct tsc2301 *tsc, int val);
+extern void tsc2301_write_pll(struct tsc2301 *tsc, int pll_n, int pll_a,
+                             int pll_pdc, int pct_e, int pll_o);
+extern void tsc2301_read_buf(struct tsc2301 *tsc, int reg, u16 *buf, int len);
+
+#define TSC2301_DECL_MOD(module)                                       \
+extern int  tsc2301_##module##_init(struct tsc2301 *tsc,               \
+                          struct tsc2301_platform_data *pdata);        \
+extern void tsc2301_##module##_exit(struct tsc2301 *tsc);              \
+extern void tsc2301_##module##_prep_for_clk_stop(struct tsc2301 *tsc); \
+extern void tsc2301_##module##_cont_after_clk_stop(struct tsc2301 *tsc);\
+extern int  tsc2301_##module##_suspend(struct tsc2301 *tsc);           \
+extern void tsc2301_##module##_resume(struct tsc2301 *tsc);
+
+#define TSC2301_DECL_EMPTY_MOD(module)                                 \
+static inline int tsc2301_##module##_init(struct tsc2301 *tsc,         \
+                          struct tsc2301_platform_data *pdata)         \
+{                                                                      \
+       return 0;                                                       \
+}                                                                      \
+static inline void tsc2301_##module##_exit(struct tsc2301 *tsc) {}     \
+static inline void tsc2301_##module##_prep_for_clk_stop                        \
+                                       (struct tsc2301 *tsc) {}        \
+static inline void tsc2301_##module##_cont_after_clk_stop              \
+                                       (struct tsc2301 *tsc) {}        \
+static inline int  tsc2301_##module##_suspend(struct tsc2301 *tsc)     \
+{                                                                      \
+       return 0;                                                       \
+}                                                                      \
+static inline void tsc2301_##module##_resume(struct tsc2301 *tsc) {}
+
+#ifdef CONFIG_SPI_TSC2301_KEYPAD
+TSC2301_DECL_MOD(kp)
+#else
+TSC2301_DECL_EMPTY_MOD(kp)
+#endif
+
+#ifdef CONFIG_SPI_TSC2301_TOUCHSCREEN
+TSC2301_DECL_MOD(ts)
+#else
+TSC2301_DECL_EMPTY_MOD(ts)
+#endif
+
+#ifdef CONFIG_SPI_TSC2301_AUDIO
+TSC2301_DECL_MOD(mixer)
+extern void tsc2301_mixer_set_power(struct device *tsc_dev, int dac, int adc);
+
+struct snd_card;
+extern int tsc2301_mixer_register_controls(struct device *tsc_dev,
+                                          struct snd_card *card);
+#else
+TSC2301_DECL_EMPTY_MOD(mixer)
+#endif
+
+extern void tsc2301_enable_mclk(struct device *tsc_dev);
+extern void tsc2301_disable_mclk(struct device *tsc_dev);
+
+#endif
diff --git a/include/linux/usb/musb.h b/include/linux/usb/musb.h
new file mode 100644 (file)
index 0000000..e1902df
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * This is used to for host and peripheral modes of the driver for
+ * Inventra (Multidrop) Highspeed Dual-Role Controllers:  (M)HDRC.
+ *
+ * Board initialization should put one of these into dev->platform_data,
+ * probably on some platform_device named "musb_hdrc".  It encapsulates
+ * key configuration differences between boards.
+ */
+
+/* The USB role is defined by the connector used on the board, so long as
+ * standards are being followed.  (Developer boards sometimes won't.)
+ */
+enum musb_mode {
+       MUSB_UNDEFINED = 0,
+       MUSB_HOST,              /* A or Mini-A connector */
+       MUSB_PERIPHERAL,        /* B or Mini-B connector */
+       MUSB_OTG                /* Mini-AB connector */
+};
+
+struct musb_hdrc_platform_data {
+       /* MUSB_HOST, MUSB_PERIPHERAL, or MUSB_OTG */
+       u8              mode;
+
+       /* (HOST or OTG) switch VBUS on/off */
+       int             (*set_vbus)(struct device *dev, int is_on);
+
+       /* (HOST or OTG) mA/2 power supplied on (default = 8mA) */
+       u8              power;
+
+       /* (PERIPHERAL) mA/2 max power consumed (default = 100mA) */
+       u8              min_power;
+
+       /* (HOST or OTG) msec/2 after VBUS on till power good */
+       u8              potpgt;
+
+       /* TBD:  chip defaults should probably go someplace else,
+        * e.g. number of tx/rx endpoints, etc
+        */
+       unsigned        multipoint:1;
+
+       /* Power the device on or off */
+       int             (*set_power)(int state);
+};
+
+
+/* TUSB 6010 support */
+
+#define        TUSB6010_OSCCLK_60      16667   /* psec/clk @ 60.0 MHz */
+#define        TUSB6010_REFCLK_24      41667   /* psec/clk @ 24.0 MHz XI */
+#define        TUSB6010_REFCLK_19      52633   /* psec/clk @ 19.2 MHz CLKIN */
+
+#ifdef CONFIG_ARCH_OMAP2
+
+extern int __init tusb6010_setup_interface(
+               struct musb_hdrc_platform_data *data,
+               unsigned ps_refclk, unsigned waitpin,
+               unsigned async_cs, unsigned sync_cs,
+               unsigned irq, unsigned dmachan);
+
+extern int tusb6010_platform_retime(unsigned is_refclk);
+
+#endif /* OMAP2 */
index c770e1a4e882289f66ae0e54451ba186f09c03d2..981d7aa5bb0424aafc1ed4e9e64fd0e3f285d681 100644 (file)
 
 #define __LOG_BUF_LEN  (1 << CONFIG_LOG_BUF_SHIFT)
 
+#ifdef        CONFIG_DEBUG_LL
+extern void printascii(char *);
+#endif
+
 /* printk's without a loglevel use this.. */
 #define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */
 
@@ -445,12 +449,23 @@ static void zap_locks(void)
        init_MUTEX(&console_sem);
 }
 
-#if defined(CONFIG_PRINTK_TIME)
-static int printk_time = 1;
-#else
 static int printk_time = 0;
-#endif
-module_param(printk_time, int, S_IRUGO | S_IWUSR);
+
+#ifdef CONFIG_PRINTK_TIME
+
+/*
+ * Initialize printk time. Note that on some systems sched_clock()
+ * does not work until timer is initialized.
+ */
+static int __init printk_time_init(void)
+{
+       printk_time = 1;
+
+       return 0;
+}
+subsys_initcall(printk_time_init);
+
+#else
 
 static int __init printk_time_setup(char *str)
 {
@@ -462,6 +477,8 @@ static int __init printk_time_setup(char *str)
 
 __setup("time", printk_time_setup);
 
+#endif
+
 __attribute__((weak)) unsigned long long printk_clock(void)
 {
        return sched_clock();
@@ -537,6 +554,10 @@ asmlinkage int vprintk(const char *fmt, va_list args)
        /* Emit the output into the temporary buffer */
        printed_len = vscnprintf(printk_buf, sizeof(printk_buf), fmt, args);
 
+#ifdef CONFIG_DEBUG_LL
+       printascii(printk_buf);
+#endif
+
        /*
         * Copy the output into log_buf.  If the caller didn't provide
         * appropriate log level tags, we insert them here
index 47bd3ad18b71eda5ca14eff95d9a67fd609eb59f..dfdab926d2cdf2f8b7aeaeab14f7314bdd25d556 100644 (file)
@@ -462,6 +462,16 @@ config IP_NF_TARGET_SAME
 
          To compile it as a module, choose M here.  If unsure, say N.
 
+config IP_NF_TARGET_IDLETIMER
+       tristate  "IDLETIMER target support"
+       depends on IP_NF_IPTABLES
+       help
+         This option adds a `IDLETIMER' target. Each matching packet resets
+         the timer associated with input and/or output interfaces. Timer
+         expiry causes kobject uevent. Idle timer can be read via sysfs.
+
+         To compile it as a module, choose M here.  If unsure, say N.
+
 config IP_NF_NAT_SNMP_BASIC
        tristate "Basic SNMP-ALG support (EXPERIMENTAL)"
        depends on EXPERIMENTAL && IP_NF_NAT
index 16d177b71bf82444c901b9b6cc6c5fe4480d501f..80fe6a019b6812abd5be09e34c6a542ddc0f85ac 100644 (file)
@@ -100,6 +100,7 @@ obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o
 obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
 obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o
 obj-$(CONFIG_IP_NF_TARGET_SAME) += ipt_SAME.o
+obj-$(CONFIG_IP_NF_TARGET_IDLETIMER) += ipt_IDLETIMER.o
 obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o
 obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o
 obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o
diff --git a/net/ipv4/netfilter/ipt_IDLETIMER.c b/net/ipv4/netfilter/ipt_IDLETIMER.c
new file mode 100644 (file)
index 0000000..a493858
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+ * 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_ipv4/ip_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 class_device *, char *buf);
+static ssize_t utimer_attr_store(struct class_device *,
+                                const char *buf, size_t count);
+
+struct utimer_t {
+       char name[IFNAMSIZ];
+       struct list_head entry;
+       struct timer_list timer;
+       struct work_struct work;
+};
+
+static LIST_HEAD(active_utimer_head);
+static DEFINE_SPINLOCK(list_lock);
+static CLASS_DEVICE_ATTR(idletimer, 0644, utimer_attr_show, utimer_attr_store);
+
+static void utimer_delete(struct utimer_t *timer)
+{
+       DEBUGP("Deleting timer '%s'\n", timer->name);
+
+       list_del(&timer->entry);
+       del_timer_sync(&timer->timer);
+       kfree(timer);
+}
+
+static void utimer_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(timer->name);
+
+       if (netdev != NULL) {
+               sysfs_notify(&netdev->class_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 class_device *dev, char *buf)
+{
+       struct utimer_t *timer;
+       unsigned long expires = 0;
+
+       spin_lock_bh(&list_lock);
+       timer = __utimer_find(dev->class_id);
+       if (timer)
+               expires = timer->timer.expires;
+       spin_unlock_bh(&list_lock);
+
+       if (expires)
+               return sprintf(buf, "%lu\n", (expires-jiffies) / HZ);
+
+       return sprintf(buf, "0\n");
+}
+
+static ssize_t utimer_attr_store(struct class_device *dev,
+                                const char *buf, size_t count)
+{
+       int expires;
+
+       if (sscanf(buf, "%d", &expires) == 1) {
+               if (expires > 0)
+                       utimer_modify(dev->class_id,
+                                     jiffies+HZ*(unsigned long)expires);
+       }
+
+       return count;
+}
+
+static int utimer_notifier_call(struct notifier_block *this,
+                               unsigned long event, void *ptr)
+{
+       struct net_device *dev = ptr;
+
+       switch (event) {
+       case NETDEV_UP:
+               DEBUGP("NETDEV_UP: %s\n", dev->name);
+               class_device_create_file(&dev->class_dev,
+                                        &class_device_attr_idletimer);
+               break;
+       case NETDEV_DOWN:
+               DEBUGP("NETDEV_DOWN: %s\n", dev->name);
+               class_device_remove_file(&dev->class_dev,
+                                        &class_device_attr_idletimer);
+               break;
+       }
+
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block utimer_notifier_block = {
+       .notifier_call  = utimer_notifier_call,
+};
+
+
+static int utimer_init(void)
+{
+        return register_netdevice_notifier(&utimer_notifier_block);
+}
+
+static void utimer_fini(void)
+{
+       struct utimer_t *entry, *next;
+       struct net_device *dev;
+
+       list_for_each_entry_safe(entry, next, &active_utimer_head, entry)
+               utimer_delete(entry);
+
+       rtnl_lock();
+       unregister_netdevice_notifier(&utimer_notifier_block);
+       for (dev = dev_base; dev; dev = dev->next)
+               utimer_notifier_call(&utimer_notifier_block,
+                                    NETDEV_DOWN, dev);
+       rtnl_unlock();
+}
+
+/*
+ * The actual iptables plugin.
+ */
+static unsigned int ipt_idletimer_target(struct sk_buff **pskb,
+                                        const struct net_device *in,
+                                        const struct net_device *out,
+                                        unsigned int hooknum,
+                                        const struct xt_target *xttarget,
+                                        const void *targinfo,
+                                        void *userinfo)
+{
+       struct ipt_idletimer_info *target = (struct ipt_idletimer_info*) targinfo;
+       unsigned long expires;
+
+       expires = jiffies + HZ*target->timeout;
+
+       if (in != NULL)
+               utimer_modify(in->name, expires);
+
+       if (out != NULL)
+               utimer_modify(out->name, expires);
+
+       return IPT_CONTINUE;
+}
+
+static int ipt_idletimer_checkentry(const char *tablename,
+                                   const void *e,
+                                   const struct xt_target *target,
+                                   void *targinfo,
+                                   unsigned int targinfosize,
+                                   unsigned int hookmask)
+{
+       struct ipt_idletimer_info *info =
+               (struct ipt_idletimer_info *) targinfo;
+
+       if (targinfosize != IPT_ALIGN(sizeof(struct ipt_idletimer_info))) {
+               DEBUGP("targinfosize %u != 0\n", targinfosize);
+               return 0;
+       }
+
+       if (info->timeout == 0) {
+               DEBUGP("timeout value is zero\n");
+               return 0;
+       }
+
+       return 1;
+}
+
+static struct ipt_target ipt_idletimer = {
+       .name           = "IDLETIMER",
+       .target         = ipt_idletimer_target,
+       .checkentry     = ipt_idletimer_checkentry,
+       .me             = THIS_MODULE,
+       .targetsize     = sizeof(struct ipt_idletimer_info),
+};
+
+static int __init init(void)
+{
+       int ret;
+
+       ret = utimer_init();
+       if (ret)
+               return ret;
+
+       if (ipt_register_target(&ipt_idletimer)) {
+               utimer_fini();
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void __exit fini(void)
+{
+       ipt_unregister_target(&ipt_idletimer);
+       utimer_fini();
+}
+
+module_init(init);
+module_exit(fini);
+
+MODULE_AUTHOR("Timo Teras <ext-timo.teras@nokia.com>");
+MODULE_DESCRIPTION("iptables idletimer target module");
+MODULE_LICENSE("GPL");
index 2e4a5e0d16db3726755dea8c8930f35138927395..4dc323f908955bf72d61f9fc11eeb1f42280eb41 100644 (file)
@@ -33,4 +33,57 @@ config SND_PXA2XX_AC97
          Say Y or M if you want to support any AC97 codec attached to
          the PXA2xx AC97 interface.
 
+config SND_OMAP_AIC23
+       tristate "OMAP AIC23 alsa driver (osk5912)"
+       depends on ARCH_OMAP && SND
+       select SND_PCM
+       select I2C
+       select I2C_OMAP if ARCH_OMAP
+       select OMAP_MCBSP
+       select SENSORS_TLV320AIC23
+       help
+         Say Y here if you have a OSK platform board
+         and want to use its AIC23 audio chip.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-omap-aic23.
+         
+config SND_OMAP_TSC2101
+       tristate "OMAP TSC2101 alsa driver"
+       depends on ARCH_OMAP && SND
+       select SND_PCM
+         select OMAP_TSC2101
+         select OMAP_UWIRE if ARCH_OMAP
+        select OMAP_MCBSP
+       help
+         Say Y here if you have a OMAP platform board
+         and want to use its TSC2101 audio chip. Driver has
+         been tested with H2 and iPAQ h6300.
+         To compile this driver as a module, choose M here: the module
+         will be called snd-omap-tsc2101.
+
+config SND_SX1
+       tristate "Siemens SX1 Egold alsa driver"
+       depends on ARCH_OMAP && SND
+       select SND_PCM
+       select OMAP_MCBSP
+       help
+         Say Y here if you have a OMAP310 based Siemens SX1.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-omap-sx1.
+
+config SND_OMAP_TSC2102
+       tristate "OMAP TSC2102 alsa driver"
+       depends on ARCH_OMAP && SND
+       select SND_PCM
+       select TSC2102
+       help
+         Say Y here if you have an OMAP platform board
+         and want to use its TSC2102 audio chip.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-omap-tsc2102.
+
 endmenu
index 4ef6dd00c6eeafb9916378ad7098b642a309a0cc..bd12f53404a6c1c975db9754381bdc14096c532c 100644 (file)
@@ -13,3 +13,5 @@ snd-pxa2xx-pcm-objs           := pxa2xx-pcm.o
 
 obj-$(CONFIG_SND_PXA2XX_AC97)  += snd-pxa2xx-ac97.o
 snd-pxa2xx-ac97-objs           := pxa2xx-ac97.o
+
+obj-$(CONFIG_SND) += omap/
diff --git a/sound/arm/omap/Makefile b/sound/arm/omap/Makefile
new file mode 100644 (file)
index 0000000..c6bebac
--- /dev/null
@@ -0,0 +1,15 @@
+#
+## Makefile for ALSA OMAP
+#
+#
+obj-$(CONFIG_SND_OMAP_AIC23) += snd-omap-alsa-aic23.o
+snd-omap-alsa-aic23-objs := omap-alsa.o omap-alsa-dma.o omap-alsa-aic23.o omap-alsa-aic23-mixer.o
+
+obj-$(CONFIG_SND_OMAP_TSC2101) += snd-omap-alsa-tsc2101.o
+snd-omap-alsa-tsc2101-objs := omap-alsa.o omap-alsa-dma.o omap-alsa-tsc2101.o omap-alsa-tsc2101-mixer.o
+
+obj-$(CONFIG_SND_OMAP_TSC2102) += snd-omap-alsa-tsc2102.o
+snd-omap-alsa-tsc2102-objs := omap-alsa.o omap-alsa-dma.o omap-alsa-tsc2102.o omap-alsa-tsc2102-mixer.o
+
+obj-$(CONFIG_SND_SX1) += snd-omap-alsa-sx1.o
+snd-omap-alsa-sx1-objs := omap-alsa.o omap-alsa-dma.o omap-alsa-sx1.o omap-alsa-sx1-mixer.o
diff --git a/sound/arm/omap/omap-alsa-aic23-mixer.c b/sound/arm/omap/omap-alsa-aic23-mixer.c
new file mode 100644 (file)
index 0000000..b4332fe
--- /dev/null
@@ -0,0 +1,495 @@
+/*
+ * sound/arm/omap/omap-alsa-aic23-mixer.c
+ *
+ * Alsa Driver Mixer for generic codecs for omap boards
+ *
+ * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ * Written by David Cohen, Daniel Petrini
+ *            {david.cohen, daniel.petrini}@indt.org.br
+ *
+ * Based on es1688_lib.c,
+ * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the  GNU General Public License along
+ * with this program; if not, write  to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * History:
+ *
+ * 2005-08-02   INdT Kernel Team - Alsa mixer driver for omap osk.
+ *                             Creation of new file omap-alsa-mixer.c.
+ *                             Initial version with aic23 codec for osk5912
+ */
+
+#include <sound/driver.h>
+#include <asm/arch/aic23.h>
+
+#include <asm/arch/omap-alsa.h>
+#include "omap-alsa-aic23.h"
+#include <sound/initval.h>
+#include <sound/control.h>
+
+MODULE_AUTHOR("David Cohen, Daniel Petrini - INdT");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("OMAP Alsa mixer driver for ALSA");
+
+/*
+ * Codec dependent region
+ */
+
+/* Codec AIC23 */
+#if defined(CONFIG_SENSORS_TLV320AIC23) || defined (CONFIG_SENSORS_TLV320AIC23_MODULE)
+
+extern void audio_aic23_write(u8, u16);
+
+#define MIXER_NAME                  "Mixer AIC23"
+#define SND_OMAP_WRITE(reg, val)     audio_aic23_write(reg, val)
+
+#endif
+
+/* Callback Functions */
+#define OMAP_BOOL(xname, xindex, reg, reg_index, mask, invert) \
+{ \
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+       .name = xname, \
+       .index = xindex, \
+       .info = snd_omap_info_bool, \
+       .get = snd_omap_get_bool, \
+       .put = snd_omap_put_bool, \
+       .private_value = reg | (reg_index << 8) | (invert << 10) | (mask << 12) \
+}
+
+#define OMAP_MUX(xname, reg, reg_index, mask) \
+{ \
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+       .name = xname, \
+       .info = snd_omap_info_mux, \
+       .get = snd_omap_get_mux, \
+       .put = snd_omap_put_mux, \
+       .private_value = reg | (reg_index << 8) | (mask << 10) \
+}
+
+#define OMAP_SINGLE(xname, xindex, reg, reg_index, reg_val, mask) \
+{\
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+       .name = xname, \
+       .index = xindex, \
+       .info = snd_omap_info_single, \
+       .get = snd_omap_get_single, \
+       .put = snd_omap_put_single, \
+       .private_value = reg | (reg_val << 8) | (reg_index << 16) | (mask << 18) \
+}
+
+#define OMAP_DOUBLE(xname, xindex, left_reg, right_reg, reg_index, mask) \
+{\
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+       .name = xname, \
+       .index = xindex, \
+       .info = snd_omap_info_double, \
+       .get = snd_omap_get_double, \
+       .put = snd_omap_put_double, \
+       .private_value = left_reg | (right_reg << 8) | (reg_index << 16) | (mask << 18) \
+}
+
+/* Local Registers */
+enum snd_device_index {
+       PCM_INDEX = 0,
+       LINE_INDEX,
+       AAC_INDEX, /* Analog Audio Control: reg = l_reg */
+};
+
+struct {
+       u16 l_reg;
+       u16 r_reg;
+       u8 sw;
+} omap_regs[3];
+
+#ifdef CONFIG_PM
+struct {
+       u16 l_reg;
+       u16 r_reg;
+       u8 sw;
+} omap_pm_regs[3];
+#endif
+
+u16 snd_sidetone[6] = {
+       SIDETONE_18,
+       SIDETONE_12,
+       SIDETONE_9,
+       SIDETONE_6,
+       SIDETONE_0,
+       0
+};
+
+/* Begin Bool Functions */
+
+static int snd_omap_info_bool(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1;
+
+       return 0;
+}
+
+static int snd_omap_get_bool(snd_kcontrol_t * kcontrol,
+                                snd_ctl_elem_value_t * ucontrol)
+{
+       int mic_index = (kcontrol->private_value >> 8) & 0x03;
+       u16 mask = (kcontrol->private_value >> 12) & 0xff;
+       int invert = (kcontrol->private_value >> 10) & 0x03;
+
+       if (invert)
+               ucontrol->value.integer.value[0] =
+                       (omap_regs[mic_index].l_reg & mask) ? 0 : 1;
+       else
+               ucontrol->value.integer.value[0] =
+                       (omap_regs[mic_index].l_reg & mask) ? 1 : 0;
+
+       return 0;
+}
+
+static int snd_omap_put_bool(snd_kcontrol_t * kcontrol,
+                                snd_ctl_elem_value_t * ucontrol)
+{
+       int mic_index = (kcontrol->private_value >> 8) & 0x03;
+       u16 mask = (kcontrol->private_value >> 12) & 0xff;
+       u16 reg = kcontrol->private_value & 0xff;
+       int invert = (kcontrol->private_value >> 10) & 0x03;
+
+       int changed = 1;
+
+       if (ucontrol->value.integer.value[0]) /* XOR */
+               if (invert)
+                       omap_regs[mic_index].l_reg &= ~mask;
+               else
+                       omap_regs[mic_index].l_reg |= mask;
+       else
+               if (invert)
+                       omap_regs[mic_index].l_reg |= mask;
+               else
+                       omap_regs[mic_index].l_reg &= ~mask;
+
+       SND_OMAP_WRITE(reg, omap_regs[mic_index].l_reg);
+
+       return changed;
+}
+
+/* End Bool Functions */
+
+/* Begin Mux Functions */
+
+static int snd_omap_info_mux(snd_kcontrol_t *kcontrol,
+                                snd_ctl_elem_info_t * uinfo)
+{
+       /* Mic = 0
+        * Line = 1 */
+       static char *texts[2] = { "Mic", "Line" };
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = 2;
+
+       if (uinfo->value.enumerated.item > 1)
+               uinfo->value.enumerated.item = 1;
+
+       strcpy(uinfo->value.enumerated.name,
+                       texts[uinfo->value.enumerated.item]);
+
+       return 0;
+}
+
+static int snd_omap_get_mux(snd_kcontrol_t * kcontrol,
+                               snd_ctl_elem_value_t * ucontrol)
+{
+       u16 mask = (kcontrol->private_value >> 10) & 0xff;
+       int mux_index = (kcontrol->private_value >> 8) & 0x03;
+
+       ucontrol->value.enumerated.item[0] =
+               (omap_regs[mux_index].l_reg & mask) ? 0 /* Mic */ : 1 /* Line */;
+
+       return 0;
+}
+
+static int snd_omap_put_mux(snd_kcontrol_t * kcontrol,
+                               snd_ctl_elem_value_t * ucontrol)
+{
+       u16 reg = kcontrol->private_value & 0xff;
+       u16 mask = (kcontrol->private_value >> 10) & 0xff;
+       int mux_index = (kcontrol->private_value >> 8) & 0x03;
+
+       int changed = 1;
+
+       if (!ucontrol->value.integer.value[0])
+               omap_regs[mux_index].l_reg |= mask; /* AIC23: Mic */
+       else
+               omap_regs[mux_index].l_reg &= ~mask; /* AIC23: Line */
+
+       SND_OMAP_WRITE(reg, omap_regs[mux_index].l_reg);
+
+       return changed;
+}
+
+/* End Mux Functions */
+
+/* Begin Single Functions */
+
+static int snd_omap_info_single(snd_kcontrol_t *kcontrol,
+                               snd_ctl_elem_info_t * uinfo)
+{
+       int mask = (kcontrol->private_value >> 18) & 0xff;
+       int reg_val = (kcontrol->private_value >> 8) & 0xff;
+
+       uinfo->type = mask ? SNDRV_CTL_ELEM_TYPE_INTEGER :
+                       SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = reg_val-1;
+
+       return 0;
+}
+
+static int snd_omap_get_single(snd_kcontrol_t * kcontrol,
+                                       snd_ctl_elem_value_t * ucontrol)
+{
+       u16 reg_val = (kcontrol->private_value >> 8) & 0xff;
+
+       ucontrol->value.integer.value[0] = snd_sidetone[reg_val];
+
+       return 0;
+}
+
+static int snd_omap_put_single(snd_kcontrol_t * kcontrol,
+                                       snd_ctl_elem_value_t * ucontrol)
+{
+       u16 reg_index = (kcontrol->private_value >> 16) & 0x03;
+       u16 mask = (kcontrol->private_value >> 18) & 0x1ff;
+       u16 reg = kcontrol->private_value & 0xff;
+       u16 reg_val = (kcontrol->private_value >> 8) & 0xff;
+
+       int changed = 0;
+
+       /* Volume */
+       if ((omap_regs[reg_index].l_reg !=
+                (ucontrol->value.integer.value[0] & mask))) {
+               changed = 1;
+
+               omap_regs[reg_index].l_reg &= ~mask;
+               omap_regs[reg_index].l_reg |=
+                       snd_sidetone[ucontrol->value.integer.value[0]];
+
+               snd_sidetone[reg_val] = ucontrol->value.integer.value[0];
+               SND_OMAP_WRITE(reg, omap_regs[reg_index].l_reg);
+       } else {
+               changed = 0;
+       }
+
+       return changed;
+}
+
+/* End Single Functions */
+
+/* Begin Double Functions */
+
+static int snd_omap_info_double(snd_kcontrol_t *kcontrol,
+                               snd_ctl_elem_info_t * uinfo)
+{
+       /* mask == 0 : Switch
+        * mask != 0 : Volume */
+       int mask = (kcontrol->private_value >> 18) & 0xff;
+
+       uinfo->type = mask ? SNDRV_CTL_ELEM_TYPE_INTEGER :
+                       SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = mask ? 2 : 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = mask ? mask : 1;
+
+       return 0;
+}
+
+static int snd_omap_get_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+       /* mask == 0 : Switch
+        * mask != 0 : Volume */
+       int mask = (kcontrol->private_value >> 18) & 0xff;
+       int vol_index = (kcontrol->private_value >> 16) & 0x03;
+
+       if (!mask) {
+               /* Switch */
+               ucontrol->value.integer.value[0] = omap_regs[vol_index].sw;
+       } else {
+               /* Volume */
+               ucontrol->value.integer.value[0] = omap_regs[vol_index].l_reg;
+               ucontrol->value.integer.value[1] = omap_regs[vol_index].r_reg;
+       }
+
+       return 0;
+}
+
+static int snd_omap_put_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+       /* mask == 0 : Switch
+        * mask != 0 : Volume */
+       int vol_index = (kcontrol->private_value >> 16) & 0x03;
+       int mask = (kcontrol->private_value >> 18) & 0xff;
+       int left_reg = kcontrol->private_value & 0xff;
+       int right_reg = (kcontrol->private_value >> 8) & 0xff;
+
+       int changed = 0;
+
+       if (!mask) {
+               /* Switch */
+               if (!ucontrol->value.integer.value[0]) {
+                       SND_OMAP_WRITE(left_reg, 0x00);
+                       SND_OMAP_WRITE(right_reg, 0x00);
+               } else {
+                       SND_OMAP_WRITE(left_reg, omap_regs[vol_index].l_reg);
+                       SND_OMAP_WRITE(right_reg, omap_regs[vol_index].r_reg);
+               }
+               changed = 1;
+               omap_regs[vol_index].sw = ucontrol->value.integer.value[0];
+       } else {
+               /* Volume */
+               if ((omap_regs[vol_index].l_reg != (ucontrol->value.integer.value[0] & mask)) ||
+                       (omap_regs[vol_index].r_reg != (ucontrol->value.integer.value[1] & mask))) {
+                       changed = 1;
+
+                       omap_regs[vol_index].l_reg &= ~mask;
+                       omap_regs[vol_index].r_reg &= ~mask;
+                       omap_regs[vol_index].l_reg |=
+                               (ucontrol->value.integer.value[0] & mask);
+                       omap_regs[vol_index].r_reg |=
+                               (ucontrol->value.integer.value[1] & mask);
+                       if (omap_regs[vol_index].sw) {
+                               /* write to registers only if sw is actived */
+                               SND_OMAP_WRITE(left_reg, omap_regs[vol_index].l_reg);
+                               SND_OMAP_WRITE(right_reg, omap_regs[vol_index].r_reg);
+                       }
+               }
+               else {
+                       changed = 0;
+               }
+       }
+
+       return changed;
+}
+
+/* End Double Functions */
+
+static snd_kcontrol_new_t snd_omap_controls[] = {
+       OMAP_DOUBLE("PCM Playback Switch", 0, LEFT_CHANNEL_VOLUME_ADDR, RIGHT_CHANNEL_VOLUME_ADDR,
+                    PCM_INDEX, 0x00),
+       OMAP_DOUBLE("PCM Playback Volume", 0, LEFT_CHANNEL_VOLUME_ADDR, RIGHT_CHANNEL_VOLUME_ADDR,
+                    PCM_INDEX, OUTPUT_VOLUME_MASK),
+       OMAP_BOOL("Line Playback Switch", 0, ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, BYPASS_ON, 0),
+       OMAP_DOUBLE("Line Capture Switch", 0, LEFT_LINE_VOLUME_ADDR, RIGHT_LINE_VOLUME_ADDR,
+                    LINE_INDEX, 0x00),
+       OMAP_DOUBLE("Line Capture Volume", 0, LEFT_LINE_VOLUME_ADDR, RIGHT_LINE_VOLUME_ADDR,
+                        LINE_INDEX, INPUT_VOLUME_MASK),
+       OMAP_BOOL("Mic Playback Switch", 0, ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, STE_ENABLED, 0),
+       OMAP_SINGLE("Mic Playback Volume", 0, ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, 5, SIDETONE_MASK),
+       OMAP_BOOL("Mic Capture Switch", 0, ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, MICM_MUTED, 1),
+       OMAP_BOOL("Mic Booster Playback Switch", 0, ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, MICB_20DB, 0),
+       OMAP_MUX("Capture Source", ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, INSEL_MIC),
+};
+
+#ifdef CONFIG_PM
+
+void snd_omap_suspend_mixer(void)
+{
+       /* Saves current values to wake-up correctly */
+       omap_pm_regs[LINE_INDEX].l_reg = omap_regs[LINE_INDEX].l_reg;
+       omap_pm_regs[LINE_INDEX].r_reg = omap_regs[LINE_INDEX].l_reg;
+       omap_pm_regs[LINE_INDEX].sw = omap_regs[LINE_INDEX].sw;
+
+       omap_pm_regs[AAC_INDEX].l_reg = omap_regs[AAC_INDEX].l_reg;
+
+       omap_pm_regs[PCM_INDEX].l_reg = omap_regs[PCM_INDEX].l_reg;
+       omap_pm_regs[PCM_INDEX].r_reg = omap_regs[PCM_INDEX].r_reg;
+       omap_pm_regs[PCM_INDEX].sw = omap_regs[PCM_INDEX].sw;
+}
+
+void snd_omap_resume_mixer(void)
+{
+       /* Line's saved values */
+       omap_regs[LINE_INDEX].l_reg = omap_pm_regs[LINE_INDEX].l_reg;
+       omap_regs[LINE_INDEX].r_reg = omap_pm_regs[LINE_INDEX].l_reg;
+       omap_regs[LINE_INDEX].sw = omap_pm_regs[LINE_INDEX].sw;
+       SND_OMAP_WRITE(LEFT_LINE_VOLUME_ADDR, omap_pm_regs[LINE_INDEX].l_reg);
+       SND_OMAP_WRITE(RIGHT_LINE_VOLUME_ADDR, omap_pm_regs[LINE_INDEX].l_reg);
+
+       /* Analog Audio Control's saved values */
+       omap_regs[AAC_INDEX].l_reg = omap_pm_regs[AAC_INDEX].l_reg;
+       SND_OMAP_WRITE(ANALOG_AUDIO_CONTROL_ADDR, omap_regs[AAC_INDEX].l_reg);
+
+       /* Headphone's saved values */
+       omap_regs[PCM_INDEX].l_reg = omap_pm_regs[PCM_INDEX].l_reg;
+       omap_regs[PCM_INDEX].r_reg = omap_pm_regs[PCM_INDEX].r_reg;
+       omap_regs[PCM_INDEX].sw = omap_pm_regs[PCM_INDEX].sw;
+       SND_OMAP_WRITE(LEFT_CHANNEL_VOLUME_ADDR, omap_pm_regs[PCM_INDEX].l_reg);
+       SND_OMAP_WRITE(RIGHT_CHANNEL_VOLUME_ADDR, omap_pm_regs[PCM_INDEX].r_reg);
+}
+#endif
+
+void snd_omap_init_mixer(void)
+{
+       u16 vol_reg;
+
+       /* Line's default values */
+       omap_regs[LINE_INDEX].l_reg = DEFAULT_INPUT_VOLUME & INPUT_VOLUME_MASK;
+       omap_regs[LINE_INDEX].r_reg = DEFAULT_INPUT_VOLUME & INPUT_VOLUME_MASK;
+       omap_regs[LINE_INDEX].sw = 0;
+       SND_OMAP_WRITE(LEFT_LINE_VOLUME_ADDR, DEFAULT_INPUT_VOLUME & INPUT_VOLUME_MASK);
+       SND_OMAP_WRITE(RIGHT_LINE_VOLUME_ADDR, DEFAULT_INPUT_VOLUME & INPUT_VOLUME_MASK);
+
+       /* Analog Audio Control's default values */
+       omap_regs[AAC_INDEX].l_reg = DEFAULT_ANALOG_AUDIO_CONTROL;
+
+       /* Headphone's default values */
+       vol_reg = LZC_ON;
+       vol_reg &= ~OUTPUT_VOLUME_MASK;
+       vol_reg |= DEFAULT_OUTPUT_VOLUME;
+       omap_regs[PCM_INDEX].l_reg = DEFAULT_OUTPUT_VOLUME;
+       omap_regs[PCM_INDEX].r_reg = DEFAULT_OUTPUT_VOLUME;
+       omap_regs[PCM_INDEX].sw = 1;
+       SND_OMAP_WRITE(LEFT_CHANNEL_VOLUME_ADDR, vol_reg);
+       SND_OMAP_WRITE(RIGHT_CHANNEL_VOLUME_ADDR, vol_reg);
+}
+
+int snd_omap_mixer(struct snd_card_omap_codec *chip)
+{
+       snd_card_t *card;
+       unsigned int idx;
+       int err;
+
+       snd_assert(chip != NULL && chip->card != NULL, return -EINVAL);
+
+       card = chip->card;
+
+       strcpy(card->mixername, MIXER_NAME);
+
+       /* Registering alsa mixer controls */
+       for (idx = 0; idx < ARRAY_SIZE(snd_omap_controls); idx++)
+               if ((err = snd_ctl_add(card,
+                       snd_ctl_new1(&snd_omap_controls[idx], chip))) < 0)
+                       return err;
+
+       return 0;
+}
diff --git a/sound/arm/omap/omap-alsa-aic23.c b/sound/arm/omap/omap-alsa-aic23.c
new file mode 100644 (file)
index 0000000..b483961
--- /dev/null
@@ -0,0 +1,325 @@
+/*
+ * arch/arm/mach-omap1/omap-alsa-aic23.c
+ * 
+ * Alsa codec Driver for AIC23 chip on OSK5912 platform board
+ *
+ * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ * Written by Daniel Petrini, David Cohen, Anderson Briglia
+ *            {daniel.petrini, david.cohen, anderson.briglia}@indt.org.br
+ *
+ * Copyright (C) 2006 Mika Laitio <lamikr@cc.jyu.fi>
+ * 
+ * Based in former alsa driver for osk and oss driver
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <linux/clk.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/aic23.h>
+
+#include <asm/arch/omap-alsa.h>
+#include "omap-alsa-aic23.h"
+
+static struct clk *aic23_mclk = 0;
+
+/* aic23 related */
+static const struct aic23_samplerate_reg_info
+ rate_reg_info[NUMBER_SAMPLE_RATES_SUPPORTED] = {
+       {4000, 0x06, 1},                /*  4000 */
+       {8000, 0x06, 0},                /*  8000 */
+       {16000, 0x0C, 1},               /* 16000 */
+       {22050, 0x11, 1},               /* 22050 */
+       {24000, 0x00, 1},               /* 24000 */
+       {32000, 0x0C, 0},               /* 32000 */
+       {44100, 0x11, 0},               /* 44100 */
+       {48000, 0x00, 0},               /* 48000 */
+       {88200, 0x1F, 0},               /* 88200 */
+       {96000, 0x0E, 0},               /* 96000 */
+};
+
+/*
+ * Hardware capabilities
+ */
+ /*
+ * DAC USB-mode sampling rates (MCLK = 12 MHz)
+ * The rates and rate_reg_into MUST be in the same order
+ */
+static unsigned int rates[] = {
+       4000, 8000, 16000, 22050,
+       24000, 32000, 44100,
+       48000, 88200, 96000,
+};
+
+static snd_pcm_hw_constraint_list_t aic23_hw_constraints_rates = {
+       .count = ARRAY_SIZE(rates),
+       .list = rates,
+       .mask = 0,
+};
+
+static snd_pcm_hardware_t aic23_snd_omap_alsa_playback = {
+       .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),      
+       .formats = (SNDRV_PCM_FMTBIT_S16_LE),
+       .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+                 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
+                 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+                 SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+                 SNDRV_PCM_RATE_KNOT),
+       .rate_min = 8000,
+       .rate_max = 96000,
+       .channels_min = 2,
+       .channels_max = 2,
+       .buffer_bytes_max = 128 * 1024,
+       .period_bytes_min = 32,
+       .period_bytes_max = 8 * 1024,
+       .periods_min = 16,
+       .periods_max = 255,
+       .fifo_size = 0,
+};
+
+static snd_pcm_hardware_t aic23_snd_omap_alsa_capture = {
+       .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
+       .formats = (SNDRV_PCM_FMTBIT_S16_LE),
+       .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+                 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
+                 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+                 SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+                 SNDRV_PCM_RATE_KNOT),
+       .rate_min = 8000,
+       .rate_max = 96000,
+       .channels_min = 2,
+       .channels_max = 2,
+       .buffer_bytes_max = 128 * 1024,
+       .period_bytes_min = 32,
+       .period_bytes_max = 8 * 1024,
+       .periods_min = 16,
+       .periods_max = 255,
+       .fifo_size = 0,
+};
+
+/*
+ * Codec/mcbsp init and configuration section
+ * codec dependent code.
+ */
+
+extern int aic23_write_value(u8 reg, u16 value);
+
+/* TLV320AIC23 is a write only device */
+void audio_aic23_write(u8 address, u16 data)
+{
+       aic23_write_value(address, data);
+}
+EXPORT_SYMBOL_GPL(audio_aic23_write);
+
+/*
+ * Sample rate changing
+ */
+void aic23_set_samplerate(long rate)
+{
+       u8 count = 0;
+       u16 data = 0;
+
+       /* Fix the rate if it has a wrong value */
+       if (rate >= 96000)
+               rate = 96000;
+       else if (rate >= 88200)
+               rate = 88200;
+       else if (rate >= 48000)
+               rate = 48000;
+       else if (rate >= 44100)
+               rate = 44100;
+       else if (rate >= 32000)
+               rate = 32000;
+       else if (rate >= 24000)
+               rate = 24000;
+       else if (rate >= 22050)
+               rate = 22050;
+       else if (rate >= 16000)
+               rate = 16000;
+       else if (rate >= 8000)
+               rate = 8000;
+       else
+               rate = 4000;
+
+       /* Search for the right sample rate */
+       /* Verify what happens if the rate is not supported
+        * now it goes to 96Khz */
+       while ((rate_reg_info[count].sample_rate != rate) &&
+              (count < (NUMBER_SAMPLE_RATES_SUPPORTED - 1))) {
+               count++;
+       }
+
+       data = (rate_reg_info[count].divider << CLKIN_SHIFT) |
+           (rate_reg_info[count].control << BOSR_SHIFT) | USB_CLK_ON;
+
+       audio_aic23_write(SAMPLE_RATE_CONTROL_ADDR, data);
+}
+
+inline void aic23_configure(void)
+{
+       /* Reset codec */
+       audio_aic23_write(RESET_CONTROL_ADDR, 0);
+
+       /* Initialize the AIC23 internal state */
+
+       /* Analog audio path control, DAC selected, delete INSEL_MIC for line in */
+       audio_aic23_write(ANALOG_AUDIO_CONTROL_ADDR, DEFAULT_ANALOG_AUDIO_CONTROL);
+
+       /* Digital audio path control, de-emphasis control 44.1kHz */
+       audio_aic23_write(DIGITAL_AUDIO_CONTROL_ADDR, DEEMP_44K);
+
+       /* Digital audio interface, master/slave mode, I2S, 16 bit */
+#ifdef AIC23_MASTER
+       audio_aic23_write(DIGITAL_AUDIO_FORMAT_ADDR,
+                         MS_MASTER | IWL_16 | FOR_DSP);
+#else
+       audio_aic23_write(DIGITAL_AUDIO_FORMAT_ADDR, IWL_16 | FOR_DSP);
+#endif
+
+       /* Enable digital interface */
+       audio_aic23_write(DIGITAL_INTERFACE_ACT_ADDR, ACT_ON);
+}
+
+/*
+ *  Omap MCBSP clock configuration and Power Management
+ *  
+ *  Here we have some functions that allows clock to be enabled and
+ *   disabled only when needed. Besides doing clock configuration 
+ *   it allows turn on/turn off audio when necessary. 
+ */
+/*
+ * Do clock framework mclk search
+ */
+void aic23_clock_setup(void)
+{
+       aic23_mclk = clk_get(0, "mclk");
+}
+
+/*
+ * Do some sanity check, set clock rate, starts it and
+ *  turn codec audio on 
+ */
+int aic23_clock_on(void)
+{
+       uint    curRate;
+
+       if (clk_get_usecount(aic23_mclk) > 0) {
+               /* MCLK is already in use */
+               printk(KERN_WARNING
+                      "MCLK in use at %d Hz. We change it to %d Hz\n",
+                      (uint) clk_get_rate(aic23_mclk),
+                      CODEC_CLOCK);
+       }
+       curRate = (uint)clk_get_rate(aic23_mclk);
+       if (curRate != CODEC_CLOCK) {
+               if (clk_set_rate(aic23_mclk, CODEC_CLOCK)) {
+                       printk(KERN_ERR
+                              "Cannot set MCLK for AIC23 CODEC\n");
+                       return -ECANCELED;
+               }
+       }
+       clk_enable(aic23_mclk);
+
+       printk(KERN_DEBUG
+               "MCLK = %d [%d], usecount = %d\n",
+              (uint) clk_get_rate(aic23_mclk), CODEC_CLOCK,
+              clk_get_usecount(aic23_mclk));
+
+       /* Now turn the audio on */
+       audio_aic23_write(POWER_DOWN_CONTROL_ADDR, 
+                         ~DEVICE_POWER_OFF & ~OUT_OFF & ~DAC_OFF &
+                         ~ADC_OFF & ~MIC_OFF & ~LINE_OFF);     
+       return 0;
+}
+
+/*
+ * Do some sanity check, turn clock off and then turn
+ *  codec audio off
+ */
+int aic23_clock_off(void)
+{
+       if  (clk_get_usecount(aic23_mclk) > 0) { 
+               if (clk_get_rate(aic23_mclk) != CODEC_CLOCK) {
+                       printk(KERN_WARNING
+                              "MCLK for audio should be %d Hz. But is %d Hz\n",
+                              (uint) clk_get_rate(aic23_mclk),
+                              CODEC_CLOCK);
+               }
+
+               clk_disable(aic23_mclk);
+       }
+       
+       audio_aic23_write(POWER_DOWN_CONTROL_ADDR,
+                         DEVICE_POWER_OFF | OUT_OFF | DAC_OFF |
+                         ADC_OFF | MIC_OFF | LINE_OFF);        
+       return 0;
+}
+
+int aic23_get_default_samplerate(void)
+{
+       return DEFAULT_SAMPLE_RATE;
+}
+
+static int __devinit snd_omap_alsa_aic23_probe(struct platform_device *pdev)
+{
+       int     ret;
+       struct  omap_alsa_codec_config *codec_cfg;
+       
+       codec_cfg = pdev->dev.platform_data;
+       if (codec_cfg != NULL) {
+               codec_cfg->hw_constraints_rates = &aic23_hw_constraints_rates;
+               codec_cfg->snd_omap_alsa_playback  = &aic23_snd_omap_alsa_playback;
+               codec_cfg->snd_omap_alsa_capture  = &aic23_snd_omap_alsa_capture;               
+               codec_cfg->codec_configure_dev  = aic23_configure;
+               codec_cfg->codec_set_samplerate = aic23_set_samplerate;
+               codec_cfg->codec_clock_setup    = aic23_clock_setup;
+               codec_cfg->codec_clock_on       = aic23_clock_on;
+               codec_cfg->codec_clock_off      = aic23_clock_off;
+               codec_cfg->get_default_samplerate = aic23_get_default_samplerate;
+               ret     = snd_omap_alsa_post_probe(pdev, codec_cfg);
+       }
+       else
+               ret = -ENODEV;
+       return ret;
+}
+
+static struct platform_driver omap_alsa_driver = {
+       .probe          = snd_omap_alsa_aic23_probe,
+       .remove         = snd_omap_alsa_remove,
+       .suspend        = snd_omap_alsa_suspend,
+       .resume         = snd_omap_alsa_resume,
+       .driver = {
+               .name = "omap_alsa_mcbsp",
+       },
+};
+
+static int __init omap_alsa_aic23_init(void)
+{
+       int err;
+       
+       ADEBUG();
+       err = platform_driver_register(&omap_alsa_driver);
+
+       return err;
+}
+
+static void __exit omap_alsa_aic23_exit(void)
+{
+       ADEBUG();
+       
+       platform_driver_unregister(&omap_alsa_driver);
+}
+
+module_init(omap_alsa_aic23_init);
+module_exit(omap_alsa_aic23_exit);
diff --git a/sound/arm/omap/omap-alsa-aic23.h b/sound/arm/omap/omap-alsa-aic23.h
new file mode 100644 (file)
index 0000000..63907c4
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * sound/arm/omap-alsa-aic23.h
+ * 
+ * Alsa Driver for AIC23 codec on OSK5912 platform board
+ *
+ * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ * Written by Daniel Petrini, David Cohen, Anderson Briglia
+ *            {daniel.petrini, david.cohen, anderson.briglia}@indt.org.br
+ *
+ * Copyright (C) 2006 Mika Laitio <lamikr@cc.jyu.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __OMAP_ALSA_AIC23_H
+#define __OMAP_ALSA_AIC23_H
+
+#include <sound/driver.h>
+#include <asm/arch/dma.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <asm/arch/mcbsp.h>
+
+/* Define to set the AIC23 as the master w.r.t McBSP */
+#define AIC23_MASTER
+
+#define NUMBER_SAMPLE_RATES_SUPPORTED  10
+
+/*
+ * AUDIO related MACROS
+ */
+#ifndef DEFAULT_BITPERSAMPLE
+#define DEFAULT_BITPERSAMPLE           16
+#endif
+
+#define DEFAULT_SAMPLE_RATE            44100
+#define CODEC_CLOCK                    12000000
+#define AUDIO_MCBSP                    OMAP_MCBSP1
+
+#define DEFAULT_OUTPUT_VOLUME          0x60
+#define DEFAULT_INPUT_VOLUME           0x00    /* 0 ==> mute line in */
+
+#define OUTPUT_VOLUME_MIN              LHV_MIN
+#define OUTPUT_VOLUME_MAX              LHV_MAX
+#define OUTPUT_VOLUME_RANGE            (OUTPUT_VOLUME_MAX - OUTPUT_VOLUME_MIN)
+#define OUTPUT_VOLUME_MASK             OUTPUT_VOLUME_MAX
+
+#define INPUT_VOLUME_MIN               LIV_MIN
+#define INPUT_VOLUME_MAX               LIV_MAX
+#define INPUT_VOLUME_RANGE             (INPUT_VOLUME_MAX - INPUT_VOLUME_MIN)
+#define INPUT_VOLUME_MASK              INPUT_VOLUME_MAX
+
+#define SIDETONE_MASK                  0x1c0
+#define SIDETONE_0                     0x100
+#define SIDETONE_6                     0x000
+#define SIDETONE_9                     0x040
+#define SIDETONE_12                    0x080
+#define SIDETONE_18                    0x0c0
+
+#define DEFAULT_ANALOG_AUDIO_CONTROL  DAC_SELECTED | STE_ENABLED | BYPASS_ON | INSEL_MIC | MICB_20DB
+
+struct aic23_samplerate_reg_info {
+       u32 sample_rate;
+       u8 control;             /* SR3, SR2, SR1, SR0 and BOSR */
+       u8 divider;             /* if 0 CLKIN = MCLK, if 1 CLKIN = MCLK/2 */
+};
+
+/*
+ * Defines codec specific functions pointers that can be used from the 
+ * common omap-alse base driver for all omap codecs. (tsc2101 and aic23)
+ */
+void define_codec_functions(struct omap_alsa_codec_config *codec_config);
+inline void aic23_configure(void);
+void aic23_set_samplerate(long rate);
+void aic23_clock_setup(void);
+int aic23_clock_on(void);
+int aic23_clock_off(void);
+int aic23_get_default_samplerate(void);
+
+#endif
diff --git a/sound/arm/omap/omap-alsa-dma.c b/sound/arm/omap/omap-alsa-dma.c
new file mode 100644 (file)
index 0000000..00359cb
--- /dev/null
@@ -0,0 +1,443 @@
+/*
+ * sound/arm/omap/omap-alsa-dma.c
+ *
+ * Common audio DMA handling for the OMAP processors
+ *
+ * Copyright (C) 2006 Mika Laitio <lamikr@cc.jyu.fi>
+ *
+ * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ * 
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *
+ * Copyright (C) 2000, 2001 Nicolas Pitre <nico@cam.org>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * History:
+ *
+ * 2004-06-07  Sriram Kannan   - Created new file from omap_audio_dma_intfc.c. This file
+ *                               will contain only the DMA interface and buffer handling of OMAP
+ *                               audio driver.
+ *
+ * 2004-06-22  Sriram Kannan   - removed legacy code (auto-init). Self-linking of DMA logical channel.
+ *
+ * 2004-08-12   Nishanth Menon  - Modified to integrate Audio requirements on 1610,1710 platforms
+ *
+ * 2004-11-01   Nishanth Menon  - 16xx platform code base modified to support multi channel chaining.
+ *
+ * 2004-12-15   Nishanth Menon  - Improved 16xx platform channel logic introduced - tasklets, queue handling updated
+ * 
+ * 2005-07-19  INdT Kernel Team - Alsa port. Creation of new file omap-alsa-dma.c based in
+ *                                omap-audio-dma-intfc.c oss file. Support for aic23 codec.
+ *                                Removal of buffer handling (Alsa does that), modifications
+ *     in dma handling and port to alsa structures.
+ *
+ * 2005-12-18   Dirk Behme      - Added L/R Channel Interchange fix as proposed by Ajaya Babu
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/poll.h>
+#include <linux/pm.h>
+#include <linux/errno.h>
+#include <linux/sound.h>
+#include <linux/soundcard.h>
+#include <linux/sysrq.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/semaphore.h>
+
+#include <asm/arch/dma.h>
+#include "omap-alsa-dma.h"
+
+#include <asm/arch/mcbsp.h>
+
+#include <asm/arch/omap-alsa.h>
+
+#undef DEBUG
+
+#define ERR(ARGS...) printk(KERN_ERR "{%s}-ERROR: ", __FUNCTION__);printk(ARGS);
+
+/* Channel Queue Handling macros
+ * tail always points to the current free entry
+ * Head always points to the current entry being used
+ * end is either head or tail
+ */
+
+#define AUDIO_QUEUE_INIT(s) s->dma_q_head = s->dma_q_tail = s->dma_q_count = 0;
+#define AUDIO_QUEUE_FULL(s) (nr_linked_channels == s->dma_q_count)
+#define AUDIO_QUEUE_LAST(s) (1 == s->dma_q_count)
+#define AUDIO_QUEUE_EMPTY(s) (0 == s->dma_q_count)
+#define __AUDIO_INCREMENT_QUEUE(end) ((end)=((end)+1) % nr_linked_channels)
+#define AUDIO_INCREMENT_HEAD(s) __AUDIO_INCREMENT_QUEUE(s->dma_q_head); s->dma_q_count--;
+#define AUDIO_INCREMENT_TAIL(s) __AUDIO_INCREMENT_QUEUE(s->dma_q_tail); s->dma_q_count++;
+
+/* DMA buffer fragmentation sizes */
+#define MAX_DMA_SIZE            0x1000000 /* todo: sync with alsa */
+//#define CUT_DMA_SIZE          0x1000
+/* TODO: To be moved to more appropriate location */
+#define DCSR_ERROR           0x3
+#define DCSR_END_BLOCK       (1 << 5)
+#define DCSR_SYNC_SET        (1 << 6)
+
+#define DCCR_FS              (1 << 5)
+#define DCCR_PRIO            (1 << 6)
+#define DCCR_EN              (1 << 7)
+#define DCCR_AI              (1 << 8)
+#define DCCR_REPEAT          (1 << 9)
+/* if 0 the channel works in 3.1 compatible mode*/
+#define DCCR_N31COMP         (1 << 10)
+#define DCCR_EP              (1 << 11)
+#define DCCR_SRC_AMODE_BIT   12
+#define DCCR_SRC_AMODE_MASK  (0x3<<12)
+#define DCCR_DST_AMODE_BIT   14
+#define DCCR_DST_AMODE_MASK  (0x3<<14)
+#define AMODE_CONST          0x0
+#define AMODE_POST_INC       0x1
+#define AMODE_SINGLE_INDEX   0x2
+#define AMODE_DOUBLE_INDEX   0x3
+
+/**************************** DATA STRUCTURES *****************************************/
+
+static spinlock_t dma_list_lock = SPIN_LOCK_UNLOCKED;
+
+static char nr_linked_channels = 1;
+
+/*********************************** MODULE SPECIFIC FUNCTIONS ***********************/
+
+static void sound_dma_irq_handler(int lch, u16 ch_status, void *data);
+static int audio_set_dma_params_play(int channel, dma_addr_t dma_ptr,
+                                    u_int dma_size);
+static int audio_set_dma_params_capture(int channel, dma_addr_t dma_ptr,
+                                       u_int dma_size);
+static int audio_start_dma_chain(struct audio_stream * s);
+
+/***************************************************************************************
+ *
+ * DMA channel requests
+ *
+ **************************************************************************************/
+static void omap_sound_dma_link_lch(void *data)
+{
+
+       struct audio_stream *s = (struct audio_stream *) data;
+       int *chan = s->lch;
+       int i;
+
+       FN_IN;
+       if (s->linked) {
+               FN_OUT(1);
+               return;
+       }
+       for (i = 0; i < nr_linked_channels; i++) {
+               int cur_chan = chan[i];
+               int nex_chan =
+                   ((nr_linked_channels - 1 ==
+                     i) ? chan[0] : chan[i + 1]);
+               omap_dma_link_lch(cur_chan, nex_chan);
+       }
+       s->linked = 1;
+       FN_OUT(0);
+}
+
+int omap_request_alsa_sound_dma(int device_id, const char *device_name,
+                          void *data, int **channels)
+{
+       int i, err = 0;
+       int *chan = NULL;
+       FN_IN;
+       if (unlikely((NULL == channels) || (NULL == device_name))) {
+               BUG();
+               return -EPERM;
+       }
+       /* Try allocate memory for the num channels */
+       *channels =
+           (int *) kmalloc(sizeof(int) * nr_linked_channels, GFP_KERNEL);
+       chan = *channels;
+       if (NULL == chan) {
+               ERR("No Memory for channel allocs!\n");
+               FN_OUT(-ENOMEM);
+               return -ENOMEM;
+       }
+       spin_lock(&dma_list_lock);
+       for (i = 0; i < nr_linked_channels; i++) {
+               err = omap_request_dma(device_id, 
+                               device_name,
+                               sound_dma_irq_handler, 
+                               data,
+                               &chan[i]);
+
+               /* Handle Failure condition here */
+               if (err < 0) {
+                       int j;
+                       for (j = 0; j < i; j++) {
+                               omap_free_dma(chan[j]);
+                       }
+                       spin_unlock(&dma_list_lock);
+                       kfree(chan);
+                       *channels = NULL;
+                       ERR("Error in requesting channel %d=0x%x\n", i,
+                           err);
+                       FN_OUT(err);
+                       return err;
+               }
+       }
+
+       /* Chain the channels together */
+       if (!cpu_is_omap15xx())
+               omap_sound_dma_link_lch(data);
+
+       spin_unlock(&dma_list_lock);
+       FN_OUT(0);
+       return 0;
+}
+
+/***************************************************************************************
+ *
+ * DMA channel requests Freeing
+ *
+ **************************************************************************************/
+static void omap_sound_dma_unlink_lch(void *data)
+{
+       struct audio_stream *s = (struct audio_stream *)data;
+       int *chan = s->lch;
+       int i;
+
+       FN_IN;
+       if (!s->linked) {
+               FN_OUT(1);
+               return;
+       }
+       for (i = 0; i < nr_linked_channels; i++) {
+               int cur_chan = chan[i];
+               int nex_chan =
+                   ((nr_linked_channels - 1 ==
+                     i) ? chan[0] : chan[i + 1]);
+               omap_dma_unlink_lch(cur_chan, nex_chan);
+       }
+       s->linked = 0;
+       FN_OUT(0);
+}
+
+int omap_free_alsa_sound_dma(void *data, int **channels)
+{
+       int i;
+       int *chan = NULL;
+       
+       FN_IN;
+       if (unlikely(NULL == channels)) {
+               BUG();
+               return -EPERM;
+       }
+       if (unlikely(NULL == *channels)) {
+               BUG();
+               return -EPERM;
+       }
+       chan = (*channels);
+
+       if (!cpu_is_omap15xx())
+               omap_sound_dma_unlink_lch(data);
+       for (i = 0; i < nr_linked_channels; i++) {
+               int cur_chan = chan[i];
+               omap_stop_dma(cur_chan);
+               omap_free_dma(cur_chan);
+       }
+       kfree(*channels);
+       *channels = NULL;
+       FN_OUT(0);
+       return 0;
+}
+
+/***************************************************************************************
+ *
+ * Stop all the DMA channels of the stream
+ *
+ **************************************************************************************/
+void omap_stop_alsa_sound_dma(struct audio_stream *s)
+{
+       int *chan = s->lch;
+       int i;
+       
+       FN_IN;
+       if (unlikely(NULL == chan)) {
+               BUG();
+               return;
+       }
+       for (i = 0; i < nr_linked_channels; i++) {
+               int cur_chan = chan[i];
+               omap_stop_dma(cur_chan);
+       }
+       s->started = 0;
+       FN_OUT(0);
+       return;
+}
+/***************************************************************************************
+ *
+ * Clear any pending transfers
+ *
+ **************************************************************************************/
+void omap_clear_alsa_sound_dma(struct audio_stream * s)
+{
+       FN_IN;
+       omap_clear_dma(s->lch[s->dma_q_head]);
+       FN_OUT(0);
+       return;
+}
+
+/***************************************************************************************
+ *
+ * DMA related functions
+ *
+ **************************************************************************************/
+static int audio_set_dma_params_play(int channel, dma_addr_t dma_ptr,
+                                    u_int dma_size)
+{
+       int dt = 0x1;           /* data type 16 */
+       int cen = 32;           /* Stereo */
+       int cfn = dma_size / (2 * cen);
+       
+       FN_IN;
+       omap_set_dma_dest_params(channel, 0x05, 0x00,
+                                (OMAP1510_MCBSP1_BASE + 0x06),
+                                0, 0);
+       omap_set_dma_src_params(channel, 0x00, 0x01, dma_ptr,
+                               0, 0);
+       omap_set_dma_transfer_params(channel, dt, cen, cfn, 0x00, 0, 0);
+       FN_OUT(0);
+       return 0;
+}
+
+static int audio_set_dma_params_capture(int channel, dma_addr_t dma_ptr,
+                                       u_int dma_size)
+{
+       int dt = 0x1;           /* data type 16 */
+       int cen = 32;           /* stereo */
+       int cfn = dma_size / (2 * cen);
+       
+       FN_IN;
+       omap_set_dma_src_params(channel, 0x05, 0x00,
+                               (OMAP1510_MCBSP1_BASE + 0x02),
+                               0, 0);
+       omap_set_dma_dest_params(channel, 0x00, 0x01, dma_ptr, 0, 0);
+       omap_set_dma_transfer_params(channel, dt, cen, cfn, 0x00, 0, 0);
+       FN_OUT(0);
+       return 0;
+}
+
+static int audio_start_dma_chain(struct audio_stream *s)
+{
+       int channel = s->lch[s->dma_q_head];
+       FN_IN;
+       if (!s->started) {
+               s->hw_stop();      /* stops McBSP Interface */
+               omap_start_dma(channel);
+               s->started = 1;
+               s->hw_start();     /* start McBSP interface */
+       } else if (cpu_is_omap310())
+               omap_start_dma(channel);
+       /* else the dma itself will progress forward with out our help */
+       FN_OUT(0);
+       return 0;
+}
+
+/* Start DMA -
+ * Do the initial set of work to initialize all the channels as required.
+ * We shall then initate a transfer
+ */
+int omap_start_alsa_sound_dma(struct audio_stream *s, 
+                       dma_addr_t dma_ptr, 
+                       u_int dma_size)
+{
+       int ret = -EPERM;
+
+       FN_IN;
+
+       if (unlikely(dma_size > MAX_DMA_SIZE)) {
+               ERR("DmaSoundDma: Start: overflowed %d-%d\n", dma_size,
+                   MAX_DMA_SIZE);
+               return -EOVERFLOW;
+       }
+       //if (AUDIO_QUEUE_FULL(s)) {
+       //      ret = -2;
+       //      goto sound_out;
+       //}
+
+       if (s->stream_id == SNDRV_PCM_STREAM_PLAYBACK) {
+               /*playback */
+               ret =
+                   audio_set_dma_params_play(s->lch[s->dma_q_tail],
+                                             dma_ptr, dma_size);
+       } else {
+               ret =
+                   audio_set_dma_params_capture(s->lch[s->dma_q_tail],
+                                                dma_ptr, dma_size);
+       }
+       if (ret != 0) {
+               ret = -3;       /* indicate queue full */
+               goto sound_out;
+       }
+       AUDIO_INCREMENT_TAIL(s);
+       ret = audio_start_dma_chain(s);
+       if (ret) {
+               ERR("dma start failed");
+       }
+      sound_out:
+       FN_OUT(ret);
+       return ret;
+
+}
+
+/* 
+ * ISRs have to be short and smart.. 
+ * Here we call alsa handling, after some error checking
+ */
+static void sound_dma_irq_handler(int sound_curr_lch, u16 ch_status,
+                                 void *data)
+{
+       int dma_status = ch_status;
+       struct audio_stream *s = (struct audio_stream *) data;
+       FN_IN;
+
+       /*
+        * some register checkings
+        */ 
+       DPRINTK("lch=%d,status=0x%x, dma_status=%d, data=%p\n",
+               sound_curr_lch, ch_status, dma_status, data);
+
+       if (dma_status & (DCSR_ERROR)) {
+               OMAP_DMA_CCR_REG(sound_curr_lch) &= ~DCCR_EN;
+               ERR("DCSR_ERROR!\n");
+               FN_OUT(-1);
+               return;
+       }
+
+       if (ch_status & DCSR_END_BLOCK) 
+               callback_omap_alsa_sound_dma(s);
+       FN_OUT(0);
+       return;
+}
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("Common DMA handling for Audio driver on OMAP processors");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(omap_start_alsa_sound_dma);
+EXPORT_SYMBOL(omap_clear_alsa_sound_dma);
+EXPORT_SYMBOL(omap_request_alsa_sound_dma);
+EXPORT_SYMBOL(omap_free_alsa_sound_dma);
+EXPORT_SYMBOL(omap_stop_alsa_sound_dma);
diff --git a/sound/arm/omap/omap-alsa-dma.h b/sound/arm/omap/omap-alsa-dma.h
new file mode 100644 (file)
index 0000000..1cecc8a
--- /dev/null
@@ -0,0 +1,53 @@
+/*  
+ * linux/sound/arm/omap/omap-alsa-dma.h
+ *
+ * Common audio DMA handling for the OMAP processors
+ *
+ * Copyright (C) 2006 Mika Laitio <lamikr@cc.jyu.fi>
+ *
+ * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ * 
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *
+ * Copyright (C) 2000, 2001 Nicolas Pitre <nico@cam.org>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * History:
+ *
+ * 
+ * 2004/08/12  Nishanth Menon - Modified to integrate Audio requirements on 1610,1710 platforms
+ *
+ * 2005/07/25  INdT Kernel Team - Renamed to omap-alsa-dma.h. Ported to Alsa.
+ */
+
+#ifndef __OMAP_AUDIO_ALSA_DMA_H
+#define __OMAP_AUDIO_ALSA_DMA_H
+
+/************************** INCLUDES *************************************/
+
+#include <asm/arch/omap-alsa.h>
+
+/************************** GLOBAL DATA STRUCTURES *********************************/
+
+typedef void (*dma_callback_t) (int lch, u16 ch_status, void *data);
+
+/**************** ARCH SPECIFIC FUNCIONS *******************************************/
+
+void omap_clear_alsa_sound_dma(struct audio_stream * s);
+
+int omap_request_alsa_sound_dma(int device_id, const char *device_name,
+                          void *data, int **channels);
+int omap_free_alsa_sound_dma(void *data, int **channels);
+
+int omap_start_alsa_sound_dma(struct audio_stream *s, dma_addr_t dma_ptr,  u_int dma_size);
+
+void omap_stop_alsa_sound_dma(struct audio_stream *s);
+
+#endif
diff --git a/sound/arm/omap/omap-alsa-sx1-mixer.c b/sound/arm/omap/omap-alsa-sx1-mixer.c
new file mode 100644 (file)
index 0000000..631b080
--- /dev/null
@@ -0,0 +1,470 @@
+/*
+ * sound/arm/omap/omap-alsa-sx1-mixer.c
+ *
+ * Alsa codec Driver for Siemens SX1 board.
+ * based on omap-alsa-tsc2101-mixer.c
+ *
+ *  Copyright (C) 2006 Vladimir Ananiev (vovan888 at gmail com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * You should have received a copy of the  GNU General Public License along
+ * with this program; if not, write  to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "omap-alsa-sx1.h"
+#include "omap-alsa-sx1-mixer.h"
+
+#include <linux/types.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+
+static int current_playback_target     = PLAYBACK_TARGET_LOUDSPEAKER;
+static int current_rec_src             = REC_SRC_SINGLE_ENDED_MICIN_HED;
+static int current_volume;     /* current volume, we cant read it */
+static int current_fm_volume;  /* current FM radio volume, we cant read it */
+
+/*
+ * Select SX1 recording source.
+ */
+static void set_record_source(int val)
+{
+       /* TODO Recording is done on McBSP2 and Mic only */
+       current_rec_src = val;
+}
+
+static int set_mixer_volume(int mixer_vol)
+{
+       int ret, i;
+       if ((mixer_vol < 0) || (mixer_vol > 9)) {
+               printk(KERN_ERR "Trying a bad mixer volume (%d)!\n", mixer_vol);
+               return -EPERM;
+       }
+       ret = (current_volume != mixer_vol);
+       current_volume = mixer_vol; /* set current volume, we cant read it */
+
+       i = cn_sx1snd_send(DAC_VOLUME_UPDATE, mixer_vol, 0);
+       if (i)
+               return i;
+       return ret;
+}
+
+static void set_loudspeaker_to_playback_target(void)
+{
+       /* TODO */
+       cn_sx1snd_send(DAC_SETAUDIODEVICE, SX1_DEVICE_SPEAKER, 0);
+
+       current_playback_target = PLAYBACK_TARGET_LOUDSPEAKER;
+}
+
+static void set_headphone_to_playback_target(void)
+{
+       /* TODO */
+       cn_sx1snd_send(DAC_SETAUDIODEVICE, SX1_DEVICE_HEADPHONE, 0);
+
+       current_playback_target = PLAYBACK_TARGET_HEADPHONE;
+}
+
+static void set_telephone_to_playback_target(void)
+{
+       /* TODO */
+       cn_sx1snd_send(DAC_SETAUDIODEVICE, SX1_DEVICE_PHONE, 0);
+
+       current_playback_target = PLAYBACK_TARGET_CELLPHONE;
+}
+
+static void set_telephone_to_record_source(void)
+{
+       cn_sx1snd_send(DAC_SETAUDIODEVICE, SX1_DEVICE_PHONE, 0);
+}
+
+static void init_playback_targets(void)
+{
+       set_loudspeaker_to_playback_target();
+       set_mixer_volume(DEFAULT_OUTPUT_VOLUME);
+}
+
+/*
+ * Initializes SX1 record source (to mic) and playback target (to loudspeaker)
+ */
+void snd_omap_init_mixer(void)
+{
+       /* Select headset to record source */
+       set_record_source(REC_SRC_SINGLE_ENDED_MICIN_HED);
+       /* Init loudspeaker as a default playback target*/
+       init_playback_targets();
+}
+
+/* ---------------------------------------------------------------------- */
+static int pcm_playback_target_info(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_info *uinfo)
+{
+       static char *texts[PLAYBACK_TARGET_COUNT] = {
+               "Loudspeaker", "Headphone", "Cellphone"
+       };
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = PLAYBACK_TARGET_COUNT;
+       if (uinfo->value.enumerated.item > PLAYBACK_TARGET_COUNT - 1) {
+               uinfo->value.enumerated.item = PLAYBACK_TARGET_COUNT - 1;
+       }
+       strcpy(uinfo->value.enumerated.name,
+                       texts[uinfo->value.enumerated.item]);
+       return 0;
+}
+
+static int pcm_playback_target_get(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.integer.value[0] = current_playback_target;
+       return 0;
+}
+
+static int pcm_playback_target_put(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       int ret_val = 0;
+       int cur_val = ucontrol->value.integer.value[0];
+
+       if ((cur_val >= 0) &&
+               (cur_val < PLAYBACK_TARGET_COUNT) &&
+               (cur_val != current_playback_target)) {
+               if (cur_val == PLAYBACK_TARGET_LOUDSPEAKER) {
+                       set_record_source(REC_SRC_SINGLE_ENDED_MICIN_HED);
+                       set_loudspeaker_to_playback_target();
+               } else if (cur_val == PLAYBACK_TARGET_HEADPHONE) {
+                       set_record_source(REC_SRC_SINGLE_ENDED_MICIN_HND);
+                       set_headphone_to_playback_target();
+               } else if (cur_val == PLAYBACK_TARGET_CELLPHONE) {
+                       set_telephone_to_record_source();
+                       set_telephone_to_playback_target();
+               }
+               ret_val = 1;
+       }
+       return ret_val;
+}
+
+/*-----------------------------------------------------------*/
+static int pcm_playback_volume_info(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count                    = 1;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 9;
+       return 0;
+}
+
+static int pcm_playback_volume_get(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.integer.value[0] = current_volume;
+       return 0;
+}
+
+static int pcm_playback_volume_put(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       return set_mixer_volume(ucontrol->value.integer.value[0]);
+}
+
+static int pcm_playback_switch_info(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count                    = 1;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 1;
+       return 0;
+}
+
+static int pcm_playback_switch_get(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.integer.value[0] = 1;
+       return 0;
+}
+
+static int pcm_playback_switch_put(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       return 0;
+}
+
+/* ----------------------------------------------------------- */
+
+static int headset_playback_volume_info(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count                    = 1;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 9;
+       return 0;
+}
+
+static int headset_playback_volume_get(struct snd_kcontrol *kcontrol,
+                                               struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.integer.value[0]        = current_volume;
+       return 0;
+}
+
+static int headset_playback_volume_put(struct snd_kcontrol *kcontrol,
+                                               struct snd_ctl_elem_value *ucontrol)
+{
+       return set_mixer_volume(ucontrol->value.integer.value[0]);
+}
+
+static int headset_playback_switch_info(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count                    = 1;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 1;
+       return 0;
+}
+
+static int headset_playback_switch_get(struct snd_kcontrol *kcontrol,
+                                               struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.integer.value[0] = 1;
+       return 0;
+}
+
+static int headset_playback_switch_put(struct snd_kcontrol *kcontrol,
+                                               struct snd_ctl_elem_value *ucontrol)
+{
+       /* mute/unmute headset */
+#if 0
+       return adc_pga_unmute_control(ucontrol->value.integer.value[0],
+                               TSC2101_HEADSET_GAIN_CTRL,
+                               15);
+#endif
+       return 0;
+}
+/* ----------------------------------------------------------- */
+static int fmradio_playback_volume_info(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count                    = 1;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 9;
+       return 0;
+}
+
+static int fmradio_playback_volume_get(struct snd_kcontrol *kcontrol,
+                                               struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.integer.value[0] = current_fm_volume;
+       return 0;
+}
+
+static int fmradio_playback_volume_put(struct snd_kcontrol *kcontrol,
+                                               struct snd_ctl_elem_value *ucontrol)
+{
+       int ret = current_fm_volume != ucontrol->value.integer.value[0];
+       int i;
+       current_fm_volume = ucontrol->value.integer.value[0];
+       i = cn_sx1snd_send(DAC_FMRADIO_OPEN, current_fm_volume, 0);
+       if (i)
+               return i;
+       return ret;
+}
+
+static int fmradio_playback_switch_info(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count                    = 1;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 1;
+       return 0;
+}
+
+static int fmradio_playback_switch_get(struct snd_kcontrol *kcontrol,
+                                               struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.integer.value[0] = 1;
+       return 0;
+}
+
+static int fmradio_playback_switch_put(struct snd_kcontrol *kcontrol,
+                                               struct snd_ctl_elem_value *ucontrol)
+{
+       /* mute/unmute FM radio */
+       if (ucontrol->value.integer.value[0])
+               cn_sx1snd_send(DAC_FMRADIO_OPEN, current_fm_volume, 0);
+       else
+               cn_sx1snd_send(DAC_FMRADIO_CLOSE, 0, 0);
+
+       return 0;
+}
+/* ----------------------------------------------------------- */
+static int cellphone_input_switch_info(struct snd_kcontrol *kcontrol,
+                                               struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count                    = 1;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 1;
+       return 0;
+}
+
+static int cellphone_input_switch_get(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.integer.value[0] = 1;
+       return 0;
+}
+
+static int cellphone_input_switch_put(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+#if 0
+       return adc_pga_unmute_control(ucontrol->value.integer.value[0],
+                               TSC2101_BUZZER_GAIN_CTRL, 15);
+#endif
+       return 0;
+}
+/* ----------------------------------------------------------- */
+
+static int buzzer_input_switch_info(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count                    = 1;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 1;
+       return 0;
+}
+
+static int buzzer_input_switch_get(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.integer.value[0] = 1;
+       return 0;
+}
+
+static int buzzer_input_switch_put(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+#if 0
+       return adc_pga_unmute_control(ucontrol->value.integer.value[0],
+                               TSC2101_BUZZER_GAIN_CTRL, 6);
+#endif
+       return 0;
+}
+/*-----------------------------------------------------------*/
+
+static struct snd_kcontrol_new egold_control[] __devinitdata = {
+       {
+               .name   = "Playback Playback Route",
+               .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index  = 0,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info   = pcm_playback_target_info,
+               .get    = pcm_playback_target_get,
+               .put    = pcm_playback_target_put,
+       }, {
+               .name   = "Master Playback Volume",
+               .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index  = 0,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info   = pcm_playback_volume_info,
+               .get    = pcm_playback_volume_get,
+               .put    = pcm_playback_volume_put,
+       }, {
+               .name   = "Master Playback Switch",
+               .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index  = 0,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info   = pcm_playback_switch_info,
+               .get    = pcm_playback_switch_get,
+               .put    = pcm_playback_switch_put,
+       }, {
+               .name   = "Headset Playback Volume",
+               .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index  = 1,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info   = headset_playback_volume_info,
+               .get    = headset_playback_volume_get,
+               .put    = headset_playback_volume_put,
+       }, {
+               .name   = "Headset Playback Switch",
+               .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index  = 1,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info   = headset_playback_switch_info,
+               .get    = headset_playback_switch_get,
+               .put    = headset_playback_switch_put,
+       }, {
+               .name   = "FM Playback Volume",
+               .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index  = 2,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info   = fmradio_playback_volume_info,
+               .get    = fmradio_playback_volume_get,
+               .put    = fmradio_playback_volume_put,
+       }, {
+               .name   = "FM Playback Switch",
+               .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index  = 2,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info   = fmradio_playback_switch_info,
+               .get    = fmradio_playback_switch_get,
+               .put    = fmradio_playback_switch_put,
+       }, {
+               .name   = "Cellphone Input Switch",
+               .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index  = 0,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info   = cellphone_input_switch_info,
+               .get    = cellphone_input_switch_get,
+               .put    = cellphone_input_switch_put,
+       }, {
+               .name   = "Buzzer Input Switch",
+               .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index  = 0,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info   = buzzer_input_switch_info,
+               .get    = buzzer_input_switch_get,
+               .put    = buzzer_input_switch_put,
+       }
+};
+
+#ifdef CONFIG_PM
+void snd_omap_suspend_mixer(void)
+{
+}
+
+void snd_omap_resume_mixer(void)
+{
+       snd_omap_init_mixer();
+}
+#endif
+
+int snd_omap_mixer(struct snd_card_omap_codec *egold)
+{
+       int i = 0;
+       int err = 0;
+
+       if (!egold)
+               return -EINVAL;
+
+       for (i=0; i < ARRAY_SIZE(egold_control); i++) {
+               err = snd_ctl_add(egold->card,
+                               snd_ctl_new1(&egold_control[i], egold->card));
+               if (err < 0)
+                       return err;
+       }
+       return 0;
+}
diff --git a/sound/arm/omap/omap-alsa-sx1-mixer.h b/sound/arm/omap/omap-alsa-sx1-mixer.h
new file mode 100644 (file)
index 0000000..686b81c
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * sound/arm/omap/omap-alsa-sx1-mixer.h
+ *
+ * Alsa codec Driver for Siemens SX1 board.
+ * based on omap-alsa-tsc2101-mixer.c
+ *
+ *  Copyright (C) 2006 Vladimir Ananiev (vovan888 at gmail com)
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * You should have received a copy of the  GNU General Public License along
+ * with this program; if not, write  to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef OMAPALSASX1MIXER_H_
+#define OMAPALSASX1MIXER_H_
+
+#include "omap-alsa-dma.h"
+
+#define PLAYBACK_TARGET_COUNT          0x03
+#define PLAYBACK_TARGET_LOUDSPEAKER    0x00
+#define PLAYBACK_TARGET_HEADPHONE      0x01
+#define PLAYBACK_TARGET_CELLPHONE      0x02
+
+/* following are used for register 03h Mixer PGA control bits
+   D7-D5 for selecting record source */
+#define REC_SRC_TARGET_COUNT           0x08
+#define REC_SRC_SINGLE_ENDED_MICIN_HED 0x00 /* oss code referred to MIXER_LINE */
+#define REC_SRC_SINGLE_ENDED_MICIN_HND 0x01 /* oss code referred to MIXER_MIC */
+#define REC_SRC_SINGLE_ENDED_AUX1      0x02
+#define REC_SRC_SINGLE_ENDED_AUX2      0x03
+#define REC_SRC_MICIN_HED_AND_AUX1     0x04
+#define REC_SRC_MICIN_HED_AND_AUX2     0x05
+#define REC_SRC_MICIN_HND_AND_AUX1     0x06
+#define REC_SRC_MICIN_HND_AND_AUX2     0x07
+
+#define DEFAULT_OUTPUT_VOLUME 5        /* default output volume to dac dgc */
+#define DEFAULT_INPUT_VOLUME  2        /* default record volume */
+
+#endif
diff --git a/sound/arm/omap/omap-alsa-sx1.c b/sound/arm/omap/omap-alsa-sx1.c
new file mode 100644 (file)
index 0000000..eadae68
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+ * Alsa codec Driver for Siemens SX1 board.
+ * based on omap-alsa-tsc2101.c        and cn_test.c example by Evgeniy Polyakov
+ *
+ * Copyright (C) 2006 Vladimir Ananiev (vovan888 at gmail com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/delay.h>
+#include <linux/soundcard.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <asm/io.h>
+#include <asm/arch/mcbsp.h>
+
+#include <linux/slab.h>
+#include <linux/pm.h>
+#include <asm/arch/dma.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/gpio.h>
+
+#include <asm/arch/omap-alsa.h>
+#include "omap-alsa-sx1.h"
+
+#include <linux/connector.h>
+
+/* Connector implementation */
+static struct cb_id cn_sx1snd_id = { CN_IDX_SX1SND, CN_VAL_SX1SND };
+static char cn_sx1snd_name[] = "cn_sx1snd";
+
+static void cn_sx1snd_callback(void *data)
+{
+       struct cn_msg *msg = (struct cn_msg *)data;
+
+       printk("%s: %lu: idx=%x, val=%x, seq=%u, ack=%u, len=%d: %s.\n",
+                       __func__, jiffies, msg->id.idx, msg->id.val,
+                       msg->seq, msg->ack, msg->len, (char *)msg->data);
+}
+
+/* Send IPC message to sound server */
+int cn_sx1snd_send(unsigned int cmd, unsigned int arg1, unsigned int arg2)
+{
+       struct cn_msg *m;
+       unsigned short data[3];
+       int err;
+
+       m = kzalloc(sizeof(*m) + sizeof(data), gfp_any());
+       if (!m)
+               return -1;
+
+       memcpy(&m->id, &cn_sx1snd_id, sizeof(m->id));
+       m->seq = 1;
+       m->len = sizeof(data);
+
+       data[0] = (unsigned short)cmd;
+       data[1] = (unsigned short)arg1;
+       data[2] = (unsigned short)arg2;
+
+       memcpy(m + 1, data, m->len);
+
+       err = cn_netlink_send(m, CN_IDX_SX1SND, gfp_any());
+       snd_printd("sent= %02X %02X %02X, err=%d\n", cmd,arg1,arg2,err);
+       kfree(m);
+
+       if (err == -ESRCH)
+               return -1;      /* there are no listeners on socket */
+       return 0;
+}
+
+/* Hardware capabilities
+ *
+ * DAC USB-mode sampling rates (MCLK = 12 MHz)
+ * The rates and rate_reg_into MUST be in the same order
+ */
+static unsigned int rates[] = {
+        8000, 11025, 12000,
+        16000, 22050, 24000,
+        32000, 44100, 48000,
+};
+
+static snd_pcm_hw_constraint_list_t egold_hw_constraints_rates = {
+       .count  = ARRAY_SIZE(rates),
+       .list   = rates,
+       .mask   = 0,
+};
+
+static snd_pcm_hardware_t egold_snd_omap_alsa_playback = {
+       .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
+       .formats = (SNDRV_PCM_FMTBIT_S16_LE),
+       .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
+                 SNDRV_PCM_RATE_16000 |
+                 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
+                 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+                 SNDRV_PCM_RATE_KNOT),
+       .rate_min               = 8000,
+       .rate_max               = 48000,
+       .channels_min           = 2,
+       .channels_max           = 2,
+       .buffer_bytes_max       = 128 * 1024,
+       .period_bytes_min       = 32,
+       .period_bytes_max       = 8 * 1024,
+       .periods_min            = 16,
+       .periods_max            = 255,
+       .fifo_size              = 0,
+};
+
+static snd_pcm_hardware_t egold_snd_omap_alsa_capture = {
+       .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
+       .formats = (SNDRV_PCM_FMTBIT_S16_LE),
+       .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
+                 SNDRV_PCM_RATE_16000 |
+                 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
+                 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+                 SNDRV_PCM_RATE_KNOT),
+       .rate_min               = 8000,
+       .rate_max               = 48000,
+       .channels_min           = 2,
+       .channels_max           = 2,
+       .buffer_bytes_max       = 128 * 1024,
+       .period_bytes_min       = 32,
+       .period_bytes_max       = 8 * 1024,
+       .periods_min            = 16,
+       .periods_max            = 255,
+       .fifo_size              = 0,
+};
+
+static long current_rate = -1; /* current rate in egold format 0..8 */
+/*
+ * ALSA operations according to board file
+ */
+
+/*
+ * Sample rate changing
+ */
+static void egold_set_samplerate(long sample_rate)
+{
+       int egold_rate = 0;
+       int clkgdv = 0;
+       u16 srgr1, srgr2;
+
+       /* Set the sample rate */
+#if 0
+       /* fw15: 5005E490 - divs are different !!! */
+       clkgdv  = CODEC_CLOCK / (sample_rate * (DEFAULT_BITPERSAMPLE * 2 - 1));
+#endif
+       switch (sample_rate) {
+               case 8000:      clkgdv = 71; egold_rate = FRQ_8000; break;
+               case 11025:     clkgdv = 51; egold_rate = FRQ_11025; break;
+               case 12000:     clkgdv = 47; egold_rate = FRQ_12000; break;
+               case 16000:     clkgdv = 35; egold_rate = FRQ_16000; break;
+               case 22050:     clkgdv = 25; egold_rate = FRQ_22050; break;
+               case 24000:     clkgdv = 23; egold_rate = FRQ_24000; break;
+               case 32000:     clkgdv = 17; egold_rate = FRQ_32000; break;
+               case 44100:     clkgdv = 12; egold_rate = FRQ_44100; break;
+               case 48000:     clkgdv = 11; egold_rate = FRQ_48000; break;
+       }
+
+       srgr1 = (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
+       srgr2 = ((FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1)));
+
+       OMAP_MCBSP_WRITE(OMAP1510_MCBSP1_BASE, SRGR2, srgr2);
+       OMAP_MCBSP_WRITE(OMAP1510_MCBSP1_BASE, SRGR1, srgr1);
+       current_rate = egold_rate;
+       snd_printd("set samplerate=%ld\n", sample_rate);
+
+}
+
+static void egold_configure(void)
+{
+}
+
+/*
+ * Omap MCBSP clock and Power Management configuration
+ *
+ * Here we have some functions that allows clock to be enabled and
+ * disabled only when needed. Besides doing clock configuration
+ * it allows turn on/turn off audio when necessary.
+ */
+
+/*
+ * Do clock framework mclk search
+ */
+static void egold_clock_setup(void)
+{
+       omap_request_gpio(OSC_EN);
+       omap_set_gpio_direction(OSC_EN, 0); /* output */
+       snd_printd("\n");
+}
+
+/*
+ * Do some sanity check, set clock rate, starts it and turn codec audio on
+ */
+static int egold_clock_on(void)
+{
+       omap_set_gpio_dataout(OSC_EN, 1);
+       egold_set_samplerate(44100); /* TODO */
+       cn_sx1snd_send(DAC_SETAUDIODEVICE, SX1_DEVICE_SPEAKER, 0);
+       cn_sx1snd_send(DAC_OPEN_DEFAULT, current_rate , 4);
+       snd_printd("\n");
+       return 0;
+}
+
+/*
+ * Do some sanity check, turn clock off and then turn codec audio off
+ */
+static int egold_clock_off(void)
+{
+       cn_sx1snd_send(DAC_CLOSE, 0 , 0);
+       cn_sx1snd_send(DAC_SETAUDIODEVICE, SX1_DEVICE_PHONE, 0);
+       omap_set_gpio_dataout(OSC_EN, 0);
+       snd_printd("\n");
+       return 0;
+}
+
+static int egold_get_default_samplerate(void)
+{
+       snd_printd("\n");
+       return DEFAULT_SAMPLE_RATE;
+}
+
+static int __init snd_omap_alsa_egold_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct omap_alsa_codec_config *codec_cfg;
+
+       codec_cfg = pdev->dev.platform_data;
+       if (!codec_cfg)
+               return -ENODEV;
+
+       codec_cfg->hw_constraints_rates = &egold_hw_constraints_rates;
+       codec_cfg->snd_omap_alsa_playback= &egold_snd_omap_alsa_playback;
+       codec_cfg->snd_omap_alsa_capture  = &egold_snd_omap_alsa_capture;
+       codec_cfg->codec_configure_dev  = egold_configure;
+       codec_cfg->codec_set_samplerate = egold_set_samplerate;
+       codec_cfg->codec_clock_setup    = egold_clock_setup;
+       codec_cfg->codec_clock_on       = egold_clock_on;
+       codec_cfg->codec_clock_off      = egold_clock_off;
+       codec_cfg->get_default_samplerate = egold_get_default_samplerate;
+       ret = snd_omap_alsa_post_probe(pdev, codec_cfg);
+
+       snd_printd("\n");
+       return ret;
+}
+
+static struct platform_driver omap_alsa_driver = {
+       .probe          = snd_omap_alsa_egold_probe,
+       .remove         = snd_omap_alsa_remove,
+       .suspend        = snd_omap_alsa_suspend,
+       .resume         = snd_omap_alsa_resume,
+       .driver = {
+               .name = "omap_alsa_mcbsp",
+       },
+};
+
+static int __init omap_alsa_egold_init(void)
+{
+       int retval;
+
+       retval = cn_add_callback(&cn_sx1snd_id, cn_sx1snd_name, cn_sx1snd_callback);
+       if (retval)
+               printk(KERN_WARNING "cn_sx1snd failed to register\n");
+       return platform_driver_register(&omap_alsa_driver);
+}
+
+static void __exit omap_alsa_egold_exit(void)
+{
+       cn_del_callback(&cn_sx1snd_id);
+       platform_driver_unregister(&omap_alsa_driver);
+}
+
+module_init(omap_alsa_egold_init);
+module_exit(omap_alsa_egold_exit);
diff --git a/sound/arm/omap/omap-alsa-sx1.h b/sound/arm/omap/omap-alsa-sx1.h
new file mode 100644 (file)
index 0000000..af7a409
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Based on omap-alsa-tsc2101.h
+ *
+ * Alsa Driver for Siemens SX1.
+ * Copyright (C) 2006 Vladimir Ananiev (vovan888 at gmail com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef OMAP_ALSA_SX1_H_
+#define OMAP_ALSA_SX1_H_
+
+#include <linux/types.h>
+
+#define NUMBER_SAMPLE_RATES_SUPPORTED  9
+
+/*
+ * AUDIO related MACROS
+ */
+#ifndef DEFAULT_BITPERSAMPLE
+#define DEFAULT_BITPERSAMPLE           16
+#endif
+
+#define DEFAULT_SAMPLE_RATE            44100
+/* fw15: 18356000 */
+#define CODEC_CLOCK                    18359000
+/* McBSP for playing music */
+#define AUDIO_MCBSP                    OMAP_MCBSP1
+/* McBSP for record/play audio from phone and mic */
+#define AUDIO_MCBSP_PCM                        OMAP_MCBSP2
+/* gpio pin for enable/disable clock */
+#define OSC_EN                         2
+
+/* Send IPC message to sound server */
+extern int cn_sx1snd_send(unsigned int cmd, unsigned int arg1, unsigned int arg2);
+/* cmd for IPC_GROUP_DAC */
+#define DAC_VOLUME_UPDATE              0
+#define DAC_SETAUDIODEVICE             1
+#define DAC_OPEN_RING                  2
+#define DAC_OPEN_DEFAULT               3
+#define DAC_CLOSE                      4
+#define DAC_FMRADIO_OPEN               5
+#define DAC_FMRADIO_CLOSE              6
+#define DAC_PLAYTONE                   7
+/* cmd for IPC_GROUP_PCM */
+#define PCM_PLAY                       (0+8)
+#define PCM_RECORD                     (1+8)
+#define PCM_CLOSE                      (2+8)
+
+/* for DAC_SETAUDIODEVICE */
+#define SX1_DEVICE_SPEAKER             0
+#define SX1_DEVICE_HEADPHONE           4
+#define SX1_DEVICE_PHONE               3
+/* frequencies for MdaDacOpenDefaultL, MdaDacOpenRingL */
+#define FRQ_8000       0
+#define FRQ_11025              1
+#define FRQ_12000              2
+#define FRQ_16000              3
+#define FRQ_22050              4
+#define FRQ_24000              5
+#define FRQ_32000              6
+#define FRQ_44100              7
+#define FRQ_48000              8
+
+#endif
diff --git a/sound/arm/omap/omap-alsa-tsc2101-mixer.c b/sound/arm/omap/omap-alsa-tsc2101-mixer.c
new file mode 100644 (file)
index 0000000..0f92266
--- /dev/null
@@ -0,0 +1,1095 @@
+/*
+ * sound/arm/omap/omap-alsa-tsc2101-mixer.c
+ * 
+ * Alsa Driver for TSC2101 codec for OMAP platform boards.
+ *
+ * Copyright (C) 2005 Mika Laitio <lamikr@cc.jyu.fi> and 
+ *                  Everett Coleman II <gcc80x86@fuzzyneural.net>
+ *
+ * Board initialization code is based on the code in TSC2101 OSS driver.
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *     Written by Nishanth Menon and Sriram Kannan
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the  GNU General Public License along
+ * with this program; if not, write  to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * History:
+ *
+ * 2006-03-01   Mika Laitio - Mixer for the tsc2101 driver used in omap boards.
+ *             Can switch between headset and loudspeaker playback, 
+ *             mute and unmute dgc, set dgc volume. Record source switch,
+ *             keyclick, buzzer and headset volume and handset volume control 
+ *             are still missing.
+ *             
+ */
+#include "omap-alsa-tsc2101.h"
+#include "omap-alsa-tsc2101-mixer.h"
+
+#include <linux/types.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+
+//#define M_DPRINTK(ARGS...)  printk(KERN_INFO "<%s>: ",__FUNCTION__);printk(ARGS)
+#define M_DPRINTK(ARGS...)             /* nop */
+
+#define CHECK_BIT(INDX, ARG) (((ARG) & TSC2101_BIT(INDX)) >> INDX)
+#define IS_UNMUTED(INDX, ARG) (((CHECK_BIT(INDX, ARG)) == 0))
+
+#define DGC_DALVL_EXTRACT(ARG) ((ARG & 0x7f00) >> 8)
+#define DGC_DARVL_EXTRACT(ARG) ((ARG & 0x007f))
+
+#define HGC_ADPGA_HED_EXTRACT(ARG) ((ARG & 0x7f00) >> 8)
+#define HNGC_ADPGA_HND_EXTRACT(ARG) ((ARG & 0x7f00) >> 8)
+#define BGC_ADPGA_BGC_EXTRACT(ARG) ((ARG & 0x7f00) >> 8)
+
+static int current_playback_target     = PLAYBACK_TARGET_LOUDSPEAKER;
+static int current_rec_src             = REC_SRC_SINGLE_ENDED_MICIN_HED;
+
+/* 
+ * Simplified write for the tsc2101 audio registers.
+ */
+inline void omap_tsc2101_audio_write(u8 address, u16 data)
+{
+       omap_tsc2101_write(PAGE2_AUDIO_CODEC_REGISTERS, address, data);
+}
+
+/* 
+ * Simplified read for the tsc2101 audio registers.
+ */
+inline u16 omap_tsc2101_audio_read(u8 address)
+{
+       return (omap_tsc2101_read(PAGE2_AUDIO_CODEC_REGISTERS, address));
+}
+
+/*
+ * For selecting tsc2101 recourd source.
+ */
+static void set_record_source(int val)
+{
+       u16     data;
+       
+       /* Mute Analog Sidetone
+        * Analog sidetone gain db?
+        * Input selected by MICSEL connected to ADC
+        */
+       data    = MPC_ASTMU | MPC_ASTG(0x45);
+       data    &= ~MPC_MICSEL(7); /* clear all MICSEL bits */
+       data    |= MPC_MICSEL(val);
+       data    |= MPC_MICADC;
+       omap_tsc2101_audio_write(TSC2101_MIXER_PGA_CTRL, data);
+       
+       current_rec_src = val;
+}
+
+/*
+ * Converts the Alsa mixer volume (0 - 100) to real 
+ * Digital Gain Control (DGC) value that can be written
+ * or read from the TSC2101 registry.
+ * 
+ * Note that the number "OUTPUT_VOLUME_MAX" is smaller than OUTPUT_VOLUME_MIN
+ * because DGC works as a volume decreaser. (The more bigger value is put
+ * to DGC, the more the volume of controlled channel is decreased)
+ * 
+ * In addition the TCS2101 chip would allow the maximum volume reduction be 63.5 DB
+ * but according to some tests user can not hear anything with this chip
+ * when the volume is set to be less than 25 db.
+ * Therefore this function will return a value that means 38.5 db (63.5 db - 25 db) 
+ * reduction in the channel volume, when mixer is set to 0.
+ * For mixer value 100, this will return a value that means 0 db volume reduction.
+ * ([mute_left_bit]0000000[mute_right_bit]0000000)
+*/
+int get_mixer_volume_as_dac_gain_control_volume(int vol)
+{
+       u16 retVal;
+
+       /* Convert 0 -> 100 volume to 0x7F(min) -> y(max) volume range */
+       retVal  = ((vol * OUTPUT_VOLUME_RANGE) / 100) + OUTPUT_VOLUME_MAX;
+       /* invert the value for getting the proper range 0 min and 100 max */
+       retVal  = OUTPUT_VOLUME_MIN - retVal;
+       
+       return retVal;
+}
+
+/*
+ * Converts the Alsa mixer volume (0 - 100) to TSC2101 
+ * Digital Gain Control (DGC) volume. Alsa mixer volume 0
+ * is converted to value meaning the volume reduction of -38.5 db
+ * and Alsa mixer volume 100 is converted to value meaning the
+ * reduction of 0 db.
+ */
+int set_mixer_volume_as_dac_gain_control_volume(int mixerVolL, int mixerVolR) 
+{
+       u16 val;
+       int retVal;
+       int volL;
+       int volR;
+       
+       if ((mixerVolL < 0) || 
+           (mixerVolL > 100) ||
+           (mixerVolR < 0) ||
+           (mixerVolR > 100)) {
+               printk(KERN_ERR "Trying a bad mixer volume as dac gain control volume value, left (%d), right (%d)!\n", mixerVolL, mixerVolR);
+               return -EPERM;
+       }
+       M_DPRINTK("mixer volume left = %d, right = %d\n", mixerVolL, mixerVolR);        
+       volL    = get_mixer_volume_as_dac_gain_control_volume(mixerVolL);
+       volR    = get_mixer_volume_as_dac_gain_control_volume(mixerVolR);
+       
+       val     = omap_tsc2101_audio_read(TSC2101_DAC_GAIN_CTRL);
+       /* keep the old mute bit settings */
+       val     &= ~(DGC_DALVL(OUTPUT_VOLUME_MIN) | DGC_DARVL(OUTPUT_VOLUME_MIN));
+       val     |= DGC_DALVL(volL) | DGC_DARVL(volR);
+       retVal  = 2;
+       if (retVal) {
+               omap_tsc2101_audio_write(TSC2101_DAC_GAIN_CTRL, val);
+       }
+       M_DPRINTK("to registry: left = %d, right = %d, total = %d\n", DGC_DALVL_EXTRACT(val), DGC_DARVL_EXTRACT(val), val);
+       return retVal;
+}
+
+/**
+ * If unmuteLeft/unmuteRight == 0  --> mute
+ * If unmuteLeft/unmuteRight == 1 --> unmute
+ */
+int dac_gain_control_unmute(int unmuteLeft, int unmuteRight)
+{
+       u16 val;
+       int count;
+
+       count   = 0;
+       val     = omap_tsc2101_audio_read(TSC2101_DAC_GAIN_CTRL);
+       /* in alsa mixer 1 --> on, 0 == off. In tsc2101 registry 1 --> off, 0 --> on
+        * so if values are same, it's time to change the registry value.
+        */
+       if (unmuteLeft != IS_UNMUTED(15, val)) {
+               if (unmuteLeft == 0) {
+                       /* mute --> turn bit on */
+                       val     = val | DGC_DALMU;
+               }
+               else {
+                       /* unmute --> turn bit off */
+                       val     = val & ~DGC_DALMU;
+               }
+               count++;
+       } /* L */
+       if (unmuteRight != IS_UNMUTED(7, val)) {
+               if (unmuteRight == 0) {
+                       /* mute --> turn bit on */
+                       val     = val | DGC_DARMU;
+               }
+               else {
+                       /* unmute --> turn bit off */
+                       val     = val & ~DGC_DARMU;
+               }               
+               count++;
+       } /* R */
+       if (count) {
+               omap_tsc2101_audio_write(TSC2101_DAC_GAIN_CTRL, val);
+               M_DPRINTK("changed value, is_unmuted left = %d, right = %d\n", 
+                       IS_UNMUTED(15, val),
+                       IS_UNMUTED(7, val));
+       }
+       return count;   
+}
+
+/**
+ * unmute: 0 --> mute, 1 --> unmute
+ * page2RegIndx: Registry index in tsc2101 page2.
+ * muteBitIndx: Index number for the bit in registry that indicates whether muted or unmuted.
+ */
+int adc_pga_unmute_control(int unmute, int page2regIndx, int muteBitIndx)
+{
+       int count;
+       u16 val;
+       
+       count   = 0;
+       val     = omap_tsc2101_audio_read(page2regIndx);
+       /* in alsa mixer 1 --> on, 0 == off. In tsc2101 registry 1 --> off, 0 --> on
+        * so if the values are same, it's time to change the registry value...
+        */
+       if (unmute != IS_UNMUTED(muteBitIndx, val)) {
+               if (unmute == 0) {
+                       /* mute --> turn bit on */
+                       val     = val | TSC2101_BIT(muteBitIndx);
+               }
+               else {
+                       /* unmute --> turn bit off */
+                       val     = val & ~TSC2101_BIT(muteBitIndx);
+               }
+               M_DPRINTK("changed value, is_unmuted = %d\n", IS_UNMUTED(muteBitIndx, val));
+               count++;
+       }
+       if (count) {
+               omap_tsc2101_audio_write(page2regIndx, val);
+       }
+       return count;
+}
+
+/*
+ * Converts the DGC registry value read from the TSC2101 registry to 
+ * Alsa mixer volume format (0 - 100).
+ */
+int get_dac_gain_control_volume_as_mixer_volume(u16 vol) 
+{
+       u16 retVal;     
+
+       retVal  = OUTPUT_VOLUME_MIN - vol;
+       retVal  = ((retVal - OUTPUT_VOLUME_MAX) * 100) / OUTPUT_VOLUME_RANGE;
+       /* fix scaling error */
+       if ((retVal > 0) && (retVal < 100)) {
+               retVal++;
+       }
+       return retVal;
+}
+
+/*
+ * Converts the headset gain control volume (0 - 63.5 db)
+ * to Alsa mixer volume (0 - 100)
+ */
+int get_headset_gain_control_volume_as_mixer_volume(u16 registerVal) 
+{
+       u16 retVal;
+       
+       retVal  = ((registerVal * 100) / INPUT_VOLUME_RANGE);
+       return retVal;
+}
+
+/*
+ * Converts the handset gain control volume (0 - 63.5 db)
+ * to Alsa mixer volume (0 - 100)
+ */
+int get_handset_gain_control_volume_as_mixer_volume(u16 registerVal) 
+{
+       return get_headset_gain_control_volume_as_mixer_volume(registerVal);
+}
+
+/*
+ * Converts the Alsa mixer volume (0 - 100) to 
+ * headset gain control volume (0 - 63.5 db)
+ */
+int get_mixer_volume_as_headset_gain_control_volume(u16 mixerVal) 
+{
+       u16 retVal;
+       
+       retVal  = ((mixerVal * INPUT_VOLUME_RANGE) / 100) + INPUT_VOLUME_MIN;   
+       return retVal;
+}
+
+/*
+ * Writes Alsa mixer volume (0 - 100) to TSC2101 headset volume registry in
+ * a TSC2101 format. (0 - 63.5 db)
+ * In TSC2101 OSS driver this functionality was controlled with "SET_LINE" parameter.
+ */
+int set_mixer_volume_as_headset_gain_control_volume(int mixerVol) 
+{
+       int volume;
+       int retVal;
+       u16 val;
+
+       if (mixerVol < 0 || mixerVol > 100) {
+               M_DPRINTK("Trying a bad headset mixer volume value(%d)!\n", mixerVol);
+               return -EPERM;
+       }
+       M_DPRINTK("mixer volume = %d\n", mixerVol);
+       /* Convert 0 -> 100 volume to 0x0(min) -> 0x7D(max) volume range */
+       /* NOTE: 0 is minimum volume and not mute */
+       volume  = get_mixer_volume_as_headset_gain_control_volume(mixerVol);    
+       val     = omap_tsc2101_audio_read(TSC2101_HEADSET_GAIN_CTRL);
+       /* preserve the old mute settings */
+       val     &= ~(HGC_ADPGA_HED(INPUT_VOLUME_MAX));
+       val     |= HGC_ADPGA_HED(volume);
+       omap_tsc2101_audio_write(TSC2101_HEADSET_GAIN_CTRL, val);       
+       retVal  = 1;
+       
+       M_DPRINTK("to registry = %d\n", val);   
+       return retVal;
+}
+
+/*
+ * Writes Alsa mixer volume (0 - 100) to TSC2101 handset volume registry in
+ * a TSC2101 format. (0 - 63.5 db)
+ * In TSC2101 OSS driver this functionality was controlled with "SET_MIC" parameter.
+ */
+int set_mixer_volume_as_handset_gain_control_volume(int mixerVol) 
+{
+       int volume;
+       int retVal;
+       u16 val;        
+
+       if (mixerVol < 0 || mixerVol > 100) {
+               M_DPRINTK("Trying a bad mic mixer volume value(%d)!\n", mixerVol);
+               return -EPERM;
+       }
+       M_DPRINTK("mixer volume = %d\n", mixerVol);
+       /* Convert 0 -> 100 volume to 0x0(min) -> 0x7D(max) volume range
+        * NOTE: 0 is minimum volume and not mute 
+        */
+       volume  = get_mixer_volume_as_headset_gain_control_volume(mixerVol);
+       val     = omap_tsc2101_audio_read(TSC2101_HANDSET_GAIN_CTRL);
+       /* preserve the old mute settigns */
+       val     &= ~(HNGC_ADPGA_HND(INPUT_VOLUME_MAX));
+       val     |= HNGC_ADPGA_HND(volume);
+       omap_tsc2101_audio_write(TSC2101_HANDSET_GAIN_CTRL, val);
+       retVal  = 1;
+       
+       M_DPRINTK("to registry = %d\n", val);   
+       return retVal;
+}
+
+void set_loudspeaker_to_playback_target(void)
+{
+       /* power down SPK1, SPK2 and loudspeaker */
+       omap_tsc2101_audio_write(TSC2101_CODEC_POWER_CTRL,
+                       CPC_SP1PWDN | CPC_SP2PWDN | CPC_LDAPWDF);       
+       /* ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled
+        * 1dB AGC hysteresis
+        * MICes bias 2V
+        */
+       omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_4, AC4_MB_HED(0));
+
+       /* DAC left and right routed to SPK1/SPK2
+        * SPK1/SPK2 unmuted
+        * Keyclicks routed to SPK1/SPK2 */
+       omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_5, 
+                       AC5_DIFFIN |
+                       AC5_DAC2SPK1(3) | AC5_AST2SPK1 | AC5_KCL2SPK1 |
+                       AC5_DAC2SPK2(3) | AC5_AST2SPK2 | AC5_KCL2SPK2);
+       
+       /* routing selected to SPK1 goes also to OUT8P/OUT8N. (loudspeaker)
+        * analog sidetone routed to loudspeaker
+        * buzzer pga routed to loudspeaker
+        * keyclick routing to loudspeaker
+        * cellphone input routed to loudspeaker
+        * mic selection (control register 04h/page2) routed to cell phone output (CP_OUT)
+        * routing selected for SPK1 goes also to cellphone output (CP_OUT)
+        * OUT8P/OUT8N (loudspeakers) unmuted (0 = unmuted)
+        * Cellphone output is not muted (0 = unmuted)
+        * Enable loudspeaker short protection control (0 = enable protection)
+        * VGND short protection control (0 = enable protection)
+        */
+       omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_6,
+                       AC6_SPL2LSK | AC6_AST2LSK | AC6_BUZ2LSK | AC6_KCL2LSK |
+                       AC6_CPI2LSK | AC6_MIC2CPO | AC6_SPL2CPO);
+       current_playback_target = PLAYBACK_TARGET_LOUDSPEAKER;
+}
+
+void set_headphone_to_playback_target(void)
+{
+       /* power down SPK1, SPK2 and loudspeaker */
+       omap_tsc2101_audio_write(TSC2101_CODEC_POWER_CTRL,
+                       CPC_SP1PWDN | CPC_SP2PWDN | CPC_LDAPWDF);
+       /* ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled */
+       /* 1dB AGC hysteresis */
+       /* MICes bias 2V */
+       omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_4, AC4_MB_HED(0));
+                               
+       /* DAC left and right routed to SPK1/SPK2
+        * SPK1/SPK2 unmuted
+        * Keyclicks routed to SPK1/SPK2 */
+       omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_5,
+                       AC5_DAC2SPK1(3) | AC5_AST2SPK1 | AC5_KCL2SPK1 |
+                       AC5_DAC2SPK2(3) | AC5_AST2SPK2 | AC5_KCL2SPK2 |
+                       AC5_HDSCPTC);
+                       
+       /* OUT8P/OUT8N muted, CPOUT muted */
+       omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_6,
+                       AC6_MUTLSPK | AC6_MUTSPK2 | AC6_LDSCPTC |
+                       AC6_VGNDSCPTC);
+       current_playback_target = PLAYBACK_TARGET_HEADPHONE;
+}
+
+void set_telephone_to_playback_target(void)
+{
+       /* 
+        * 0110 1101 0101 1100
+        * power down MICBIAS_HED, Analog sidetone, SPK2, DAC, 
+        * Driver virtual ground, loudspeaker. Values D2-d5 are flags.
+        */      
+       omap_tsc2101_audio_write(TSC2101_CODEC_POWER_CTRL,
+                       CPC_MBIAS_HED | CPC_ASTPWD | CPC_SP2PWDN | CPC_DAPWDN |
+                       CPC_VGPWDN | CPC_LSPWDN);
+                       
+       /* 
+        * 0010 1010 0100 0000
+        * ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled
+        * 1dB AGC hysteresis
+        * MICes bias 2V
+        */
+       omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_4,
+                       AC4_MB_HND | AC4_MB_HED(0) | AC4_AGCHYS(1) | 
+                       AC4_BISTPD | AC4_ASSTPD | AC4_DASTPD);
+       printk("set_telephone_to_playback_target(), TSC2101_AUDIO_CTRL_4 = %d\n", omap_tsc2101_audio_read(TSC2101_AUDIO_CTRL_4));
+                       
+       /* 
+        * 1110 0010 0000 0010
+        * DAC left and right routed to SPK1/SPK2
+        * SPK1/SPK2 unmuted
+        * keyclicks routed to SPK1/SPK2
+        */      
+       omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_5,
+                       AC5_DIFFIN | AC5_DAC2SPK1(3) | 
+                       AC5_CPI2SPK1 | AC5_MUTSPK2);
+       
+       omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_6,
+                       AC6_MIC2CPO | AC6_MUTLSPK | 
+                       AC6_LDSCPTC | AC6_VGNDSCPTC | AC6_CAPINTF);
+       current_playback_target = PLAYBACK_TARGET_CELLPHONE;
+}
+
+/*
+ * 1100 0101 1101 0000
+ * 
+ * #define MPC_ASTMU           TSC2101_BIT(15)
+ * #define MPC_ASTG(ARG)       (((ARG) & 0x7F) << 8)
+ * #define MPC_MICSEL(ARG)     (((ARG) & 0x07) << 5)
+ * #define MPC_MICADC          TSC2101_BIT(4)
+ * #define MPC_CPADC           TSC2101_BIT(3)
+ * #define MPC_ASTGF           (0x01)
+ */
+static void set_telephone_to_record_source(void)
+{
+       u16     val;
+       
+       /* 
+        * D0       = 0: 
+        *              --> AGC is off for handset input.
+        *              --> ADC PGA is controlled by the ADMUT_HDN + ADPGA_HND
+        *          (D15, D14-D8)
+        * D4 - D1  = 0000 
+        *              --> AGC time constant for handset input, 
+        *              attack time = 8 mc, decay time = 100 ms
+        * D7 - D5  = 000
+        *              --> AGC Target gain for handset input = -5.5 db
+        * D14 - D8 = 011 1100
+        *              --> ADC handset PGA settings = 60 = 30 db
+        * D15          = 0
+        *              --> Handset input ON (unmuted)
+        */
+       val     = 0x3c00;       // 0011 1100 0000 0000 = 60 = 30
+       omap_tsc2101_audio_write(TSC2101_HANDSET_GAIN_CTRL, val);
+       
+       /*
+        * D0           = 0
+        *              --> AGC is off for headset/Aux input
+        *              --> ADC headset/Aux PGA is contoller by ADMUT_HED + ADPGA_HED
+        *          (D15, D14-D8)
+        * D4 - D1      = 0000 
+        *              --> Agc constant for headset/Aux input,
+        *              attack time = 8 mc, decay time = 100 ms      
+        * D7 - D5      = 000
+        *              --> AGC target gain for headset input = -5.5 db
+        * D14 - D8 = 000 0000
+        *              --> Adc headset/AUX pga settings = 0 db
+        * D15          = 1
+        *              --> Headset/AUX input muted
+        * 
+        * Mute headset aux input
+        */
+       val     = 0x8000;       // 1000 0000 0000 0000
+       omap_tsc2101_audio_write(TSC2101_HEADSET_GAIN_CTRL, val);
+       set_record_source(REC_SRC_MICIN_HND_AND_AUX1);
+
+       // hacks start
+       /* D0           = flag, Headset/Aux or handset PGA flag
+        *              --> & with 1 (= 1 -->gain applied == pga register settings)
+        * D1           = 0, DAC channel PGA soft stepping control
+        *              --> 0.5 db change every WCLK
+        * D2           = flag, DAC right channel PGA flag
+        *              --> & with 1
+        * D3           = flag, DAC left channel PGA flag
+        *              -- > & with 1
+        * D7 - D4      = 0001, keyclick length
+        *              --> 4 periods key clicks
+        * D10 - D8 = 100, keyclick frequenzy
+        *              --> 1 kHz, 
+        * D11          = 0, Headset/Aux or handset soft stepping control
+        *              --> 0,5 db change every WCLK or ADWS
+        * D14 -D12 = 100, Keyclick applitude control
+        *              --> Medium amplitude
+        * D15          = 0, keyclick disabled
+        */
+       val     = omap_tsc2101_audio_read(TSC2101_AUDIO_CTRL_2);
+       val     = val & 0x441d;
+       val     = val | 0x4410; // D14, D10, D4 bits == 1
+       omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_2, val);
+
+       /*
+        * D0           = 0     (reserved, write always 0)
+        * D1           = flag,
+        *                      --> & with 1
+        * D2 - D5      = 0000 (reserved, write always 0000)
+        * D6           = 1
+        *                      --> MICBIAS_HND = 2.0 v
+        * D8 - D7      = 00
+        *                      --> MICBIAS_HED = 3.3 v
+        * D10 - D9     = 01, 
+        *                      --> Mic AGC hysteric selection = 2 db
+        * D11          = 1, 
+        *                      --> Disable buzzer PGA soft stepping
+        * D12          = 0,
+        *                      --> Enable CELL phone PGA soft stepping control
+        * D13          = 1
+        *                      --> Disable analog sidetone soft stepping control
+        * D14          = 0
+        *                      --> Enable DAC PGA soft stepping control
+        * D15          = 0,
+        *                      --> Enable headset/Aux or Handset soft stepping control
+        */
+       val     = omap_tsc2101_audio_read(TSC2101_AUDIO_CTRL_4);
+       val     = val & 0x2a42; // 0010 1010 0100 0010
+       val     = val | 0x2a40; // bits D13, D11, D9, D6 == 1
+       omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_4, val);
+       printk("set_telephone_to_record_source(), TSC2101_AUDIO_CTRL_4 = %d\n", omap_tsc2101_audio_read(TSC2101_AUDIO_CTRL_4));
+       /*
+        * D0           = 0
+        *              --> reserved, write always = 0
+        * D1           = flag, read only
+        *              --> & with 1
+        * D5 - D2      = 1111, Buzzer input PGA settings
+        *              --> 0 db
+        * D6           = 1,
+        *              --> power down buzzer input pga
+        * D7           = flag, read only
+        *              --> & with 1
+        * D14 - D8     = 101 1101
+        *              --> 12 DB
+        * D15          = 0
+        *              --> power up cell phone input PGA
+        */
+       val     = omap_tsc2101_audio_read(TSC2101_BUZZER_GAIN_CTRL);
+       val     = val & 0x5dfe;
+       val     = val | 0x5dfe; // bits, D14, D12, D11, D10, D8, D6, D5,D4,D3,D2
+       omap_tsc2101_audio_write(TSC2101_BUZZER_GAIN_CTRL, val);
+       
+       /* D6 - D0      = 000 1001
+        *              --> -4.5 db for DAC right channel volume control
+        * D7           = 1
+        *              -->  DAC right channel muted
+        * D14 - D8 = 000 1001
+        *              --> -4.5 db for DAC left channel volume control
+        * D15          = 1
+        *              --> DAC left channel muted
+        */
+       //val   = omap_tsc2101_audio_read(TSC2101_DAC_GAIN_CTRL);
+       val     = 0x8989;
+       omap_tsc2101_audio_write(TSC2101_DAC_GAIN_CTRL, val);   
+       
+       /*  0000 0000 0100 0000
+        * 
+        * D1 - D0      = 0
+        *              --> GPIO 1 pin output is three stated
+        * D2           = 0
+        *              --> Disaple GPIO2 for CLKOUT mode
+        * D3           = 0
+        *              --> Disable GPUI1 for interrupt detection
+        * D4           = 0
+        *              --> Disable GPIO2 for headset detection interrupt
+        * D5           = reserved, always 0
+        * D7 - D6      = 01
+        *              --> 8 ms clitch detection
+        * D8           = reserved, write only 0
+        * D10 -D9      = 00
+        *              --> 16 ms de bouncing programmatitily 
+        *          for glitch detection during headset detection
+        * D11          = flag for button press
+        * D12          = flag for headset detection
+        * D14-D13      = 00
+        *              --> type of headset detected = 00 == no stereo headset deected
+        * D15          = 0
+        *              --> Disable headset detection
+        * 
+        * */
+       val     = 0x40;
+       omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_7, val);    
+}
+
+/*
+ * Checks whether the headset is detected.
+ * If headset is detected, the type is returned. Type can be
+ *     0x01    = stereo headset detected
+ *     0x02    = cellurar headset detected
+ *     0x03    = stereo + cellurar headset detected
+ * If headset is not detected 0 is returned.
+ */
+u16 get_headset_detected(void)
+{
+       u16     curDetected;
+       u16     curType;
+       u16     curVal;
+       
+       curType = 0;    /* not detected */
+       curVal  = omap_tsc2101_audio_read(TSC2101_AUDIO_CTRL_7);
+       curDetected     = curVal & AC7_HDDETFL;
+       if (curDetected) {
+               printk("headset detected, checking type from %d \n", curVal);
+               curType = ((curVal & 0x6000) >> 13);
+               printk("headset type detected = %d \n", curType);
+       }
+       else {
+               printk("headset not detected\n");
+       }
+       return curType;
+}
+
+void init_playback_targets(void)
+{
+       u16     val;
+
+       set_loudspeaker_to_playback_target();
+       /* Left line input volume control
+        * = SET_LINE in the OSS driver
+        */
+       set_mixer_volume_as_headset_gain_control_volume(DEFAULT_INPUT_VOLUME);
+
+       /* Set headset to be controllable by handset mixer
+        * AGC enable for handset input
+        * Handset input not muted
+        */
+       val     = omap_tsc2101_audio_read(TSC2101_HANDSET_GAIN_CTRL);
+       val     = val | HNGC_AGCEN_HND; 
+       val     = val & ~HNGC_ADMUT_HND;
+       omap_tsc2101_audio_write(TSC2101_HANDSET_GAIN_CTRL, val);       
+                       
+       /* mic input volume control
+        * SET_MIC in the OSS driver 
+        */
+       set_mixer_volume_as_handset_gain_control_volume(DEFAULT_INPUT_VOLUME);
+
+       /* Left/Right headphone channel volume control
+        * Zero-cross detect on
+        */
+       set_mixer_volume_as_dac_gain_control_volume(DEFAULT_OUTPUT_VOLUME, DEFAULT_OUTPUT_VOLUME);      
+       /* unmute */
+       dac_gain_control_unmute(1, 1);
+}
+
+/*
+ * Initializes tsc2101 recourd source (to line) and playback target (to loudspeaker)
+ */
+void snd_omap_init_mixer(void)
+{      
+       FN_IN;
+       
+       /* Headset/Hook switch detect enabled */
+       omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_7, AC7_DETECT);
+
+       /* Select headset to record source (MIC_INHED)*/
+       set_record_source(REC_SRC_SINGLE_ENDED_MICIN_HED);
+       /* Init loudspeaker as a default playback target*/
+       init_playback_targets();
+
+       FN_OUT(0);
+}
+
+static int __pcm_playback_target_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) 
+{
+       static char *texts[PLAYBACK_TARGET_COUNT] = {
+               "Loudspeaker", "Headphone", "Cellphone"
+       };
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = PLAYBACK_TARGET_COUNT;
+       if (uinfo->value.enumerated.item > PLAYBACK_TARGET_COUNT - 1) {
+               uinfo->value.enumerated.item = PLAYBACK_TARGET_COUNT - 1;
+       }
+       strcpy(uinfo->value.enumerated.name,
+               texts[uinfo->value.enumerated.item]);
+       return 0;
+}
+
+static int __pcm_playback_target_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
+{
+       ucontrol->value.integer.value[0] = current_playback_target;
+       return 0;
+}
+
+static int __pcm_playback_target_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
+{
+       int     retVal;
+       int     curVal;
+       
+       retVal  = 0;
+       curVal  = ucontrol->value.integer.value[0];
+       if ((curVal >= 0) &&
+           (curVal < PLAYBACK_TARGET_COUNT) &&
+           (curVal != current_playback_target)) {              
+               if (curVal == PLAYBACK_TARGET_LOUDSPEAKER) {
+                       set_record_source(REC_SRC_SINGLE_ENDED_MICIN_HED);
+                       set_loudspeaker_to_playback_target();
+               }
+               else if (curVal == PLAYBACK_TARGET_HEADPHONE) {
+                       set_record_source(REC_SRC_SINGLE_ENDED_MICIN_HND);
+                       set_headphone_to_playback_target();
+               }
+               else if (curVal == PLAYBACK_TARGET_CELLPHONE) {
+                       set_telephone_to_record_source();
+                       set_telephone_to_playback_target();
+               }
+               retVal  = 1;
+       }
+       return retVal;
+}      
+
+static int __pcm_playback_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) 
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count                    = 2;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 100;
+       return 0;
+}
+
+/*
+ * Alsa mixer interface function for getting the volume read from the DGC in a 
+ * 0 -100 alsa mixer format.
+ */
+static int __pcm_playback_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
+{
+       u16 volL;
+       u16 volR;       
+       u16 val;
+       
+       val     = omap_tsc2101_audio_read(TSC2101_DAC_GAIN_CTRL);
+       M_DPRINTK("registry value = %d!\n", val);
+       volL    = DGC_DALVL_EXTRACT(val);
+       volR    = DGC_DARVL_EXTRACT(val);
+       /* make sure that other bits are not on */
+       volL    = volL & ~DGC_DALMU;
+       volR    = volR & ~DGC_DARMU;
+
+       volL    = get_dac_gain_control_volume_as_mixer_volume(volL);
+       volR    = get_dac_gain_control_volume_as_mixer_volume(volR);
+       
+       ucontrol->value.integer.value[0]        = volL; /* L */
+       ucontrol->value.integer.value[1]        = volR; /* R */
+       
+       M_DPRINTK("mixer volume left = %ld, right = %ld\n", ucontrol->value.integer.value[0], ucontrol->value.integer.value[1]);
+       return 0;
+}
+
+static int __pcm_playback_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
+{
+       return set_mixer_volume_as_dac_gain_control_volume(ucontrol->value.integer.value[0], 
+                                                       ucontrol->value.integer.value[1]);
+}
+
+static int __pcm_playback_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) 
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count                    = 2;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 1;
+       return 0;
+}
+
+/* 
+ * When DGC_DALMU (bit 15) is 1, the left channel is muted.
+ * When DGC_DALMU is 0, left channel is not muted.
+ * Same logic apply also for the right channel.
+ */
+static int __pcm_playback_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
+{
+       u16 val = omap_tsc2101_audio_read(TSC2101_DAC_GAIN_CTRL);
+       
+       ucontrol->value.integer.value[0]        = IS_UNMUTED(15, val);  // left
+       ucontrol->value.integer.value[1]        = IS_UNMUTED(7, val);   // right
+       return 0;
+}
+
+static int __pcm_playback_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
+{
+       return dac_gain_control_unmute(ucontrol->value.integer.value[0], 
+                                       ucontrol->value.integer.value[1]);
+}
+
+static int __headset_playback_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) 
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count                    = 1;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 100;
+       return 0;
+}
+
+static int __headset_playback_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
+{
+       u16 val;
+       u16 vol;
+       
+       val     = omap_tsc2101_audio_read(TSC2101_HEADSET_GAIN_CTRL);
+       M_DPRINTK("registry value = %d\n", val);
+       vol     = HGC_ADPGA_HED_EXTRACT(val);
+       vol     = vol & ~HGC_ADMUT_HED;
+
+       vol     = get_headset_gain_control_volume_as_mixer_volume(vol);
+       ucontrol->value.integer.value[0]        = vol;
+       
+       M_DPRINTK("mixer volume returned = %ld\n", ucontrol->value.integer.value[0]);
+       return 0;
+}
+
+static int __headset_playback_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
+{
+       return set_mixer_volume_as_headset_gain_control_volume(ucontrol->value.integer.value[0]);       
+}
+
+static int __headset_playback_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) 
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count                    = 1;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 1;
+       return 0;
+}
+
+/* When HGC_ADMUT_HED (bit 15) is 1, the headset is muted.
+ * When HGC_ADMUT_HED is 0, headset is not muted.
+ */
+static int __headset_playback_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
+{
+       u16 val = omap_tsc2101_audio_read(TSC2101_HEADSET_GAIN_CTRL);
+       ucontrol->value.integer.value[0]        = IS_UNMUTED(15, val);
+       return 0;
+}
+
+static int __headset_playback_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
+{
+       // mute/unmute headset
+       return adc_pga_unmute_control(ucontrol->value.integer.value[0],
+                               TSC2101_HEADSET_GAIN_CTRL,
+                               15);
+}
+
+static int __handset_playback_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) 
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count                    = 1;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 100;
+       return 0;
+}
+
+static int __handset_playback_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
+{
+       u16 val;
+       u16 vol;
+       
+       val     = omap_tsc2101_audio_read(TSC2101_HANDSET_GAIN_CTRL);
+       M_DPRINTK("registry value = %d\n", val);
+       vol     = HNGC_ADPGA_HND_EXTRACT(val);
+       vol     = vol & ~HNGC_ADMUT_HND;
+       vol     = get_handset_gain_control_volume_as_mixer_volume(vol);
+       ucontrol->value.integer.value[0]        = vol;
+       
+       M_DPRINTK("mixer volume returned = %ld\n", ucontrol->value.integer.value[0]);
+       return 0;
+}
+
+static int __handset_playback_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
+{
+       return set_mixer_volume_as_handset_gain_control_volume(ucontrol->value.integer.value[0]);       
+}
+
+static int __handset_playback_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) 
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count                    = 1;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 1;
+       return 0;
+}
+
+/* When HNGC_ADMUT_HND (bit 15) is 1, the handset is muted.
+ * When HNGC_ADMUT_HND is 0, handset is not muted.
+ */
+static int __handset_playback_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
+{
+       u16 val = omap_tsc2101_audio_read(TSC2101_HANDSET_GAIN_CTRL);
+       ucontrol->value.integer.value[0]        = IS_UNMUTED(15, val);
+       return 0;
+}
+
+static int __handset_playback_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
+{
+       // handset mute/unmute
+       return adc_pga_unmute_control(ucontrol->value.integer.value[0],
+                               TSC2101_HANDSET_GAIN_CTRL,
+                               15);
+}
+
+static int __cellphone_input_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) 
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count                    = 1;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 1;
+       return 0;
+}
+
+/* When BGC_MUT_CP (bit 15) = 1, power down cellphone input pga.
+ * When BGC_MUT_CP = 0, power up cellphone input pga.
+ */
+static int __cellphone_input_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
+{
+       u16 val = omap_tsc2101_audio_read(TSC2101_BUZZER_GAIN_CTRL);
+       ucontrol->value.integer.value[0]        = IS_UNMUTED(15, val);
+       return 0;
+}
+
+static int __cellphone_input_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
+{
+       return adc_pga_unmute_control(ucontrol->value.integer.value[0],
+                               TSC2101_BUZZER_GAIN_CTRL,
+                               15);    
+}
+
+static int __buzzer_input_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) 
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count                    = 1;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 1;
+       return 0;
+}
+
+/* When BGC_MUT_BU (bit 6) = 1, power down cellphone input pga.
+ * When BGC_MUT_BU = 0, power up cellphone input pga.
+ */
+static int __buzzer_input_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
+{
+       u16 val = omap_tsc2101_audio_read(TSC2101_BUZZER_GAIN_CTRL);
+       ucontrol->value.integer.value[0]        = IS_UNMUTED(6, val);
+       return 0;
+}
+
+static int __buzzer_input_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
+{
+       return adc_pga_unmute_control(ucontrol->value.integer.value[0],
+                               TSC2101_BUZZER_GAIN_CTRL,
+                               6);     
+}
+
+static snd_kcontrol_new_t tsc2101_control[] __devinitdata = {
+       {
+               .name  = "Target Playback Route",
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index = 0,
+               .access= SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info  = __pcm_playback_target_info,
+               .get   = __pcm_playback_target_get,
+               .put   = __pcm_playback_target_put,
+       }, {
+               .name  = "Master Playback Volume",
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index = 0,
+               .access= SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info  = __pcm_playback_volume_info,
+               .get   = __pcm_playback_volume_get,
+               .put   = __pcm_playback_volume_put,
+       }, {
+               .name  = "Master Playback Switch",
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index = 0,
+               .access= SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info  = __pcm_playback_switch_info,
+               .get   = __pcm_playback_switch_get,
+               .put   = __pcm_playback_switch_put,
+       }, {
+               .name  = "Headset Playback Volume",
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index = 0,
+               .access= SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info  = __headset_playback_volume_info,
+               .get   = __headset_playback_volume_get,
+               .put   = __headset_playback_volume_put,
+       }, {
+               .name  = "Headset Playback Switch",
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index = 0,
+               .access= SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info  = __headset_playback_switch_info,
+               .get   = __headset_playback_switch_get,
+               .put   = __headset_playback_switch_put,
+       }, {
+               .name  = "Handset Playback Volume",
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index = 0,
+               .access= SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info  = __handset_playback_volume_info,
+               .get   = __handset_playback_volume_get,
+               .put   = __handset_playback_volume_put,
+       }, {
+               .name  = "Handset Playback Switch",
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index = 0,
+               .access= SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info  = __handset_playback_switch_info,
+               .get   = __handset_playback_switch_get,
+               .put   = __handset_playback_switch_put,
+       }, {
+               .name  = "Cellphone Input Switch",
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index = 0,
+               .access= SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info  = __cellphone_input_switch_info,
+               .get   = __cellphone_input_switch_get,
+               .put   = __cellphone_input_switch_put,
+       }, {
+               .name  = "Buzzer Input Switch",
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index = 0,
+               .access= SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info  = __buzzer_input_switch_info,
+               .get   = __buzzer_input_switch_get,
+               .put   = __buzzer_input_switch_put,
+       }
+};
+
+#ifdef CONFIG_PM
+
+void snd_omap_suspend_mixer(void)
+{
+}
+
+void snd_omap_resume_mixer(void)
+{
+       snd_omap_init_mixer();
+}
+#endif
+
+int snd_omap_mixer(struct snd_card_omap_codec *tsc2101) 
+{
+       int i=0;
+       int err=0;
+
+       if (!tsc2101) {
+               return -EINVAL;
+       }
+       for (i=0; i < ARRAY_SIZE(tsc2101_control); i++) {
+               if ((err = snd_ctl_add(tsc2101->card, 
+                               snd_ctl_new1(&tsc2101_control[i], 
+                               tsc2101->card))) < 0) {
+                       return err;
+               }
+       }
+       return 0;
+}
diff --git a/sound/arm/omap/omap-alsa-tsc2101-mixer.h b/sound/arm/omap/omap-alsa-tsc2101-mixer.h
new file mode 100644 (file)
index 0000000..3f27e27
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * sound/arm/omap/omap-alsa-tsc2101-mixer.c
+ * 
+ * Alsa Driver for TSC2101 codec for OMAP platform boards.
+ *
+ * Copyright (C) 2005 Mika Laitio <lamikr@cc.jyu.fi> and 
+ *                  Everett Coleman II <gcc80x86@fuzzyneural.net>
+ *
+ * Based on the ideas in omap-aic23.c and sa11xx-uda1341.c
+ * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ * Copyright (C) 2002 Tomas Kasparek <tomas.kasparek@seznam.cz>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the  GNU General Public License along
+ * with this program; if not, write  to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * History:
+ *
+ * 2006-03-01   Mika Laitio - Mixer for the tsc2101 driver used in omap boards.
+ *             Can switch between headset and loudspeaker playback, 
+ *             mute and unmute dgc, set dgc volume. Record source switch,
+ *             keyclick, buzzer and headset volume and handset volume control 
+ *             are still missing.
+ */
+
+#ifndef OMAPALSATSC2101MIXER_H_
+#define OMAPALSATSC2101MIXER_H_
+
+#include <asm/hardware/tsc2101.h>
+#include <../drivers/ssi/omap-tsc2101.h>
+#include "omap-alsa-dma.h"
+
+/* tsc2101 DAC gain control volume specific  */
+#define OUTPUT_VOLUME_MIN              0x7F    // 1111111 = -63.5 DB
+#define OUTPUT_VOLUME_MAX              0x32    // 110010
+#define OUTPUT_VOLUME_RANGE            (OUTPUT_VOLUME_MIN - OUTPUT_VOLUME_MAX)
+
+/* use input vol of 75 for 0dB gain */
+#define INPUT_VOLUME_MIN               0x0
+#define INPUT_VOLUME_MAX               0x7D
+#define INPUT_VOLUME_RANGE             (INPUT_VOLUME_MAX - INPUT_VOLUME_MIN)
+
+#define PLAYBACK_TARGET_COUNT          0x03
+#define PLAYBACK_TARGET_LOUDSPEAKER    0x00
+#define PLAYBACK_TARGET_HEADPHONE      0x01
+#define PLAYBACK_TARGET_CELLPHONE      0x02
+
+/* following are used for register 03h Mixer PGA control bits D7-D5 for selecting record source */
+#define REC_SRC_TARGET_COUNT           0x08
+#define REC_SRC_SINGLE_ENDED_MICIN_HED 0x00    // oss code referred to MIXER_LINE
+#define REC_SRC_SINGLE_ENDED_MICIN_HND 0x01    // oss code referred to MIXER_MIC
+#define REC_SRC_SINGLE_ENDED_AUX1      0x02
+#define REC_SRC_SINGLE_ENDED_AUX2      0x03
+#define REC_SRC_MICIN_HED_AND_AUX1     0x04
+#define REC_SRC_MICIN_HED_AND_AUX2     0x05
+#define REC_SRC_MICIN_HND_AND_AUX1     0x06
+#define REC_SRC_MICIN_HND_AND_AUX2     0x07
+
+#define DEFAULT_OUTPUT_VOLUME          90      // default output volume to dac dgc
+#define DEFAULT_INPUT_VOLUME           20      // default record volume
+
+#define TSC2101_AUDIO_CODEC_REGISTERS_PAGE2     (2)
+
+#endif /*OMAPALSATSC2101MIXER_H_*/
diff --git a/sound/arm/omap/omap-alsa-tsc2101.c b/sound/arm/omap/omap-alsa-tsc2101.c
new file mode 100644 (file)
index 0000000..9bbf0c7
--- /dev/null
@@ -0,0 +1,438 @@
+/*
+ * arch/arm/mach-omap1/omap-alsa-tsc2101.c
+ * 
+ * Alsa codec Driver for TSC2101 chip for OMAP platform boards. 
+ * Code obtained from oss omap drivers
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *     Written by Nishanth Menon and Sriram Kannan
+ *     
+ * Copyright (C) 2006 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ *     Alsa modularization by Daniel Petrini (d.pensator@gmail.com)
+ * 
+ * Copyright (C) 2006 Mika Laitio <lamikr@cc.jyu.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/delay.h>
+#include <linux/soundcard.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <asm/io.h>
+#include <asm/arch/mcbsp.h>
+
+#include <linux/slab.h>
+#ifdef CONFIG_PM
+#include <linux/pm.h>
+#endif
+#include <asm/mach-types.h>
+#include <asm/arch/dma.h>
+#include <asm/arch/clock.h>
+
+#include <asm/hardware/tsc2101.h>
+#include <../drivers/ssi/omap-tsc2101.h>
+
+#include <asm/arch/omap-alsa.h>
+#include "omap-alsa-tsc2101.h"
+
+static struct clk *tsc2101_mclk = 0;
+
+//#define DUMP_TSC2101_AUDIO_REGISTERS
+#undef DUMP_TSC2101_AUDIO_REGISTERS
+
+/*
+ * Hardware capabilities 
+ */
+
+/*
+ * DAC USB-mode sampling rates (MCLK = 12 MHz)
+ * The rates and rate_reg_into MUST be in the same order
+ */
+static unsigned int rates[] = {
+       7350, 8000, 8018, 8727,
+       8820, 9600, 11025, 12000,
+       14700, 16000, 22050, 24000,
+       29400, 32000, 44100, 48000,
+};
+
+static snd_pcm_hw_constraint_list_t tsc2101_hw_constraints_rates = {
+       .count = ARRAY_SIZE(rates),
+       .list = rates,
+       .mask = 0,
+};
+
+static const struct tsc2101_samplerate_reg_info
+    rate_reg_info[NUMBER_SAMPLE_RATES_SUPPORTED] = {
+       /* Div 6 */
+       {7350, 7, 1},
+       {8000, 7, 0},
+       /* Div 5.5 */
+       {8018, 6, 1},
+       {8727, 6, 0},
+       /* Div 5 */
+       {8820, 5, 1},
+       {9600, 5, 0},   
+       /* Div 4 */
+       {11025, 4, 1},
+       {12000, 4, 0},
+       /* Div 3 */
+       {14700, 3, 1},
+       {16000, 3, 0},
+       /* Div 2 */
+       {22050, 2, 1},
+       {24000, 2, 0},
+       /* Div 1.5 */
+       {29400, 1, 1},
+       {32000, 1, 0},
+       /* Div 1 */
+       {44100, 0, 1},
+       {48000, 0, 0},          
+};
+
+static snd_pcm_hardware_t tsc2101_snd_omap_alsa_playback = {
+       .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),      
+#ifdef CONFIG_MACH_OMAP_H6300
+       .formats = (SNDRV_PCM_FMTBIT_S8),
+#else
+       .formats = (SNDRV_PCM_FMTBIT_S16_LE),
+#endif
+       .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
+                 SNDRV_PCM_RATE_16000 |
+                 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
+                 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+                 SNDRV_PCM_RATE_KNOT),
+       .rate_min = 7350,
+       .rate_max = 48000,
+       .channels_min = 2,
+       .channels_max = 2,
+       .buffer_bytes_max = 128 * 1024,
+       .period_bytes_min = 32,
+       .period_bytes_max = 8 * 1024,
+       .periods_min = 16,
+       .periods_max = 255,
+       .fifo_size = 0,
+};
+
+static snd_pcm_hardware_t tsc2101_snd_omap_alsa_capture = {
+       .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
+       .formats = (SNDRV_PCM_FMTBIT_S16_LE),
+       .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
+                 SNDRV_PCM_RATE_16000 |
+                 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
+                 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+                 SNDRV_PCM_RATE_KNOT),
+       .rate_min = 7350,
+       .rate_max = 48000,
+       .channels_min = 2,
+       .channels_max = 2,
+       .buffer_bytes_max = 128 * 1024,
+       .period_bytes_min = 32,
+       .period_bytes_max = 8 * 1024,
+       .periods_min = 16,
+       .periods_max = 255,
+       .fifo_size = 0,
+};
+
+/* 
+ * Simplified write for tsc2101 audio registers.
+ */
+inline void tsc2101_audio_write(u8 address, u16 data)
+{
+       omap_tsc2101_write(PAGE2_AUDIO_CODEC_REGISTERS, address, data);
+}
+
+/* 
+ * Simplified read for tsc2101 audio registers.
+ */
+inline u16 tsc2101_audio_read(u8 address)
+{
+       return (omap_tsc2101_read(PAGE2_AUDIO_CODEC_REGISTERS, address));
+}
+
+#ifdef DUMP_TSC2101_AUDIO_REGISTERS
+void dump_tsc2101_audio_reg(void) {
+       printk("TSC2101_AUDIO_CTRL_1 = 0x%04x\n",       tsc2101_audio_read(TSC2101_AUDIO_CTRL_1));
+       printk("TSC2101_HEADSET_GAIN_CTRL = 0x%04x\n",  tsc2101_audio_read(TSC2101_HEADSET_GAIN_CTRL));
+       printk("TSC2101_DAC_GAIN_CTRL = 0x%04x\n", tsc2101_audio_read(TSC2101_DAC_GAIN_CTRL));
+       printk("TSC2101_MIXER_PGA_CTRL = 0x%04x\n",     tsc2101_audio_read(TSC2101_MIXER_PGA_CTRL));
+       printk("TSC2101_AUDIO_CTRL_2 = 0x%04x\n",       tsc2101_audio_read(TSC2101_AUDIO_CTRL_2));
+       printk("TSC2101_CODEC_POWER_CTRL = 0x%04x\n",   tsc2101_audio_read(TSC2101_CODEC_POWER_CTRL));
+       printk("TSC2101_AUDIO_CTRL_3 = 0x%04x\n",       tsc2101_audio_read(TSC2101_AUDIO_CTRL_3));
+       printk("TSC2101_LCH_BASS_BOOST_N0 = 0x%04x\n",  tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_N0));
+       printk("TSC2101_LCH_BASS_BOOST_N1 = 0x%04x\n",  tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_N1));
+       printk("TSC2101_LCH_BASS_BOOST_N2 = 0x%04x\n",  tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_N2));
+       printk("TSC2101_LCH_BASS_BOOST_N3 = 0x%04x\n",  tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_N3));
+       printk("TSC2101_LCH_BASS_BOOST_N4 = 0x%04x\n",  tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_N4));
+       printk("TSC2101_LCH_BASS_BOOST_N5 = 0x%04x\n",  tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_N5));
+       printk("TSC2101_LCH_BASS_BOOST_D1 = 0x%04x\n",  tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_D1));
+       printk("TSC2101_LCH_BASS_BOOST_D2 = 0x%04x\n",  tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_D2));
+       printk("TSC2101_LCH_BASS_BOOST_D4 = 0x%04x\n",  tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_D4));
+       printk("TSC2101_LCH_BASS_BOOST_D5 = 0x%04x\n",  tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_D5));
+       
+       printk("TSC2101_RCH_BASS_BOOST_N0 = 0x%04x\n",  tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_N0));
+       printk("TSC2101_RCH_BASS_BOOST_N1 = 0x%04x\n",  tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_N1));
+       printk("TSC2101_RCH_BASS_BOOST_N2 = 0x%04x\n",  tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_N2));
+       printk("TSC2101_RCH_BASS_BOOST_N3 = 0x%04x\n",  tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_N3));
+       printk("TSC2101_RCH_BASS_BOOST_N4 = 0x%04x\n",  tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_N4));
+       printk("TSC2101_RCH_BASS_BOOST_N5 = 0x%04x\n",  tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_N5));
+       printk("TSC2101_RCH_BASS_BOOST_D1 = 0x%04x\n",  tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_D1));
+       printk("TSC2101_RCH_BASS_BOOST_D2 = 0x%04x\n",  tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_D2));
+       printk("TSC2101_RCH_BASS_BOOST_D4 = 0x%04x\n",  tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_D4));
+       printk("TSC2101_RCH_BASS_BOOST_D5 = 0x%04x\n",  tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_D5));
+                                       
+       printk("TSC2101_PLL_PROG_1 = 0x%04x\n", tsc2101_audio_read(TSC2101_PLL_PROG_1));
+       printk("TSC2101_PLL_PROG_1 = 0x%04x\n", tsc2101_audio_read(TSC2101_PLL_PROG_2));
+       printk("TSC2101_AUDIO_CTRL_4 = 0x%04x\n",       tsc2101_audio_read(TSC2101_AUDIO_CTRL_4));
+       printk("TSC2101_HANDSET_GAIN_CTRL = 0x%04x\n",  tsc2101_audio_read(TSC2101_HANDSET_GAIN_CTRL));
+       printk("TSC2101_BUZZER_GAIN_CTRL = 0x%04x\n",   tsc2101_audio_read(TSC2101_BUZZER_GAIN_CTRL));
+       printk("TSC2101_AUDIO_CTRL_5 = 0x%04x\n",       tsc2101_audio_read(TSC2101_AUDIO_CTRL_5));
+       printk("TSC2101_AUDIO_CTRL_6 = 0x%04x\n",       tsc2101_audio_read(TSC2101_AUDIO_CTRL_6));
+       printk("TSC2101_AUDIO_CTRL_7 = 0x%04x\n",       tsc2101_audio_read(TSC2101_AUDIO_CTRL_7));
+       printk("TSC2101_GPIO_CTRL = 0x%04x\n",  tsc2101_audio_read(TSC2101_GPIO_CTRL));
+       printk("TSC2101_AGC_CTRL = 0x%04x\n",   tsc2101_audio_read(TSC2101_AGC_CTRL));
+       printk("TSC2101_POWERDOWN_STS = 0x%04x\n",      tsc2101_audio_read(TSC2101_POWERDOWN_STS));
+       printk("TSC2101_MIC_AGC_CONTROL = 0x%04x\n",    tsc2101_audio_read(TSC2101_MIC_AGC_CONTROL));
+       printk("TSC2101_CELL_AGC_CONTROL = 0x%04x\n",   tsc2101_audio_read(TSC2101_CELL_AGC_CONTROL));
+}
+#endif
+
+/*
+ * ALSA operations according to board file
+ */
+
+/*
+ * Sample rate changing
+ */
+void tsc2101_set_samplerate(long sample_rate)
+{
+       u8 count = 0;
+       u16 data = 0;
+       int clkgdv = 0;
+
+       u16 srgr1, srgr2;
+       /* wait for any frame to complete */
+       udelay(125);
+       ADEBUG();
+
+       sample_rate     = sample_rate;
+       /* Search for the right sample rate */
+       while ((rate_reg_info[count].sample_rate != sample_rate) &&
+              (count < NUMBER_SAMPLE_RATES_SUPPORTED)) {
+               count++;
+       }
+       if (count == NUMBER_SAMPLE_RATES_SUPPORTED) {
+               printk(KERN_ERR "Invalid Sample Rate %d requested\n",
+                      (int) sample_rate);
+               return;         // -EPERM;
+       }
+
+       /* Set AC1 */
+       data    = tsc2101_audio_read(TSC2101_AUDIO_CTRL_1);
+       /* Clear prev settings */
+       data    &= ~(AC1_DACFS(0x07) | AC1_ADCFS(0x07));
+       data    |= AC1_DACFS(rate_reg_info[count].divisor) | 
+                       AC1_ADCFS(rate_reg_info[count].divisor);
+       tsc2101_audio_write(TSC2101_AUDIO_CTRL_1, data);
+
+       /* Set the AC3 */
+       data    = tsc2101_audio_read(TSC2101_AUDIO_CTRL_3);
+       /*Clear prev settings */
+       data    &= ~(AC3_REFFS | AC3_SLVMS);
+       data    |= (rate_reg_info[count].fs_44kHz) ? AC3_REFFS : 0;
+#ifdef TSC_MASTER
+       data    |= AC3_SLVMS;
+#endif                         /* #ifdef TSC_MASTER */
+       tsc2101_audio_write(TSC2101_AUDIO_CTRL_3, data);
+
+       /* Program the PLLs. This code assumes that the 12 Mhz MCLK is in use.
+         * If MCLK rate is something else, these values must be changed.
+        * See the tsc2101 specification for the details.
+        */
+       if (rate_reg_info[count].fs_44kHz) {
+               /* samplerate = (44.1kHZ / x), where x is int. */
+               tsc2101_audio_write(TSC2101_PLL_PROG_1, PLL1_PLLSEL |
+                               PLL1_PVAL(1) | PLL1_I_VAL(7));  /* PVAL 1; I_VAL 7 */
+               tsc2101_audio_write(TSC2101_PLL_PROG_2, PLL2_D_VAL(0x1490));    /* D_VAL 5264 */
+       } else {
+               /* samplerate = (48.kHZ / x), where x is int. */
+               tsc2101_audio_write(TSC2101_PLL_PROG_1, PLL1_PLLSEL |
+                              PLL1_PVAL(1) | PLL1_I_VAL(8));   /* PVAL 1; I_VAL 8 */
+               tsc2101_audio_write(TSC2101_PLL_PROG_2, PLL2_D_VAL(0x780));     /* D_VAL 1920 */
+       }
+
+       /* Set the sample rate */
+#ifndef TSC_MASTER
+       clkgdv  = CODEC_CLOCK / (sample_rate * (DEFAULT_BITPERSAMPLE * 2 - 1));
+       if (clkgdv)
+               srgr1 = (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
+       else
+               return (1);
+
+       /* Stereo Mode */
+       srgr2 = (CLKSM | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1));
+#else
+       srgr1 = (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
+       srgr2 = ((GSYNC | CLKSP | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1)));
+
+#endif                         /* end of #ifdef TSC_MASTER */
+       OMAP_MCBSP_WRITE(OMAP1610_MCBSP1_BASE, SRGR2, srgr2);
+       OMAP_MCBSP_WRITE(OMAP1610_MCBSP1_BASE, SRGR1, srgr1);
+}
+
+void tsc2101_configure(void)
+{
+}
+
+/*
+ *  Omap MCBSP clock and Power Management configuration
+ *  
+ *  Here we have some functions that allows clock to be enabled and
+ *   disabled only when needed. Besides doing clock configuration 
+ *   it allows turn on/turn off audio when necessary. 
+ */
+/*
+ * Do clock framework mclk search
+ */
+void tsc2101_clock_setup(void)
+{
+       tsc2101_mclk = clk_get(0, "mclk");
+}
+
+/*
+ * Do some sanity check, set clock rate, starts it and turn codec audio on
+ */
+int tsc2101_clock_on(void) 
+{
+       int     curUseCount;
+       uint    curRate;
+       int     err;
+
+       curUseCount     = clk_get_usecount(tsc2101_mclk);
+       DPRINTK("clock use count = %d\n", curUseCount);
+       if (curUseCount > 0) {
+               // MCLK is already in use
+               printk(KERN_WARNING
+                      "MCLK already in use at %d Hz. We change it to %d Hz\n",
+                      (uint) clk_get_rate(tsc2101_mclk),
+                      CODEC_CLOCK);
+       }
+       curRate = (uint)clk_get_rate(tsc2101_mclk);
+       if (curRate != CODEC_CLOCK) {
+               err     = clk_set_rate(tsc2101_mclk, CODEC_CLOCK);
+               if (err) {
+                       printk(KERN_WARNING
+                              "Cannot set MCLK clock rate for TSC2101 CODEC, error code = %d\n", err);
+                       return -ECANCELED;
+               }
+       }
+       err             = clk_enable(tsc2101_mclk);
+       curRate         = (uint)clk_get_rate(tsc2101_mclk);
+       curUseCount     = clk_get_usecount(tsc2101_mclk);
+       DPRINTK("MCLK = %d [%d], usecount = %d, clk_enable retval = %d\n",
+              curRate, 
+              CODEC_CLOCK,
+              curUseCount,
+              err);
+
+       // Now turn the audio on
+       omap_tsc2101_write(PAGE2_AUDIO_CODEC_REGISTERS,
+                       TSC2101_CODEC_POWER_CTRL,
+                       0x0000);        
+       return 0;       
+}
+
+/*
+ * Do some sanity check, turn clock off and then turn codec audio off
+ */
+int tsc2101_clock_off(void) 
+{
+       int curUseCount;
+       int curRate;
+
+       curUseCount     = clk_get_usecount(tsc2101_mclk);
+       DPRINTK("clock use count = %d\n", curUseCount);
+       if  (curUseCount > 0) {
+               curRate = clk_get_rate(tsc2101_mclk);
+               DPRINTK("clock rate = %d\n", curRate);
+               if (curRate != CODEC_CLOCK) {
+                       printk(KERN_WARNING
+                              "MCLK for audio should be %d Hz. But is %d Hz\n",
+                              (uint) clk_get_rate(tsc2101_mclk),
+                              CODEC_CLOCK);
+               }
+               clk_disable(tsc2101_mclk);
+               DPRINTK("clock disabled\n");
+       }
+       tsc2101_audio_write(TSC2101_CODEC_POWER_CTRL,
+                           ~(CPC_SP1PWDN | CPC_SP2PWDN | CPC_BASSBC));
+       DPRINTK("audio codec off\n");
+       return 0;       
+}
+
+int tsc2101_get_default_samplerate(void)
+{
+       return DEFAULT_SAMPLE_RATE;
+}
+
+static int __devinit snd_omap_alsa_tsc2101_probe(struct platform_device *pdev)
+{
+       int     ret;
+       struct  omap_alsa_codec_config *codec_cfg;
+       
+       codec_cfg = pdev->dev.platform_data;
+       if (codec_cfg != NULL) {
+               codec_cfg->hw_constraints_rates = &tsc2101_hw_constraints_rates;
+               codec_cfg->snd_omap_alsa_playback  = &tsc2101_snd_omap_alsa_playback;
+               codec_cfg->snd_omap_alsa_capture  = &tsc2101_snd_omap_alsa_capture;
+               codec_cfg->codec_configure_dev  = tsc2101_configure;
+               codec_cfg->codec_set_samplerate = tsc2101_set_samplerate;
+               codec_cfg->codec_clock_setup    = tsc2101_clock_setup;
+               codec_cfg->codec_clock_on       = tsc2101_clock_on;
+               codec_cfg->codec_clock_off      = tsc2101_clock_off;
+               codec_cfg->get_default_samplerate = tsc2101_get_default_samplerate;
+               ret     = snd_omap_alsa_post_probe(pdev, codec_cfg);
+       }
+       else
+               ret = -ENODEV;
+       return ret;
+}
+
+static struct platform_driver omap_alsa_driver = {
+       .probe          = snd_omap_alsa_tsc2101_probe,
+       .remove         = snd_omap_alsa_remove,
+       .suspend        = snd_omap_alsa_suspend,
+       .resume         = snd_omap_alsa_resume,
+       .driver = {
+               .name = "omap_alsa_mcbsp",
+       },
+};
+
+static int __init omap_alsa_tsc2101_init(void)
+{      
+       ADEBUG();
+#ifdef DUMP_TSC2101_AUDIO_REGISTERS
+       printk("omap_alsa_tsc2101_init()\n");
+       dump_tsc2101_audio_reg();
+#endif
+       return platform_driver_register(&omap_alsa_driver);
+}
+
+static void __exit omap_alsa_tsc2101_exit(void)
+{
+       ADEBUG();
+#ifdef DUMP_TSC2101_AUDIO_REGISTERS
+       printk("omap_alsa_tsc2101_exit()\n");
+       dump_tsc2101_audio_reg();
+#endif
+       platform_driver_unregister(&omap_alsa_driver);
+}
+
+module_init(omap_alsa_tsc2101_init);
+module_exit(omap_alsa_tsc2101_exit);
diff --git a/sound/arm/omap/omap-alsa-tsc2101.h b/sound/arm/omap/omap-alsa-tsc2101.h
new file mode 100644 (file)
index 0000000..803d215
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * arch/arc/mach-omap1/omap-alsa-tsc2101.h
+ * 
+ * Alsa Driver for TSC2101 codec for OMAP platform boards.
+ *
+ * Based on former omap-aic23.h and tsc2101 OSS drivers.
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *     Written by Nishanth Menon and Sriram Kannan
+ *
+ * Copyright (C) 2006 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ *          Alsa modularization by Daniel Petrini (d.pensator@gmail.com)
+ * 
+ * Copyright (C) 2006 Mika Laitio <lamikr@cc.jyu.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef OMAP_ALSA_TSC2101_H_
+#define OMAP_ALSA_TSC2101_H_
+
+#include <linux/types.h>
+
+/* Define to set the tsc as the master w.r.t McBSP */
+#define TSC_MASTER
+
+#define NUMBER_SAMPLE_RATES_SUPPORTED  16
+
+/*
+ * AUDIO related MACROS
+ */
+#ifndef DEFAULT_BITPERSAMPLE
+#define DEFAULT_BITPERSAMPLE           16
+#endif
+
+#define DEFAULT_SAMPLE_RATE            44100
+#define CODEC_CLOCK                    12000000
+#define AUDIO_MCBSP                    OMAP_MCBSP1
+
+#define PAGE2_AUDIO_CODEC_REGISTERS    (2)
+
+struct tsc2101_samplerate_reg_info {
+       u16 sample_rate;
+       u8 divisor;
+       u8 fs_44kHz;    /* if 0 48 khz, if 1 44.1 khz fsref */
+};
+
+/*
+ * Defines codec specific functions pointers that can be used from the 
+ * common omap-alse base driver for all omap codecs. (tsc2101 and aic23)
+ */
+inline void tsc2101_configure(void);
+void tsc2101_set_samplerate(long rate);
+void tsc2101_clock_setup(void);
+int tsc2101_clock_on(void);
+int tsc2101_clock_off(void);
+int tsc2101_get_default_samplerate(void);
+
+#endif /*OMAP_ALSA_TSC2101_H_*/
diff --git a/sound/arm/omap/omap-alsa-tsc2102-mixer.c b/sound/arm/omap/omap-alsa-tsc2102-mixer.c
new file mode 100644 (file)
index 0000000..2e06d70
--- /dev/null
@@ -0,0 +1,283 @@
+/*
+ * sound/arm/omap/omap-alsa-tsc2102-mixer.c
+ *
+ * Alsa mixer driver for TSC2102 chip for OMAP platforms.
+ *
+ * Copyright (c) 2006 Andrzej Zaborowski  <balrog@zabor.org>
+ * Code based on the TSC2101 ALSA driver.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the  GNU General Public License along
+ * with this program; if not, write  to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/types.h>
+#include <linux/spi/tsc2102.h>
+
+#include <asm/arch/omap-alsa.h>
+
+#include <sound/driver.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+
+#include "omap-alsa-tsc2102.h"
+#include "omap-alsa-dma.h"
+
+static int vol[2], mute[2], filter[2];
+
+/*
+ * Converts the Alsa mixer volume (0 - 100) to actual Digital
+ * Gain Control (DGC) value that can be written or read from the
+ * TSC2102 registers.
+ *
+ * Note that the number "OUTPUT_VOLUME_MAX" is smaller than
+ * OUTPUT_VOLUME_MIN because DGC works as a volume decreaser.  (The
+ * higher the value sent to DAC, the more the volume of controlled
+ * channel is decreased)
+ */
+static void set_dac_gain_stereo(int left_ch, int right_ch)
+{
+       int lch, rch;
+
+       if (left_ch > 100)
+               vol[0] = 100;
+       else if (left_ch < 0)
+               vol[0] = 0;
+       else
+               vol[0] = left_ch;
+       lch = OUTPUT_VOLUME_MIN - vol[0] *
+               (OUTPUT_VOLUME_MIN - OUTPUT_VOLUME_MAX) / 100;
+
+       if (right_ch > 100)
+               vol[1] = 100;
+       else if (right_ch < 0)
+               vol[1] = 0;
+       else
+               vol[1] = right_ch;
+       rch = OUTPUT_VOLUME_MIN - vol[1] *
+               (OUTPUT_VOLUME_MIN - OUTPUT_VOLUME_MAX) / 100;
+
+       tsc2102_set_volume(lch, rch);
+}
+
+void init_playback_targets(void)
+{
+       set_dac_gain_stereo(DEFAULT_OUTPUT_VOLUME, DEFAULT_OUTPUT_VOLUME);
+
+       /* Unmute */
+       tsc2102_set_mute(0, 0);
+
+       mute[0] = mute[1] = 0;
+       filter[0] = filter[1] = 0;
+}
+
+/*
+ * Initializes TSC 2102 and playback target.
+ */
+void snd_omap_init_mixer(void)
+{
+       FN_IN;
+
+       init_playback_targets();
+
+       FN_OUT(0);
+}
+
+static int __pcm_playback_volume_info(
+               snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count                    = 2;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 100;
+       return 0;
+}
+
+static int __pcm_playback_volume_get(
+               snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+       ucontrol->value.integer.value[0] = vol[0];      /* L */
+       ucontrol->value.integer.value[1] = vol[1];      /* R */
+
+       return 0;
+}
+
+static int __pcm_playback_volume_put(
+               snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+       set_dac_gain_stereo(
+                       ucontrol->value.integer.value[0],       /* L */
+                       ucontrol->value.integer.value[1]);      /* R */
+       return 1;
+}
+
+static int __pcm_playback_switch_info(
+               snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count                    = 2;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 1;
+       return 0;
+}
+
+static int __pcm_playback_switch_get(
+               snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+       ucontrol->value.integer.value[0] = !mute[0];            /* L */
+       ucontrol->value.integer.value[1] = !mute[1];            /* R */
+
+       return 0;
+}
+
+static int __pcm_playback_switch_put(
+               snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
+{
+       mute[0] = (ucontrol->value.integer.value[0] == 0);      /* L */
+       mute[1] = (ucontrol->value.integer.value[1] == 0);      /* R */
+
+       tsc2102_set_mute(mute[0], mute[1]);
+       return 1;
+}
+
+static int __pcm_playback_deemphasis_info(
+               snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count                    = 1;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 1;
+       return 0;
+}
+
+static int __pcm_playback_deemphasis_get(
+               snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+       ucontrol->value.integer.value[0] = filter[0];
+       return 0;
+}
+
+static int __pcm_playback_deemphasis_put(
+               snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
+{
+       filter[0] = (ucontrol->value.integer.value[0] > 0);
+
+       tsc2102_set_deemphasis(filter[0]);
+       return 1;
+}
+
+static int __pcm_playback_bassboost_info(
+               snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count                    = 1;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 1;
+       return 0;
+}
+
+static int __pcm_playback_bassboost_get(
+               snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+       ucontrol->value.integer.value[0] = filter[1];
+       return 0;
+}
+
+static int __pcm_playback_bassboost_put(
+               snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
+{
+       filter[1] = (ucontrol->value.integer.value[0] > 0);
+
+       tsc2102_set_bassboost(filter[1]);
+       return 1;
+}
+
+static snd_kcontrol_new_t tsc2102_control[] __devinitdata = {
+       {
+               .name   = "Master Playback Volume",
+               .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index  = 0,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info   = __pcm_playback_volume_info,
+               .get    = __pcm_playback_volume_get,
+               .put    = __pcm_playback_volume_put,
+       },
+       {
+               .name   = "Master Playback Switch",
+               .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index  = 0,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info   = __pcm_playback_switch_info,
+               .get    = __pcm_playback_switch_get,
+               .put    = __pcm_playback_switch_put,
+       },
+       {
+               .name   = "De-emphasis Filter Switch",
+               .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index  = 0,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info   = __pcm_playback_deemphasis_info,
+               .get    = __pcm_playback_deemphasis_get,
+               .put    = __pcm_playback_deemphasis_put,
+       },
+       {
+               .name   = "Bass-boost Filter Switch",
+               .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index  = 0,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info   = __pcm_playback_bassboost_info,
+               .get    = __pcm_playback_bassboost_get,
+               .put    = __pcm_playback_bassboost_put,
+       },
+};
+
+#ifdef CONFIG_PM
+void snd_omap_suspend_mixer(void)
+{
+       /* Nothing to do */
+}
+
+void snd_omap_resume_mixer(void)
+{
+       /* The chip was reset, restore the last used values */
+       set_dac_gain_stereo(vol[0], vol[1]);
+
+       tsc2102_set_mute(mute[0], mute[1]);
+       tsc2102_set_deemphasis(filter[0]);
+       tsc2102_set_bassboost(filter[1]);
+}
+#endif
+
+int snd_omap_mixer(struct snd_card_omap_codec *tsc2102)
+{
+       int i, err;
+
+       if (!tsc2102)
+               return -EINVAL;
+
+       for (i = 0; i < ARRAY_SIZE(tsc2102_control); i ++) {
+               err = snd_ctl_add(tsc2102->card,
+                               snd_ctl_new1(&tsc2102_control[i],
+                               tsc2102->card));
+
+               if (err < 0)
+                       return err;
+       }
+       return 0;
+}
diff --git a/sound/arm/omap/omap-alsa-tsc2102.c b/sound/arm/omap/omap-alsa-tsc2102.c
new file mode 100644 (file)
index 0000000..41e2d07
--- /dev/null
@@ -0,0 +1,317 @@
+/*
+ * sound/arm/omap/omap-alsa-tsc2102.c
+ * 
+ * Alsa codec driver for TSC2102 chip for OMAP platforms.
+ *
+ * Copyright (c) 2006 Andrzej Zaborowski  <balrog@zabor.org>
+ * Code based on the TSC2101 ALSA driver.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/delay.h>
+#include <linux/soundcard.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/spi/tsc2102.h>
+
+#include <asm/arch/mcbsp.h>
+#include <asm/arch/dma.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/omap-alsa.h>
+
+#include "omap-alsa-tsc2102.h"
+
+static struct clk *tsc2102_bclk = 0;
+
+/*
+ * Hardware capabilities
+ */
+
+/* DAC sampling rates (BCLK = 12 MHz) */
+static unsigned int rates[] = {
+       7350, 8000, 8820, 9600, 11025, 12000, 14700,
+       16000, 22050, 24000, 29400, 32000, 44100, 48000,
+};
+
+static snd_pcm_hw_constraint_list_t tsc2102_hw_constraints_rates = {
+       .count = ARRAY_SIZE(rates),
+       .list = rates,
+       .mask = 0,
+};
+
+static snd_pcm_hardware_t tsc2102_snd_omap_alsa_playback = {
+       .info                   = SNDRV_PCM_INFO_INTERLEAVED |
+               SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP |
+               SNDRV_PCM_INFO_MMAP_VALID,
+       .formats                = SNDRV_PCM_FMTBIT_S16_LE,
+       .rates                  = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
+               SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |
+               SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+               SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_KNOT,
+       .rate_min               = 7350,
+       .rate_max               = 48000,
+       .channels_min           = 2,
+       .channels_max           = 2,
+       .buffer_bytes_max       = 128 * 1024,
+       .period_bytes_min       = 32,
+       .period_bytes_max       = 8 * 1024,
+       .periods_min            = 16,
+       .periods_max            = 255,
+       .fifo_size              = 0,
+};
+
+#ifdef DUMP_TSC2102_AUDIO_REGISTERS
+static void dump_tsc2102_audio_regs(void) {
+       printk("TSC2102_AUDIO1_CTRL = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_AUDIO1_CTRL));
+       printk("TSC2102_DAC_GAIN_CTRL = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_DAC_GAIN_CTRL));
+       printk("TSC2102_AUDIO2_CTRL = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_AUDIO2_CTRL));
+       printk("TSC2102_DAC_POWER_CTRL = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_DAC_POWER_CTRL));
+       printk("TSC2102_AUDIO3_CTRL = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_AUDIO_CTRL_3));
+       printk("TSC2102_LCH_BASS_BOOST_N0 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_N0));
+       printk("TSC2102_LCH_BASS_BOOST_N1 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_N1));
+       printk("TSC2102_LCH_BASS_BOOST_N2 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_N2));
+       printk("TSC2102_LCH_BASS_BOOST_N3 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_N3));
+       printk("TSC2102_LCH_BASS_BOOST_N4 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_N4));
+       printk("TSC2102_LCH_BASS_BOOST_N5 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_N5));
+       printk("TSC2102_LCH_BASS_BOOST_D1 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_D1));
+       printk("TSC2102_LCH_BASS_BOOST_D2 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_D2));
+       printk("TSC2102_LCH_BASS_BOOST_D4 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_D4));
+       printk("TSC2102_LCH_BASS_BOOST_D5 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_D5));
+       printk("TSC2102_RCH_BASS_BOOST_N0 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_N0));
+       printk("TSC2102_RCH_BASS_BOOST_N1 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_N1));
+       printk("TSC2102_RCH_BASS_BOOST_N2 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_N2));
+       printk("TSC2102_RCH_BASS_BOOST_N3 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_N3));
+       printk("TSC2102_RCH_BASS_BOOST_N4 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_N4));
+       printk("TSC2102_RCH_BASS_BOOST_N5 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_N5));
+       printk("TSC2102_RCH_BASS_BOOST_D1 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_D1));
+       printk("TSC2102_RCH_BASS_BOOST_D2 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_D2));
+       printk("TSC2102_RCH_BASS_BOOST_D4 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_D4));
+       printk("TSC2102_RCH_BASS_BOOST_D5 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_D5));
+       printk("TSC2102_PLL1_CTRL = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_PLL1_CTRL));
+       printk("TSC2102_PLL2_CTRL = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_PLL2_CTRL));
+       printk("TSC2102_AUDIO4_CTRL = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_AUDIO4_CTRL));
+}
+#endif
+
+/*
+ * ALSA operations according to board file
+ */
+
+static long current_rate = 0;
+
+/*
+ * Sample rate changing
+ */
+static void tsc2102_set_samplerate(long sample_rate)
+{
+       int clkgdv = 0;
+       u16 srgr1, srgr2;
+
+       if (sample_rate == current_rate)
+               return;
+       current_rate = 0;
+
+       if (tsc2102_set_rate(sample_rate))
+               return;
+
+       /* Set the sample rate */
+#ifndef TSC_MASTER
+       clkgdv = CODEC_CLOCK / (sample_rate * (DEFAULT_BITPERSAMPLE * 2 - 1));
+       if (clkgdv)
+               srgr1 = (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
+       else
+               return;
+
+       /* Stereo Mode */
+       srgr2 = CLKSM | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1);
+#else
+       srgr1 = FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv);
+       srgr2 = GSYNC | CLKSP | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1);
+#endif
+       OMAP_MCBSP_WRITE(OMAP1510_MCBSP1_BASE, SRGR2, srgr2);
+       OMAP_MCBSP_WRITE(OMAP1510_MCBSP1_BASE, SRGR1, srgr1);
+       current_rate = sample_rate;
+}
+
+static void tsc2102_configure(void)
+{
+       tsc2102_dac_power(1);
+
+#ifdef TSC_MASTER
+       tsc2102_set_i2s_master(1);
+#else
+       tsc2102_set_i2s_master(0);
+#endif
+}
+
+/*
+ * Omap McBSP clock and Power Management configuration
+ *  
+ * Here we have some functions that allow clock to be enabled and
+ * disabled only when needed.  Besides doing clock configuration
+ * they allow turn audio on and off when necessary.
+ */
+
+/*
+ * Do clock framework bclk search
+ */
+static void tsc2102_clock_setup(void)
+{
+       tsc2102_bclk = clk_get(0, "bclk");
+}
+
+/*
+ * Do some sanity checks, set clock rate, start it.
+ */
+static int tsc2102_clock_on(void)
+{
+       int err;
+
+       if (clk_get_usecount(tsc2102_bclk) > 0 &&
+                       clk_get_rate(tsc2102_bclk) != CODEC_CLOCK) {
+               /* BCLK is already in use */
+               printk(KERN_WARNING
+                       "BCLK already in use at %d Hz. We change it to %d Hz\n",
+                       (uint) clk_get_rate(tsc2102_bclk), CODEC_CLOCK);
+
+               err = clk_set_rate(tsc2102_bclk, CODEC_CLOCK);
+               if (err)
+                       printk(KERN_WARNING "Cannot set BCLK clock rate "
+                               "for TSC2102 codec, error code = %d\n", err);
+       }
+
+       clk_enable(tsc2102_bclk);
+       return 0;
+}
+
+/*
+ * Turn off the audio codec and then stop the clock.
+ */
+static int tsc2102_clock_off(void)
+{
+       DPRINTK("clock use count = %d\n", clk_get_usecount(tsc2102_bclk));
+
+       clk_disable(tsc2102_bclk);
+       return 0;
+}
+
+static int tsc2102_get_default_samplerate(void)
+{
+       return DEFAULT_SAMPLE_RATE;
+}
+
+static int snd_omap_alsa_tsc2102_suspend(
+               struct platform_device *pdev, pm_message_t state)
+{
+       tsc2102_dac_power(0);
+       current_rate = 0;
+
+       return snd_omap_alsa_suspend(pdev, state);
+}
+
+static int snd_omap_alsa_tsc2102_resume(struct platform_device *pdev)
+{
+       tsc2102_dac_power(1);
+
+#ifdef TSC_MASTER
+       tsc2102_set_i2s_master(1);
+#else
+       tsc2102_set_i2s_master(0);
+#endif
+
+       return snd_omap_alsa_resume(pdev);
+}
+
+static int __init snd_omap_alsa_tsc2102_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct omap_alsa_codec_config *codec_cfg = pdev->dev.platform_data;
+
+       if (codec_cfg) {
+               codec_cfg->hw_constraints_rates =
+                       &tsc2102_hw_constraints_rates;
+               codec_cfg->snd_omap_alsa_playback =
+                       &tsc2102_snd_omap_alsa_playback;
+               codec_cfg->codec_configure_dev = tsc2102_configure;
+               codec_cfg->codec_set_samplerate = tsc2102_set_samplerate;
+               codec_cfg->codec_clock_setup = tsc2102_clock_setup;
+               codec_cfg->codec_clock_on = tsc2102_clock_on;
+               codec_cfg->codec_clock_off = tsc2102_clock_off;
+               codec_cfg->get_default_samplerate =
+                       tsc2102_get_default_samplerate;
+               ret = snd_omap_alsa_post_probe(pdev, codec_cfg);
+       } else
+               ret = -ENODEV;
+
+       return ret;
+}
+
+static int snd_omap_alsa_tsc2102_remove(struct platform_device *pdev)
+{
+       tsc2102_dac_power(0);
+
+       return snd_omap_alsa_remove(pdev);
+}
+
+static struct platform_driver omap_alsa_driver = {
+       .probe          = snd_omap_alsa_tsc2102_probe,
+       .remove         = snd_omap_alsa_tsc2102_remove,
+       .suspend        = snd_omap_alsa_tsc2102_suspend,
+       .resume         = snd_omap_alsa_tsc2102_resume,
+       .driver         = {
+               .name   = "tsc2102-alsa",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init omap_alsa_tsc2102_init(void)
+{
+       int err;
+
+       ADEBUG();
+       err = platform_driver_register(&omap_alsa_driver);
+
+       return err;
+}
+
+static void __exit omap_alsa_tsc2102_exit(void)
+{
+       ADEBUG();
+       platform_driver_unregister(&omap_alsa_driver);
+}
+
+module_init(omap_alsa_tsc2102_init);
+module_exit(omap_alsa_tsc2102_exit);
diff --git a/sound/arm/omap/omap-alsa-tsc2102.h b/sound/arm/omap/omap-alsa-tsc2102.h
new file mode 100644 (file)
index 0000000..c4b34f8
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * sound/arm/omap/omap-alsa-tsc2102.h
+ * 
+ * Alsa codec driver for TSC2102 chip for OMAP platforms.
+ *
+ * Copyright (c) 2006 Andrzej Zaborowski  <balrog@zabor.org>
+ * Code based on the TSC2101 ALSA driver.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef OMAP_ALSA_TSC2102_H_
+#define OMAP_ALSA_TSC2102_H_
+
+/* Define to set the tsc as the master w.r.t McBSP */
+#define TSC_MASTER
+
+/*
+ * Audio related macros
+ */
+#ifndef DEFAULT_BITPERSAMPLE
+#define DEFAULT_BITPERSAMPLE           16
+#endif
+
+#define DEFAULT_SAMPLE_RATE            44100
+#define CODEC_CLOCK                    12000000
+#define AUDIO_MCBSP                    OMAP_MCBSP1
+
+/*
+ * ALSA mixer related macros
+ */
+#define OUTPUT_VOLUME_MIN              0x7f    /* 1111111 = -63.5 dB */
+#define OUTPUT_VOLUME_MAX              0x00    /* 0000000 */
+#define OUTPUT_VOLUME_RANGE            (OUTPUT_VOLUME_MIN - OUTPUT_VOLUME_MAX)
+
+#define DEFAULT_OUTPUT_VOLUME          90      /* Default output volume */
+
+#endif /* OMAP_ALSA_TSC2102_H_ */
diff --git a/sound/arm/omap/omap-alsa.c b/sound/arm/omap/omap-alsa.c
new file mode 100644 (file)
index 0000000..11675f2
--- /dev/null
@@ -0,0 +1,580 @@
+/*
+ * sound/arm/omap-alsa.c
+ * 
+ * Alsa Driver for OMAP
+ *
+ * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ * Written by Daniel Petrini, David Cohen, Anderson Briglia
+ *            {daniel.petrini, david.cohen, anderson.briglia}@indt.org.br
+ *
+ * Copyright (C) 2006 Mika Laitio <lamikr@cc.jyu.fi>
+ *
+ * Based on sa11xx-uda1341.c, 
+ * Copyright (C) 2002 Tomas Kasparek <tomas.kasparek@seznam.cz>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the  GNU General Public License along
+ * with this program; if not, write  to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * History:
+ *
+ * 2005-07-29   INdT Kernel Team - Alsa driver for omap osk. Creation of new 
+ *                                 file omap-aic23.c
+ * 
+ * 2005-12-18   Dirk Behme       - Added L/R Channel Interchange fix as proposed 
+ *                                 by Ajaya Babu
+ *
+ */
+
+#include <linux/platform_device.h>
+#ifdef CONFIG_PM
+#include <linux/pm.h>
+#endif
+#include <sound/driver.h>
+#include <sound/core.h>
+
+#include <asm/arch/omap-alsa.h>
+#include "omap-alsa-dma.h"
+
+MODULE_AUTHOR("Mika Laitio, Daniel Petrini, David Cohen, Anderson Briglia - INdT");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("OMAP driver for ALSA");
+MODULE_ALIAS("omap_alsa_mcbsp.1");
+
+static char *id        = NULL; 
+static struct snd_card_omap_codec      *alsa_codec             = NULL;
+static struct omap_alsa_codec_config   *alsa_codec_config      = NULL;
+
+/*
+ * HW interface start and stop helper functions
+ */
+static int audio_ifc_start(void)
+{
+       omap_mcbsp_start(AUDIO_MCBSP);
+       return 0;
+}
+
+static int audio_ifc_stop(void)
+{
+       omap_mcbsp_stop(AUDIO_MCBSP);
+       return 0;
+}
+
+static void omap_alsa_audio_init(struct snd_card_omap_codec *omap_alsa)
+{
+       /* Setup DMA stuff */
+       omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].id = "Alsa omap out";
+       omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].stream_id =
+           SNDRV_PCM_STREAM_PLAYBACK;
+       omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].dma_dev =
+           OMAP_DMA_MCBSP1_TX;
+       omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].hw_start =
+           audio_ifc_start;
+       omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].hw_stop =
+           audio_ifc_stop;
+
+       omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].id = "Alsa omap in";
+       omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].stream_id =
+           SNDRV_PCM_STREAM_CAPTURE;
+       omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].dma_dev =
+           OMAP_DMA_MCBSP1_RX;
+       omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].hw_start =
+           audio_ifc_start;
+       omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].hw_stop =
+           audio_ifc_stop;
+}
+
+/* 
+ * DMA functions 
+ * Depends on omap-alsa-dma.c functions and (omap) dma.c
+ * 
+ */
+static int audio_dma_request(struct audio_stream *s,
+                            void (*callback) (void *))
+{
+       int err;
+       ADEBUG();
+
+       err = omap_request_alsa_sound_dma(s->dma_dev, s->id, s, &s->lch);
+       if (err < 0)
+               printk(KERN_ERR "Unable to grab audio dma 0x%x\n", s->dma_dev);
+       return err;
+}
+
+static int audio_dma_free(struct audio_stream *s)
+{
+       int err = 0;
+       ADEBUG();
+
+       err = omap_free_alsa_sound_dma(s, &s->lch);
+       if (err < 0)
+               printk(KERN_ERR "Unable to free audio dma channels!\n");
+       return err;
+}
+
+/*
+ *  This function should calculate the current position of the dma in the
+ *  buffer. It will help alsa middle layer to continue update the buffer.
+ *  Its correctness is crucial for good functioning.
+ */
+static u_int audio_get_dma_pos(struct audio_stream *s)
+{
+       snd_pcm_substream_t *substream = s->stream;
+       snd_pcm_runtime_t *runtime = substream->runtime;
+       unsigned int offset;
+       unsigned long flags;
+       dma_addr_t count;
+       ADEBUG();
+
+       /* this must be called w/ interrupts locked as requested in dma.c */
+       spin_lock_irqsave(&s->dma_lock, flags);
+
+       /* For the current period let's see where we are */
+       count = omap_get_dma_src_addr_counter(s->lch[s->dma_q_head]);
+
+       spin_unlock_irqrestore(&s->dma_lock, flags);
+
+       /* Now, the position related to the end of that period */
+       offset = bytes_to_frames(runtime, s->offset) - bytes_to_frames(runtime, count);
+
+       if (offset >= runtime->buffer_size)
+               offset = 0;
+
+       return offset;
+}
+
+/*
+ * this stops the dma and clears the dma ptrs
+ */
+static void audio_stop_dma(struct audio_stream *s)
+{
+       unsigned long flags;
+       ADEBUG();
+
+       spin_lock_irqsave(&s->dma_lock, flags);
+       s->active = 0;
+       s->period = 0;
+       s->periods = 0;
+
+       /* this stops the dma channel and clears the buffer ptrs */
+       omap_stop_alsa_sound_dma(s);
+
+       omap_clear_alsa_sound_dma(s);
+
+       spin_unlock_irqrestore(&s->dma_lock, flags);
+}
+
+/*
+ *  Main dma routine, requests dma according where you are in main alsa buffer
+ */
+static void audio_process_dma(struct audio_stream *s)
+{
+       snd_pcm_substream_t *substream = s->stream;
+       snd_pcm_runtime_t *runtime;
+       unsigned int dma_size;
+       unsigned int offset;
+       int ret;
+       
+       ADEBUG();
+       runtime = substream->runtime;
+       if (s->active) {
+               dma_size = frames_to_bytes(runtime, runtime->period_size);
+               offset = dma_size * s->period;
+               snd_assert(dma_size <= DMA_BUF_SIZE,);
+               /*
+                * On omap1510 based devices, we need to call the stop_dma
+                * before calling the start_dma or we will not receive the
+                * irq from DMA after the first transfered/played buffer.
+                * (invocation of callback_omap_alsa_sound_dma() method).
+                */
+               if (cpu_is_omap1510()) {
+                       omap_stop_alsa_sound_dma(s);
+               }
+               ret = omap_start_alsa_sound_dma(s,
+                               (dma_addr_t)runtime->dma_area + offset,
+                               dma_size);
+               if (ret) {
+                       printk(KERN_ERR
+                              "audio_process_dma: cannot queue DMA buffer (%i)\n",
+                              ret);
+                       return;
+               }
+
+               s->period++;
+               s->period %= runtime->periods;
+               s->periods++;
+               s->offset = offset;
+       }
+}
+
+/* 
+ *  This is called when dma IRQ occurs at the end of each transmited block
+ */
+void callback_omap_alsa_sound_dma(void *data)
+{
+       struct audio_stream *s = data;
+       
+       ADEBUG();
+       /* 
+        * If we are getting a callback for an active stream then we inform
+        * the PCM middle layer we've finished a period
+        */
+       if (s->active)
+               snd_pcm_period_elapsed(s->stream);
+
+       spin_lock(&s->dma_lock);
+       if (s->periods > 0) 
+               s->periods--;
+       
+       audio_process_dma(s);
+       spin_unlock(&s->dma_lock);
+}
+
+/* 
+ * Alsa section
+ * PCM settings and callbacks
+ */
+static int snd_omap_alsa_trigger(snd_pcm_substream_t * substream, int cmd)
+{
+       struct snd_card_omap_codec *chip =
+           snd_pcm_substream_chip(substream);
+       int stream_id = substream->pstr->stream;
+       struct audio_stream *s = &chip->s[stream_id];
+       int err = 0;
+       
+       ADEBUG();
+       /* note local interrupts are already disabled in the midlevel code */
+       spin_lock(&s->dma_lock);
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               /* requested stream startup */
+               s->active = 1;
+               audio_process_dma(s);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               /* requested stream shutdown */
+               audio_stop_dma(s);
+               break;
+       default:
+               err = -EINVAL;
+               break;
+       }
+       spin_unlock(&s->dma_lock);
+       
+       return err;
+}
+
+static int snd_omap_alsa_prepare(snd_pcm_substream_t * substream)
+{
+       struct snd_card_omap_codec *chip = snd_pcm_substream_chip(substream);
+       snd_pcm_runtime_t *runtime = substream->runtime;
+       struct audio_stream *s = &chip->s[substream->pstr->stream];
+       
+       ADEBUG();
+       /* set requested samplerate */
+       alsa_codec_config->codec_set_samplerate(runtime->rate);
+       chip->samplerate = runtime->rate;
+
+       s->period = 0;
+       s->periods = 0;
+
+       return 0;
+}
+
+static snd_pcm_uframes_t snd_omap_alsa_pointer(snd_pcm_substream_t *substream)
+{
+       struct snd_card_omap_codec *chip = snd_pcm_substream_chip(substream);
+
+       ADEBUG();       
+       return audio_get_dma_pos(&chip->s[substream->pstr->stream]);
+}
+
+static int snd_card_omap_alsa_open(snd_pcm_substream_t * substream)
+{
+       struct snd_card_omap_codec *chip =
+           snd_pcm_substream_chip(substream);
+       snd_pcm_runtime_t *runtime = substream->runtime;
+       int stream_id = substream->pstr->stream;
+       int err;
+       
+       ADEBUG();
+       chip->s[stream_id].stream = substream;
+       alsa_codec_config->codec_clock_on();
+       if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) 
+               runtime->hw = *(alsa_codec_config->snd_omap_alsa_playback);
+       else 
+               runtime->hw = *(alsa_codec_config->snd_omap_alsa_capture);
+       
+       if ((err = snd_pcm_hw_constraint_integer(runtime,
+                                          SNDRV_PCM_HW_PARAM_PERIODS)) < 0) 
+               return err;
+       
+       if ((err = snd_pcm_hw_constraint_list(runtime,
+                                       0,
+                                       SNDRV_PCM_HW_PARAM_RATE,
+                                       alsa_codec_config->hw_constraints_rates)) < 0) 
+               return err;
+       
+       return 0;
+}
+
+static int snd_card_omap_alsa_close(snd_pcm_substream_t * substream)
+{
+       struct snd_card_omap_codec *chip = snd_pcm_substream_chip(substream);
+       
+       ADEBUG();
+       alsa_codec_config->codec_clock_off();
+       chip->s[substream->pstr->stream].stream = NULL;
+       
+       return 0;
+}
+
+/* HW params & free */
+static int snd_omap_alsa_hw_params(snd_pcm_substream_t * substream,
+                                   snd_pcm_hw_params_t * hw_params)
+{
+       return snd_pcm_lib_malloc_pages(substream,
+                                       params_buffer_bytes(hw_params));
+}
+
+static int snd_omap_alsa_hw_free(snd_pcm_substream_t * substream)
+{
+       return snd_pcm_lib_free_pages(substream);
+}
+
+/* pcm operations */
+static snd_pcm_ops_t snd_card_omap_alsa_playback_ops = {
+       .open =         snd_card_omap_alsa_open,
+       .close =        snd_card_omap_alsa_close,
+       .ioctl =        snd_pcm_lib_ioctl,
+       .hw_params =    snd_omap_alsa_hw_params,
+       .hw_free =      snd_omap_alsa_hw_free,
+       .prepare =      snd_omap_alsa_prepare,
+       .trigger =      snd_omap_alsa_trigger,
+       .pointer =      snd_omap_alsa_pointer,
+};
+
+static snd_pcm_ops_t snd_card_omap_alsa_capture_ops = {
+       .open =         snd_card_omap_alsa_open,
+       .close =        snd_card_omap_alsa_close,
+       .ioctl =        snd_pcm_lib_ioctl,
+       .hw_params =    snd_omap_alsa_hw_params,
+       .hw_free =      snd_omap_alsa_hw_free,
+       .prepare =      snd_omap_alsa_prepare,
+       .trigger =      snd_omap_alsa_trigger,
+       .pointer =      snd_omap_alsa_pointer,
+};
+
+/*
+ *  Alsa init and exit section
+ *  
+ *  Inits pcm alsa structures, allocate the alsa buffer, suspend, resume
+ */
+static int __init snd_card_omap_alsa_pcm(struct snd_card_omap_codec *omap_alsa, 
+                                       int device)
+{
+       snd_pcm_t *pcm;
+       int err;
+       
+       ADEBUG();
+       if ((err = snd_pcm_new(omap_alsa->card, "OMAP PCM", device, 1, 1, &pcm)) < 0)
+               return err;
+
+       /* sets up initial buffer with continuous allocation */
+       snd_pcm_lib_preallocate_pages_for_all(pcm,
+                                             SNDRV_DMA_TYPE_CONTINUOUS,
+                                             snd_dma_continuous_data
+                                             (GFP_KERNEL),
+                                             128 * 1024, 128 * 1024);
+
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+                       &snd_card_omap_alsa_playback_ops);
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+                       &snd_card_omap_alsa_capture_ops);
+       pcm->private_data = omap_alsa;
+       pcm->info_flags = 0;
+       strcpy(pcm->name, "omap alsa pcm");
+
+       omap_alsa_audio_init(omap_alsa);
+
+       /* setup DMA controller */
+       audio_dma_request(&omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK],
+                         callback_omap_alsa_sound_dma);
+       audio_dma_request(&omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE],
+                         callback_omap_alsa_sound_dma);
+
+       omap_alsa->pcm = pcm;
+
+       return 0;
+}
+
+
+#ifdef CONFIG_PM
+/*
+ * Driver suspend/resume - calls alsa functions. Some hints from aaci.c
+ */
+int snd_omap_alsa_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct snd_card_omap_codec *chip;
+       snd_card_t *card = platform_get_drvdata(pdev);
+       
+       if (card->power_state != SNDRV_CTL_POWER_D3hot) {
+               chip = card->private_data;
+               if (chip->card->power_state != SNDRV_CTL_POWER_D3hot) {
+                       snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot);
+                       snd_pcm_suspend_all(chip->pcm);
+                       /* Mutes and turn clock off */
+                       alsa_codec_config->codec_clock_off();
+                       snd_omap_suspend_mixer();
+               }
+       }
+       return 0;
+}
+
+int snd_omap_alsa_resume(struct platform_device *pdev)
+{
+       struct snd_card_omap_codec *chip;
+       snd_card_t *card = platform_get_drvdata(pdev);
+
+       if (card->power_state != SNDRV_CTL_POWER_D0) {                          
+               chip = card->private_data;
+               if (chip->card->power_state != SNDRV_CTL_POWER_D0) {
+                       snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0);
+                       alsa_codec_config->codec_clock_on();
+                       snd_omap_resume_mixer();
+               }
+       }
+       return 0;
+}
+
+#endif /* CONFIG_PM */
+
+void snd_omap_alsa_free(snd_card_t * card)
+{
+       struct snd_card_omap_codec *chip = card->private_data;
+       ADEBUG();
+       
+       /*
+        * Turn off codec after it is done.
+        * Can't do it immediately, since it may still have
+        * buffered data.
+        */
+       schedule_timeout_interruptible(2);
+
+       omap_mcbsp_stop(AUDIO_MCBSP);
+       omap_mcbsp_free(AUDIO_MCBSP);
+
+       audio_dma_free(&chip->s[SNDRV_PCM_STREAM_PLAYBACK]);
+       audio_dma_free(&chip->s[SNDRV_PCM_STREAM_CAPTURE]);
+}
+
+/* module init & exit */
+
+/* 
+ * Inits alsa soudcard structure.
+ * Called by the probe method in codec after function pointers has been set.
+ */
+int snd_omap_alsa_post_probe(struct platform_device *pdev, struct omap_alsa_codec_config *config)
+{
+       int err = 0;
+       int def_rate;
+       snd_card_t *card;
+       
+       ADEBUG();
+       alsa_codec_config       = config;
+
+       alsa_codec_config->codec_clock_setup();
+       alsa_codec_config->codec_clock_on(); 
+
+       omap_mcbsp_request(AUDIO_MCBSP);
+       omap_mcbsp_stop(AUDIO_MCBSP);
+       omap_mcbsp_config(AUDIO_MCBSP, alsa_codec_config->mcbsp_regs_alsa);
+       omap_mcbsp_start(AUDIO_MCBSP);
+       
+       if (alsa_codec_config && alsa_codec_config->codec_configure_dev)
+               alsa_codec_config->codec_configure_dev();
+
+       alsa_codec_config->codec_clock_off();
+
+       /* register the soundcard */
+       card = snd_card_new(-1, id, THIS_MODULE, sizeof(alsa_codec));
+       if (card == NULL)
+               goto nodev1;
+
+       alsa_codec = kcalloc(1, sizeof(*alsa_codec), GFP_KERNEL);
+       if (alsa_codec == NULL)
+               goto nodev2;
+
+       card->private_data = (void *)alsa_codec;
+       card->private_free = snd_omap_alsa_free;
+
+       alsa_codec->card        = card;
+       def_rate                = alsa_codec_config->get_default_samplerate(); 
+       alsa_codec->samplerate  = def_rate;
+
+       spin_lock_init(&alsa_codec->s[0].dma_lock);
+       spin_lock_init(&alsa_codec->s[1].dma_lock);
+
+       /* mixer */
+       if ((err = snd_omap_mixer(alsa_codec)) < 0)
+               goto nodev3;
+
+       /* PCM */
+       if ((err = snd_card_omap_alsa_pcm(alsa_codec, 0)) < 0)
+               goto nodev3;
+
+       strcpy(card->driver, "OMAP_ALSA");
+       strcpy(card->shortname, alsa_codec_config->name);
+       sprintf(card->longname, alsa_codec_config->name);
+
+       snd_omap_init_mixer();
+       snd_card_set_dev(card, &pdev->dev);
+       
+       if ((err = snd_card_register(card)) == 0) {
+               printk(KERN_INFO "audio support initialized\n");
+               platform_set_drvdata(pdev, card);
+               return 0;
+       }
+       
+nodev3:
+       kfree(alsa_codec);      
+nodev2:        
+       snd_card_free(card);
+nodev1:
+       omap_mcbsp_stop(AUDIO_MCBSP);
+       omap_mcbsp_free(AUDIO_MCBSP);
+
+       return err;
+}
+
+int snd_omap_alsa_remove(struct platform_device *pdev)
+{
+       snd_card_t *card = platform_get_drvdata(pdev);
+       struct snd_card_omap_codec *chip = card->private_data;
+       
+       snd_card_free(card);
+
+       alsa_codec = NULL;
+       card->private_data = NULL;
+       kfree(chip);
+       
+       platform_set_drvdata(pdev, NULL);
+       
+       return 0;
+}
index 2489bd6bb08561ab5e8cc296eca87d20427a354b..e0b15e9d4f16242d6f7797822a9a38f1745386ca 100644 (file)
@@ -8,6 +8,10 @@
 obj-$(CONFIG_SOUND_OSS)                += sound.o
 obj-$(CONFIG_SOUND_CS4232)     += cs4232.o ad1848.o 
 
+obj-$(CONFIG_SOUND_OMAP)        += omap-audio-dma-intfc.o omap-audio.o
+obj-$(CONFIG_SOUND_OMAP_TSC2101)+= omap-audio-tsc2101.o
+obj-$(CONFIG_SOUND_OMAP_AIC23)  += omap-audio-aic23.o
+
 # Please leave it as is, cause the link order is significant !
 
 obj-$(CONFIG_SOUND_SH_DAC_AUDIO)       += sh_dac_audio.o
diff --git a/sound/oss/omap-audio-aic23.c b/sound/oss/omap-audio-aic23.c
new file mode 100644 (file)
index 0000000..0ecb2f7
--- /dev/null
@@ -0,0 +1,754 @@
+/*
+ * linux/sound/oss/omap-audio-aic23.c
+ *
+ * Glue audio driver for TI TLV320AIC23 codec
+ *
+ * Copyright (c) 2000 Nicolas Pitre <nico@cam.org>
+ * Copyright (C) 2001, Steve Johnson <stevej@ridgerun.com>
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ * Copyright (C) 2005 Dirk Behme <dirk.behme@de.bosch.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the  GNU General Public License along
+ * with this program; if not, write  to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/errno.h>
+#include <linux/sound.h>
+#include <linux/soundcard.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+
+#include <asm/uaccess.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/mcbsp.h>
+#include <asm/arch/fpga.h>
+#include <asm/arch/aic23.h>
+#include <asm/arch/clock.h>
+
+#include "omap-audio.h"
+#include "omap-audio-dma-intfc.h"
+
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#define PROC_START_FILE "driver/aic23-audio-start"
+#define PROC_STOP_FILE  "driver/aic23-audio-stop"
+#endif
+
+//#define DEBUG
+
+#ifdef DEBUG
+#define DPRINTK(ARGS...)  printk("<%s>: ",__FUNCTION__);printk(ARGS)
+#else
+#define DPRINTK( x... )
+#endif
+
+#define CODEC_NAME              "AIC23"
+
+#if CONFIG_MACH_OMAP_OSK
+#define PLATFORM_NAME            "OMAP OSK"
+#elif CONFIG_MACH_OMAP_INNOVATOR
+#define PLATFORM_NAME            "OMAP INNOVATOR"
+#else
+#error "Unsupported plattform"
+#endif
+
+/* Define to set the AIC23 as the master w.r.t McBSP */
+#define AIC23_MASTER
+
+#define CODEC_CLOCK                   12000000
+
+/*
+ * AUDIO related MACROS
+ */
+#define DEFAULT_BITPERSAMPLE          16
+#define AUDIO_RATE_DEFAULT           44100
+
+/* Select the McBSP For Audio */
+#define AUDIO_MCBSP                   OMAP_MCBSP1
+
+#define REC_MASK                     (SOUND_MASK_LINE | SOUND_MASK_MIC)
+#define DEV_MASK                     (REC_MASK | SOUND_MASK_VOLUME)
+
+#define SET_VOLUME                   1
+#define SET_LINE                     2
+
+#define DEFAULT_OUTPUT_VOLUME         93
+#define DEFAULT_INPUT_VOLUME          0        /* 0 ==> mute line in */
+
+#define OUTPUT_VOLUME_MIN             LHV_MIN
+#define OUTPUT_VOLUME_MAX             LHV_MAX
+#define OUTPUT_VOLUME_RANGE           (OUTPUT_VOLUME_MAX - OUTPUT_VOLUME_MIN)
+#define OUTPUT_VOLUME_MASK            OUTPUT_VOLUME_MAX
+
+#define INPUT_VOLUME_MIN             LIV_MIN
+#define INPUT_VOLUME_MAX             LIV_MAX
+#define INPUT_VOLUME_RANGE           (INPUT_VOLUME_MAX - INPUT_VOLUME_MIN)
+#define INPUT_VOLUME_MASK            INPUT_VOLUME_MAX
+
+#define NUMBER_SAMPLE_RATES_SUPPORTED 9
+
+/*
+ * HW interface start and stop helper functions
+ */
+static int audio_ifc_start(void)
+{
+       omap_mcbsp_start(AUDIO_MCBSP);
+       return 0;
+}
+
+static int audio_ifc_stop(void)
+{
+       omap_mcbsp_stop(AUDIO_MCBSP);
+       return 0;
+}
+
+static audio_stream_t output_stream = {
+        .id              = "AIC23 out",
+        .dma_dev         = OMAP_DMA_MCBSP1_TX,
+       .input_or_output = FMODE_WRITE,
+       .hw_start       = audio_ifc_start,
+       .hw_stop         = audio_ifc_stop
+};
+
+static audio_stream_t input_stream = {
+        .id              = "AIC23 in",
+        .dma_dev         = OMAP_DMA_MCBSP1_RX,
+       .input_or_output = FMODE_READ,
+       .hw_start       = audio_ifc_start,
+       .hw_stop         = audio_ifc_stop
+};
+
+static struct clk *aic23_mclk = 0;
+
+static int audio_dev_id, mixer_dev_id;
+
+static struct aic23_local_info {
+        u8  volume;
+        u16 volume_reg;
+        u8  line;
+        u8  mic;
+        u16 input_volume_reg;
+        int mod_cnt;
+} aic23_local;
+
+struct sample_rate_reg_info {
+        u32 sample_rate;
+        u8  control;            /* SR3, SR2, SR1, SR0 and BOSR */
+        u8  divider;           /* if 0 CLKIN = MCLK, if 1 CLKIN = MCLK/2 */
+};
+
+/* To Store the default sample rate */
+static long audio_samplerate = AUDIO_RATE_DEFAULT;
+
+/* DAC USB-mode sampling rates (MCLK = 12 MHz) */
+static const struct sample_rate_reg_info
+reg_info[NUMBER_SAMPLE_RATES_SUPPORTED] = {
+        {96000, 0x0E, 0},
+        {88200, 0x1F, 0},
+        {48000, 0x00, 0},
+        {44100, 0x11, 0},
+        {32000, 0x0C, 0},
+        {24000, 0x00, 1},
+        {16000, 0x0C, 1},
+        { 8000, 0x06, 0},
+        { 4000, 0x06, 1},
+};
+
+static struct omap_mcbsp_reg_cfg initial_config = {
+        .spcr2 = FREE | FRST | GRST | XRST | XINTM(3),
+        .spcr1 = RINTM(3) | RRST,
+        .rcr2  = RPHASE | RFRLEN2(OMAP_MCBSP_WORD_8) |
+       RWDLEN2(OMAP_MCBSP_WORD_16) | RDATDLY(0),
+        .rcr1  = RFRLEN1(OMAP_MCBSP_WORD_8) | RWDLEN1(OMAP_MCBSP_WORD_16),
+        .xcr2  = XPHASE | XFRLEN2(OMAP_MCBSP_WORD_8) |
+        XWDLEN2(OMAP_MCBSP_WORD_16) | XDATDLY(0) | XFIG,
+        .xcr1  = XFRLEN1(OMAP_MCBSP_WORD_8) | XWDLEN1(OMAP_MCBSP_WORD_16),
+        .srgr1 = FWID(DEFAULT_BITPERSAMPLE - 1),
+        .srgr2 = GSYNC | CLKSP | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1),
+#ifndef AIC23_MASTER
+        /* configure McBSP to be the I2S master */
+        .pcr0  = FSXM | FSRM | CLKXM | CLKRM | CLKXP | CLKRP,
+#else
+        /* configure McBSP to be the I2S slave */
+        .pcr0  = CLKXP | CLKRP,
+#endif /* AIC23_MASTER */
+};
+
+static void omap_aic23_initialize(void *dummy);
+static void omap_aic23_shutdown(void *dummy);
+static int  omap_aic23_ioctl(struct inode *inode, struct file *file,
+                             uint cmd, ulong arg);
+static int  omap_aic23_probe(void);
+#ifdef MODULE
+static void omap_aic23_remove(void);
+#endif
+static int  omap_aic23_suspend(void);
+static int  omap_aic23_resume(void);
+static inline void aic23_configure(void);
+static int  mixer_open(struct inode *inode, struct file *file);
+static int  mixer_release(struct inode *inode, struct file *file);
+static int  mixer_ioctl(struct inode *inode, struct file *file, uint cmd,
+                        ulong arg);
+
+#ifdef CONFIG_PROC_FS
+static int codec_start(char *buf, char **start, off_t offset, int count,
+                       int *eof, void *data);
+static int codec_stop(char *buf, char **start, off_t offset, int count,
+                      int *eof, void *data);
+#endif
+
+
+/* File Op structure for mixer */
+static struct file_operations omap_mixer_fops = {
+        .open           = mixer_open,
+        .release        = mixer_release,
+        .ioctl          = mixer_ioctl,
+        .owner          = THIS_MODULE
+};
+
+/* To store characteristic info regarding the codec for the audio driver */
+static audio_state_t aic23_state = {
+        .output_stream  = &output_stream,
+        .input_stream   = &input_stream,
+/*     .need_tx_for_rx = 1, //Once the Full Duplex works  */
+        .need_tx_for_rx = 0,
+        .hw_init        = omap_aic23_initialize,
+        .hw_shutdown    = omap_aic23_shutdown,
+        .client_ioctl   = omap_aic23_ioctl,
+        .hw_probe       = omap_aic23_probe,
+        .hw_remove      =  __exit_p(omap_aic23_remove),
+        .hw_suspend     = omap_aic23_suspend,
+        .hw_resume      = omap_aic23_resume,
+};
+
+/* This will be defined in the audio.h */
+static struct file_operations *omap_audio_fops;
+
+extern int aic23_write_value(u8 reg, u16 value);
+
+/* TLV320AIC23 is a write only device */
+static __inline__ void audio_aic23_write(u8 address, u16 data)
+{
+        aic23_write_value(address, data);
+}
+
+static int aic23_update(int flag, int val)
+{
+        u16 volume;
+
+        /* Ignore separate left/right channel for now,
+           even the codec does support it. */
+        val &= 0xff;
+
+        if (val < 0 || val > 100) {
+                printk(KERN_ERR "Trying a bad volume value(%d)!\n",val);
+                return -EPERM;
+        }
+
+        switch (flag) {
+        case SET_VOLUME:
+                // Convert 0 -> 100 volume to 0x00 (LHV_MIN) -> 0x7f (LHV_MAX) 
+                // volume range
+                volume = ((val * OUTPUT_VOLUME_RANGE) / 100) + OUTPUT_VOLUME_MIN;
+                
+                // R/LHV[6:0] 1111111 (+6dB) to 0000000 (-73dB) in 1db steps,
+                // default 1111001 (0dB)
+                aic23_local.volume_reg &= ~OUTPUT_VOLUME_MASK;
+                aic23_local.volume_reg |= volume;
+                audio_aic23_write(LEFT_CHANNEL_VOLUME_ADDR, aic23_local.volume_reg);
+                audio_aic23_write(RIGHT_CHANNEL_VOLUME_ADDR, aic23_local.volume_reg);
+                break;
+
+        case SET_LINE:
+                // Convert 0 -> 100 volume to 0x0 (LIV_MIN) -> 0x1f (LIV_MAX) 
+                // volume range
+                volume = ((val * INPUT_VOLUME_RANGE) / 100) + INPUT_VOLUME_MIN;
+
+                // R/LIV[4:0] 11111 (+12dB) to 00000 (-34.5dB) in 1.5dB steps,
+                // default 10111 (0dB)
+                aic23_local.input_volume_reg &= ~INPUT_VOLUME_MASK;
+                aic23_local.input_volume_reg |= volume;
+                audio_aic23_write(LEFT_LINE_VOLUME_ADDR, aic23_local.input_volume_reg);
+                audio_aic23_write(RIGHT_LINE_VOLUME_ADDR, aic23_local.input_volume_reg);
+                break;
+        }
+        return 0;
+}
+
+static int mixer_open(struct inode *inode, struct file *file)
+{
+        /* Any mixer specific initialization */
+
+        return 0;
+}
+
+static int mixer_release(struct inode *inode, struct file *file)
+{
+        /* Any mixer specific Un-initialization */
+
+        return 0;
+}
+
+static int
+mixer_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
+{
+        int val;
+        int ret = 0;
+        int nr = _IOC_NR(cmd);
+
+        /*
+         * We only accept mixer (type 'M') ioctls.
+         */
+        if (_IOC_TYPE(cmd) != 'M')
+                return -EINVAL;
+
+        DPRINTK(" 0x%08x\n", cmd);
+
+        if (cmd == SOUND_MIXER_INFO) {
+                struct mixer_info mi;
+
+                strncpy(mi.id, "AIC23", sizeof(mi.id));
+                strncpy(mi.name, "TI AIC23", sizeof(mi.name));
+                mi.modify_counter = aic23_local.mod_cnt;
+                return copy_to_user((void *)arg, &mi, sizeof(mi));
+        }
+
+        if (_IOC_DIR(cmd) & _IOC_WRITE) {
+                ret = get_user(val, (int *)arg);
+                if (ret)
+                        goto out;
+
+        
+                switch (nr) {
+                case SOUND_MIXER_VOLUME:
+                        aic23_local.volume = val;
+                        aic23_local.mod_cnt++;
+                        ret = aic23_update(SET_VOLUME, val);
+                        break;
+
+                case SOUND_MIXER_LINE:
+                        aic23_local.line = val;
+                        aic23_local.mod_cnt++;
+                        ret = aic23_update(SET_LINE, val);
+                        break;
+
+                case SOUND_MIXER_MIC:
+                        aic23_local.mic = val;
+                        aic23_local.mod_cnt++;
+                        ret = aic23_update(SET_LINE, val);
+                        break;
+
+                case SOUND_MIXER_RECSRC:
+                        break;
+
+                default:
+                        ret = -EINVAL;
+                }
+        }
+
+        if (ret == 0 && _IOC_DIR(cmd) & _IOC_READ) {
+                ret = 0;
+
+                switch (nr) {
+                case SOUND_MIXER_VOLUME:
+                        val = aic23_local.volume;
+                        break;
+                case SOUND_MIXER_LINE:
+                        val = aic23_local.line;
+                        break;
+                case SOUND_MIXER_MIC:
+                        val = aic23_local.mic;
+                        break;
+                case SOUND_MIXER_RECSRC:
+                        val = REC_MASK;
+                        break;
+                case SOUND_MIXER_RECMASK:
+                        val = REC_MASK;
+                        break;
+                case SOUND_MIXER_DEVMASK:
+                        val = DEV_MASK;
+                        break;
+                case SOUND_MIXER_CAPS:
+                        val = 0;
+                        break;
+                case SOUND_MIXER_STEREODEVS:
+                        val = 0;
+                        break;
+                default:
+                        val = 0;
+                        ret = -EINVAL;
+                        break;
+                }
+
+                if (ret == 0)
+                        ret = put_user(val, (int *)arg);
+        }
+out:
+        return ret;
+
+}
+
+int omap_set_samplerate(long sample_rate)
+{
+        u8 count = 0;
+        u16 data = 0;
+        /* wait for any frame to complete */
+        udelay(125);
+
+        /* Search for the right sample rate */
+        while ((reg_info[count].sample_rate != sample_rate) &&
+               (count < NUMBER_SAMPLE_RATES_SUPPORTED)) {
+                count++;
+        }
+        if (count == NUMBER_SAMPLE_RATES_SUPPORTED) {
+                printk(KERN_ERR "Invalid Sample Rate %d requested\n",
+                       (int)sample_rate);
+                return -EPERM;
+        }
+
+        if (machine_is_omap_innovator()) {
+                /* set the CODEC clock input source to 12.000MHz */
+                fpga_write(fpga_read(OMAP1510_FPGA_POWER) & ~0x01, 
+                           OMAP1510_FPGA_POWER);
+        }
+
+        data = (reg_info[count].divider << CLKIN_SHIFT) | 
+                (reg_info[count].control << BOSR_SHIFT) | USB_CLK_ON;
+
+        audio_aic23_write(SAMPLE_RATE_CONTROL_ADDR, data);
+
+        audio_samplerate = sample_rate;
+
+#ifndef AIC23_MASTER
+        {
+                int clkgdv = 0;
+                /* 
+                   Set Sample Rate at McBSP
+
+                   Formula : 
+                   Codec System Clock = CODEC_CLOCK, or half if clock_divider = 1;
+                   clkgdv = ((Codec System Clock / (SampleRate * BitsPerSample * 2)) - 1);
+
+                   FWID = BitsPerSample - 1;
+                   FPER = (BitsPerSample * 2) - 1;
+                */  
+                if (reg_info[count].divider)
+                        clkgdv = CODEC_CLOCK / 2;
+                else 
+                        clkgdv = CODEC_CLOCK;
+
+                clkgdv = (clkgdv / (sample_rate * DEFAULT_BITPERSAMPLE * 2)) - 1;
+
+                initial_config.srgr1 = (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
+
+                initial_config.srgr2 =
+                        (CLKSM | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1));
+
+                omap_mcbsp_config(AUDIO_MCBSP, &initial_config);
+        }
+#endif /* AIC23_MASTER */
+
+        return 0;
+}
+
+static void omap_aic23_initialize(void *dummy)
+{
+        DPRINTK("entry\n");
+
+        /* initialize with default sample rate */
+        audio_samplerate = AUDIO_RATE_DEFAULT;
+
+        omap_mcbsp_request(AUDIO_MCBSP);
+
+        /* if configured, then stop mcbsp */
+        omap_mcbsp_stop(AUDIO_MCBSP);
+
+        omap_mcbsp_config(AUDIO_MCBSP, &initial_config);
+        omap_mcbsp_start(AUDIO_MCBSP);
+        aic23_configure();
+
+        DPRINTK("exit\n");
+}
+
+static void omap_aic23_shutdown(void *dummy)
+{
+        /*
+          Turn off codec after it is done.
+          Can't do it immediately, since it may still have
+          buffered data.
+
+          Wait 20ms (arbitrary value) and then turn it off.
+        */
+
+        set_current_state(TASK_INTERRUPTIBLE);
+        schedule_timeout(2);
+
+        omap_mcbsp_stop(AUDIO_MCBSP);
+        omap_mcbsp_free(AUDIO_MCBSP);
+
+        audio_aic23_write(RESET_CONTROL_ADDR, 0);
+        audio_aic23_write(POWER_DOWN_CONTROL_ADDR, 0xff);
+}
+
+static inline void aic23_configure()
+{
+        /* Reset codec */
+        audio_aic23_write(RESET_CONTROL_ADDR, 0);
+
+        /* Initialize the AIC23 internal state */
+
+        /* Left/Right line input volume control */
+        aic23_local.line = DEFAULT_INPUT_VOLUME;
+        aic23_local.mic = DEFAULT_INPUT_VOLUME;
+        aic23_update(SET_LINE, DEFAULT_INPUT_VOLUME);
+
+        /* Left/Right headphone channel volume control */
+        /* Zero-cross detect on */
+        aic23_local.volume_reg = LZC_ON;
+        aic23_update(SET_VOLUME, aic23_local.volume);
+
+        /* Analog audio path control, DAC selected, delete INSEL_MIC for line in */
+        audio_aic23_write(ANALOG_AUDIO_CONTROL_ADDR, DAC_SELECTED | INSEL_MIC);
+
+        /* Digital audio path control, de-emphasis control 44.1kHz */
+        audio_aic23_write(DIGITAL_AUDIO_CONTROL_ADDR, DEEMP_44K);
+
+        /* Power control, everything is on */
+        audio_aic23_write(POWER_DOWN_CONTROL_ADDR, 0);
+
+        /* Digital audio interface, master/slave mode, I2S, 16 bit */
+#ifdef AIC23_MASTER
+        audio_aic23_write(DIGITAL_AUDIO_FORMAT_ADDR, MS_MASTER | IWL_16 | FOR_DSP);
+#else
+        audio_aic23_write(DIGITAL_AUDIO_FORMAT_ADDR, IWL_16 | FOR_DSP);
+#endif /* AIC23_MASTER */
+
+        /* Enable digital interface */
+        audio_aic23_write(DIGITAL_INTERFACE_ACT_ADDR, ACT_ON);
+
+        /* clock configuration */
+        omap_set_samplerate(audio_samplerate);
+}
+
+static int
+omap_aic23_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
+{
+        long val;
+        int ret = 0;
+
+        DPRINTK(" 0x%08x\n", cmd);
+
+        /*
+         * These are platform dependent ioctls which are not handled by the
+         * generic omap-audio module.
+         */
+        switch (cmd) {
+        case SNDCTL_DSP_STEREO:
+                ret = get_user(val, (int *)arg);
+                if (ret)
+                        return ret;
+                /* the AIC23 is stereo only */
+                ret = (val == 0) ? -EINVAL : 1;
+                return put_user(ret, (int *)arg);
+
+        case SNDCTL_DSP_CHANNELS:
+        case SOUND_PCM_READ_CHANNELS:
+                /* the AIC23 is stereo only */
+                return put_user(2, (long *)arg);
+
+        case SNDCTL_DSP_SPEED:
+                ret = get_user(val, (long *)arg);
+                if (ret)
+                        break;
+                ret = omap_set_samplerate(val);
+                if (ret)
+                        break;
+                /* fall through */
+
+        case SOUND_PCM_READ_RATE:
+                return put_user(audio_samplerate, (long *)arg);
+
+        case SOUND_PCM_READ_BITS:
+        case SNDCTL_DSP_SETFMT:
+        case SNDCTL_DSP_GETFMTS:
+                /* we can do 16-bit only */
+                return put_user(AFMT_S16_LE, (long *)arg);
+
+        default:
+                /* Maybe this is meant for the mixer (As per OSS Docs) */
+                return mixer_ioctl(inode, file, cmd, arg);
+        }
+
+        return ret;
+}
+
+static int omap_aic23_probe(void)
+{
+        /* Get the fops from audio oss driver */
+        if (!(omap_audio_fops = audio_get_fops())) {
+                printk(KERN_ERR "Unable to get the file operations for AIC23 OSS driver\n");
+                audio_unregister_codec(&aic23_state);
+                return -EPERM;
+        }
+
+        aic23_local.volume = DEFAULT_OUTPUT_VOLUME;
+
+        /* register devices */
+        audio_dev_id = register_sound_dsp(omap_audio_fops, -1);
+        mixer_dev_id = register_sound_mixer(&omap_mixer_fops, -1);
+
+#ifdef CONFIG_PROC_FS
+        create_proc_read_entry(PROC_START_FILE, 0 /* default mode */ ,
+                               NULL /* parent dir */ ,
+                               codec_start, NULL /* client data */ );
+
+        create_proc_read_entry(PROC_STOP_FILE, 0 /* default mode */ ,
+                               NULL /* parent dir */ ,
+                               codec_stop, NULL /* client data */ );
+#endif
+
+        /* Announcement Time */
+        printk(KERN_INFO PLATFORM_NAME " " CODEC_NAME
+               " audio support initialized\n");
+        return 0;
+}
+
+#ifdef MODULE
+static void __exit omap_aic23_remove(void)
+{
+        /* Un-Register the codec with the audio driver */
+        unregister_sound_dsp(audio_dev_id);
+        unregister_sound_mixer(mixer_dev_id);
+
+#ifdef CONFIG_PROC_FS
+        remove_proc_entry(PROC_START_FILE, NULL);
+        remove_proc_entry(PROC_STOP_FILE, NULL);
+#endif
+}
+#endif /* MODULE */
+
+static int omap_aic23_suspend(void)
+{
+        /* Empty for the moment */
+        return 0;
+}
+
+static int omap_aic23_resume(void)
+{
+        /* Empty for the moment */
+        return 0;
+}
+
+static int __init audio_aic23_init(void)
+{
+
+        int err = 0;
+
+       if (machine_is_omap_h2() || machine_is_omap_h3())
+               return -ENODEV;
+
+       mutex_init(&aic23_state.mutex);
+
+        if (machine_is_omap_osk()) {
+                /* Set MCLK to be clock input for AIC23 */
+                aic23_mclk = clk_get(0, "mclk");
+            
+                if(clk_get_rate( aic23_mclk) != CODEC_CLOCK){
+                        /* MCLK ist not at CODEC_CLOCK */
+                        if( clk_get_usecount(aic23_mclk) > 0 ){
+                                /* MCLK is already in use */
+                                printk(KERN_WARNING "MCLK in use at %d Hz. We change it to %d Hz\n",
+                                       (uint)clk_get_rate( aic23_mclk), CODEC_CLOCK);
+                        }
+                        if( clk_set_rate( aic23_mclk, CODEC_CLOCK ) ){
+                                printk(KERN_ERR "Cannot set MCLK for AIC23 CODEC\n");
+                                return -ECANCELED;
+                       }
+               }
+
+                clk_enable( aic23_mclk );
+
+                DPRINTK("MCLK = %d [%d], usecount = %d\n",(uint)clk_get_rate( aic23_mclk ), 
+                        CODEC_CLOCK, clk_get_usecount( aic23_mclk));
+        }
+
+        if (machine_is_omap_innovator()) {
+                u8 fpga;
+                /*
+                  Turn on chip select for CODEC (shared with touchscreen).  
+                  Don't turn it back off, in case touch screen needs it.
+                */                           
+                fpga = fpga_read(OMAP1510_FPGA_TOUCHSCREEN);
+                fpga |= 0x4;
+                fpga_write(fpga, OMAP1510_FPGA_TOUCHSCREEN);
+        }
+
+        /* register the codec with the audio driver */
+        if ((err = audio_register_codec(&aic23_state))) {
+                printk(KERN_ERR
+                       "Failed to register AIC23 driver with Audio OSS Driver\n");
+        }
+
+        return err;
+}
+
+static void __exit audio_aic23_exit(void)
+{
+        (void)audio_unregister_codec(&aic23_state);
+        return;
+}
+
+#ifdef CONFIG_PROC_FS
+static int codec_start(char *buf, char **start, off_t offset, int count,
+                       int *eof, void *data)
+{
+        void *foo = NULL;
+
+        omap_aic23_initialize(foo);
+
+        printk("AIC23 codec initialization done.\n");
+        return 0;
+}
+static int codec_stop(char *buf, char **start, off_t offset, int count,
+                      int *eof, void *data)
+{
+        void *foo = NULL;
+
+        omap_aic23_shutdown(foo);
+
+        printk("AIC23 codec shutdown.\n");
+        return 0;
+}
+#endif /* CONFIG_PROC_FS */
+
+module_init(audio_aic23_init);
+module_exit(audio_aic23_exit);
+
+MODULE_AUTHOR("Dirk Behme <dirk.behme@de.bosch.com>");
+MODULE_DESCRIPTION("Glue audio driver for the TI AIC23 codec.");
+MODULE_LICENSE("GPL");
diff --git a/sound/oss/omap-audio-dma-intfc.c b/sound/oss/omap-audio-dma-intfc.c
new file mode 100644 (file)
index 0000000..146e288
--- /dev/null
@@ -0,0 +1,986 @@
+/*
+ * linux/sound/oss/omap-audio-dma-intfc.c
+ *
+ * Common audio DMA handling for the OMAP processors
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *
+ * Copyright (C) 2000, 2001 Nicolas Pitre <nico@cam.org>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * History:
+ *
+ * 2004-06-07  Sriram Kannan   - Created new file from omap_audio_dma_intfc.c. This file
+ *                               will contain only the DMA interface and buffer handling of OMAP
+ *                               audio driver.
+ *
+ * 2004-06-22  Sriram Kannan   - removed legacy code (auto-init). Self-linking of DMA logical channel.
+ *
+ * 2004-08-12   Nishanth Menon  - Modified to integrate Audio requirements on 1610,1710 platforms
+ *
+ * 2004-11-01   Nishanth Menon  - 16xx platform code base modified to support multi channel chaining.
+ *
+ * 2004-12-15   Nishanth Menon  - Improved 16xx platform channel logic introduced - tasklets, queue handling updated
+ *
+ * 2005-12-10   Dirk Behme      - Added L/R Channel Interchange fix as proposed by Ajaya Babu
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/poll.h>
+#include <linux/pm.h>
+#include <linux/errno.h>
+#include <linux/sound.h>
+#include <linux/soundcard.h>
+#include <linux/sysrq.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/completion.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/semaphore.h>
+
+#include <asm/arch/dma.h>
+#include "omap-audio-dma-intfc.h"
+
+#include <asm/arch/mcbsp.h>
+
+#include "omap-audio.h"
+
+#undef DEBUG
+//#define DEBUG
+#ifdef DEBUG
+#define DPRINTK(ARGS...)  printk(KERN_INFO "<%s>: ",__FUNCTION__);printk(ARGS)
+#define FN_IN printk(KERN_INFO "[%s]: start\n", __FUNCTION__)
+#define FN_OUT(n) printk(KERN_INFO "[%s]: end(%u)\n",__FUNCTION__, n)
+#else
+
+#define DPRINTK( x... )
+#define FN_IN
+#define FN_OUT(x)
+#endif
+
+#define ERR(ARGS...) printk(KERN_ERR "{%s}-ERROR: ", __FUNCTION__);printk(ARGS);
+
+#define AUDIO_NAME             "omap-audio"
+#define AUDIO_NBFRAGS_DEFAULT  8
+#define AUDIO_FRAGSIZE_DEFAULT 8192
+
+#define AUDIO_ACTIVE(state)    ((state)->rd_ref || (state)->wr_ref)
+
+#define SPIN_ADDR              (dma_addr_t)0
+#define SPIN_SIZE              2048
+
+/* Channel Queue Handling macros
+ * tail always points to the current free entry
+ * Head always points to the current entry being used
+ * end is either head or tail
+ */
+
+#define AUDIO_QUEUE_INIT(s) s->dma_q_head = s->dma_q_tail = s->dma_q_count = 0;
+#define AUDIO_QUEUE_FULL(s) (nr_linked_channels == s->dma_q_count)
+#define AUDIO_QUEUE_LAST(s) (1 == s->dma_q_count)
+#define AUDIO_QUEUE_EMPTY(s) (0 == s->dma_q_count)
+#define __AUDIO_INCREMENT_QUEUE(end) ((end)=((end)+1) % nr_linked_channels)
+#define AUDIO_INCREMENT_HEAD(s) __AUDIO_INCREMENT_QUEUE(s->dma_q_head); s->dma_q_count--;
+#define AUDIO_INCREMENT_TAIL(s) __AUDIO_INCREMENT_QUEUE(s->dma_q_tail); s->dma_q_count++;
+
+/* DMA buffer fragmentation sizes */
+#define MAX_DMA_SIZE            0x1000000
+#define CUT_DMA_SIZE            0x1000
+/* TODO: To be moved to more appropriate location */
+#define DCSR_ERROR           0x3
+#define DCSR_SYNC_SET        (1 << 6)
+
+#define DCCR_FS              (1 << 5)
+#define DCCR_PRIO            (1 << 6)
+#define DCCR_EN              (1 << 7)
+#define DCCR_AI              (1 << 8)
+#define DCCR_REPEAT          (1 << 9)
+/* if 0 the channel works in 3.1 compatible mode*/
+#define DCCR_N31COMP         (1 << 10)
+#define DCCR_EP              (1 << 11)
+#define DCCR_SRC_AMODE_BIT   12
+#define DCCR_SRC_AMODE_MASK  (0x3<<12)
+#define DCCR_DST_AMODE_BIT   14
+#define DCCR_DST_AMODE_MASK  (0x3<<14)
+#define AMODE_CONST          0x0
+#define AMODE_POST_INC       0x1
+#define AMODE_SINGLE_INDEX   0x2
+#define AMODE_DOUBLE_INDEX   0x3
+
+/**************************** DATA STRUCTURES *****************************************/
+
+static spinlock_t dma_list_lock = SPIN_LOCK_UNLOCKED;
+
+struct audio_isr_work_item {
+       int current_lch;
+       u16 ch_status;
+       audio_stream_t *s;
+};
+
+static char work_item_running = 0;
+static char nr_linked_channels = 1;
+static struct audio_isr_work_item work1, work2;
+
+
+/*********************************** MODULE SPECIFIC FUNCTIONS PROTOTYPES *************/
+
+static void audio_dsr_handler(unsigned long);
+static DECLARE_TASKLET(audio_isr_work1, audio_dsr_handler,
+               (unsigned long)&work1);
+static DECLARE_TASKLET(audio_isr_work2, audio_dsr_handler,
+               (unsigned long)&work2);
+
+static void sound_dma_irq_handler(int lch, u16 ch_status, void *data);
+static void audio_dma_callback(int lch, u16 ch_status, void *data);
+static int omap_start_sound_dma(audio_stream_t * s, dma_addr_t dma_ptr,
+                               u_int size);
+static int audio_set_dma_params_play(int channel, dma_addr_t dma_ptr,
+                                    u_int dma_size);
+static int audio_set_dma_params_capture(int channel, dma_addr_t dma_ptr,
+                                       u_int dma_size);
+static int audio_start_dma_chain(audio_stream_t * s);
+
+/*********************************** GLOBAL FUNCTIONS DEFINTIONS ***********************/
+
+/***************************************************************************************
+ *
+ * Buffer creation/destruction
+ *
+ **************************************************************************************/
+int audio_setup_buf(audio_stream_t * s)
+{
+       int frag;
+       int dmasize = 0;
+       char *dmabuf = NULL;
+       dma_addr_t dmaphys = 0;
+       FN_IN;
+       if (s->buffers) {
+               FN_OUT(1);
+               return -EBUSY;
+       }
+       s->buffers = kmalloc(sizeof(audio_buf_t) * s->nbfrags, GFP_KERNEL);
+       if (!s->buffers)
+               goto err;
+       memset(s->buffers, 0, sizeof(audio_buf_t) * s->nbfrags);
+       for (frag = 0; frag < s->nbfrags; frag++) {
+               audio_buf_t *b = &s->buffers[frag];
+               /*
+                * Let's allocate non-cached memory for DMA buffers.
+                * We try to allocate all memory at once.
+                * If this fails (a common reason is memory fragmentation),
+                * then we allocate more smaller buffers.
+                */
+               if (!dmasize) {
+                       dmasize = (s->nbfrags - frag) * s->fragsize;
+                       do {
+                               dmabuf =
+                                   dma_alloc_coherent(NULL, dmasize, &dmaphys,
+                                                      0);
+                               if (!dmabuf)
+                                       dmasize -= s->fragsize;
+                       }
+                       while (!dmabuf && dmasize);
+                       if (!dmabuf)
+                               goto err;
+                       b->master = dmasize;
+                       memzero(dmabuf, dmasize);
+               }
+               b->data = dmabuf;
+               b->dma_addr = dmaphys;
+               dmabuf += s->fragsize;
+               dmaphys += s->fragsize;
+               dmasize -= s->fragsize;
+       }
+       s->usr_head = s->dma_head = s->dma_tail = 0;
+       AUDIO_QUEUE_INIT(s);
+       s->started = 0;
+       s->bytecount = 0;
+       s->fragcount = 0;
+       init_completion(&s->wfc);
+       s->wfc.done = s->nbfrags;
+       FN_OUT(0);
+       return 0;
+      err:
+       audio_discard_buf(s);
+       FN_OUT(1);
+       return -ENOMEM;
+}
+
+void audio_discard_buf(audio_stream_t * s)
+{
+       FN_IN;
+       /* ensure DMA isn't using those buffers */
+       audio_reset(s);
+       if (s->buffers) {
+               int frag;
+               for (frag = 0; frag < s->nbfrags; frag++) {
+                       if (!s->buffers[frag].master)
+                               continue;
+                       dma_free_coherent(NULL,
+                                         s->buffers[frag].master,
+                                         s->buffers[frag].data,
+                                         s->buffers[frag].dma_addr);
+               }
+               kfree(s->buffers);
+               s->buffers = NULL;
+       }
+       FN_OUT(0);
+}
+
+/***************************************************************************************
+ *
+ * DMA channel requests
+ *
+ **************************************************************************************/
+static void omap_sound_dma_link_lch(void *data)
+{
+       audio_stream_t *s = (audio_stream_t *) data;
+       int *chan = s->lch;
+       int i;
+
+       FN_IN;
+       if (s->linked) {
+               FN_OUT(1);
+               return;
+       }
+       for (i = 0; i < nr_linked_channels; i++) {
+               int cur_chan = chan[i];
+               int nex_chan =
+                   ((nr_linked_channels - 1 ==
+                     i) ? chan[0] : chan[i + 1]);
+               omap_dma_link_lch(cur_chan, nex_chan);
+       }
+       s->linked = 1;
+       FN_OUT(0);
+}
+
+int
+omap_request_sound_dma(int device_id, const char *device_name, void *data,
+                      int **channels)
+{
+       int i, err = 0;
+       int *chan = NULL;
+       FN_IN;
+       if (unlikely((NULL == channels) || (NULL == device_name))) {
+               BUG();
+               return -EPERM;
+       }
+       /* Try allocate memory for the num channels */
+       *channels =
+           (int *)kmalloc(sizeof(int) * nr_linked_channels,
+                          GFP_KERNEL);
+       chan = *channels;
+       if (NULL == chan) {
+               ERR("No Memory for channel allocs!\n");
+               FN_OUT(-ENOMEM);
+               return -ENOMEM;
+       }
+       spin_lock(&dma_list_lock);
+       for (i = 0; i < nr_linked_channels; i++) {
+               err =
+                   omap_request_dma(device_id, device_name,
+                                    sound_dma_irq_handler, data, &chan[i]);
+               /* Handle Failure condition here */
+               if (err < 0) {
+                       int j;
+                       for (j = 0; j < i; j++) {
+                               omap_free_dma(chan[j]);
+                       }
+                       spin_unlock(&dma_list_lock);
+                       kfree(chan);
+                       *channels = NULL;
+                       ERR("Error in requesting channel %d=0x%x\n", i, err);
+                       FN_OUT(err);
+                       return err;
+               }
+       }
+
+       /* Chain the channels together */
+       if (!cpu_is_omap15xx())
+               omap_sound_dma_link_lch(data);
+
+       spin_unlock(&dma_list_lock);
+       FN_OUT(0);
+       return 0;
+}
+
+/***************************************************************************************
+ *
+ * DMA channel requests Freeing
+ *
+ **************************************************************************************/
+static void omap_sound_dma_unlink_lch(void *data)
+{
+       audio_stream_t *s = (audio_stream_t *) data;
+       int *chan = s->lch;
+       int i;
+
+       FN_IN;
+       if (!s->linked) {
+               FN_OUT(1);
+               return;
+       }
+       for (i = 0; i < nr_linked_channels; i++) {
+               int cur_chan = chan[i];
+               int nex_chan =
+                   ((nr_linked_channels - 1 ==
+                     i) ? chan[0] : chan[i + 1]);
+               omap_dma_unlink_lch(cur_chan, nex_chan);
+       }
+       s->linked = 0;
+       FN_OUT(0);
+}
+
+int omap_free_sound_dma(void *data, int **channels)
+{
+       int i;
+       int *chan = NULL;
+       FN_IN;
+       if (unlikely(NULL == channels)) {
+               BUG();
+               return -EPERM;
+       }
+       if (unlikely(NULL == *channels)) {
+               BUG();
+               return -EPERM;
+       }
+       chan = (*channels);
+
+       if (!cpu_is_omap15xx())
+               omap_sound_dma_unlink_lch(data);
+       for (i = 0; i < nr_linked_channels; i++) {
+               int cur_chan = chan[i];
+               omap_stop_dma(cur_chan);
+               omap_free_dma(cur_chan);
+       }
+       kfree(*channels);
+       *channels = NULL;
+       FN_OUT(0);
+       return 0;
+}
+
+/***************************************************************************************
+ *
+ * Process DMA requests - This will end up starting the transfer. Proper fragments of
+ * Transfers will be initiated.
+ *
+ **************************************************************************************/
+int audio_process_dma(audio_stream_t * s)
+{
+       int ret = 0;
+       unsigned long flags;
+       FN_IN;
+
+       /* Dont let the ISR over ride touching the in_use flag */
+       local_irq_save(flags);
+       if (1 == s->in_use) {
+               local_irq_restore(flags);
+               ERR("Called again while In Use\n");
+               return 0;
+       }
+       s->in_use = 1;
+       local_irq_restore(flags);
+
+       if (s->stopped)
+               goto spin;
+
+       if (s->dma_spinref > 0 && s->pending_frags) {
+               s->dma_spinref = 0;
+               DMA_CLEAR(s);
+       }
+       while (s->pending_frags) {
+               audio_buf_t *b = &s->buffers[s->dma_head];
+               u_int dma_size = s->fragsize - b->offset;
+               if (dma_size > MAX_DMA_SIZE)
+                       dma_size = CUT_DMA_SIZE;
+               ret =
+                   omap_start_sound_dma(s, b->dma_addr + b->offset, dma_size);
+               if (ret) {
+                       goto process_out;
+               }
+               b->dma_ref++;
+               b->offset += dma_size;
+               if (b->offset >= s->fragsize) {
+                       s->pending_frags--;
+                       if (++s->dma_head >= s->nbfrags)
+                               s->dma_head = 0;
+               }
+       }
+      spin:
+       if (s->spin_idle) {
+               int spincnt = 0;
+               ERR("we are spinning\n");
+               while (omap_start_sound_dma(s, SPIN_ADDR, SPIN_SIZE) == 0)
+                       spincnt++;
+               /*
+                * Note: if there is still a data buffer being
+                * processed then the ref count is negative.  This
+                * allows for the DMA termination to be accounted in
+                * the proper order.  Of course dma_spinref can't be
+                * greater than 0 if dma_ref is not 0 since we kill
+                * the spinning above as soon as there is real data to process.
+                */
+               if (s->buffers && s->buffers[s->dma_tail].dma_ref)
+                       spincnt = -spincnt;
+               s->dma_spinref += spincnt;
+       }
+
+      process_out:
+       s->in_use = 0;
+
+       FN_OUT(ret);
+       return ret;
+}
+
+/***************************************************************************************
+ *
+ * Prime Rx - Since the recieve buffer has no time limit as to when it would arrive,
+ *            we need to prime it
+ *            
+ **************************************************************************************/
+void audio_prime_rx(audio_state_t * state)
+{
+       audio_stream_t *is = state->input_stream;
+
+       FN_IN;
+       if (state->need_tx_for_rx) {
+               /*
+                * With some codecs like the Philips UDA1341 we must ensure
+                * there is an output stream at any time while recording since
+                * this is how the UDA1341 gets its clock from the SA1100.
+                * So while there is no playback data to send, the output DMA
+                * will spin with all zeroes.  We use the cache flush special
+                * area for that.
+                */
+               state->output_stream->spin_idle = 1;
+               audio_process_dma(state->output_stream);
+       }
+       is->pending_frags = is->nbfrags;
+       init_completion(&is->wfc);
+       is->wfc.done = 0;
+
+       is->active = 1;
+       audio_process_dma(is);
+
+       FN_OUT(0);
+       return;
+}
+
+/***************************************************************************************
+ *
+ * set the fragment size
+ *
+ **************************************************************************************/
+int audio_set_fragments(audio_stream_t * s, int val)
+{
+       FN_IN;
+       if (s->active)
+               return -EBUSY;
+       if (s->buffers)
+               audio_discard_buf(s);
+       s->nbfrags = (val >> 16) & 0x7FFF;
+       val &= 0xFFFF;
+       if (val < 4)
+               val = 4;
+       if (val > 15)
+               val = 15;
+       s->fragsize = 1 << val;
+       if (s->nbfrags < 2)
+               s->nbfrags = 2;
+       if (s->nbfrags * s->fragsize > 128 * 1024)
+               s->nbfrags = 128 * 1024 / s->fragsize;
+       FN_OUT(0);
+       if (audio_setup_buf(s))
+               return -ENOMEM;
+       return val | (s->nbfrags << 16);
+
+}
+
+/***************************************************************************************
+ *
+ * Sync up the buffers before we shutdown, else under-run errors will happen
+ *
+ **************************************************************************************/
+int audio_sync(struct file *file)
+{
+       audio_state_t *state = file->private_data;
+       audio_stream_t *s = state->output_stream;
+       audio_buf_t *b;
+       u_int shiftval = 0;
+       unsigned long flags;
+
+       DECLARE_WAITQUEUE(wait, current);
+
+       FN_IN;
+
+       if (!(file->f_mode & FMODE_WRITE) || !s->buffers || s->mapped) {
+               FN_OUT(1);
+               return 0;
+       }
+
+       /*
+        * Send current buffer if it contains data.  Be sure to send
+        * a full sample count.
+        */
+       b = &s->buffers[s->usr_head];
+       if (b->offset &= ~3) {
+               /* Wait for a buffer to become free */
+               if (wait_for_completion_interruptible(&s->wfc))
+                       return 0;
+               /*
+                * HACK ALERT !
+                * To avoid increased complexity in the rest of the code
+                * where full fragment sizes are assumed, we cheat a little
+                * with the start pointer here and don't forget to restore
+                * it later.
+                */
+               
+               /* As this is a last frag we need only one dma channel
+                * to complete. So it's need to unlink dma channels
+                * to avoid empty dma work.
+                */
+               if (!cpu_is_omap15xx() && AUDIO_QUEUE_EMPTY(s))
+                       omap_sound_dma_unlink_lch(s);
+
+               shiftval = s->fragsize - b->offset;
+               b->offset = shiftval;
+               b->dma_addr -= shiftval;
+               b->data -= shiftval;
+               local_irq_save(flags);
+               s->bytecount -= shiftval;
+               if (++s->usr_head >= s->nbfrags)
+                       s->usr_head = 0;
+
+               s->pending_frags++;
+               audio_process_dma(s);
+               local_irq_restore(flags);
+       }
+
+       /* Let's wait for all buffers to complete */
+       set_current_state(TASK_INTERRUPTIBLE);
+       add_wait_queue(&s->wq, &wait);
+       while ((s->pending_frags || (s->wfc.done < s->nbfrags))
+              && !signal_pending(current)) {
+               schedule();
+               set_current_state(TASK_INTERRUPTIBLE);
+       }
+       set_current_state(TASK_RUNNING);
+       remove_wait_queue(&s->wq, &wait);
+
+       /* undo the pointer hack above */
+       if (shiftval) {
+               local_irq_save(flags);
+               b->dma_addr += shiftval;
+               b->data += shiftval;
+               /* ensure sane DMA code behavior if not yet processed */
+               if (b->offset != 0)
+                       b->offset = s->fragsize;
+               local_irq_restore(flags);
+       }
+
+       FN_OUT(0);
+       return 0;
+}
+
+/***************************************************************************************
+ *
+ * Stop all the DMA channels of the stream
+ *
+ **************************************************************************************/
+void audio_stop_dma(audio_stream_t * s)
+{
+       int *chan = s->lch;
+       int i;
+       FN_IN;
+       if (unlikely(NULL == chan)) {
+               BUG();
+               return;
+       }
+       for (i = 0; i < nr_linked_channels; i++) {
+               int cur_chan = chan[i];
+               omap_stop_dma(cur_chan);
+       }
+       s->started = 0;
+       FN_OUT(0);
+       return;
+}
+
+/***************************************************************************************
+ *
+ * Get the dma posn
+ *
+ **************************************************************************************/
+u_int audio_get_dma_pos(audio_stream_t * s)
+{
+       audio_buf_t *b = &s->buffers[s->dma_tail];
+       u_int offset;
+
+       FN_IN;
+       if (b->dma_ref) {
+               offset = omap_get_dma_src_pos(s->lch[s->dma_q_head]) - b->dma_addr;
+               if (offset >= s->fragsize)
+                       offset = s->fragsize - 4;
+       } else if (s->pending_frags) {
+               offset = b->offset;
+       } else {
+               offset = 0;
+       }
+       FN_OUT(offset);
+       return offset;
+}
+
+/***************************************************************************************
+ *
+ * Reset the audio buffers
+ *
+ **************************************************************************************/
+void audio_reset(audio_stream_t * s)
+{
+       FN_IN;
+       if (s->buffers) {
+               audio_stop_dma(s);
+               s->buffers[s->dma_head].offset = 0;
+               s->buffers[s->usr_head].offset = 0;
+               s->usr_head = s->dma_head;
+               s->pending_frags = 0;
+               init_completion(&s->wfc);
+               s->wfc.done = s->nbfrags;
+       }
+       s->active = 0;
+       s->stopped = 0;
+       s->started = 0;
+       FN_OUT(0);
+       return;
+}
+
+/***************************************************************************************
+ *
+ * Clear any pending transfers
+ *
+ **************************************************************************************/
+void omap_clear_sound_dma(audio_stream_t * s)
+{
+       FN_IN;
+       omap_clear_dma(s->lch[s->dma_q_head]);
+       FN_OUT(0);
+       return;
+}
+
+/***************************************************************************************
+ *
+ * DMA related functions
+ *
+ **************************************************************************************/
+static int audio_set_dma_params_play(int channel, dma_addr_t dma_ptr,
+                                    u_int dma_size)
+{
+       int dt = 0x1;           /* data type 16 */
+       int cen = 32;           /* Stereo */
+       int cfn = dma_size / (2 * cen);
+       unsigned long dest_start;
+       int dest_port = 0;
+       int sync_dev = 0;
+
+       FN_IN;
+
+       if (cpu_is_omap15xx() || cpu_is_omap16xx()) {
+               dest_start = AUDIO_MCBSP_DATAWRITE;
+               dest_port = OMAP_DMA_PORT_MPUI;
+       }
+       if (cpu_is_omap24xx()) {
+               dest_start = AUDIO_MCBSP_DATAWRITE;
+               sync_dev = AUDIO_DMA_TX;
+       }
+
+       omap_set_dma_dest_params(channel, dest_port, OMAP_DMA_AMODE_CONSTANT, dest_start, 0, 0);
+       omap_set_dma_src_params(channel, 0, OMAP_DMA_AMODE_POST_INC, dma_ptr, 0, 0);
+       omap_set_dma_transfer_params(channel, dt, cen, cfn, OMAP_DMA_SYNC_ELEMENT, sync_dev, 0);
+
+       FN_OUT(0);
+       return 0;
+}
+
+static int audio_set_dma_params_capture(int channel, dma_addr_t dma_ptr,
+                                       u_int dma_size)
+{
+       int dt = 0x1;           /* data type 16 */
+       int cen = 16;           /* mono */
+       int cfn = dma_size / (2 * cen);
+       unsigned long src_start;
+       int src_port = 0;
+       int sync_dev = 0;
+       int src_sync = 0;
+
+       FN_IN;
+
+       if (cpu_is_omap15xx() || cpu_is_omap16xx()) {
+               src_start = AUDIO_MCBSP_DATAREAD;
+               src_port = OMAP_DMA_PORT_MPUI;
+       }
+       if (cpu_is_omap24xx()) {
+               src_start = AUDIO_MCBSP_DATAREAD;
+               sync_dev = AUDIO_DMA_RX;
+               src_sync = 1;
+       }
+
+       omap_set_dma_src_params(channel, src_port, OMAP_DMA_AMODE_CONSTANT, src_start, 0, 0);
+       omap_set_dma_dest_params(channel, 0, OMAP_DMA_AMODE_POST_INC, dma_ptr, 0, 0);
+       omap_set_dma_transfer_params(channel, dt, cen, cfn, OMAP_DMA_SYNC_ELEMENT, sync_dev, src_sync);
+
+       FN_OUT(0);
+       return 0;
+}
+
+static int audio_start_dma_chain(audio_stream_t * s)
+{
+       int channel = s->lch[s->dma_q_head];
+       FN_IN;
+       if (!s->started) {
+               s->hw_stop();           /* stops McBSP Interface */
+               omap_start_dma(channel);
+               s->started = 1;
+               s->hw_start();          /* start McBSP interface */
+       }
+       /* else the dma itself will progress forward with out our help */
+       FN_OUT(0);
+       return 0;
+}
+
+/* Start DMA -
+ * Do the initial set of work to initialize all the channels as required.
+ * We shall then initate a transfer
+ */
+static int omap_start_sound_dma(audio_stream_t * s, dma_addr_t dma_ptr,
+                               u_int dma_size)
+{
+       int ret = -EPERM;
+
+       FN_IN;
+       if (unlikely(dma_size > MAX_DMA_SIZE)) {
+               ERR("DmaSoundDma: Start: overflowed %d-%d\n", dma_size,
+                   MAX_DMA_SIZE);
+               return -EOVERFLOW;
+       }
+
+       if (AUDIO_QUEUE_FULL(s)) {
+               ret = -2;
+               goto sound_out;
+       }
+       
+       if (s->input_or_output == FMODE_WRITE)
+               /*playback */
+       {
+               ret =
+                   audio_set_dma_params_play(s->lch[s->dma_q_tail], dma_ptr,
+                                             dma_size);
+       } else {
+               ret =
+                   audio_set_dma_params_capture(s->lch[s->dma_q_tail], dma_ptr,
+                                                dma_size);
+       }
+       if (ret != 0) {
+               ret = -2;       /* indicate queue full */
+               goto sound_out;
+       }
+       AUDIO_INCREMENT_TAIL(s);
+       ret = audio_start_dma_chain(s);
+       if (ret) {
+               ERR("dma start failed");
+       }
+      sound_out:
+       FN_OUT(ret);
+       return ret;
+
+}
+
+/***************************************************************************************
+ *
+ * ISR related functions
+ *
+ **************************************************************************************/
+/* The work item handler */
+static void audio_dsr_handler(unsigned long inData)
+{
+       void *data = (void *)inData;
+       struct audio_isr_work_item *work = data;
+       audio_stream_t *s = (work->s);
+       int sound_curr_lch = work->current_lch;
+       u16 ch_status = work->ch_status;
+
+       FN_IN;
+       DPRINTK("lch=%d,status=0x%x, data=%p as=%p\n", sound_curr_lch,
+               ch_status, data, s);
+       if (AUDIO_QUEUE_EMPTY(s)) {
+               ERR("Interrupt(%d)  for empty queue(h=%d, T=%d)???\n",
+                   sound_curr_lch, s->dma_q_head, s->dma_q_tail);
+               ERR("nbfrag=%d,pendfrags=%d,USR-H=%d, QH-%d QT-%d\n",
+                   s->nbfrags, s->pending_frags, s->usr_head, s->dma_head,
+                   s->dma_tail);
+               FN_OUT(-1);
+               return;
+       }
+
+       AUDIO_INCREMENT_HEAD(s);        /* Empty the queue */
+
+       /* Try to fill again */
+       audio_dma_callback(sound_curr_lch, ch_status, s);
+       FN_OUT(0);
+
+}
+
+/* Macro to trace the IRQ calls - checks for multi-channel irqs */
+//#define IRQ_TRACE
+#ifdef IRQ_TRACE
+#define MAX_UP 10
+static char xyz[MAX_UP] = { 0 };
+static int h = 0;
+#endif
+
+/* ISRs have to be short and smart.. So we transfer every heavy duty stuff to the 
+ * work item
+ */
+static void sound_dma_irq_handler(int sound_curr_lch, u16 ch_status, void *data)
+{
+       int dma_status = ch_status;
+       audio_stream_t *s = (audio_stream_t *) data;
+       FN_IN;
+#ifdef IRQ_TRACE
+       xyz[h++] = '0' + sound_curr_lch;
+       if (h == MAX_UP - 1) {
+               printk("%s-", xyz);
+               h = 0;
+       }
+#endif
+       DPRINTK("lch=%d,status=0x%x, dma_status=%d, data=%p\n", sound_curr_lch,
+               ch_status, dma_status, data);
+
+       if (dma_status & (DCSR_ERROR)) {
+               if (cpu_is_omap15xx() || cpu_is_omap16xx())
+                       OMAP_DMA_CCR_REG(sound_curr_lch) &= ~DCCR_EN;
+               ERR("DCSR_ERROR!\n");
+               FN_OUT(-1);
+               return;
+       }
+
+       if (AUDIO_QUEUE_LAST(s))
+               audio_stop_dma(s);
+
+       /* Start the work item  - we ping pong the work items */
+       if (!work_item_running) {
+               work1.current_lch = sound_curr_lch;
+               work1.ch_status = ch_status;
+               work1.s = s;
+               /* schedule tasklet 1 */
+               tasklet_schedule(&audio_isr_work1);
+               work_item_running = 1;
+       } else {
+               work2.current_lch = sound_curr_lch;
+               work2.ch_status = ch_status;
+               work2.s = s;
+               /* schedule tasklet 2 */
+               tasklet_schedule(&audio_isr_work2);
+               work_item_running = 0;
+       }
+       FN_OUT(0);
+       return;
+}
+
+/* The call back that handles buffer stuff */
+static void audio_dma_callback(int lch, u16 ch_status, void *data)
+{
+       audio_stream_t *s = data;
+       audio_buf_t *b = &s->buffers[s->dma_tail];
+       FN_IN;
+
+       if (s->dma_spinref > 0) {
+               s->dma_spinref--;
+       } else if (!s->buffers) {
+               printk(KERN_CRIT
+                      "omap_audio: received DMA IRQ for non existent buffers!\n");
+               return;
+       } else if (b->dma_ref && --b->dma_ref == 0 && b->offset >= s->fragsize) {
+               /* This fragment is done */
+               b->offset = 0;
+               s->bytecount += s->fragsize;
+               s->fragcount++;
+               s->dma_spinref = -s->dma_spinref;
+
+               if (++s->dma_tail >= s->nbfrags)
+                       s->dma_tail = 0;
+
+               if (!s->mapped)
+                       complete(&s->wfc);
+               else
+                       s->pending_frags++;
+
+               wake_up(&s->wq);
+       }
+
+       audio_process_dma(s);
+       
+       FN_OUT(0);
+       return;
+}
+
+/*********************************************************************************
+ *
+ * audio_get_dma_callback(): return the dma interface call back function
+ *
+ *********************************************************************************/
+dma_callback_t audio_get_dma_callback(void)
+{
+       FN_IN;
+       FN_OUT(0);
+       return audio_dma_callback;
+}
+
+static int __init audio_dma_init(void)
+{
+       if (!cpu_is_omap15xx())
+               nr_linked_channels = 2;
+
+       return 0;
+}
+
+static void __exit audio_dma_exit(void)
+{
+       /* Nothing */
+}
+
+module_init(audio_dma_init);
+module_exit(audio_dma_exit);
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("Common DMA handling for Audio driver on OMAP processors");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(omap_clear_sound_dma);
+EXPORT_SYMBOL(omap_request_sound_dma);
+EXPORT_SYMBOL(omap_free_sound_dma);
+
+EXPORT_SYMBOL(audio_get_dma_callback);
+EXPORT_SYMBOL(audio_setup_buf);
+EXPORT_SYMBOL(audio_process_dma);
+EXPORT_SYMBOL(audio_prime_rx);
+EXPORT_SYMBOL(audio_set_fragments);
+EXPORT_SYMBOL(audio_sync);
+EXPORT_SYMBOL(audio_stop_dma);
+EXPORT_SYMBOL(audio_get_dma_pos);
+EXPORT_SYMBOL(audio_reset);
+EXPORT_SYMBOL(audio_discard_buf);
diff --git a/sound/oss/omap-audio-dma-intfc.h b/sound/oss/omap-audio-dma-intfc.h
new file mode 100644 (file)
index 0000000..65aa528
--- /dev/null
@@ -0,0 +1,63 @@
+/*  
+ * linux/sound/oss/omap-audio-dma-intfc.h
+ *
+ * Common audio DMA handling for the OMAP processors
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *
+ * Copyright (C) 2000, 2001 Nicolas Pitre <nico@cam.org>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * History:
+ *
+ * 2004/08/12  Nishanth Menon - Modified to integrate Audio requirements on 1610,1710 platforms
+ */
+
+#ifndef __OMAP_AUDIO_DMA_INTFC_H
+#define __OMAP_AUDIO_DMA_INTFC_H
+
+/************************** INCLUDES *************************************/
+
+/* Requires omap-audio.h */
+#include "omap-audio.h"
+
+/************************** GLOBAL MACROS *************************************/
+
+/* Provide the Macro interfaces common across platforms */
+#define DMA_REQUEST(e,s, cb)   {e=omap_request_sound_dma(s->dma_dev, s->id, s, &s->lch);}
+#define DMA_FREE(s)            omap_free_sound_dma(s, &s->lch)
+#define DMA_CLEAR(s)           omap_clear_sound_dma(s)
+
+/************************** GLOBAL DATA STRUCTURES *********************************/
+
+typedef void (*dma_callback_t) (int lch, u16 ch_status, void *data);
+
+/************************** GLOBAL FUNCTIONS ***************************************/
+
+dma_callback_t audio_get_dma_callback(void);
+int audio_setup_buf(audio_stream_t * s);
+int audio_process_dma(audio_stream_t * s);
+void audio_prime_rx(audio_state_t * state);
+int audio_set_fragments(audio_stream_t * s, int val);
+int audio_sync(struct file *file);
+void audio_stop_dma(audio_stream_t * s);
+u_int audio_get_dma_pos(audio_stream_t * s);
+void audio_reset(audio_stream_t * s);
+void audio_discard_buf(audio_stream_t * s);
+
+/**************** ARCH SPECIFIC FUNCIONS *******************************************/
+
+void omap_clear_sound_dma(audio_stream_t * s);
+
+int omap_request_sound_dma(int device_id, const char *device_name, void *data,
+                          int **channels);
+int omap_free_sound_dma(void *data, int **channels);
+
+#endif                         /* #ifndef __OMAP_AUDIO_DMA_INTFC_H */
diff --git a/sound/oss/omap-audio-tsc2101.c b/sound/oss/omap-audio-tsc2101.c
new file mode 100644 (file)
index 0000000..cbabcf5
--- /dev/null
@@ -0,0 +1,1238 @@
+/*
+ * linux/sound/oss/omap-audio-tsc2101.c
+ *
+ * Glue driver for TSC2101 for OMAP processors
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * History:
+ *  -------
+ *  2004-08-12 Nishanth Menon - Modified to integrate Audio requirements on 1610,1710 platforms.
+ *  2004-09-14 Sriram Kannan - Added /proc support for asynchronous starting/stopping the codec
+ *             (without affecting the normal driver flow).
+ *  2004-11-04 Nishanth Menon - Support for power management
+ *  2004-11-07 Nishanth Menon - Support for Common TSC access b/w Touchscreen and audio drivers
+ */
+
+/***************************** INCLUDES ************************************/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/errno.h>
+#include <linux/sound.h>
+#include <linux/soundcard.h>
+#include <linux/mutex.h>
+
+#include <asm/uaccess.h>
+#include <asm/hardware.h>
+#include <asm/arch/dma.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+
+#include <asm/arch/mux.h>
+#include <asm/arch/io.h>
+#include <asm/mach-types.h>
+
+#include "omap-audio.h"
+#include "omap-audio-dma-intfc.h"
+#include <asm/arch/mcbsp.h>
+#ifdef CONFIG_ARCH_OMAP16XX
+#include <../drivers/ssi/omap-uwire.h>
+#include <asm/arch/dsp_common.h>
+#elif defined(CONFIG_ARCH_OMAP24XX)
+#else
+#error "Unsupported configuration"
+#endif
+
+#include <asm/hardware/tsc2101.h>
+#include <../drivers/ssi/omap-tsc2101.h>
+
+/***************************** MACROS ************************************/
+
+#define PROC_SUPPORT
+
+#ifdef PROC_SUPPORT
+#include <linux/proc_fs.h>
+#define PROC_START_FILE "driver/tsc2101-audio-start"
+#define PROC_STOP_FILE  "driver/tsc2101-audio-stop"
+#endif
+
+#define CODEC_NAME              "TSC2101"
+
+#ifdef CONFIG_ARCH_OMAP16XX
+#define PLATFORM_NAME "OMAP16XX"
+#elif defined(CONFIG_ARCH_OMAP24XX)
+#define PLATFORM_NAME "OMAP2"
+#endif
+
+/* Define to set the tsc as the master w.r.t McBSP */
+#define TSC_MASTER
+
+/*
+ * AUDIO related MACROS
+ */
+#define DEFAULT_BITPERSAMPLE          16
+#define AUDIO_RATE_DEFAULT               44100
+#define PAGE2_AUDIO_CODEC_REGISTERS   (2)
+#define LEAVE_CS                                 0x80
+
+/* Select the McBSP For Audio */
+/* 16XX is MCBSP1 and 24XX is MCBSP2*/
+/* see include/asm-arm/arch-omap/mcbsp.h */
+#ifndef AUDIO_MCBSP
+#error "UnSupported Configuration"
+#endif
+
+#define REC_MASK                                 (SOUND_MASK_LINE | SOUND_MASK_MIC)
+#define DEV_MASK                                 (REC_MASK | SOUND_MASK_VOLUME)
+
+#define SET_VOLUME                               1
+#define SET_LINE                                 2
+#define SET_MIC              3
+#define SET_RECSRC           4
+
+#define DEFAULT_VOLUME                93
+#define DEFAULT_INPUT_VOLUME     20    /* An minimal volume */
+
+/* Tsc Audio Specific */
+#define NUMBER_SAMPLE_RATES_SUPPORTED 16
+#define OUTPUT_VOLUME_MIN 0x7F
+#define OUTPUT_VOLUME_MAX 0x32
+#define OUTPUT_VOLUME_RANGE           (OUTPUT_VOLUME_MIN - OUTPUT_VOLUME_MAX)
+#define OUTPUT_VOLUME_MASK            OUTPUT_VOLUME_MIN
+#define DEFAULT_VOLUME_LEVEL          OUTPUT_VOLUME_MAX
+
+/* use input vol of 75 for 0dB gain */
+#define INPUT_VOLUME_MIN                     0x0
+#define INPUT_VOLUME_MAX        0x7D
+#define INPUT_VOLUME_RANGE                   (INPUT_VOLUME_MAX - INPUT_VOLUME_MIN)
+#define INPUT_VOLUME_MASK                    INPUT_VOLUME_MAX
+
+/*********** Debug Macros ********/
+/* To Generate a rather shrill tone -test the entire path */
+//#define TONE_GEN
+/* To Generate a tone for each keyclick - test the tsc,spi paths*/
+//#define TEST_KEYCLICK
+/* To dump the tsc registers for debug */
+//#define TSC_DUMP_REGISTERS
+
+#ifdef DPRINTK
+#undef DPRINTK
+#endif
+#undef DEBUG
+
+//#define DEBUG
+#ifdef DEBUG
+#define DPRINTK(ARGS...)  printk(KERN_INFO "<%s>: ",__FUNCTION__);printk(ARGS)
+#define FN_IN printk(KERN_INFO "[%s]: start\n", __FUNCTION__)
+#define FN_OUT(n) printk(KERN_INFO "[%s]: end(%u)\n",__FUNCTION__, n)
+#else
+#define DPRINTK( x... )
+#define FN_IN
+#define FN_OUT(n)
+#endif
+
+/***************************** Data Structures **********************************/
+
+static int audio_ifc_start(void)
+{
+       omap_mcbsp_start(AUDIO_MCBSP);
+       return 0;
+}
+
+static int audio_ifc_stop(void)
+{
+       omap_mcbsp_stop(AUDIO_MCBSP);
+       return 0;
+}
+
+static audio_stream_t output_stream = {
+       .id                     = "TSC2101 out",
+       .dma_dev                = AUDIO_DMA_TX,
+       .input_or_output        = FMODE_WRITE,
+       .hw_start               = audio_ifc_start,
+       .hw_stop                = audio_ifc_stop,
+};
+
+static audio_stream_t input_stream = {
+       .id                     = "TSC2101 in",
+       .dma_dev                = AUDIO_DMA_RX,
+       .input_or_output        = FMODE_READ,
+       .hw_start               = audio_ifc_start,
+       .hw_stop                = audio_ifc_stop,
+};
+
+static int audio_dev_id, mixer_dev_id;
+
+typedef struct {
+       u8      volume;
+       u8      line;
+       u8      mic;
+       int     recsrc;
+       int     mod_cnt;
+} tsc2101_local_info;
+
+static tsc2101_local_info tsc2101_local = {
+       volume:         DEFAULT_VOLUME,
+       line:           DEFAULT_INPUT_VOLUME,
+       mic:            DEFAULT_INPUT_VOLUME,
+       recsrc:         SOUND_MASK_LINE,
+       mod_cnt:        0
+};
+
+struct sample_rate_reg_info {
+       u16 sample_rate;
+       u8  divisor;
+       u8  fs_44kHz;           /* if 0 48 khz, if 1 44.1 khz fsref */
+};
+
+/* To Store the default sample rate */
+static long audio_samplerate = AUDIO_RATE_DEFAULT;
+
+static const struct sample_rate_reg_info
+ reg_info[NUMBER_SAMPLE_RATES_SUPPORTED] = {
+       /* Div 1 */
+       {48000, 0, 0},
+       {44100, 0, 1},
+       /* Div 1.5 */
+       {32000, 1, 0},
+       {29400, 1, 1},
+       /* Div 2 */
+       {24000, 2, 0},
+       {22050, 2, 1},
+       /* Div 3 */
+       {16000, 3, 0},
+       {14700, 3, 1},
+       /* Div 4 */
+       {12000, 4, 0},
+       {11025, 4, 1},
+       /* Div 5 */
+       {9600, 5, 0},
+       {8820, 5, 1},
+       /* Div 5.5 */
+       {8727, 6, 0},
+       {8018, 6, 1},
+       /* Div 6 */
+       {8000, 7, 0},
+       {7350, 7, 1},
+};
+
+static struct omap_mcbsp_reg_cfg initial_config = {
+       .spcr2 = FREE | FRST | GRST | XRST | XINTM(3),
+       .spcr1 = RINTM(3) | RRST,
+       .rcr2  = RPHASE | RFRLEN2(OMAP_MCBSP_WORD_8) |
+                RWDLEN2(OMAP_MCBSP_WORD_16) | RDATDLY(1),
+       .rcr1  = RFRLEN1(OMAP_MCBSP_WORD_8) | RWDLEN1(OMAP_MCBSP_WORD_16),
+       .xcr2  = XPHASE | XFRLEN2(OMAP_MCBSP_WORD_8) |
+                XWDLEN2(OMAP_MCBSP_WORD_16) | XDATDLY(1) | XFIG,
+       .xcr1  = XFRLEN1(OMAP_MCBSP_WORD_8) | XWDLEN1(OMAP_MCBSP_WORD_16),
+       .srgr1 = FWID(15),
+       .srgr2 = GSYNC | CLKSP | FSGM | FPER(31),
+
+       /* platform specific initialization */
+#ifdef CONFIG_MACH_OMAP_H2
+       .pcr0  = CLKXM | CLKRM | FSXP | FSRP | CLKXP | CLKRP,
+#elif defined(CONFIG_MACH_OMAP_H3) || defined(CONFIG_MACH_OMAP_H4) || defined(CONFIG_MACH_OMAP_APOLLON)
+
+#ifndef TSC_MASTER
+       .pcr0  = FSXM | FSRM | CLKXM | CLKRM | CLKXP | CLKRP,
+#else
+       .pcr0  = CLKRM | SCLKME | FSXP | FSRP | CLKXP | CLKRP,
+#endif                         /* tsc Master defs */
+
+#endif                         /* platform specific inits */
+};
+
+/***************************** MODULES SPECIFIC FUNCTION PROTOTYPES ********************/
+
+static void omap_tsc2101_initialize(void *dummy);
+
+static void omap_tsc2101_shutdown(void *dummy);
+
+static int  omap_tsc2101_ioctl(struct inode *inode, struct file *file,
+                              uint cmd, ulong arg);
+
+static int  omap_tsc2101_probe(void);
+
+static void omap_tsc2101_remove(void);
+
+static int  omap_tsc2101_suspend(void);
+
+static int  omap_tsc2101_resume(void);
+
+static void tsc2101_configure(void);
+
+static int  mixer_open(struct inode *inode, struct file *file);
+
+static int  mixer_release(struct inode *inode, struct file *file);
+
+static int  mixer_ioctl(struct inode *inode, struct file *file, uint cmd,
+                       ulong arg);
+
+#ifdef TEST_KEYCLICK
+void tsc2101_testkeyclick(void);
+#endif
+
+#ifdef TONE_GEN
+void toneGen(void);
+#endif
+
+#ifdef TSC_DUMP_REGISTERS
+static void tsc2101_dumpRegisters(void);
+#endif
+
+#ifdef PROC_SUPPORT
+static int codec_start(char *buf, char **start, off_t offset, int count,
+                      int *eof, void *data);
+
+static int codec_stop(char *buf, char **start, off_t offset, int count,
+                     int *eof, void *data);
+
+static void tsc2101_start(void);
+#endif
+
+/******************** DATA STRUCTURES USING FUNCTION POINTERS **************************/
+
+/* File Op structure for mixer */
+static struct file_operations omap_mixer_fops = {
+       .open           = mixer_open,
+       .release        = mixer_release,
+       .ioctl          = mixer_ioctl,
+       .owner          = THIS_MODULE
+};
+
+/* To store characteristic info regarding the codec for the audio driver */
+static audio_state_t tsc2101_state = {
+       .output_stream  = &output_stream,
+       .input_stream   = &input_stream,
+/*     .need_tx_for_rx = 1, //Once the Full Duplex works  */
+       .need_tx_for_rx = 0,
+       .hw_init        = omap_tsc2101_initialize,
+       .hw_shutdown    = omap_tsc2101_shutdown,
+       .client_ioctl   = omap_tsc2101_ioctl,
+       .hw_probe       = omap_tsc2101_probe,
+       .hw_remove      = omap_tsc2101_remove,
+       .hw_suspend     = omap_tsc2101_suspend,
+       .hw_resume      = omap_tsc2101_resume,
+};
+
+/* This will be defined in the Audio.h */
+static struct file_operations *omap_audio_fops;
+
+/***************************** MODULES SPECIFIC FUNCTIONs *******************************/
+
+/*********************************************************************************
+ *
+ * Simplified write for tsc Audio
+ *
+ *********************************************************************************/
+static __inline__ void audio_tsc2101_write(u8 address, u16 data)
+{
+       omap_tsc2101_write(PAGE2_AUDIO_CODEC_REGISTERS, address, data);
+}
+
+/*********************************************************************************
+ *
+ * Simplified read for tsc  Audio
+ *
+ *********************************************************************************/
+static __inline__ u16 audio_tsc2101_read(u8 address)
+{
+       return (omap_tsc2101_read(PAGE2_AUDIO_CODEC_REGISTERS, address));
+}
+
+/*********************************************************************************
+ *
+ * tsc2101_update()
+ * Volume Adj etc
+ *
+ ********************************************************************************/
+static int tsc2101_update(int flag, int val)
+{
+       u16 volume;
+       u16 data;
+
+       FN_IN;
+       switch (flag) {
+       case SET_VOLUME:
+               if (val < 0 || val > 100) {
+                       printk(KERN_ERR "Trying a bad volume value(%d)!\n", val);
+                       return -EPERM;
+               }
+               /* Convert 0 -> 100 volume to 0x7F(min) -> y(max) volume range */
+               volume =
+                   ((val * OUTPUT_VOLUME_RANGE) / 100) + OUTPUT_VOLUME_MAX;
+               /* invert the value for getting the proper range 0 min and 100 max */
+               volume = OUTPUT_VOLUME_MIN - volume;
+               data = audio_tsc2101_read(TSC2101_DAC_GAIN_CTRL);
+               data &=
+                   ~(DGC_DALVL(OUTPUT_VOLUME_MIN) |
+                     DGC_DARVL(OUTPUT_VOLUME_MIN));
+               data |= DGC_DALVL(volume) | DGC_DARVL(volume);
+               audio_tsc2101_write(TSC2101_DAC_GAIN_CTRL, data);
+               data = audio_tsc2101_read(TSC2101_DAC_GAIN_CTRL);
+
+               break;
+
+       case SET_LINE:
+               if (val < 0 || val > 100) {
+                       printk(KERN_ERR "Trying a bad volume value(%d)!\n", val);
+                       return -EPERM;
+               }
+               /* Convert 0 -> 100 volume to 0x0(min) -> 0x7D(max) volume range */
+               /* NOTE: 0 is minimum volume and not mute */
+               volume = ((val * INPUT_VOLUME_RANGE) / 100) + INPUT_VOLUME_MIN;
+               /* Handset Input not muted, AGC for Handset In off */
+               audio_tsc2101_write(TSC2101_HEADSET_GAIN_CTRL,
+       HGC_ADPGA_HED(volume));
+               break;
+
+       case SET_MIC:
+               if (val < 0 || val > 100) {
+                       printk(KERN_ERR "Trying a bad volume value(%d)!\n", val);
+                       return -EPERM;
+               }
+               /* Convert 0 -> 100 volume to 0x0(min) -> 0x7D(max) volume range */
+               /* NOTE: 0 is minimum volume and not mute */
+               volume = ((val * INPUT_VOLUME_RANGE) / 100) + INPUT_VOLUME_MIN;
+               /* Handset Input not muted, AGC for Handset In off */
+               audio_tsc2101_write(TSC2101_HANDSET_GAIN_CTRL,
+       HNGC_ADPGA_HND(volume));
+               break;
+
+       case SET_RECSRC:
+               /*
+                * If more than one recording device selected,
+                * disable the device that is currently in use.
+                */
+               if (hweight32(val) > 1)
+                       val &= ~tsc2101_local.recsrc;
+
+               data = audio_tsc2101_read(TSC2101_MIXER_PGA_CTRL);
+               data &= ~MPC_MICSEL(7); /* clear all MICSEL bits */
+
+               if (val == SOUND_MASK_MIC) {
+                       data |=  MPC_MICSEL(1);
+                       audio_tsc2101_write(TSC2101_MIXER_PGA_CTRL, data);
+               }
+               else if (val == SOUND_MASK_LINE) {
+                       data |=  MPC_MICSEL(0);
+                       audio_tsc2101_write(TSC2101_MIXER_PGA_CTRL, data);
+               }
+               else {
+                       printk(KERN_WARNING "omap1610-tsc2101: Wrong RECSRC"
+        " value specified\n");
+                       return -EINVAL;
+               }
+               tsc2101_local.recsrc = val;
+               break;
+       default:
+               printk(KERN_WARNING "omap1610-tsc2101: Wrong tsc2101_update "
+       "flag specified\n");
+               break;
+       }
+
+       FN_OUT(0);
+       return 0;
+}
+
+/*********************************************************************************
+ *
+ * mixer_open()
+ *
+ ********************************************************************************/
+static int mixer_open(struct inode *inode, struct file *file)
+{
+       /* Any mixer specific initialization */
+
+       /* Initalize the tsc2101 */
+       omap_tsc2101_enable();
+
+       return 0;
+}
+
+/*********************************************************************************
+ *
+ * mixer_release()
+ *
+ ********************************************************************************/
+static int mixer_release(struct inode *inode, struct file *file)
+{
+       /* Any mixer specific Un-initialization */
+       omap_tsc2101_disable();
+
+       return 0;
+}
+
+/*********************************************************************************
+ *
+ * mixer_ioctl()
+ *
+ ********************************************************************************/
+static int
+mixer_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
+{
+       int val;
+       int gain;
+       int ret = 0;
+       int nr = _IOC_NR(cmd);
+
+       /*
+        * We only accept mixer (type 'M') ioctls.
+        */
+       FN_IN;
+       if (_IOC_TYPE(cmd) != 'M')
+               return -EINVAL;
+
+       DPRINTK(" 0x%08x\n", cmd);
+
+       if (cmd == SOUND_MIXER_INFO) {
+               struct mixer_info mi;
+
+               strncpy(mi.id, "TSC2101", sizeof(mi.id));
+               strncpy(mi.name, "TI TSC2101", sizeof(mi.name));
+               mi.modify_counter = tsc2101_local.mod_cnt;
+               FN_OUT(1);
+               return copy_to_user((void __user *)arg, &mi, sizeof(mi));
+       }
+
+       if (_IOC_DIR(cmd) & _IOC_WRITE) {
+               ret = get_user(val, (int __user *)arg);
+               if (ret)
+                       goto out;
+
+               /* Ignore separate left/right channel for now,
+                * even the codec does support it.
+                */
+               gain = val & 255;
+
+               switch (nr) {
+               case SOUND_MIXER_VOLUME:
+                       tsc2101_local.volume = val;
+                       tsc2101_local.mod_cnt++;
+                       ret = tsc2101_update(SET_VOLUME, gain);
+                       break;
+
+               case SOUND_MIXER_LINE:
+                       tsc2101_local.line = val;
+                       tsc2101_local.mod_cnt++;
+                       ret = tsc2101_update(SET_LINE, gain);
+                       break;
+
+               case SOUND_MIXER_MIC:
+                       tsc2101_local.mic = val;
+                       tsc2101_local.mod_cnt++;
+                       ret = tsc2101_update(SET_MIC, gain);
+                       break;
+
+               case SOUND_MIXER_RECSRC:
+                       if ((val & SOUND_MASK_LINE) ||
+                           (val & SOUND_MASK_MIC)) {
+                               if (tsc2101_local.recsrc != val) {
+                                       tsc2101_local.mod_cnt++;
+                                       tsc2101_update(SET_RECSRC, val);
+                               }
+                       }
+                       else {
+                               ret = -EINVAL;
+                       }
+                       break;
+
+               default:
+                       ret = -EINVAL;
+               }
+       }
+
+       if (ret == 0 && _IOC_DIR(cmd) & _IOC_READ) {
+               ret = 0;
+
+               switch (nr) {
+               case SOUND_MIXER_VOLUME:
+                       val = tsc2101_local.volume;
+                       val = (tsc2101_local.volume << 8) |
+         tsc2101_local.volume;
+                       break;
+               case SOUND_MIXER_LINE:
+                       val = (tsc2101_local.line << 8) |
+         tsc2101_local.line;
+                       break;
+               case SOUND_MIXER_MIC:
+                       val = (tsc2101_local.mic << 8) |
+         tsc2101_local.mic;
+                       break;
+               case SOUND_MIXER_RECSRC:
+                       val = tsc2101_local.recsrc;
+                       break;
+               case SOUND_MIXER_RECMASK:
+                       val = REC_MASK;
+                       break;
+               case SOUND_MIXER_DEVMASK:
+                       val = DEV_MASK;
+                       break;
+               case SOUND_MIXER_CAPS:
+                       val = 0;
+                       break;
+               case SOUND_MIXER_STEREODEVS:
+                       val = SOUND_MASK_VOLUME;
+                       break;
+               default:
+                       val = 0;
+                       printk(KERN_WARNING "omap1610-tsc2101: unknown mixer "
+        "read ioctl flag specified\n");
+                       ret = -EINVAL;
+                       break;
+               }
+
+               if (ret == 0)
+                       ret = put_user(val, (int __user *)arg);
+       }
+      out:
+       FN_OUT(0);
+       return ret;
+
+}
+
+/*********************************************************************************
+ *
+ * omap_set_samplerate()
+ *
+ ********************************************************************************/
+static int omap_set_samplerate(long sample_rate)
+{
+       u8 count = 0;
+       u16 data = 0;
+       int clkgdv = 0;
+       /* wait for any frame to complete */
+       udelay(125);
+
+       /* Search for the right sample rate */
+       while ((reg_info[count].sample_rate != sample_rate) &&
+              (count < NUMBER_SAMPLE_RATES_SUPPORTED)) {
+               count++;
+       }
+       if (count == NUMBER_SAMPLE_RATES_SUPPORTED) {
+               printk(KERN_ERR "Invalid Sample Rate %d requested\n",
+                      (int)sample_rate);
+               return -EPERM;
+       }
+
+       /* Set AC1 */
+       data = audio_tsc2101_read(TSC2101_AUDIO_CTRL_1);
+       /*Clear prev settings */
+       data &= ~(AC1_DACFS(0x07) | AC1_ADCFS(0x07));
+       data |=
+           AC1_DACFS(reg_info[count].divisor) | AC1_ADCFS(reg_info[count].
+                                                          divisor);
+       audio_tsc2101_write(TSC2101_AUDIO_CTRL_1, data);
+
+       /* Set the AC3 */
+       data = audio_tsc2101_read(TSC2101_AUDIO_CTRL_3);
+       /*Clear prev settings */
+       data &= ~(AC3_REFFS | AC3_SLVMS);
+       data |= (reg_info[count].fs_44kHz) ? AC3_REFFS : 0;
+#ifdef TSC_MASTER
+       data |= AC3_SLVMS;
+#endif                         /* #ifdef TSC_MASTER */
+       audio_tsc2101_write(TSC2101_AUDIO_CTRL_3, data);
+
+       /* program the PLLs */
+       if (reg_info[count].fs_44kHz) {
+               /* 44.1 khz - 12 MHz Mclk */
+               audio_tsc2101_write(TSC2101_PLL_PROG_1, PLL1_PLLSEL | PLL1_PVAL(1) | PLL1_I_VAL(7));    /* PVAL 1; I_VAL 7 */
+               audio_tsc2101_write(TSC2101_PLL_PROG_2, PLL2_D_VAL(0x1490));    /* D_VAL 5264 */
+       } else {
+               /* 48 khz - 12 Mhz Mclk */
+               audio_tsc2101_write(TSC2101_PLL_PROG_1, PLL1_PLLSEL | PLL1_PVAL(1) | PLL1_I_VAL(8));    /* PVAL 1; I_VAL 8 */
+               audio_tsc2101_write(TSC2101_PLL_PROG_2, PLL2_D_VAL(0x780));     /* D_VAL 1920 */
+       }
+
+       audio_samplerate = sample_rate;
+
+       /* Set the sample rate */
+#ifndef TSC_MASTER
+       clkgdv =
+           DEFAULT_MCBSP_CLOCK / (sample_rate *
+                                  (DEFAULT_BITPERSAMPLE * 2 - 1));
+       if (clkgdv)
+               initial_config.srgr1 =
+                   (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
+       else
+               return (1);
+
+       /* Stereo Mode */
+       initial_config.srgr2 =
+           (CLKSM | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1));
+#else
+       initial_config.srgr1 =
+           (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
+       initial_config.srgr2 =
+           ((GSYNC | CLKSP | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1)));
+
+#endif                         /* end of #ifdef TSC_MASTER */
+       omap_mcbsp_config(AUDIO_MCBSP, &initial_config);
+
+       return 0;
+}
+
+/*********************************************************************************
+ *
+ * omap_tsc2101_initialize() [hw_init() ]
+ *
+ ********************************************************************************/
+static void omap_tsc2101_initialize(void *dummy)
+{
+
+       DPRINTK("omap_tsc2101_initialize entry\n");
+
+       /* initialize with default sample rate */
+       audio_samplerate = AUDIO_RATE_DEFAULT;
+
+       omap_mcbsp_request(AUDIO_MCBSP);
+
+       /* if configured, then stop mcbsp */
+       omap_mcbsp_stop(AUDIO_MCBSP);
+
+       omap_tsc2101_enable();
+
+       omap_mcbsp_config(AUDIO_MCBSP, &initial_config);
+       omap_mcbsp_start(AUDIO_MCBSP);
+       tsc2101_configure();
+
+#ifdef TEST_KEYCLICK
+       tsc2101_testkeyclick();
+#endif
+
+#ifdef TONE_GEN
+       toneGen();
+#endif
+
+       DPRINTK("omap_tsc2101_initialize exit\n");
+}
+
+/*********************************************************************************
+ *
+ * omap_tsc2101_shutdown() [hw_shutdown() ]
+ *
+ ********************************************************************************/
+static void omap_tsc2101_shutdown(void *dummy)
+{
+       /*
+          Turn off codec after it is done.
+          Can't do it immediately, since it may still have
+          buffered data.
+
+          Wait 20ms (arbitrary value) and then turn it off.
+        */
+
+       FN_IN;
+       set_current_state(TASK_INTERRUPTIBLE);
+       schedule_timeout(2);
+
+       omap_mcbsp_stop(AUDIO_MCBSP);
+       omap_mcbsp_free(AUDIO_MCBSP);
+
+       audio_tsc2101_write(TSC2101_CODEC_POWER_CTRL,
+                           ~(CPC_SP1PWDN | CPC_SP2PWDN | CPC_BASSBC));
+
+       omap_tsc2101_disable();
+
+       FN_OUT(0);
+}
+
+/*********************************************************************************
+ *
+ * tsc2101_configure
+ *
+ ********************************************************************************/
+static void tsc2101_configure(void)
+{
+       FN_IN;
+
+       audio_tsc2101_write(TSC2101_CODEC_POWER_CTRL, 0x0000);
+
+       /*Mute Analog Sidetone */
+       /*Select MIC_INHED input for headset */
+       /*Cell Phone In not connected */
+       audio_tsc2101_write(TSC2101_MIXER_PGA_CTRL,
+                           MPC_ASTMU | MPC_ASTG(0x40) | MPC_MICADC);
+
+       /* Set record source */
+       tsc2101_update(SET_RECSRC, tsc2101_local.recsrc);
+
+       /* ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled */
+       /* 1dB AGC hysteresis */
+       /* MICes bias 2V */
+       audio_tsc2101_write(TSC2101_AUDIO_CTRL_4, AC4_MB_HED(0));
+
+       /* Set codec output volume */
+       audio_tsc2101_write(TSC2101_DAC_GAIN_CTRL, 0x0000);
+
+       /* DAC left and right routed to SPK2 */
+       /* SPK1/2 unmuted */
+       audio_tsc2101_write(TSC2101_AUDIO_CTRL_5,
+                           AC5_DAC2SPK1(3) | AC5_AST2SPK1 | AC5_KCL2SPK1 |
+                           AC5_DAC2SPK2(3) | AC5_AST2SPK2 | AC5_KCL2SPK2 |
+                           AC5_HDSCPTC);
+
+       /* OUT8P/N muted, CPOUT muted */
+
+       audio_tsc2101_write(TSC2101_AUDIO_CTRL_6,
+                           AC6_MUTLSPK | AC6_MUTSPK2 | AC6_LDSCPTC |
+                           AC6_VGNDSCPTC);
+
+       /* Headset/Hook switch detect disabled */
+       audio_tsc2101_write(TSC2101_AUDIO_CTRL_7, 0x0000);
+
+       /* Left line input volume control */
+       tsc2101_update(SET_LINE, tsc2101_local.line);
+
+       /* mic input volume control */
+       tsc2101_update(SET_MIC, tsc2101_local.mic);
+
+       /* Left/Right headphone channel volume control */
+       /* Zero-cross detect on */
+       tsc2101_update(SET_VOLUME, tsc2101_local.volume);
+
+       /* clock configuration */
+       omap_set_samplerate(audio_samplerate);
+
+#ifdef TSC_DUMP_REGISTERS
+       tsc2101_dumpRegisters();
+#endif
+
+       FN_OUT(0);
+}
+
+#ifdef PROC_SUPPORT
+static void tsc2101_start(void)
+{
+       FN_IN;
+
+       audio_tsc2101_write(TSC2101_CODEC_POWER_CTRL, 0x0000);
+
+       /*Mute Analog Sidetone */
+       /*Select MIC_INHED input for headset */
+       /*Cell Phone In not connected */
+       audio_tsc2101_write(TSC2101_MIXER_PGA_CTRL,
+                           MPC_ASTMU | MPC_ASTG(0x40) | MPC_MICADC);
+
+       /* Set record source */
+       tsc2101_update(SET_RECSRC, tsc2101_local.recsrc);
+
+       /* ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled */
+       /* 1dB AGC hysteresis */
+       /* MICes bias 2V */
+       audio_tsc2101_write(TSC2101_AUDIO_CTRL_4, AC4_MB_HED(0));
+
+       /* Set codec output volume */
+       audio_tsc2101_write(TSC2101_DAC_GAIN_CTRL, 0x0000);
+
+       /* DAC left and right routed to SPK2 */
+       /* SPK1/2 unmuted */
+       audio_tsc2101_write(TSC2101_AUDIO_CTRL_5,
+                           AC5_DAC2SPK1(3) | AC5_AST2SPK1 | AC5_KCL2SPK1 |
+                           AC5_DAC2SPK2(3) | AC5_AST2SPK2 | AC5_KCL2SPK2 |
+                           AC5_HDSCPTC);
+
+       /* OUT8P/N muted, CPOUT muted */
+
+       audio_tsc2101_write(TSC2101_AUDIO_CTRL_6,
+                           AC6_MUTLSPK | AC6_MUTSPK2 | AC6_LDSCPTC |
+                           AC6_VGNDSCPTC);
+
+       /* Headset/Hook switch detect disabled */
+       audio_tsc2101_write(TSC2101_AUDIO_CTRL_7, 0x0000);
+
+       /* Left line input volume control */
+       tsc2101_update(SET_LINE, tsc2101_local.line);
+
+       /* mic input volume control */
+       tsc2101_update(SET_MIC, tsc2101_local.mic);
+
+       /* Left/Right headphone channel volume control */
+       /* Zero-cross detect on */
+       tsc2101_update(SET_VOLUME, tsc2101_local.volume);
+
+       FN_OUT(0);
+
+}
+#endif
+
+/******************************************************************************************
+ *
+ * All generic ioctl's are handled by audio_ioctl() [File: omap-audio.c]. This
+ * routine handles some platform specific ioctl's
+ *
+ ******************************************************************************************/
+static int
+omap_tsc2101_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
+{
+       long val;
+       int ret = 0;
+
+       DPRINTK(" 0x%08x\n", cmd);
+
+       /*
+        * These are platform dependent ioctls which are not handled by the
+        * generic omap-audio module.
+        */
+       switch (cmd) {
+       case SNDCTL_DSP_STEREO:
+               ret = get_user(val, (int __user *)arg);
+               if (ret)
+                       return ret;
+               /* the AIC23 is stereo only */
+               ret = (val == 0) ? -EINVAL : 1;
+               FN_OUT(1);
+               return put_user(ret, (int __user *)arg);
+
+       case SNDCTL_DSP_CHANNELS:
+       case SOUND_PCM_READ_CHANNELS:
+               /* the AIC23 is stereo only */
+               FN_OUT(2);
+               return put_user(2, (long __user *)arg);
+
+       case SNDCTL_DSP_SPEED:
+               ret = get_user(val, (long __user *)arg);
+               if (ret)
+                       break;
+               ret = omap_set_samplerate(val);
+               if (ret)
+                       break;
+               /* fall through */
+
+       case SOUND_PCM_READ_RATE:
+               FN_OUT(3);
+               return put_user(audio_samplerate, (long __user *)arg);
+
+       case SOUND_PCM_READ_BITS:
+       case SNDCTL_DSP_SETFMT:
+       case SNDCTL_DSP_GETFMTS:
+               /* we can do 16-bit only */
+               FN_OUT(4);
+               return put_user(AFMT_S16_LE, (long __user *)arg);
+
+       default:
+               /* Maybe this is meant for the mixer (As per OSS Docs) */
+               FN_OUT(5);
+               return mixer_ioctl(inode, file, cmd, arg);
+       }
+
+       FN_OUT(0);
+       return ret;
+}
+
+/*********************************************************************************
+ *
+ * module_probe for TSC2101
+ *
+ ********************************************************************************/
+static int omap_tsc2101_probe(void)
+{
+       FN_IN;
+
+       /* Get the fops from audio oss driver */
+       if (!(omap_audio_fops = audio_get_fops())) {
+               printk(KERN_ERR "Unable to Get the FOPs of Audio OSS driver\n");
+               audio_unregister_codec(&tsc2101_state);
+               return -EPERM;
+       }
+
+       /* register devices */
+       audio_dev_id = register_sound_dsp(omap_audio_fops, -1);
+       mixer_dev_id = register_sound_mixer(&omap_mixer_fops, -1);
+
+#ifdef PROC_SUPPORT
+       create_proc_read_entry(PROC_START_FILE, 0 /* default mode */ ,
+                              NULL /* parent dir */ ,
+                              codec_start, NULL /* client data */ );
+
+       create_proc_read_entry(PROC_STOP_FILE, 0 /* default mode */ ,
+                              NULL /* parent dir */ ,
+                              codec_stop, NULL /* client data */ );
+#endif
+
+       /* Announcement Time */
+       printk(KERN_INFO PLATFORM_NAME " " CODEC_NAME
+              " Audio support initialized\n");
+
+       FN_OUT(0);
+       return 0;
+}
+
+/*********************************************************************************
+ *
+ * Module Remove for TSC2101
+ *
+ ********************************************************************************/
+static void omap_tsc2101_remove(void)
+{
+       FN_IN;
+       /* Un-Register the codec with the audio driver */
+       unregister_sound_dsp(audio_dev_id);
+       unregister_sound_mixer(mixer_dev_id);
+
+#ifdef PROC_SUPPORT
+       remove_proc_entry(PROC_START_FILE, NULL);
+       remove_proc_entry(PROC_STOP_FILE, NULL);
+#endif
+       FN_OUT(0);
+
+}
+
+/*********************************************************************************
+ *
+ * Module Suspend for TSC2101
+ *
+ ********************************************************************************/
+static int omap_tsc2101_suspend(void)
+{
+
+       FN_OUT(0);
+       return 0;
+}
+
+/*********************************************************************************
+ *
+ * Module Resume for TSC2101
+ *
+ ********************************************************************************/
+static int omap_tsc2101_resume(void)
+{
+
+       FN_OUT(0);
+       return 0;
+}
+
+/*********************************************************************************
+ *
+ * module_init for TSC2101
+ *
+ ********************************************************************************/
+static int __init audio_tsc2101_init(void)
+{
+
+       int err = 0;
+       FN_IN;
+
+       if (machine_is_omap_osk() || machine_is_omap_innovator())
+               return -ENODEV;
+
+       mutex_init(&tsc2101_state.mutex);
+
+       /* register the codec with the audio driver */
+       if ((err = audio_register_codec(&tsc2101_state))) {
+               printk(KERN_ERR
+                      "Failed to register TSC driver with Audio OSS Driver\n");
+       }
+       FN_OUT(err);
+       return err;
+}
+
+/*********************************************************************************
+ *
+ * module_exit for TSC2101
+ *
+ ********************************************************************************/
+static void __exit audio_tsc2101_exit(void)
+{
+
+       FN_IN;
+       (void)audio_unregister_codec(&tsc2101_state);
+       FN_OUT(0);
+       return;
+}
+
+/**************************** DEBUG FUNCTIONS ***********************************/
+
+/*********************************************************************************
+ * TEST_KEYCLICK:
+ * This is a test to generate various keyclick sound on tsc.
+ * verifies if the tsc and the spi interfaces are operational.
+ *
+ ********************************************************************************/
+#ifdef TEST_KEYCLICK
+void tsc2101_testkeyclick(void)
+{
+       u8 freq = 0;
+       u16 old_reg_val, reg_val;
+       u32 uDummyVal = 0;
+       u32 uTryVal = 0;
+
+       old_reg_val = audio_tsc2101_read(TSC2101_AUDIO_CTRL_2);
+
+       /* Keyclick active, max amplitude and longest key click len(32 period) */
+       printk(KERN_INFO " TESTING KEYCLICK\n Listen carefully NOW....\n");
+       printk(KERN_INFO " OLD REG VAL=0x%x\n", old_reg_val);
+       /* try all frequencies */
+       for (; freq < 8; freq++) {
+               /* Keyclick active, max amplitude and longest key click len(32 period) */
+               reg_val = old_reg_val | AC2_KCLAC(0x7) | AC2_KCLLN(0xF);
+               uDummyVal = 0;
+               uTryVal = 0;
+               printk(KERN_INFO "\n\nTrying frequency %d reg val= 0x%x\n",
+                      freq, reg_val | AC2_KCLFRQ(freq) | AC2_KCLEN);
+               audio_tsc2101_write(TSC2101_AUDIO_CTRL_2,
+                                   reg_val | AC2_KCLFRQ(freq) | AC2_KCLEN);
+               printk("DONE. Wait 10 ms ...\n");
+               /* wait till the kclk bit is auto cleared! time out also to be considered. */
+               while (audio_tsc2101_read(TSC2101_AUDIO_CTRL_2) & AC2_KCLEN) {
+                       udelay(3);
+                       uTryVal++;
+                       if (uTryVal > 2000) {
+                               printk(KERN_ERR
+                                      "KEYCLICK TIMED OUT! freq val=%d, POSSIBLE ERROR!\n",
+                                      freq);
+                               printk(KERN_INFO
+                                      "uTryVal == %d: Read back new reg val= 0x%x\n",
+                                      uTryVal,
+                                      audio_tsc2101_read
+                                      (TSC2101_AUDIO_CTRL_2));
+                               /* clear */
+                               audio_tsc2101_write(TSC2101_AUDIO_CTRL_2, 0x00);
+                               break;
+                       }
+               }
+       }
+       /* put the old value back */
+       audio_tsc2101_write(TSC2101_AUDIO_CTRL_2, old_reg_val);
+       printk(KERN_INFO " KEYCLICK TEST COMPLETE\n");
+
+}                              /* End of tsc2101_testkeyclick */
+
+#endif                         /* TEST_KEYCLICK */
+
+/*********************************************************************************
+ * TONEGEN:
+ * This is a test to generate a rather unpleasant sound..
+ * verifies if the mcbsp is active (requires MCBSP_DIRECT_RW to be active on McBSP)
+ *
+ ********************************************************************************/
+#ifdef TONE_GEN
+/* Generates a shrill tone */
+u16 tone[] = {
+       0x0ce4, 0x0ce4, 0x1985, 0x1985, 0x25A1, 0x25A1, 0x30FD, 0x30FE,
+       0x3B56, 0x3B55, 0x447A, 0x447A, 0x4C3B, 0x4C3C, 0x526D, 0x526C,
+       0x56F1, 0x56F1, 0x59B1, 0x59B1, 0x5A9E, 0x5A9D, 0x59B1, 0x59B2,
+       0x56F3, 0x56F2, 0x526D, 0x526D, 0x4C3B, 0x4C3B, 0x447C, 0x447C,
+       0x3B5A, 0x3B59, 0x30FE, 0x30FE, 0x25A5, 0x25A6, 0x1989, 0x198A,
+       0x0CE5, 0x0CE3, 0x0000, 0x0000, 0xF31C, 0xF31C, 0xE677, 0xE676,
+       0xDA5B, 0xDA5B, 0xCF03, 0xCF03, 0xC4AA, 0xC4AA, 0xBB83, 0xBB83,
+       0xB3C5, 0xB3C5, 0xAD94, 0xAD94, 0xA90D, 0xA90E, 0xA64F, 0xA64E,
+       0xA562, 0xA563, 0xA64F, 0xA64F, 0xA910, 0xA90F, 0xAD93, 0xAD94,
+       0xB3C4, 0xB3C4, 0xBB87, 0xBB86, 0xC4AB, 0xC4AB, 0xCF03, 0xCF03,
+       0xDA5B, 0xDA5A, 0xE67B, 0xE67B, 0xF31B, 0xF3AC, 0x0000, 0x0000,
+       0x0CE4, 0x0CE4, 0x1985, 0x1985, 0x25A1, 0x25A1, 0x30FD, 0x30FE,
+       0x3B56, 0x3B55, 0x447A, 0x447A, 0x4C3B, 0x4C3C, 0x526D, 0x526C,
+       0x56F1, 0x56F1, 0x59B1, 0x59B1, 0x5A9E, 0x5A9D, 0x59B1, 0x59B2,
+       0x56F3, 0x56F2, 0x526D, 0x526D, 0x4C3B, 0x4C3B, 0x447C, 0x447C,
+       0x3B5A, 0x3B59, 0x30FE, 0x30FE, 0x25A5, 0x25A6, 0x1989, 0x198A,
+       0x0CE5, 0x0CE3, 0x0000, 0x0000, 0xF31C, 0xF31C, 0xE677, 0xE676,
+       0xDA5B, 0xDA5B, 0xCF03, 0xCF03, 0xC4AA, 0xC4AA, 0xBB83, 0xBB83,
+       0xB3C5, 0xB3C5, 0xAD94, 0xAD94, 0xA90D, 0xA90E, 0xA64F, 0xA64E,
+       0xA562, 0xA563, 0xA64F, 0xA64F, 0xA910, 0xA90F, 0xAD93, 0xAD94,
+       0xB3C4, 0xB3C4, 0xBB87, 0xBB86, 0xC4AB, 0xC4AB, 0xCF03, 0xCF03,
+       0xDA5B, 0xDA5A, 0xE67B, 0xE67B, 0xF31B, 0xF3AC, 0x0000, 0x0000,
+       0x0CE4, 0x0CE4, 0x1985, 0x1985, 0x25A1, 0x25A1, 0x30FD, 0x30FE,
+       0x3B56, 0x3B55, 0x447A, 0x447A, 0x4C3B, 0x4C3C, 0x526D, 0x526C,
+       0x56F1, 0x56F1, 0x59B1, 0x59B1, 0x5A9E, 0x5A9D, 0x59B1, 0x59B2,
+       0x56F3, 0x56F2, 0x526D, 0x526D, 0x4C3B, 0x4C3B, 0x447C, 0x447C,
+       0x3B5A, 0x3B59, 0x30FE, 0x30FE, 0x25A5, 0x25A6, 0x1989, 0x198A,
+       0x0CE5, 0x0CE3, 0x0000, 0x0000, 0xF31C, 0xF31C, 0xE677, 0xE676,
+       0xDA5B, 0xDA5B, 0xCF03, 0xCF03, 0xC4AA, 0xC4AA, 0xBB83, 0xBB83,
+       0xB3C5, 0xB3C5, 0xAD94, 0xAD94, 0xA90D, 0xA90E, 0xA64F, 0xA64E,
+       0xA562, 0xA563, 0xA64F, 0xA64F, 0xA910, 0xA90F, 0xAD93, 0xAD94,
+       0xB3C4, 0xB3C4, 0xBB87, 0xBB86, 0xC4AB, 0xC4AB, 0xCF03, 0xCF03,
+       0xDA5B, 0xDA5A, 0xE67B, 0xE67B, 0xF31B, 0xF3AC, 0x0000, 0x0000
+};
+
+void toneGen(void)
+{
+       int count = 0;
+       int ret = 0;
+       printk(KERN_INFO "TONE GEN TEST :");
+
+       for (count = 0; count < 5000; count++) {
+               int bytes;
+               for (bytes = 0; bytes < sizeof(tone) / 2; bytes++) {
+                       ret = omap_mcbsp_pollwrite(AUDIO_MCBSP, tone[bytes]);
+                       if (ret == -1) {
+                               /* retry */
+                               bytes--;
+                       } else if (ret == -2) {
+                               printk(KERN_INFO "ERROR:bytes=%d\n", bytes);
+                               return;
+                       }
+               }
+       }
+       printk(KERN_INFO "SUCCESS\n");
+}
+
+#endif                         /* End of TONE_GEN */
+
+/*********************************************************************************
+ *
+ * TSC_DUMP_REGISTERS:
+ * This will dump the entire register set of Page 2 tsc2101. 
+ * Useful for major goof ups
+ *
+ ********************************************************************************/
+#ifdef TSC_DUMP_REGISTERS
+static void tsc2101_dumpRegisters(void)
+{
+       int i = 0;
+       u16 data = 0;
+       printk("TSC 2101 Register dump for Page 2 \n");
+       for (i = 0; i < 0x27; i++) {
+               data = audio_tsc2101_read(i);
+               printk(KERN_INFO "Register[%x]=0x%04x\n", i, data);
+
+       }
+}
+#endif                         /* End of #ifdef TSC_DUMP_REGISTERS */
+
+#ifdef PROC_SUPPORT
+static int codec_start(char *buf, char **start, off_t offset, int count,
+                      int *eof, void *data)
+{
+       omap_tsc2101_enable();
+       tsc2101_start();
+       printk("Codec initialization done.\n");
+       return 0;
+}
+static int codec_stop(char *buf, char **start, off_t offset, int count,
+                     int *eof, void *data)
+{
+
+       omap_tsc2101_disable();
+       audio_tsc2101_write(TSC2101_CODEC_POWER_CTRL,
+                           ~(CPC_SP1PWDN | CPC_SP2PWDN | CPC_BASSBC));
+       printk("Codec shutdown.\n");
+       return 0;
+}
+#endif
+
+/*********************************************************************************
+ *
+ * Other misc management, registration etc
+ *
+ ********************************************************************************/
+module_init(audio_tsc2101_init);
+module_exit(audio_tsc2101_exit);
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION
+    ("Glue audio driver for the TI OMAP1610/OMAP1710 TSC2101 codec.");
+MODULE_LICENSE("GPL");
diff --git a/sound/oss/omap-audio.c b/sound/oss/omap-audio.c
new file mode 100644 (file)
index 0000000..84f5445
--- /dev/null
@@ -0,0 +1,1162 @@
+/*
+ * linux/sound/oss/omap-audio.c
+ *
+ * Common audio handling for the OMAP processors
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *
+ * Copyright (C) 2000, 2001 Nicolas Pitre <nico@cam.org>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * History:
+ *
+ * 2004/08/12   Nishanth Menon - Modified to integrate Audio requirements on 1610,1710 platforms
+ *
+ * 2004-11-01   Nishanth Menon - modified to support 16xx and 17xx 
+ *                platform multi channel chaining.
+ *
+ * 2004-11-04   Nishanth Menon - Added support for power management
+ *
+ * 2004-12-17   Nishanth Menon - Provided proper module handling support
+ */
+
+/***************************** INCLUDES ************************************/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/poll.h>
+#include <linux/pm.h>
+#include <linux/errno.h>
+#include <linux/sound.h>
+#include <linux/soundcard.h>
+#include <linux/sysrq.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/completion.h>
+#include <linux/mutex.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+
+#include "omap-audio-dma-intfc.h"
+#include "omap-audio.h"
+
+/***************************** MACROS ************************************/
+
+#undef DEBUG
+//#define DEBUG
+#ifdef DEBUG
+#define DPRINTK  printk
+#define FN_IN printk("[omap_audio.c:[%s] start\n", __FUNCTION__)
+#define FN_OUT(n) printk("[omap_audio.c:[%s] end(%d)\n", __FUNCTION__ , n)
+#else
+#define DPRINTK( x... )
+#define FN_IN
+#define FN_OUT(x)
+#endif
+
+#define OMAP_AUDIO_NAME                "omap-audio"
+#define AUDIO_NBFRAGS_DEFAULT  8
+#define AUDIO_FRAGSIZE_DEFAULT 8192
+
+/* HACK ALERT!: These values will bave to be tuned as this is a trade off b/w
+ * Sampling Rate vs buffer size and delay we are prepared to do before giving up
+ */
+#define MAX_QUEUE_FULL_RETRIES 1000000
+#define QUEUE_WAIT_TIME        10
+
+#define AUDIO_ACTIVE(state)    ((state)->rd_ref || (state)->wr_ref)
+
+#define SPIN_ADDR              (dma_addr_t)0
+#define SPIN_SIZE              2048
+
+/***************************** MODULES SPECIFIC FUNCTION PROTOTYPES ********************/
+
+static int audio_write(struct file *file, const char __user *buffer,
+                      size_t count, loff_t * ppos);
+
+static int audio_read(struct file *file, char __user *buffer, size_t count,
+                     loff_t * ppos);
+
+static int audio_mmap(struct file *file, struct vm_area_struct *vma);
+
+static unsigned int audio_poll(struct file *file,
+                              struct poll_table_struct *wait);
+
+static loff_t audio_llseek(struct file *file, loff_t offset, int origin);
+
+static int audio_ioctl(struct inode *inode, struct file *file, uint cmd,
+                      ulong arg);
+
+static int audio_open(struct inode *inode, struct file *file);
+
+static int audio_release(struct inode *inode, struct file *file);
+
+static int audio_probe(struct platform_device *pdev);
+
+static int audio_remove(struct platform_device *pdev);
+
+static void audio_shutdown(struct platform_device *pdev);
+
+static int audio_suspend(struct platform_device *pdev, pm_message_t mesg);
+
+static int audio_resume(struct platform_device *pdev);
+
+static void audio_free(struct device *dev);
+
+/***************************** Data Structures **********************************/
+
+/*
+ * The function pointer set to be registered by the codec.
+ */
+static audio_state_t audio_state = { NULL };
+
+/* DMA Call back function */
+static dma_callback_t audio_dma_callback = NULL;
+
+/* File Ops structure */
+static struct file_operations omap_audio_fops = {
+       .open           = audio_open,
+       .release        = audio_release,
+       .write          = audio_write,
+       .read           = audio_read,
+       .mmap           = audio_mmap,
+       .poll           = audio_poll,
+       .ioctl          = audio_ioctl,
+       .llseek         = audio_llseek,
+       .owner          = THIS_MODULE
+};
+
+/* Driver information */
+static struct platform_driver omap_audio_driver = {
+       .probe          = audio_probe,
+       .remove         = audio_remove,
+       .suspend        = audio_suspend,
+       .shutdown       = audio_shutdown,
+       .resume         = audio_resume,
+       .driver         = {
+               .name   = OMAP_AUDIO_NAME,
+       },
+};
+
+/* Device Information */
+static struct platform_device omap_audio_device = {
+       .name = OMAP_AUDIO_NAME,
+       .dev = {
+               .driver_data = &audio_state,
+               .release = audio_free,
+               },
+       .id = 0,
+};
+
+/***************************** GLOBAL FUNCTIONs **********************************/
+
+/* Power Management Functions for Linux Device Model  */
+/* DEBUG PUPOSES ONLY! */
+#ifdef CONFIG_PM
+//#undef CONFIG_PM
+#endif
+
+#ifdef CONFIG_PM
+/*********************************************************************************
+ *
+ * audio_ldm_suspend(): Suspend operation
+ *
+ *********************************************************************************/
+static int audio_ldm_suspend(void *data)
+{
+       audio_state_t *state = data;
+
+       FN_IN;
+
+       /* 
+        * Reject the suspend request if we are already actively transmitting data 
+        * Rationale: We dont want to be suspended while in the middle of a call!
+        */
+       if (AUDIO_ACTIVE(state) && state->hw_init) {
+               printk(KERN_ERR "Audio device Active, Cannot Suspend");
+               return -EPERM;
+#if 0
+               /* NOTE:
+                * This Piece of code is commented out in hope
+                * That one day we would need to suspend the device while 
+                * audio operations are in progress and resume the operations
+                * once the resume is done.
+                * This is just a sample implementation of how it could be done.
+                * Currently NOT SUPPORTED
+                */
+               audio_stream_t *is = state->input_stream;
+               audio_stream_t *os = state->output_stream;
+               int stopstate;
+               if (is && is->buffers) {
+                       printk("IS Suspend\n");
+                       stopstate = is->stopped;
+                       audio_stop_dma(is);
+                       DMA_CLEAR(is);
+                       is->dma_spinref = 0;
+                       is->stopped = stopstate;
+               }
+               if (os && os->buffers) {
+                       printk("OS Suspend\n");
+                       stopstate = os->stopped;
+                       audio_stop_dma(os);
+                       DMA_CLEAR(os);
+                       os->dma_spinref = 0;
+                       os->stopped = stopstate;
+               }
+#endif
+       }
+
+       FN_OUT(0);
+       return 0;
+}
+
+/*********************************************************************************
+ *
+ * audio_ldm_resume(): Resume Operations
+ *
+ *********************************************************************************/
+static int audio_ldm_resume(void *data)
+{
+       audio_state_t *state = data;
+
+       FN_IN;
+       if (AUDIO_ACTIVE(state) && state->hw_init) {
+               /* Should never occur - since we never suspend with active state */
+               BUG();
+               return -EPERM;
+#if 0
+               /* NOTE:
+                * This Piece of code is commented out in hope
+                * That one day we would need to suspend the device while 
+                * audio operations are in progress and resume the operations
+                * once the resume is done.
+                * This is just a sample implementation of how it could be done.
+                * Currently NOT SUPPORTED
+                */
+               audio_stream_t *is = state->input_stream;
+               audio_stream_t *os = state->output_stream;
+               if (os && os->buffers) {
+                       printk("OS Resume\n");
+                       audio_reset(os);
+                       audio_process_dma(os);
+               }
+               if (is && is->buffers) {
+                       printk("IS Resume\n");
+                       audio_reset(is);
+                       audio_process_dma(is);
+               }
+#endif
+       }
+       FN_OUT(0);
+       return 0;
+}
+#endif                         /* End of #ifdef CONFIG_PM */
+
+/*********************************************************************************
+ *
+ * audio_free(): The Audio driver release function
+ * This is a dummy function required by the platform driver
+ *
+ *********************************************************************************/
+static void audio_free(struct device *dev)
+{
+       /* Nothing to Release! */
+}
+
+/*********************************************************************************
+ *
+ * audio_probe(): The Audio driver probe function
+ * WARNING!!!!  : It is expected that the codec would have registered with us by now
+ *
+ *********************************************************************************/
+static int audio_probe(struct platform_device *pdev)
+{
+       int ret;
+       FN_IN;
+       if (!audio_state.hw_probe) {
+               printk(KERN_ERR "Probe Function Not Registered\n");
+               return -ENODEV;
+       }
+       ret = audio_state.hw_probe();
+       FN_OUT(ret);
+       return ret;
+}
+
+/*********************************************************************************
+ *
+ * audio_remove() Function to handle removal operations
+ *
+ *********************************************************************************/
+static int audio_remove(struct platform_device *pdev)
+{
+       FN_IN;
+       if (audio_state.hw_remove) {
+               audio_state.hw_remove();
+       }
+       FN_OUT(0);
+       return 0;
+}
+
+/*********************************************************************************
+ *
+ * audio_shutdown(): Function to handle shutdown operations
+ *
+ *********************************************************************************/
+static void audio_shutdown(struct platform_device *pdev)
+{
+       FN_IN;
+       if (audio_state.hw_cleanup) {
+               audio_state.hw_cleanup();
+       }
+       FN_OUT(0);
+       return;
+}
+
+/*********************************************************************************
+ *
+ * audio_suspend(): Function to handle suspend operations 
+ *
+ *********************************************************************************/
+static int audio_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+       int ret = 0;
+
+#ifdef CONFIG_PM
+       void *data = pdev->dev.driver_data;
+       FN_IN;
+       if (audio_state.hw_suspend) {
+               ret = audio_ldm_suspend(data);
+               if (ret == 0)
+                       ret = audio_state.hw_suspend();
+       }
+       if (ret) {
+               printk(KERN_INFO "Audio Suspend Failed \n");
+       } else {
+               printk(KERN_INFO "Audio Suspend Success \n");
+       }
+#endif                         /* CONFIG_PM */
+
+       FN_OUT(ret);
+       return ret;
+}
+
+/*********************************************************************************
+ *
+ * audio_resume(): Function to handle resume operations
+ *
+ *********************************************************************************/
+static int audio_resume(struct platform_device *pdev)
+{
+       int ret = 0;
+
+#ifdef CONFIG_PM
+       void *data = pdev->dev.driver_data;
+       FN_IN;
+       if (audio_state.hw_resume) {
+               ret = audio_ldm_resume(data);
+               if (ret == 0)
+                       ret = audio_state.hw_resume();
+       }
+       if (ret) {
+               printk(KERN_INFO " Audio Resume Failed \n");
+       } else {
+               printk(KERN_INFO " Audio Resume Success \n");
+       }
+#endif                         /* CONFIG_PM */
+
+       FN_OUT(ret);
+       return ret;
+}
+
+/*********************************************************************************
+ *
+ * audio_get_fops(): Return the fops required to get the function pointers of 
+ *                   OMAP Audio Driver
+ *
+ *********************************************************************************/
+struct file_operations *audio_get_fops(void)
+{
+       FN_IN;
+       FN_OUT(0);
+       return &omap_audio_fops;
+}
+
+/*********************************************************************************
+ *
+ * audio_register_codec(): Register a Codec fn points using this function
+ * WARNING!!!!!          : Codecs should ensure that they do so! no sanity checks
+ *                         during runtime is done due to obvious performance 
+ *                         penalties.
+ *
+ *********************************************************************************/
+int audio_register_codec(audio_state_t * codec_state)
+{
+       int ret;
+       FN_IN;
+
+       /* We dont handle multiple codecs now */
+       if (audio_state.hw_init) {
+               printk(KERN_ERR " Codec Already registered\n");
+               return -EPERM;
+       }
+
+       /* Grab the dma Callback */
+       audio_dma_callback = audio_get_dma_callback();
+       if (!audio_dma_callback) {
+               printk(KERN_ERR "Unable to get call back function\n");
+               return -EPERM;
+       }
+
+       /* Sanity checks */
+       if (!codec_state) {
+               printk(KERN_ERR "NULL ARGUMENT!\n");
+               return -EPERM;
+       }
+
+       if (!codec_state->hw_probe || !codec_state->hw_init
+           || !codec_state->hw_shutdown || !codec_state->client_ioctl) {
+               printk(KERN_ERR
+                      "Required Fn Entry point Missing probe=%p init=%p,down=%p,ioctl=%p!\n",
+                      codec_state->hw_probe, codec_state->hw_init,
+                      codec_state->hw_shutdown, codec_state->client_ioctl);
+               return -EPERM;
+       }
+
+       memcpy(&audio_state, codec_state, sizeof(audio_state_t));
+       mutex_init(&audio_state.mutex);
+
+       ret = platform_device_register(&omap_audio_device);
+       if (ret != 0) {
+               printk(KERN_ERR "Platform dev_register failed =%d\n", ret);
+               ret = -ENODEV;
+               goto register_out;
+       }
+
+       ret = platform_driver_register(&omap_audio_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Device Register failed =%d\n", ret);
+               ret = -ENODEV;
+               platform_device_unregister(&omap_audio_device);
+               goto register_out;
+       }
+
+      register_out:
+
+       FN_OUT(ret);
+       return ret;
+}
+
+/*********************************************************************************
+ *
+ * audio_unregister_codec(): Un-Register a Codec using this function
+ *
+ *********************************************************************************/
+int audio_unregister_codec(audio_state_t * codec_state)
+{
+       FN_IN;
+
+       /* We dont handle multiple codecs now */
+       if (!audio_state.hw_init) {
+               printk(KERN_ERR " No Codec registered\n");
+               return -EPERM;
+       }
+       /* Security check */
+       if (audio_state.hw_init != codec_state->hw_init) {
+               printk(KERN_ERR
+                      " Attempt to unregister codec which was not registered with us\n");
+               return -EPERM;
+       }
+
+       platform_driver_unregister(&omap_audio_driver);
+       platform_device_unregister(&omap_audio_device);
+
+       memset(&audio_state, 0, sizeof(audio_state_t));
+
+       FN_OUT(0);
+       return 0;
+}
+
+/***************************** MODULES SPECIFIC FUNCTION *************************/
+
+/*********************************************************************************
+ *
+ * audio_write(): Exposed to write() call
+ *
+ *********************************************************************************/
+static int
+audio_write(struct file *file, const char __user *buffer,
+               size_t count, loff_t * ppos)
+{
+       const char __user *buffer0 = buffer;
+       audio_state_t *state = file->private_data;
+       audio_stream_t *s = state->output_stream;
+       int chunksize, ret = 0;
+
+       DPRINTK("audio_write: count=%d\n", count);
+       if (*ppos != file->f_pos) {
+               printk("FPOS not ppos ppos=0x%x fpos =0x%x\n", (u32) * ppos,
+                      (u32) file->f_pos);
+               return -ESPIPE;
+       }
+       if (s->mapped) {
+               printk("s already mapped\n");
+               return -ENXIO;
+       }
+       if (!s->buffers && audio_setup_buf(s)) {
+               printk("NO MEMORY\n");
+               return -ENOMEM;
+       }
+
+       while (count > 0) {
+               audio_buf_t *b = &s->buffers[s->usr_head];
+
+               /* Wait for a buffer to become free */
+               if (file->f_flags & O_NONBLOCK) {
+                       ret = -EAGAIN;
+                       if (!s->wfc.done)
+                               break;
+               }
+               ret = -ERESTARTSYS;
+               if (wait_for_completion_interruptible(&s->wfc))
+                       break;
+
+               /* Feed the current buffer */
+               chunksize = s->fragsize - b->offset;
+               if (chunksize > count)
+                       chunksize = count;
+               DPRINTK("write %d to %d\n", chunksize, s->usr_head);
+               if (copy_from_user(b->data + b->offset, buffer, chunksize)) {
+                       printk(KERN_ERR "Audio: CopyFrom User failed \n");
+                       complete(&s->wfc);
+                       return -EFAULT;
+               }
+
+               buffer += chunksize;
+               count -= chunksize;
+               b->offset += chunksize;
+
+               if (b->offset < s->fragsize) {
+                       complete(&s->wfc);
+                       break;
+               }
+
+               /* Update pointers and send current fragment to DMA */
+               b->offset = 0;
+               if (++s->usr_head >= s->nbfrags)
+                       s->usr_head = 0;
+               /* Add the num of frags pending */
+               s->pending_frags++;
+               s->active = 1;
+
+               audio_process_dma(s);
+
+       }
+
+       if ((buffer - buffer0))
+               ret = buffer - buffer0;
+       DPRINTK("audio_write: return=%d\n", ret);
+       return ret;
+}
+
+/*********************************************************************************
+ *
+ * audio_read(): Exposed as read() function
+ *
+ *********************************************************************************/
+static int
+audio_read(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
+{
+       char __user *buffer0 = buffer;
+       audio_state_t *state = file->private_data;
+       audio_stream_t *s = state->input_stream;
+       int chunksize, ret = 0;
+       unsigned long flags;
+
+       DPRINTK("audio_read: count=%d\n", count);
+
+       if (*ppos != file->f_pos) {
+               printk("AudioRead - FPOS not ppos ppos=0x%x fpos =0x%x\n",
+                      (u32) * ppos, (u32) file->f_pos);
+               return -ESPIPE;
+       }
+       if (s->mapped) {
+               printk("AudioRead - s already mapped\n");
+               return -ENXIO;
+       }
+
+       if (!s->active) {
+               if (!s->buffers && audio_setup_buf(s)) {
+                       printk("AudioRead - No Memory\n");
+                       return -ENOMEM;
+               }
+               audio_prime_rx(state);
+       }
+
+       while (count > 0) {
+               audio_buf_t *b = &s->buffers[s->usr_head];
+
+               /* Wait for a buffer to become full */
+               if (file->f_flags & O_NONBLOCK) {
+                       ret = -EAGAIN;
+                       if (!s->wfc.done)
+                               break;
+               }
+               ret = -ERESTARTSYS;
+               if (wait_for_completion_interruptible(&s->wfc))
+                       break;
+
+               /* Grab data from the current buffer */
+               chunksize = s->fragsize - b->offset;
+               if (chunksize > count)
+                       chunksize = count;
+               DPRINTK("read %d from %d\n", chunksize, s->usr_head);
+               if (copy_to_user(buffer, b->data + b->offset, chunksize)) {
+                       complete(&s->wfc);
+                       return -EFAULT;
+               }
+               buffer += chunksize;
+               count -= chunksize;
+               b->offset += chunksize;
+               if (b->offset < s->fragsize) {
+                       complete(&s->wfc);
+                       break;
+               }
+
+               /* Update pointers and return current fragment to DMA */
+               local_irq_save(flags);
+               b->offset = 0;
+               if (++s->usr_head >= s->nbfrags)
+                       s->usr_head = 0;
+
+               s->pending_frags++;
+               local_irq_restore(flags);
+               audio_process_dma(s);
+
+       }
+
+       if ((buffer - buffer0))
+               ret = buffer - buffer0;
+       DPRINTK("audio_read: return=%d\n", ret);
+       return ret;
+}
+
+/*********************************************************************************
+ *
+ * audio_mmap(): Exposed as mmap Function
+ * !!WARNING: Still under development
+ *
+ *********************************************************************************/
+static int audio_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       audio_state_t *state = file->private_data;
+       audio_stream_t *s;
+       unsigned long size, vma_addr;
+       int i, ret;
+
+       FN_IN;
+       if (vma->vm_pgoff != 0)
+               return -EINVAL;
+
+       if (vma->vm_flags & VM_WRITE) {
+               if (!state->wr_ref)
+                       return -EINVAL;;
+               s = state->output_stream;
+       } else if (vma->vm_flags & VM_READ) {
+               if (!state->rd_ref)
+                       return -EINVAL;
+               s = state->input_stream;
+       } else
+               return -EINVAL;
+
+       if (s->mapped)
+               return -EINVAL;
+       size = vma->vm_end - vma->vm_start;
+       if (size != s->fragsize * s->nbfrags)
+               return -EINVAL;
+       if (!s->buffers && audio_setup_buf(s))
+               return -ENOMEM;
+       vma_addr = vma->vm_start;
+       for (i = 0; i < s->nbfrags; i++) {
+               audio_buf_t *buf = &s->buffers[i];
+               if (!buf->master)
+                       continue;
+               ret =
+                   remap_pfn_range(vma, vma_addr, buf->dma_addr >> PAGE_SHIFT,
+                                   buf->master, vma->vm_page_prot);
+               if (ret)
+                       return ret;
+               vma_addr += buf->master;
+       }
+       s->mapped = 1;
+
+       FN_OUT(0);
+       return 0;
+}
+
+/*********************************************************************************
+ *
+ * audio_poll(): Exposed as poll function
+ *
+ *********************************************************************************/
+static unsigned int
+audio_poll(struct file *file, struct poll_table_struct *wait)
+{
+       audio_state_t *state = file->private_data;
+       audio_stream_t *is = state->input_stream;
+       audio_stream_t *os = state->output_stream;
+       unsigned int mask = 0;
+
+       DPRINTK("audio_poll(): mode=%s%s\n",
+               (file->f_mode & FMODE_READ) ? "r" : "",
+               (file->f_mode & FMODE_WRITE) ? "w" : "");
+
+       if (file->f_mode & FMODE_READ) {
+               /* Start audio input if not already active */
+               if (!is->active) {
+                       if (!is->buffers && audio_setup_buf(is))
+                               return -ENOMEM;
+                       audio_prime_rx(state);
+               }
+               poll_wait(file, &is->wq, wait);
+       }
+
+       if (file->f_mode & FMODE_WRITE) {
+               if (!os->buffers && audio_setup_buf(os))
+                       return -ENOMEM;
+               poll_wait(file, &os->wq, wait);
+       }
+
+       if (file->f_mode & FMODE_READ)
+               if ((is->mapped && is->bytecount > 0) ||
+                   (!is->mapped && is->wfc.done > 0))
+                       mask |= POLLIN | POLLRDNORM;
+
+       if (file->f_mode & FMODE_WRITE)
+               if ((os->mapped && os->bytecount > 0) ||
+                   (!os->mapped && os->wfc.done > 0))
+                       mask |= POLLOUT | POLLWRNORM;
+
+       DPRINTK("audio_poll() returned mask of %s%s\n",
+               (mask & POLLIN) ? "r" : "", (mask & POLLOUT) ? "w" : "");
+
+       FN_OUT(mask);
+       return mask;
+}
+
+/*********************************************************************************
+ *
+ * audio_llseek(): Exposed as lseek() function.
+ *
+ *********************************************************************************/
+static loff_t audio_llseek(struct file *file, loff_t offset, int origin)
+{
+       FN_IN;
+       FN_OUT(0);
+       return -ESPIPE;
+}
+
+/*********************************************************************************
+ *
+ * audio_ioctl(): Handles generic ioctls. If there is a request for something this
+ * fn cannot handle, its then given to client specific ioctl routine, that will take
+ * up platform specific requests
+ *
+ *********************************************************************************/
+static int
+audio_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
+{
+       audio_state_t *state = file->private_data;
+       audio_stream_t *os = state->output_stream;
+       audio_stream_t *is = state->input_stream;
+       long val;
+
+       DPRINTK(__FILE__ " audio_ioctl 0x%08x\n", cmd);
+
+       /* dispatch based on command */
+       switch (cmd) {
+       case OSS_GETVERSION:
+               return put_user(SOUND_VERSION, (int __user *)arg);
+
+       case SNDCTL_DSP_GETBLKSIZE:
+               if (file->f_mode & FMODE_WRITE)
+                       return put_user(os->fragsize, (int __user *)arg);
+               else
+                       return put_user(is->fragsize, (int __user *)arg);
+
+       case SNDCTL_DSP_GETCAPS:
+               val = DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP;
+               if (is && os)
+                       val |= DSP_CAP_DUPLEX;
+               FN_OUT(1);
+               return put_user(val, (int __user *)arg);
+
+       case SNDCTL_DSP_SETFRAGMENT:
+               if (get_user(val, (long __user *)arg)) {
+                       FN_OUT(2);
+                       return -EFAULT;
+               }
+               if (file->f_mode & FMODE_READ) {
+                       int ret = audio_set_fragments(is, val);
+                       if (ret < 0) {
+                               FN_OUT(3);
+                               return ret;
+                       }
+                       ret = put_user(ret, (int __user *)arg);
+                       if (ret) {
+                               FN_OUT(4);
+                               return ret;
+                       }
+               }
+               if (file->f_mode & FMODE_WRITE) {
+                       int ret = audio_set_fragments(os, val);
+                       if (ret < 0) {
+                               FN_OUT(5);
+                               return ret;
+                       }
+                       ret = put_user(ret, (int __user *)arg);
+                       if (ret) {
+                               FN_OUT(6);
+                               return ret;
+                       }
+               }
+               FN_OUT(7);
+               return 0;
+
+       case SNDCTL_DSP_SYNC:
+               FN_OUT(8);
+               return audio_sync(file);
+
+       case SNDCTL_DSP_SETDUPLEX:
+               FN_OUT(9);
+               return 0;
+
+       case SNDCTL_DSP_POST:
+               FN_OUT(10);
+               return 0;
+
+       case SNDCTL_DSP_GETTRIGGER:
+               val = 0;
+               if (file->f_mode & FMODE_READ && is->active && !is->stopped)
+                       val |= PCM_ENABLE_INPUT;
+               if (file->f_mode & FMODE_WRITE && os->active && !os->stopped)
+                       val |= PCM_ENABLE_OUTPUT;
+               FN_OUT(11);
+               return put_user(val, (int __user *)arg);
+
+       case SNDCTL_DSP_SETTRIGGER:
+               if (get_user(val, (int __user *)arg)) {
+                       FN_OUT(12);
+                       return -EFAULT;
+               }
+               if (file->f_mode & FMODE_READ) {
+                       if (val & PCM_ENABLE_INPUT) {
+                               unsigned long flags;
+                               if (!is->active) {
+                                       if (!is->buffers && audio_setup_buf(is)) {
+                                               FN_OUT(13);
+                                               return -ENOMEM;
+                                       }
+                                       audio_prime_rx(state);
+                               }
+                               local_irq_save(flags);
+                               is->stopped = 0;
+                               local_irq_restore(flags);
+                               audio_process_dma(is);
+
+                       } else {
+                               audio_stop_dma(is);
+                       }
+               }
+               if (file->f_mode & FMODE_WRITE) {
+                       if (val & PCM_ENABLE_OUTPUT) {
+                               unsigned long flags;
+                               if (!os->buffers && audio_setup_buf(os)) {
+                                       FN_OUT(14);
+                                       return -ENOMEM;
+                               }
+                               local_irq_save(flags);
+                               if (os->mapped && !os->pending_frags) {
+                                       os->pending_frags = os->nbfrags;
+                                       init_completion(&os->wfc);
+                                       os->wfc.done = 0;
+                                       os->active = 1;
+                               }
+                               os->stopped = 0;
+                               local_irq_restore(flags);
+                               audio_process_dma(os);
+
+                       } else {
+                               audio_stop_dma(os);
+                       }
+               }
+               FN_OUT(15);
+               return 0;
+
+       case SNDCTL_DSP_GETOPTR:
+       case SNDCTL_DSP_GETIPTR:
+               {
+                       count_info inf = { 0, };
+                       audio_stream_t *s =
+                           (cmd == SNDCTL_DSP_GETOPTR) ? os : is;
+                       int bytecount, offset;
+                       unsigned long flags;
+
+                       if ((s == is && !(file->f_mode & FMODE_READ)) ||
+                           (s == os && !(file->f_mode & FMODE_WRITE))) {
+                               FN_OUT(16);
+                               return -EINVAL;
+                       }
+                       if (s->active) {
+                               local_irq_save(flags);
+                               offset = audio_get_dma_pos(s);
+                               inf.ptr = s->dma_tail * s->fragsize + offset;
+                               bytecount = s->bytecount + offset;
+                               s->bytecount = -offset;
+                               inf.blocks = s->fragcount;
+                               s->fragcount = 0;
+                               local_irq_restore(flags);
+                               if (bytecount < 0)
+                                       bytecount = 0;
+                               inf.bytes = bytecount;
+                       }
+                       FN_OUT(17);
+                       return copy_to_user((void __user *)arg, &inf, sizeof(inf));
+               }
+
+       case SNDCTL_DSP_GETOSPACE:
+       case SNDCTL_DSP_GETISPACE:
+               {
+                       audio_buf_info inf = { 0, };
+                       audio_stream_t *s =
+                           (cmd == SNDCTL_DSP_GETOSPACE) ? os : is;
+
+                       if ((s == is && !(file->f_mode & FMODE_READ)) ||
+                           (s == os && !(file->f_mode & FMODE_WRITE))) {
+                               FN_OUT(18);
+                               return -EINVAL;
+                       }
+                       if (!s->buffers && audio_setup_buf(s)) {
+                               FN_OUT(19);
+                               return -ENOMEM;
+                       }
+                       inf.bytes = s->wfc.done * s->fragsize;
+
+                       inf.fragments = inf.bytes / s->fragsize;
+                       inf.fragsize = s->fragsize;
+                       inf.fragstotal = s->nbfrags;
+                       FN_OUT(20);
+                       return copy_to_user((void __user *)arg, &inf, sizeof(inf));
+               }
+
+       case SNDCTL_DSP_NONBLOCK:
+               file->f_flags |= O_NONBLOCK;
+               FN_OUT(21);
+               return 0;
+
+       case SNDCTL_DSP_RESET:
+               if (file->f_mode & FMODE_READ) {
+                       audio_reset(is);
+                       if (state->need_tx_for_rx) {
+                               unsigned long flags;
+                               local_irq_save(flags);
+                               os->spin_idle = 0;
+                               local_irq_restore(flags);
+                       }
+               }
+               if (file->f_mode & FMODE_WRITE) {
+                       audio_reset(os);
+               }
+               FN_OUT(22);
+               return 0;
+
+       default:
+               /*
+                * Let the client of this module handle the
+                * non generic ioctls
+                */
+               FN_OUT(23);
+               return state->client_ioctl(inode, file, cmd, arg);
+       }
+
+       FN_OUT(0);
+       return 0;
+}
+
+/*********************************************************************************
+ *
+ * audio_open(): Exposed as open() function
+ *
+ *********************************************************************************/
+static int audio_open(struct inode *inode, struct file *file)
+{
+       audio_state_t *state = (&audio_state);
+       audio_stream_t *os = state->output_stream;
+       audio_stream_t *is = state->input_stream;
+       int err, need_tx_dma;
+       static unsigned char tsc2101_init_flag = 0;
+
+       FN_IN;
+
+       /* Lock the module */
+       if (!try_module_get(THIS_MODULE)) {
+               printk(KERN_CRIT "Failed to get module\n");
+               return -ESTALE;
+       }
+       /* Lock the codec module */
+       if (!try_module_get(state->owner)) {
+               printk(KERN_CRIT "Failed to get codec module\n");
+               module_put(THIS_MODULE);
+               return -ESTALE;
+       }
+
+       mutex_lock(&state->mutex);
+
+       /* access control */
+       err = -ENODEV;
+       if ((file->f_mode & FMODE_WRITE) && !os)
+               goto out;
+       if ((file->f_mode & FMODE_READ) && !is)
+               goto out;
+       err = -EBUSY;
+       if ((file->f_mode & FMODE_WRITE) && state->wr_ref)
+               goto out;
+       if ((file->f_mode & FMODE_READ) && state->rd_ref)
+               goto out;
+       err = -EINVAL;
+       if ((file->f_mode & FMODE_READ) && state->need_tx_for_rx && !os)
+               goto out;
+
+       /* request DMA channels */
+       need_tx_dma = ((file->f_mode & FMODE_WRITE) ||
+                      ((file->f_mode & FMODE_READ) && state->need_tx_for_rx));
+       if (state->wr_ref || (state->rd_ref && state->need_tx_for_rx))
+               need_tx_dma = 0;
+       if (need_tx_dma) {
+               DMA_REQUEST(err, os, audio_dma_callback);
+               if (err < 0)
+                       goto out;
+       }
+       if (file->f_mode & FMODE_READ) {
+               DMA_REQUEST(err, is, audio_dma_callback);
+               if (err < 0) {
+                       if (need_tx_dma)
+                               DMA_FREE(os);
+                       goto out;
+               }
+       }
+
+       /* now complete initialisation */
+       if (!AUDIO_ACTIVE(state)) {
+               if (state->hw_init && !tsc2101_init_flag) {
+                       state->hw_init(state->data);
+                       tsc2101_init_flag = 0;
+
+               }
+
+       }
+
+       if ((file->f_mode & FMODE_WRITE)) {
+               state->wr_ref = 1;
+               audio_reset(os);
+               os->fragsize = AUDIO_FRAGSIZE_DEFAULT;
+               os->nbfrags = AUDIO_NBFRAGS_DEFAULT;
+               os->mapped = 0;
+               init_waitqueue_head(&os->wq);
+       }
+
+       if (file->f_mode & FMODE_READ) {
+               state->rd_ref = 1;
+               audio_reset(is);
+               is->fragsize = AUDIO_FRAGSIZE_DEFAULT;
+               is->nbfrags = AUDIO_NBFRAGS_DEFAULT;
+               is->mapped = 0;
+               init_waitqueue_head(&is->wq);
+       }
+
+       file->private_data = state;
+       err = 0;
+
+      out:
+       mutex_unlock(&state->mutex);
+       if (err) {
+               module_put(state->owner);
+               module_put(THIS_MODULE);
+       }
+       FN_OUT(err);
+       return err;
+}
+
+/*********************************************************************************
+ *
+ * audio_release(): Exposed as release function()
+ *
+ *********************************************************************************/
+static int audio_release(struct inode *inode, struct file *file)
+{
+       audio_state_t *state = file->private_data;
+       audio_stream_t *os = state->output_stream;
+       audio_stream_t *is = state->input_stream;
+
+       FN_IN;
+
+       mutex_lock(&state->mutex);
+
+       if (file->f_mode & FMODE_READ) {
+               audio_discard_buf(is);
+               DMA_FREE(is);
+               is->dma_spinref = 0;
+               if (state->need_tx_for_rx) {
+                       os->spin_idle = 0;
+                       if (!state->wr_ref) {
+                               DMA_FREE(os);
+                               os->dma_spinref = 0;
+                       }
+               }
+               state->rd_ref = 0;
+       }
+
+       if (file->f_mode & FMODE_WRITE) {
+               audio_sync(file);
+               audio_discard_buf(os);
+               if (!state->need_tx_for_rx || !state->rd_ref) {
+                       DMA_FREE(os);
+                       os->dma_spinref = 0;
+               }
+               state->wr_ref = 0;
+       }
+
+       if (!AUDIO_ACTIVE(state)) {
+               if (state->hw_shutdown)
+                       state->hw_shutdown(state->data);
+       }
+
+       mutex_unlock(&state->mutex);
+
+       module_put(state->owner);
+       module_put(THIS_MODULE);
+
+       FN_OUT(0);
+       return 0;
+}
+
+EXPORT_SYMBOL(audio_register_codec);
+EXPORT_SYMBOL(audio_unregister_codec);
+EXPORT_SYMBOL(audio_get_fops);
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("Common audio handling for OMAP processors");
+MODULE_LICENSE("GPL");
diff --git a/sound/oss/omap-audio.h b/sound/oss/omap-audio.h
new file mode 100644 (file)
index 0000000..c039dee
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * linux/sound/oss/omap-audio.h
+ *
+ * Common audio handling for the OMAP processors
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *
+ * Copyright (C) 2000, 2001 Nicolas Pitre <nico@cam.org>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *  History
+ *  -------
+ *  2004/08/12 Nishanth Menon - Modified to integrate Audio requirements on 1610,1710 platforms
+ *
+ *  2004/04/04 Nishanth menon - Added hooks for power management
+ *
+ *  2005/12/10 Dirk Behme     - Added L/R Channel Interchange fix as proposed by Ajaya Babu
+ */
+
+#ifndef __OMAP_AUDIO_H
+#define __OMAP_AUDIO_H
+
+/* Requires dma.h */
+#include <asm/arch/dma.h>
+
+/*
+ * Buffer Management
+ */
+typedef struct {
+       int offset;             /* current offset */
+       char *data;             /* points to actual buffer */
+       dma_addr_t dma_addr;    /* physical buffer address */
+       int dma_ref;            /* DMA refcount */
+       int master;             /* owner for buffer allocation, contain size when true */
+} audio_buf_t;
+
+/*
+ * Structure describing the data stream related information
+ */
+typedef struct {
+       char *id;               /* identification string */
+       audio_buf_t *buffers;   /* pointer to audio buffer structures */
+       u_int usr_head;         /* user fragment index */
+       u_int dma_head;         /* DMA fragment index to go */
+       u_int dma_tail;         /* DMA fragment index to complete */
+       u_int fragsize;         /* fragment i.e. buffer size */
+       u_int nbfrags;          /* nbr of fragments i.e. buffers */
+       u_int pending_frags;    /* Fragments sent to DMA */
+       int dma_dev;            /* device identifier for DMA */
+
+#ifdef OMAP_DMA_CHAINING_SUPPORT
+       lch_chain *dma_chain;
+       dma_regs_t *dma_regs;   /* points to our DMA registers */
+#else
+       char started;           /* to store if the chain was started or not */
+       int dma_q_head;         /* DMA Channel Q Head */
+       int dma_q_tail;         /* DMA Channel Q Tail */
+       char dma_q_count;       /* DMA Channel Q Count */
+       char in_use;            /*  Is this is use? */
+       int *lch;               /*  Chain of channels this stream is linked to */
+#endif
+       int input_or_output;    /* Direction of this data stream */
+       int bytecount;          /* nbr of processed bytes */
+       int fragcount;          /* nbr of fragment transitions */
+       struct completion wfc;  /* wait for "nbfrags" fragment completion */
+       wait_queue_head_t wq;   /* for poll */
+       int dma_spinref;        /* DMA is spinning */
+       unsigned mapped:1;      /* mmap()'ed buffers */
+       unsigned active:1;      /* actually in progress */
+       unsigned stopped:1;     /* might be active but stopped */
+       unsigned spin_idle:1;   /* have DMA spin on zeros when idle */
+       unsigned linked:1;      /* dma channels linked */
+       int (*hw_start)(void);  /* interface to start HW interface, e.g. McBSP */
+       int (*hw_stop)(void);   /* interface to stop HW interface, e.g. McBSP */
+} audio_stream_t;
+
+/*
+ * State structure for one instance
+ */
+typedef struct {
+       struct module *owner;   /* Codec module ID */
+       audio_stream_t *output_stream;
+       audio_stream_t *input_stream;
+       unsigned rd_ref:1;      /* open reference for recording */
+       unsigned wr_ref:1;      /* open reference for playback */
+       unsigned need_tx_for_rx:1; /* if data must be sent while receiving */
+       void *data;
+       void (*hw_init) (void *);
+       void (*hw_shutdown) (void *);
+       int (*client_ioctl) (struct inode *, struct file *, uint, ulong);
+       int (*hw_probe) (void);
+       void (*hw_remove) (void);
+       void (*hw_cleanup) (void);
+       int (*hw_suspend) (void);
+       int (*hw_resume) (void);
+       struct pm_dev *pm_dev;
+       struct mutex mutex;     /* to protect against races in attach() */
+} audio_state_t;
+
+#ifdef AUDIO_PM
+void audio_ldm_suspend(void *data);
+
+void audio_ldm_resume(void *data);
+
+#endif
+
+/* Register a Codec using this function */
+extern int audio_register_codec(audio_state_t * codec_state);
+/* Un-Register a Codec using this function */
+extern int audio_unregister_codec(audio_state_t * codec_state);
+/* Function to provide fops of omap audio driver */
+extern struct file_operations *audio_get_fops(void);
+/* Function to initialize the device info for audio driver */
+extern int audio_dev_init(void);
+/* Function to un-initialize the device info for audio driver */
+void audio_dev_uninit(void);
+
+#endif                         /* End of #ifndef __OMAP_AUDIO_H */